diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b81d0cd..c77e2ef 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -4,6 +4,9 @@ on: push: branches: - master + pull_request: + branches: + - master release: types: [published] issue_comment: @@ -50,6 +53,33 @@ jobs: if: always() run: docker compose -p "ci-${{ github.run_id }}" -f docker-compose.yml down -v + build-check: + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + strategy: + matrix: + include: + - component: backend + dockerfile: backend.Dockerfile + - component: frontend + dockerfile: frontend.Dockerfile + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build Docker image (${{ matrix.component }}) + uses: docker/build-push-action@v6 + with: + context: . + file: ${{ matrix.dockerfile }} + push: false + build-args: | + GIT_COMMIT=${{ github.sha }} + GIT_BRANCH=${{ github.head_ref }} + # Determine deployment environment prepare: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 9b11168..ab6a0b7 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,7 @@ dist/ downloads/ eggs/ .eggs/ -lib/ +/lib/ lib64/ parts/ sdist/ diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e595d41..7a7a69b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,23 +1,64 @@ { - "version": "2.0.0", - "tasks": [ - { - "label": "Test backend (all)", - "type": "shell", - "command": "docker", - "args": ["compose", "exec", "backend", "pytest", "DOSPORTAL/tests/"], - "group": "test", - "problemMatcher": [] - }, - { - "label": "Test backend (path)", - "type": "shell", - "command": "docker", - "args": ["compose", "exec", "backend", "pytest", "${input:testPath}"], - "group": "test", - "problemMatcher": [] - } - ], + "version": "2.0.0", + "tasks": [ + { + "label": "Test backend", + "type": "shell", + "command": "docker compose exec backend pytest DOSPORTAL/tests/", + "problemMatcher": [] + }, + { + "label": "docker compose down", + "type": "shell", + "command": "docker compose down", + "problemMatcher": [] + }, + { + "label": "docker compose up build", + "type": "shell", + "command": "docker compose up -d --build", + "problemMatcher": [] + }, + { + "label": "rebuild project", + "dependsOn": [ + "docker compose down", + "docker compose up build" + ], + "dependsOrder": "sequence" + }, + { + "label": "makemigrations & migrate", + "dependsOn": [ + "docker compose makemigrations", + "docker compose migrate" + ], + "dependsOrder": "sequence" + }, + { + "label": "docker compose makemigrations", + "type": "shell", + "command": "docker compose exec backend python manage.py makemigrations" + }, + { + "label": "docker compose migrate", + "type": "shell", + "command": "docker compose exec backend python manage.py migrate" + }, + { + "label": "orval gen api", + "type": "shell", + "command": "docker compose exec frontend npm run generate-api" + }, + { + "label": "Test backend (path)", + "type": "shell", + "command": "docker", + "args": ["compose", "exec", "backend", "pytest", "${input:testPath}"], + "group": "test", + "problemMatcher": [] + } + ], "inputs": [ { "id": "testPath", diff --git a/backend/DOSPORTAL/admin.py b/backend/DOSPORTAL/admin.py index 9e08b5e..a09bfb6 100644 --- a/backend/DOSPORTAL/admin.py +++ b/backend/DOSPORTAL/admin.py @@ -14,6 +14,7 @@ Flight, MeasurementDataFlight, MeasurementCampaign, + MeasurementSegment, Trajectory, TrajectoryPoint, SpectrumData, @@ -95,6 +96,7 @@ class DetectorAdmin(admin.ModelAdmin): admin.site.register(Airports, AirportsAdmin) admin.site.register(Flight) admin.site.register(MeasurementDataFlight) +admin.site.register(MeasurementSegment) admin.site.register(MeasurementCampaign) diff --git a/backend/DOSPORTAL/migrations/0006_measurementsegment.py b/backend/DOSPORTAL/migrations/0006_measurementsegment.py new file mode 100644 index 0000000..1adb207 --- /dev/null +++ b/backend/DOSPORTAL/migrations/0006_measurementsegment.py @@ -0,0 +1,29 @@ +# Generated by Django 6.0.2 on 2026-02-20 14:30 + +import django.db.models.deletion +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('DOSPORTAL', '0005_alter_spectralrecord_owner'), + ] + + operations = [ + migrations.CreateModel( + name='MeasurementSegment', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), + ('time_from', models.DateTimeField(blank=True, null=True, verbose_name='Segment start time')), + ('time_to', models.DateTimeField(blank=True, null=True, verbose_name='Segment end time')), + ('position', models.IntegerField(default=0, verbose_name='Position / order within measurement')), + ('measurement', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='segments', to='DOSPORTAL.measurement', verbose_name='Measurement')), + ('spectral_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='segments', to='DOSPORTAL.spectralrecord', verbose_name='Spectral record')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/backend/DOSPORTAL/migrations/0007_remove_measurement_records.py b/backend/DOSPORTAL/migrations/0007_remove_measurement_records.py new file mode 100644 index 0000000..5b71666 --- /dev/null +++ b/backend/DOSPORTAL/migrations/0007_remove_measurement_records.py @@ -0,0 +1,17 @@ +# Generated by Django 6.0.2 on 2026-02-20 14:49 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('DOSPORTAL', '0006_measurementsegment'), + ] + + operations = [ + migrations.RemoveField( + model_name='measurement', + name='records', + ), + ] diff --git a/backend/DOSPORTAL/migrations/0008_detector_deleted_at_detector_deleted_by_and_more.py b/backend/DOSPORTAL/migrations/0008_detector_deleted_at_detector_deleted_by_and_more.py new file mode 100644 index 0000000..a0e42f2 --- /dev/null +++ b/backend/DOSPORTAL/migrations/0008_detector_deleted_at_detector_deleted_by_and_more.py @@ -0,0 +1,106 @@ +# Generated by Django 6.0.2 on 2026-02-24 12:03 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('DOSPORTAL', '0007_remove_measurement_records'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name='detector', + name='deleted_at', + field=models.DateTimeField(blank=True, null=True), + ), + migrations.AddField( + model_name='detector', + name='deleted_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='detector', + name='is_deleted', + field=models.BooleanField(db_index=True, default=False), + ), + migrations.AddField( + model_name='detectorlogbook', + name='deleted_at', + field=models.DateTimeField(blank=True, null=True), + ), + migrations.AddField( + model_name='detectorlogbook', + name='deleted_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='detectorlogbook', + name='is_deleted', + field=models.BooleanField(db_index=True, default=False), + ), + migrations.AddField( + model_name='file', + name='deleted_at', + field=models.DateTimeField(blank=True, null=True), + ), + migrations.AddField( + model_name='file', + name='deleted_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='file', + name='is_deleted', + field=models.BooleanField(db_index=True, default=False), + ), + migrations.AddField( + model_name='measurement', + name='deleted_at', + field=models.DateTimeField(blank=True, null=True), + ), + migrations.AddField( + model_name='measurement', + name='deleted_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='measurement', + name='is_deleted', + field=models.BooleanField(db_index=True, default=False), + ), + migrations.AddField( + model_name='organization', + name='deleted_at', + field=models.DateTimeField(blank=True, null=True), + ), + migrations.AddField( + model_name='organization', + name='deleted_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='organization', + name='is_deleted', + field=models.BooleanField(db_index=True, default=False), + ), + migrations.AddField( + model_name='spectralrecord', + name='deleted_at', + field=models.DateTimeField(blank=True, null=True), + ), + migrations.AddField( + model_name='spectralrecord', + name='deleted_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='spectralrecord', + name='is_deleted', + field=models.BooleanField(db_index=True, default=False), + ), + ] diff --git a/backend/DOSPORTAL/migrations/0009_detector_created.py b/backend/DOSPORTAL/migrations/0009_detector_created.py new file mode 100644 index 0000000..a3dacc0 --- /dev/null +++ b/backend/DOSPORTAL/migrations/0009_detector_created.py @@ -0,0 +1,18 @@ +# Generated by Django 6.0.2 on 2026-02-24 13:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('DOSPORTAL', '0008_detector_deleted_at_detector_deleted_by_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='detector', + name='created', + field=models.DateTimeField(auto_now_add=True, null=True), + ), + ] diff --git a/backend/DOSPORTAL/migrations/0010_measurementartifact.py b/backend/DOSPORTAL/migrations/0010_measurementartifact.py new file mode 100644 index 0000000..4eda0e5 --- /dev/null +++ b/backend/DOSPORTAL/migrations/0010_measurementartifact.py @@ -0,0 +1,27 @@ +# Generated by Django 6.0.2 on 2026-02-27 08:40 + +import django.db.models.deletion +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('DOSPORTAL', '0009_detector_created'), + ] + + operations = [ + migrations.CreateModel( + name='MeasurementArtifact', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Creation time')), + ('artifact', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='measurement_artifacts', to='DOSPORTAL.file', verbose_name='Artifact file')), + ('measurement', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='artifacts', to='DOSPORTAL.measurement', verbose_name='Measurement')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/backend/DOSPORTAL/migrations/0011_measurementartifact_artifact_type.py b/backend/DOSPORTAL/migrations/0011_measurementartifact_artifact_type.py new file mode 100644 index 0000000..f2a0b28 --- /dev/null +++ b/backend/DOSPORTAL/migrations/0011_measurementartifact_artifact_type.py @@ -0,0 +1,18 @@ +# Generated by Django 6.0.2 on 2026-02-27 10:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('DOSPORTAL', '0010_measurementartifact'), + ] + + operations = [ + migrations.AddField( + model_name='measurementartifact', + name='artifact_type', + field=models.CharField(choices=[('spectral', 'Processed log file into spectral file (Parquet)')], default='spectral', max_length=50, verbose_name='Artifact type'), + ), + ] diff --git a/backend/DOSPORTAL/migrations/0012_alter_measurementartifact_artifact_type.py b/backend/DOSPORTAL/migrations/0012_alter_measurementartifact_artifact_type.py new file mode 100644 index 0000000..34098ad --- /dev/null +++ b/backend/DOSPORTAL/migrations/0012_alter_measurementartifact_artifact_type.py @@ -0,0 +1,18 @@ +# Generated by Django 6.0.2 on 2026-02-27 10:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('DOSPORTAL', '0011_measurementartifact_artifact_type'), + ] + + operations = [ + migrations.AlterField( + model_name='measurementartifact', + name='artifact_type', + field=models.CharField(choices=[('spectral', 'Processed log file into spectral file (Parquet)'), ('measurement_file', 'Combined measurement parquet file')], default='spectral', max_length=50, verbose_name='Artifact type'), + ), + ] diff --git a/backend/DOSPORTAL/migrations/0013_measurement_processing_status.py b/backend/DOSPORTAL/migrations/0013_measurement_processing_status.py new file mode 100644 index 0000000..11a3190 --- /dev/null +++ b/backend/DOSPORTAL/migrations/0013_measurement_processing_status.py @@ -0,0 +1,18 @@ +# Generated by Django 6.0.2 on 2026-02-27 11:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('DOSPORTAL', '0012_alter_measurementartifact_artifact_type'), + ] + + operations = [ + migrations.AddField( + model_name='measurement', + name='processing_status', + field=models.CharField(choices=[('pending', 'Pending processing'), ('processing', 'Processing in progress'), ('completed', 'Processing completed'), ('failed', 'Processing failed')], default='pending', help_text='Status of async background processing', max_length=16), + ), + ] diff --git a/backend/DOSPORTAL/migrations/0014_detector_image.py b/backend/DOSPORTAL/migrations/0014_detector_image.py new file mode 100644 index 0000000..39f0798 --- /dev/null +++ b/backend/DOSPORTAL/migrations/0014_detector_image.py @@ -0,0 +1,18 @@ +# Generated by Django 6.0.2 on 2026-03-03 22:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('DOSPORTAL', '0013_measurement_processing_status'), + ] + + operations = [ + migrations.AddField( + model_name='detector', + name='image', + field=models.ImageField(blank=True, help_text='Photo of the detector', null=True, upload_to='detector_photos', verbose_name='Detector image'), + ), + ] diff --git a/backend/DOSPORTAL/migrations/0015_detectorlogbook_metadata.py b/backend/DOSPORTAL/migrations/0015_detectorlogbook_metadata.py new file mode 100644 index 0000000..a83ef5f --- /dev/null +++ b/backend/DOSPORTAL/migrations/0015_detectorlogbook_metadata.py @@ -0,0 +1,18 @@ +# Generated by Django 6.0.3 on 2026-03-23 16:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('DOSPORTAL', '0014_detector_image'), + ] + + operations = [ + migrations.AddField( + model_name='detectorlogbook', + name='metadata', + field=models.JSONField(blank=True, default=dict), + ), + ] diff --git a/backend/DOSPORTAL/models/__init__.py b/backend/DOSPORTAL/models/__init__.py index d5cac88..ac5a151 100644 --- a/backend/DOSPORTAL/models/__init__.py +++ b/backend/DOSPORTAL/models/__init__.py @@ -1,21 +1,23 @@ +from .soft_delete import SoftDeleteModel, SoftDeleteManager, SoftDeleteQuerySet from .utils import UUIDMixin, Profile from .detectors import DetectorManufacturer, DetectorType, DetectorCalib, Detector, DetectorLogbook from .organizations import Organization, OrganizationUser, OrganizationInvite -from .flights import CARImodel, Airports, Flight +from .flights import CARImodel, Airports, Flight, Trajectory, TrajectoryPoint from .measurements import ( _validate_data_file, _validate_metadata_file, _validate_log_file, - MeasurementDataFlight, - MeasurementCampaign, Measurement, Trajectory, TrajectoryPoint, SpectrumData + MeasurementDataFlight, MeasurementArtifact, + MeasurementCampaign, Measurement, MeasurementSegment, SpectrumData ) from .files import File from .spectrals import SpectralRecord, SpectralRecordArtifact __all__ = [ + "SoftDeleteModel", "SoftDeleteManager", "SoftDeleteQuerySet", "UUIDMixin", "Profile", "DetectorManufacturer", "DetectorType", "DetectorCalib", "Detector", "DetectorLogbook", "Organization", "OrganizationUser", "OrganizationInvite", "_validate_data_file", "_validate_metadata_file", "_validate_log_file", - "CARImodel", "Airports", "Flight", "MeasurementDataFlight", - "MeasurementCampaign", "Measurement", "File", "Trajectory", "TrajectoryPoint", "SpectrumData", + "CARImodel", "Airports", "Flight", "MeasurementDataFlight", "MeasurementArtifact", + "MeasurementCampaign", "Measurement", "MeasurementSegment", "File", "Trajectory", "TrajectoryPoint", "SpectrumData", "SpectralRecord", "SpectralRecordArtifact" ] \ No newline at end of file diff --git a/backend/DOSPORTAL/models/detectors.py b/backend/DOSPORTAL/models/detectors.py index 13857cd..9bae6dd 100644 --- a/backend/DOSPORTAL/models/detectors.py +++ b/backend/DOSPORTAL/models/detectors.py @@ -1,5 +1,6 @@ from django.db import models from .utils import UUIDMixin +from .soft_delete import SoftDeleteModel from django.conf import settings from django.utils.translation import gettext as _ from django.urls import reverse @@ -88,7 +89,7 @@ def __str__(self) -> str: return f"Calibration '{self.name}' ({self.coef0/1000:.2f}+x*{self.coef1/1000:.2f} KeV), {self.created}, {self.description}" -class Detector(UUIDMixin): +class Detector(UUIDMixin, SoftDeleteModel): sn = models.CharField( max_length=80, @@ -116,6 +117,14 @@ class Detector(UUIDMixin): blank=True, ) + image = models.ImageField( + verbose_name=_("Detector image"), + help_text=_("Photo of the detector"), + upload_to="detector_photos", + null=True, + blank=True, + ) + data = models.JSONField( _("Detector metadata"), help_text="Detector metadata, used for advanced data processing and maintaining", @@ -123,6 +132,8 @@ class Detector(UUIDMixin): blank=True, ) + created = models.DateTimeField(auto_now_add=True, null=True) + owner = models.ForeignKey( Organization, on_delete=models.DO_NOTHING, @@ -149,7 +160,7 @@ def formatted_label(self): {self.name} ({self.sn})""" -class DetectorLogbook(UUIDMixin): +class DetectorLogbook(UUIDMixin, SoftDeleteModel): detector = models.ForeignKey( Detector, on_delete=models.CASCADE, related_name="logbook" @@ -250,5 +261,7 @@ class DetectorLogbook(UUIDMixin): help_text=_("Location description in text format (e.g., address)"), ) + metadata = models.JSONField(blank=True, default=dict) + class Meta: ordering = ["-created"] \ No newline at end of file diff --git a/backend/DOSPORTAL/models/files.py b/backend/DOSPORTAL/models/files.py index 244a31f..214e3c0 100644 --- a/backend/DOSPORTAL/models/files.py +++ b/backend/DOSPORTAL/models/files.py @@ -1,10 +1,11 @@ from .utils import UUIDMixin +from .soft_delete import SoftDeleteModel from django.db import models from ..models.organizations import Organization from django.conf import settings -class File(UUIDMixin): +class File(UUIDMixin, SoftDeleteModel): FILE_TYPE_LOG = "log" FILE_TYPE_TRAJECTORY = "trajectory" FILE_TYPE_DOCUMENT = "document" diff --git a/backend/DOSPORTAL/models/flights.py b/backend/DOSPORTAL/models/flights.py index 5bb9473..249b272 100644 --- a/backend/DOSPORTAL/models/flights.py +++ b/backend/DOSPORTAL/models/flights.py @@ -1,6 +1,7 @@ from django.db import models from django.urls import reverse from django.utils.translation import gettext as _ +from django.contrib.gis.db import models as geomodels from ..models.utils import UUIDMixin @@ -69,4 +70,34 @@ def save(self, *args, **kwargs): super(Flight, self).save(*args, **kwargs) class Meta: - unique_together = ("flight_number", "departure_time") \ No newline at end of file + unique_together = ("flight_number", "departure_time") + + +class Trajectory(UUIDMixin): + name = models.CharField(max_length=80) + + description = models.TextField(null=True, blank=True) + + def __str__(self) -> str: + return "Trajectory: {}".format(self.name) + + +class TrajectoryPoint(models.Model): + datetime = models.DateTimeField( + null=True, + blank=True, + verbose_name=_("Point timestamp"), + ) + + location = geomodels.PointField( + null=True, + blank=True, + geography=True, + ) + + trajectory = models.ForeignKey( + Trajectory, on_delete=models.CASCADE, related_name="points" + ) + + def __str__(self) -> str: + return "Trajectory point: {}".format(self.trajectory) \ No newline at end of file diff --git a/backend/DOSPORTAL/models/measurements.py b/backend/DOSPORTAL/models/measurements.py index c49c139..9f10c90 100644 --- a/backend/DOSPORTAL/models/measurements.py +++ b/backend/DOSPORTAL/models/measurements.py @@ -1,13 +1,13 @@ -from django.contrib.gis.db import models as geomodels from django.db import models from django.conf import settings from django.urls import reverse from django.utils.translation import gettext as _ from django.contrib.postgres.fields import ArrayField -from ..models.utils import UUIDMixin +from ..models.utils import UUIDMixin, ProcessingStatusMixin +from ..models.soft_delete import SoftDeleteModel from martor.models import MartorField from DOSPORTAL.services.file_validation import validate_uploaded_file -from .flights import Flight +from .flights import Flight, TrajectoryPoint from .files import File from .spectrals import SpectralRecord from .organizations import Organization @@ -66,7 +66,7 @@ def __str__(self) -> str: return "Campaign: {}".format(self.name) -class Measurement(UUIDMixin): +class Measurement(UUIDMixin, SoftDeleteModel, ProcessingStatusMixin): """ Měřením se rozumí sada zaznamů (record), které analyzují jednu a tu samou věc a jsou změřeny jedním detektorem. Pokud jsou v latedle dva detektory, tak to jsou dvě měření. Pokud je ale záznam z jednoho detektoru @@ -147,14 +147,6 @@ def __str__(self): def user_directory_path(instance, filename): return "data/user_records/{0}/{1}".format(instance.user.id, filename) - records = models.ManyToManyField( - SpectralRecord, - related_name='measurements', - blank=True, - verbose_name=_('Spectral records'), - help_text=_('Spectral records associated with this measurement.'), - ) - files = models.ManyToManyField( File, related_name='measurements', @@ -181,37 +173,83 @@ def user_directory_path(instance, filename): help_text=_('Measurement campaigns this measurement belongs to.'), ) - - - -class Trajectory(UUIDMixin): - name = models.CharField(max_length=80) - - description = models.TextField(null=True, blank=True) +class MeasurementSegment(UUIDMixin): + """ + A segment represents a (part of a) SpectralRecord within a Measurement. + A measurement can consist of multiple records or record parts sliced by time. + """ - def __str__(self) -> str: - return "Trajectory: {}".format(self.name) + measurement = models.ForeignKey( + Measurement, + on_delete=models.CASCADE, + related_name='segments', + verbose_name=_('Measurement'), + ) + spectral_record = models.ForeignKey( + SpectralRecord, + on_delete=models.CASCADE, + related_name='segments', + verbose_name=_('Spectral record'), + ) -class TrajectoryPoint(models.Model): - datetime = models.DateTimeField( + time_from = models.DateTimeField( + verbose_name=_('Segment start time'), null=True, blank=True, - verbose_name=_("Point timestamp"), ) - location = geomodels.PointField( + time_to = models.DateTimeField( + verbose_name=_('Segment end time'), null=True, blank=True, - geography=True, ) - trajectory = models.ForeignKey( - Trajectory, on_delete=models.CASCADE, related_name="points" + position = models.IntegerField( + verbose_name=_('Position / order within measurement'), + default=0, ) - def __str__(self) -> str: - return "Trajectory point: {}".format(self.trajectory) + def __str__(self): + return f"Segment {self.position} of {self.measurement} — {self.spectral_record}" + +class MeasurementArtifact(UUIDMixin): + SPECTRAL_FILE = "spectral" + MEASUREMENT_FILE = "measurement_file" + + measurement = models.ForeignKey( + 'Measurement', + on_delete=models.CASCADE, + related_name='artifacts', + verbose_name=_('Measurement'), + ) + + artifact = models.ForeignKey( + 'File', + on_delete=models.CASCADE, + related_name='measurement_artifacts', + verbose_name=_('Artifact file'), + ) + + ARTIFACT_TYPES = ( + (SPECTRAL_FILE, "Processed log file into spectral file (Parquet)"), + (MEASUREMENT_FILE, "Combined measurement parquet file"), + ) + + artifact_type = models.CharField( + max_length=50, + choices=ARTIFACT_TYPES, + default=SPECTRAL_FILE, + verbose_name=_('Artifact type'), + ) + + created_at = models.DateTimeField( + auto_now_add=True, + verbose_name=_('Creation time'), + ) + + def __str__(self): + return f"MeasurementArtifact: {self.artifact_type} for Measurement {self.measurement_id}" diff --git a/backend/DOSPORTAL/models/organizations.py b/backend/DOSPORTAL/models/organizations.py index fd179de..b8af8ca 100644 --- a/backend/DOSPORTAL/models/organizations.py +++ b/backend/DOSPORTAL/models/organizations.py @@ -6,9 +6,10 @@ from .utils import UUIDMixin import hashlib from django.utils import timezone +from .soft_delete import SoftDeleteModel -class Organization(UUIDMixin): +class Organization(UUIDMixin, SoftDeleteModel): DATA_POLICY_CHOICES = [ ("PR", "Private"), ("PU", "Public"), diff --git a/backend/DOSPORTAL/models/soft_delete.py b/backend/DOSPORTAL/models/soft_delete.py new file mode 100644 index 0000000..d9310e0 --- /dev/null +++ b/backend/DOSPORTAL/models/soft_delete.py @@ -0,0 +1,63 @@ +from django.db import models +from django.conf import settings +from django.utils.timezone import now + + +class SoftDeleteQuerySet(models.QuerySet): + def delete(self): + return self.update(is_deleted=True, deleted_at=now()) + + def hard_delete(self): + return super().delete() + + def active(self): + return self.filter(is_deleted=False) + + def deleted_only(self): + return self.filter(is_deleted=True) + + +class SoftDeleteManager(models.Manager): + def get_queryset(self): + return SoftDeleteQuerySet(self.model, using=self._db).filter(is_deleted=False) + + def deleted_only(self): + return SoftDeleteQuerySet(self.model, using=self._db).filter(is_deleted=True) + + def all_with_deleted(self): + return SoftDeleteQuerySet(self.model, using=self._db) + + +class SoftDeleteModel(models.Model): + is_deleted = models.BooleanField(default=False, db_index=True) + deleted_at = models.DateTimeField(null=True, blank=True) + deleted_by = models.ForeignKey( + settings.AUTH_USER_MODEL, + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + ) + + objects = SoftDeleteManager() + objects_default = models.Manager() + + class Meta: + abstract = True + + def soft_delete(self, deleted_by=None): + if not self.is_deleted: + self.is_deleted = True + self.deleted_at = now() + self.deleted_by = deleted_by + self.save(update_fields=["is_deleted", "deleted_at", "deleted_by"]) + + def restore(self): + if self.is_deleted: + self.is_deleted = False + self.deleted_at = None + self.deleted_by = None + self.save(update_fields=["is_deleted", "deleted_at", "deleted_by"]) + + def hard_delete(self): + super().delete() diff --git a/backend/DOSPORTAL/models/spectrals.py b/backend/DOSPORTAL/models/spectrals.py index 59cfe7a..a198c21 100644 --- a/backend/DOSPORTAL/models/spectrals.py +++ b/backend/DOSPORTAL/models/spectrals.py @@ -1,4 +1,5 @@ -from .utils import UUIDMixin +from .utils import UUIDMixin, ProcessingStatusMixin +from .soft_delete import SoftDeleteModel from django.db import models from ..models.organizations import Organization from django.conf import settings @@ -58,7 +59,7 @@ def user_directory_path_data(instance, extension="pk"): """Generate data file path.""" return f"user_records/record_{instance.pk}/data.{extension}" -class SpectralRecord(UUIDMixin): +class SpectralRecord(UUIDMixin, SoftDeleteModel, ProcessingStatusMixin): name = models.CharField( max_length=80, @@ -170,25 +171,7 @@ class SpectralRecord(UUIDMixin): blank=True, ) - # Processing status for async tasks - PROCESSING_PENDING = "pending" # uploaded to, waiting for being processed into artifacts - PROCESSING_IN_PROGRESS = "processing" # post processing in async task started - PROCESSING_COMPLETED = "completed" # post processing finished: artifacts created - PROCESSING_FAILED = "failed" # post processing finished: artifacts NOT created - - PROCESSING_STATUS_CHOICES = ( - (PROCESSING_PENDING, "Pending processing"), - (PROCESSING_IN_PROGRESS, "Processing in progress"), - (PROCESSING_COMPLETED, "Processing completed"), - (PROCESSING_FAILED, "Processing failed"), - ) - - processing_status = models.CharField( - max_length=16, - choices=PROCESSING_STATUS_CHOICES, - default=PROCESSING_PENDING, - help_text="Status of async background processing" - ) + class SpectralRecordArtifact(UUIDMixin): @@ -222,6 +205,4 @@ class SpectralRecordArtifact(UUIDMixin): created_at = models.DateTimeField( auto_now_add=True, help_text="Time when the artifact was created", - ) - - \ No newline at end of file + ) \ No newline at end of file diff --git a/backend/DOSPORTAL/models/utils.py b/backend/DOSPORTAL/models/utils.py index 2f64910..81c5065 100644 --- a/backend/DOSPORTAL/models/utils.py +++ b/backend/DOSPORTAL/models/utils.py @@ -17,6 +17,33 @@ def get_admin_url(self): class Meta: abstract = True + +class ProcessingStatusMixin(models.Model): + """Mixin that adds async processing status tracking to a model.""" + + PROCESSING_PENDING = "pending" + PROCESSING_IN_PROGRESS = "processing" + PROCESSING_COMPLETED = "completed" + PROCESSING_FAILED = "failed" + + PROCESSING_STATUS_CHOICES = ( + (PROCESSING_PENDING, "Pending processing"), + (PROCESSING_IN_PROGRESS, "Processing in progress"), + (PROCESSING_COMPLETED, "Processing completed"), + (PROCESSING_FAILED, "Processing failed"), + ) + + processing_status = models.CharField( + max_length=16, + choices=PROCESSING_STATUS_CHOICES, + default=PROCESSING_PENDING, + help_text="Status of async background processing", + ) + + class Meta: + abstract = True + + class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) image = models.ImageField( diff --git a/backend/DOSPORTAL/selectors/__init__.py b/backend/DOSPORTAL/selectors/__init__.py new file mode 100644 index 0000000..df74ea4 --- /dev/null +++ b/backend/DOSPORTAL/selectors/__init__.py @@ -0,0 +1,12 @@ +from .measurements import measurements_visible, measurement_segments_visible +from .files import files_visible +from .spectrals import spectral_records_visible +from .detectors import detectors_visible + +__all__ = [ + "measurements_visible", + "measurement_segments_visible", + "files_visible", + "spectral_records_visible", + "detectors_visible", +] diff --git a/backend/DOSPORTAL/selectors/detectors.py b/backend/DOSPORTAL/selectors/detectors.py new file mode 100644 index 0000000..98940d1 --- /dev/null +++ b/backend/DOSPORTAL/selectors/detectors.py @@ -0,0 +1,22 @@ +from DOSPORTAL.models.detectors import Detector + + +def detectors_visible(user=None): + """ + Return all non-deleted detectors whose organization is also not deleted. + Optionally filter to a specific user's accessible detectors. + """ + if user is not None: + from DOSPORTAL.models import OrganizationUser + + user_orgs = OrganizationUser.objects.filter( + user=user, + user_type__in=["OW", "AD", "ME"], + ).values_list("organization_id", flat=True) + + return Detector.objects.filter( + owner__in=user_orgs, + owner__is_deleted=False, + ).distinct() + + return Detector.objects.filter(owner__is_deleted=False) diff --git a/backend/DOSPORTAL/selectors/files.py b/backend/DOSPORTAL/selectors/files.py new file mode 100644 index 0000000..a22e314 --- /dev/null +++ b/backend/DOSPORTAL/selectors/files.py @@ -0,0 +1,22 @@ +from DOSPORTAL.models import File + + +def files_visible(user=None): + """ + Return all non-deleted files whose organization is also not deleted. + Optionally filter to a specific user's accessible files. + """ + if user is not None: + from DOSPORTAL.models import OrganizationUser + + user_orgs = OrganizationUser.objects.filter( + user=user, + user_type__in=["OW", "AD", "ME"], + ).values_list("organization_id", flat=True) + + return ( + File.objects.filter(owner__in=user_orgs, owner__is_deleted=False) + | File.objects.filter(author=user) + ).distinct() + + return File.objects.filter(owner__is_deleted=False) | File.objects.filter(owner__isnull=True) diff --git a/backend/DOSPORTAL/selectors/measurements.py b/backend/DOSPORTAL/selectors/measurements.py new file mode 100644 index 0000000..261e1be --- /dev/null +++ b/backend/DOSPORTAL/selectors/measurements.py @@ -0,0 +1,35 @@ +from DOSPORTAL.models import Measurement, MeasurementSegment + + +def measurements_visible(user=None): + """ + Return all non-deleted measurements whose organization is also not deleted. + Optionally filter to a specific user's accessible measurements. + """ + qs = ( + Measurement.objects.filter( + owner__is_deleted=False, + ) + | Measurement.objects.filter(owner__isnull=True) + ).distinct() + + if user is not None: + from DOSPORTAL.models import OrganizationUser + + user_orgs = OrganizationUser.objects.filter( + user=user, + user_type__in=["OW", "AD", "ME"], + ).values_list("organization_id", flat=True) + + qs = ( + Measurement.objects.filter(owner__in=user_orgs, owner__is_deleted=False) + | Measurement.objects.filter(author=user) + ).distinct() + + return qs + + +def measurement_segments_visible(): + return MeasurementSegment.objects.filter( + measurement__is_deleted=False, + ) diff --git a/backend/DOSPORTAL/selectors/spectrals.py b/backend/DOSPORTAL/selectors/spectrals.py new file mode 100644 index 0000000..cbc7b23 --- /dev/null +++ b/backend/DOSPORTAL/selectors/spectrals.py @@ -0,0 +1,22 @@ +from DOSPORTAL.models.spectrals import SpectralRecord + + +def spectral_records_visible(user=None): + """ + Return all non-deleted spectral records whose organization is also not deleted. + Optionally filter to a specific user's accessible records. + """ + if user is not None: + from DOSPORTAL.models import OrganizationUser + + user_orgs = OrganizationUser.objects.filter( + user=user, + user_type__in=["OW", "AD", "ME"], + ).values_list("organization_id", flat=True) + + return ( + SpectralRecord.objects.filter(owner__in=user_orgs, owner__is_deleted=False) + | SpectralRecord.objects.filter(author=user) + ).distinct() + + return SpectralRecord.objects.filter(owner__is_deleted=False) | SpectralRecord.objects.filter(owner__isnull=True) diff --git a/backend/DOSPORTAL/settings.py b/backend/DOSPORTAL/settings.py index 1c82087..6bae1fb 100644 --- a/backend/DOSPORTAL/settings.py +++ b/backend/DOSPORTAL/settings.py @@ -241,6 +241,8 @@ "DEFAULT_PERMISSION_CLASSES": [ "rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly" ], + "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination", + "PAGE_SIZE": 40, } SPECTACULAR_SETTINGS = { diff --git a/backend/DOSPORTAL/signals.py b/backend/DOSPORTAL/signals.py index 304c092..984c4a3 100644 --- a/backend/DOSPORTAL/signals.py +++ b/backend/DOSPORTAL/signals.py @@ -22,7 +22,8 @@ def create_profile(sender, instance, created, **kwargs): @receiver(post_save, sender=User) def save_profile(sender, instance, **kwargs): - instance.profile.save() + profile, _ = Profile.objects.get_or_create(user=instance) + profile.save() @receiver(post_save, sender=SpectralRecord) @@ -40,4 +41,4 @@ def process_spectral_record(sender, instance: SpectralRecord, created=False, **k # Post-process spectral record raw file into artefacts async_task('DOSPORTAL.tasks.process_spectral_record_into_spectral_file_async', instance.id) - print(f"Async task scheduled for SpectralRecord {instance.id}") + print(f"Async task scheduled for SpectralRecord {instance.id}") \ No newline at end of file diff --git a/backend/DOSPORTAL/tasks.py b/backend/DOSPORTAL/tasks.py index d78c380..0b311f9 100644 --- a/backend/DOSPORTAL/tasks.py +++ b/backend/DOSPORTAL/tasks.py @@ -1,6 +1,4 @@ - -from .models import File -from .models.spectrals import SpectralRecord, SpectralRecordArtifact +from .models import File, SpectralRecord, SpectralRecordArtifact, ProcessingStatusMixin, Measurement, MeasurementSegment, MeasurementArtifact from .helpers_cari import create_cari_input from django.core.files.base import ContentFile import io @@ -129,7 +127,7 @@ def get_candy_line_lenght(file_obj): record = SpectralRecord.objects.get(id=spectral_record_id) print(f"Processing SpectralRecord {record.id}") - record.processing_status = SpectralRecord.PROCESSING_IN_PROGRESS + record.processing_status = ProcessingStatusMixin.PROCESSING_IN_PROGRESS record.save(update_fields=['processing_status']) # Get raw file @@ -220,7 +218,7 @@ def get_candy_line_lenght(file_obj): artifact_type=SpectralRecordArtifact.SPECTRAL_FILE ) - record.processing_status = SpectralRecord.PROCESSING_COMPLETED + record.processing_status = ProcessingStatusMixin.PROCESSING_COMPLETED record.save(update_fields=['processing_status']) print(f"SpectralRecord {record.id} processed successfully - Parquet artifact created: {spectral_file.id}") @@ -232,7 +230,7 @@ def get_candy_line_lenght(file_obj): try: record = SpectralRecord.objects.get(id=spectral_record_id) - record.processing_status = SpectralRecord.PROCESSING_FAILED + record.processing_status = ProcessingStatusMixin.PROCESSING_FAILED record.metadata = record.metadata or {} record.metadata['processing_error'] = str(e) record.save(update_fields=['processing_status', 'metadata']) @@ -243,6 +241,88 @@ def get_candy_line_lenght(file_obj): raise +def create_measurement_artifact(measurement_id): + try: + measurement = Measurement.objects.get(id=measurement_id) + print(f"Creating artifact for Measurement {measurement.id}") + + # Retrieve all segments, sorted by position + segments = MeasurementSegment.objects.filter(measurement=measurement).order_by("position") + + if not segments.exists(): + raise ValueError("No segments found for the measurement.") + + # Combine data from all segments + combined_data = [] + for segment in segments: + spectral_record = segment.spectral_record + artifact = spectral_record.artifacts.filter(artifact_type=SpectralRecordArtifact.SPECTRAL_FILE).first() + + if not artifact: + raise ValueError(f"No spectral artifact found for segment {segment.id}.") + + artifact.artifact.file.open("rb") + df = pd.read_parquet(artifact.artifact.file, engine="fastparquet") + artifact.artifact.file.close() + combined_data.append(df) + combined_df = pd.concat(combined_data, ignore_index=True) + # Normalize time to start from 0 + combined_df["time_ms"] = combined_df["time_ms"] - combined_df["time_ms"].min() + + parquet_buffer = io.BytesIO() + combined_df.to_parquet(parquet_buffer, engine="fastparquet", index=False) + parquet_buffer.seek(0) + + artifact_file = File.objects.create( + filename=f"measurement_{measurement.id}.parquet", + file_type=File.FILE_TYPE_PARQUET, + source_type="generated", + owner=measurement.owner, + metadata={ + "measurement_id": str(measurement.id), + "records_count": len(combined_df), + "time_range_ms": [ + float(combined_df["time_ms"].min()), + float(combined_df["time_ms"].max()), + ], + }, + ) + + artifact_file.file.save( + f"measurement_{measurement.id}.parquet", + ContentFile(parquet_buffer.read()), + save=True, + ) + + # deletes old artifact (when generating a new one) + old = MeasurementArtifact.objects.filter( + measurement=measurement, + artifact_type=MeasurementArtifact.MEASUREMENT_FILE, + ).first() + if old: + old.artifact.file.delete(save=False) + old.artifact.delete() + + MeasurementArtifact.objects.update_or_create( + measurement=measurement, + artifact_type=MeasurementArtifact.MEASUREMENT_FILE, + defaults={"artifact": artifact_file}, + ) + + measurement.processing_status = ProcessingStatusMixin.PROCESSING_COMPLETED + measurement.save(update_fields=["processing_status"]) + + print(f"MeasurementArtifact created for Measurement {measurement.id}") + + except Exception as e: + print(f"Error creating MeasurementArtifact for Measurement {measurement_id}: {str(e)}") + try: + measurement = Measurement.objects.get(id=measurement_id) + measurement.processing_status = ProcessingStatusMixin.PROCESSING_FAILED + measurement.save(update_fields=["processing_status"]) + except Exception: # noqa: BLE001 - best-effort status update; don't mask the original error + pass + raise diff --git a/backend/DOSPORTAL/tests/api/test_detector.py b/backend/DOSPORTAL/tests/api/test_detector.py index aa57490..f726598 100644 --- a/backend/DOSPORTAL/tests/api/test_detector.py +++ b/backend/DOSPORTAL/tests/api/test_detector.py @@ -12,7 +12,6 @@ @pytest.mark.django_db def test_create_detector_success(): - # Setup user, org, manufacturer, type user = User.objects.create_user(username="admin", password="pass12345") org = Organization.objects.create(name="Test Org") OrganizationUser.objects.create(user=user, organization=org, user_type="OW") @@ -26,12 +25,12 @@ def test_create_detector_success(): "sn": "SN001", "name": "Detector1", "type_id": str(dtype.id), - "owner": str(org.id), + "owner_id": str(org.id), } - response = client.post("/api/detector/", data, format="json") + response = client.post("/api/detectors/", data, format="json") assert response.status_code == 201 assert response.data["name"] == "Detector1" - assert response.data["owner"] == str(org.id) + assert response.data["owner"]["name"] == "Test Org" @pytest.mark.django_db @@ -48,9 +47,9 @@ def test_create_detector_no_permission(): "sn": "SN002", "name": "Detector2", "type_id": str(dtype.id), - "owner": str(org.id), + "owner_id": str(org.id), } - response = client.post("/api/detector/", data, format="json") + response = client.post("/api/detectors/", data, format="json") assert response.status_code == 403 assert "permission" in response.data["detail"] @@ -60,26 +59,10 @@ def test_create_detector_invalid_org(): user = User.objects.create_user(username="admin2", password="pass12345") client = APIClient() client.force_authenticate(user=user) - data = { - "sn": "SN003", - "name": "Detector3", - "type_id": None, - "owner": "00000000-0000-0000-0000-000000000000", - } - response = client.post("/api/detector/", data, format="json") - assert response.status_code == 404 - assert "Organization not found" in response.data["detail"] - - -@pytest.mark.django_db -def test_create_detector_missing_owner(): - user = User.objects.create_user(username="admin3", password="pass12345") - client = APIClient() - client.force_authenticate(user=user) - data = {"sn": "SN004", "name": "Detector4", "type_id": None} - response = client.post("/api/detector/", data, format="json") + nonexistent_org_id = "00000000-0000-0000-0000-000000000000" + data = {"sn": "SN003", "name": "Detector3", "type_id": None, "owner_id": nonexistent_org_id} + response = client.post("/api/detectors/", data, format="json") assert response.status_code == 400 - assert "Owner organization is required" in response.data["detail"] @pytest.mark.django_db @@ -98,9 +81,9 @@ def test_create_detector_owner_in_other_org(): "sn": "SN005", "name": "Detector5", "type_id": str(dtype.id), - "owner": str(org2.id), + "owner_id": str(org2.id), } - response = client.post("/api/detector/", data, format="json") + response = client.post("/api/detectors/", data, format="json") assert response.status_code == 403 assert "permission" in response.data["detail"] @@ -120,9 +103,9 @@ def test_create_detector_member_only(): "sn": "SN006", "name": "Detector6", "type_id": str(dtype.id), - "owner": str(org.id), + "owner_id": str(org.id), } - response = client.post("/api/detector/", data, format="json") + response = client.post("/api/detectors/", data, format="json") assert response.status_code == 403 assert "permission" in response.data["detail"] @@ -135,42 +118,40 @@ def test_create_detector_invalid_data(): client = APIClient() client.force_authenticate(user=user) data = { - "sn": "", # Missing required fields + "sn": "", "name": "", "type_id": "", - "owner": str(org.id), + "owner_id": str(org.id), } - response = client.post("/api/detector/", data, format="json") + response = client.post("/api/detectors/", data, format="json") assert response.status_code == 400 assert "sn" in response.data or "name" in response.data or "type" in response.data @pytest.mark.django_db def test_get_detectors_empty(): - """GET /detector/ - empty list""" user = User.objects.create_user(username="user1", password="pass123") client = APIClient() client.force_authenticate(user=user) - response = client.get("/api/detector/") + response = client.get("/api/detectors/") assert response.status_code == 200 - assert response.data == [] + assert response.data["results"] == [] @pytest.mark.django_db def test_get_detectors_with_data(): - """GET /detector/ - with existing detectors""" - # Setup user = User.objects.create_user(username="user1", password="pass123") manuf = DetectorManufacturer.objects.create(name="Sony", url="http://sony.com") dtype = DetectorType.objects.create(name="Gamma", manufacturer=manuf) org = Organization.objects.create(name="TestOrg") + OrganizationUser.objects.create(user=user, organization=org, user_type="ME") Detector.objects.create(name="Detector 1", type=dtype, owner=org, sn="SN001") Detector.objects.create(name="Detector 2", type=dtype, owner=org, sn="SN002") client = APIClient() client.force_authenticate(user=user) - response = client.get("/api/detector/") + response = client.get("/api/detectors/") assert response.status_code == 200 - assert len(response.data) == 2 - assert response.data[0]["name"] in ["Detector 1", "Detector 2"] + assert len(response.data["results"]) == 2 + assert response.data["results"][0]["name"] in ["Detector 1", "Detector 2"] diff --git a/backend/DOSPORTAL/tests/api/test_detector_logbook.py b/backend/DOSPORTAL/tests/api/test_detector_logbook.py index 8df4677..c73a1db 100644 --- a/backend/DOSPORTAL/tests/api/test_detector_logbook.py +++ b/backend/DOSPORTAL/tests/api/test_detector_logbook.py @@ -19,10 +19,10 @@ def test_logbook_get_empty(): client = APIClient() client.force_authenticate(user=user) - response = client.get("/api/logbook/") + response = client.get("/api/logbooks/") assert response.status_code == 200 - assert response.data == [] + assert response.data["results"] == [] @pytest.mark.django_db @@ -56,12 +56,12 @@ def test_logbook_get_filtered_by_detector_and_type(): client = APIClient() client.force_authenticate(user=user) response = client.get( - f"/api/logbook/?detector={detector1.id}&entry_type=maintenance" + f"/api/logbooks/?detector={detector1.id}&entry_type=maintenance" ) assert response.status_code == 200 - assert len(response.data) == 1 - assert response.data[0]["text"] == "Maintenance done" + assert len(response.data["results"]) == 1 + assert response.data["results"][0]["text"] == "Maintenance done" @pytest.mark.django_db @@ -80,7 +80,7 @@ def test_logbook_post_success(): client = APIClient() client.force_authenticate(user=user) response = client.post( - "/api/logbook/add/", + "/api/logbooks/", {"detector": str(detector.id), "text": "Created entry", "entry_type": "note"}, format="json", ) @@ -111,8 +111,8 @@ def test_logbook_put_success(): client = APIClient() client.force_authenticate(user=user) - response = client.put( - f"/api/logbook/{entry.id}/", + response = client.patch( + f"/api/logbooks/{entry.id}/", {"text": "Updated entry", "entry_type": "reset"}, format="json", ) diff --git a/backend/DOSPORTAL/tests/api/test_detector_manufacturer.py b/backend/DOSPORTAL/tests/api/test_detector_manufacturer.py index 8b32a9d..172ed6a 100644 --- a/backend/DOSPORTAL/tests/api/test_detector_manufacturer.py +++ b/backend/DOSPORTAL/tests/api/test_detector_manufacturer.py @@ -1,43 +1,56 @@ import pytest +from django.contrib.auth.models import User from rest_framework.test import APIClient from DOSPORTAL.models import DetectorManufacturer +LIST_URL = "/api/detector-manufacturers/" + + +def detail_url(pk): + return f"/api/detector-manufacturers/{pk}/" + + +@pytest.fixture +def user(db): + return User.objects.create_user(username="testuser", password="testpass") + + +@pytest.fixture +def auth_client(user): + client = APIClient() + client.force_authenticate(user=user) + return client + @pytest.mark.django_db def test_get_manufacturers_empty(): - """GET /detector-manufacturer/ - empty list""" client = APIClient() - response = client.get("/api/detector-manufacturer/") + response = client.get(LIST_URL) assert response.status_code == 200 - assert response.data == [] + assert response.data["count"] == 0 + assert response.data["results"] == [] @pytest.mark.django_db def test_get_manufacturers_with_data(): - """GET /detector-manufacturer/ - with existing manufacturers""" - # Setup DetectorManufacturer.objects.create(name="Sony", url="http://sony.com") DetectorManufacturer.objects.create(name="Bosch", url="http://bosch.com") client = APIClient() - response = client.get("/api/detector-manufacturer/") + response = client.get(LIST_URL) assert response.status_code == 200 - assert len(response.data) == 2 - names = [item["name"] for item in response.data] + assert response.data["count"] == 2 + names = [item["name"] for item in response.data["results"]] assert "Sony" in names assert "Bosch" in names @pytest.mark.django_db def test_get_manufacturer_detail_success(): - """GET /detector-manufacturer/{id}/ - existing manufacturer""" - # Setup - manuf = DetectorManufacturer.objects.create( - name="Samsung", url="http://samsung.com" - ) + manuf = DetectorManufacturer.objects.create(name="Samsung", url="http://samsung.com") client = APIClient() - response = client.get(f"/api/detector-manufacturer/{manuf.id}/") + response = client.get(detail_url(manuf.id)) assert response.status_code == 200 assert response.data["name"] == "Samsung" assert response.data["url"] == "http://samsung.com" @@ -46,54 +59,51 @@ def test_get_manufacturer_detail_success(): @pytest.mark.django_db def test_get_manufacturer_detail_not_found(): - """GET /detector-manufacturer/{id}/ - non-existent manufacturer""" client = APIClient() - response = client.get( - "/api/detector-manufacturer/00000000-0000-0000-0000-000000000000/" - ) + response = client.get(detail_url("00000000-0000-0000-0000-000000000000")) assert response.status_code == 404 - assert "Not found" in response.data["detail"] @pytest.mark.django_db -def test_create_manufacturer_success(): - """POST /detector-manufacturer/ - create with valid data""" - client = APIClient() - data = {"name": "LG Electronics", "url": "http://lg.com"} - response = client.post("/api/detector-manufacturer/", data, format="json") +def test_create_manufacturer_success(auth_client): + response = auth_client.post(LIST_URL, {"name": "LG Electronics", "url": "http://lg.com"}, format="json") assert response.status_code == 201 assert response.data["name"] == "LG Electronics" assert response.data["url"] == "http://lg.com" assert "id" in response.data - - # Verify it was created assert DetectorManufacturer.objects.filter(name="LG Electronics").exists() @pytest.mark.django_db -def test_create_manufacturer_minimal(): - """POST /detector-manufacturer/ - create with name and url""" - client = APIClient() - data = {"name": "HP", "url": "https://hp.com"} - response = client.post("/api/detector-manufacturer/", data, format="json") +def test_create_manufacturer_minimal(auth_client): + response = auth_client.post(LIST_URL, {"name": "HP", "url": "https://hp.com"}, format="json") assert response.status_code == 201 assert response.data["name"] == "HP" - assert response.data["name"] == "HP" @pytest.mark.django_db -def test_create_manufacturer_missing_name(): - """POST /detector-manufacturer/ - missing required name field""" - client = APIClient() - data = {"url": "http://example.com"} - response = client.post("/api/detector-manufacturer/", data, format="json") +def test_create_manufacturer_missing_name(auth_client): + response = auth_client.post(LIST_URL, {"url": "http://example.com"}, format="json") assert response.status_code == 400 - assert "name" in response.data or "name" in str(response.data) + assert "name" in response.data @pytest.mark.django_db -def test_create_manufacturer_empty_data(): - """POST /detector-manufacturer/ - empty data""" - client = APIClient() - response = client.post("/api/detector-manufacturer/", {}, format="json") +def test_create_manufacturer_missing_url(auth_client): + response = auth_client.post(LIST_URL, {"name": "NoURL Corp"}, format="json") assert response.status_code == 400 + assert "url" in response.data + + +@pytest.mark.django_db +def test_create_manufacturer_empty_data(auth_client): + response = auth_client.post(LIST_URL, {}, format="json") + assert response.status_code == 400 + assert "name" in response.data + + +@pytest.mark.django_db +def test_create_manufacturer_unauthenticated(): + client = APIClient() + response = client.post(LIST_URL, {"name": "Ghost Corp", "url": "http://ghost.com"}, format="json") + assert response.status_code == 401 diff --git a/backend/DOSPORTAL/tests/api/test_detector_qr.py b/backend/DOSPORTAL/tests/api/test_detector_qr.py index 1dc8a0d..acca209 100644 --- a/backend/DOSPORTAL/tests/api/test_detector_qr.py +++ b/backend/DOSPORTAL/tests/api/test_detector_qr.py @@ -13,7 +13,6 @@ @pytest.mark.django_db def test_get_detector_qr_code_success(): """GET /detector/{detector_id}/qr/ - success""" - # Setup user = User.objects.create_user(username="user1", password="pass123") manuf = DetectorManufacturer.objects.create(name="Sony", url="http://sony.com") dtype = DetectorType.objects.create(name="Gamma", manufacturer=manuf) @@ -27,7 +26,7 @@ def test_get_detector_qr_code_success(): client = APIClient() client.force_authenticate(user=user) - response = client.get(f"/api/detector/{detector.id}/qr/") + response = client.get(f"/api/detectors/{detector.id}/qr/") assert response.status_code == 200 # QR code returns image/png content assert response["Content-Type"] == "image/png" @@ -50,7 +49,7 @@ def test_get_detector_qr_code_with_label(): client = APIClient() client.force_authenticate(user=user) - response = client.get(f"/api/detector/{detector.id}/qr/?label=true") + response = client.get(f"/api/detectors/{detector.id}/qr/?label=true") assert response.status_code == 200 assert response["Content-Type"] == "image/png" @@ -61,7 +60,7 @@ def test_get_detector_qr_code_not_found(): user = User.objects.create_user(username="user1", password="pass123") client = APIClient() client.force_authenticate(user=user) - response = client.get("/api/detector/00000000-0000-0000-0000-000000000000/qr/") + response = client.get("/api/detectors/00000000-0000-0000-0000-000000000000/qr/") assert response.status_code == 404 @@ -80,5 +79,5 @@ def test_get_detector_qr_code_unauthorized(): ) client = APIClient() - response = client.get(f"/api/detector/{detector.id}/qr/") + response = client.get(f"/api/detectors/{detector.id}/qr/") assert response.status_code == 401 diff --git a/backend/DOSPORTAL/tests/api/test_detectortype.py b/backend/DOSPORTAL/tests/api/test_detectortype.py index 9186c3d..ad712c0 100644 --- a/backend/DOSPORTAL/tests/api/test_detectortype.py +++ b/backend/DOSPORTAL/tests/api/test_detectortype.py @@ -15,7 +15,7 @@ def test_create_detector_type_success(): 'url': 'http://typea.com', 'description': 'Test type' } - response = client.post('/api/detector-type/', data, format='json') + response = client.post('/api/detector-types/', data, format='json') assert response.status_code == 201 assert response.data['name'] == 'TypeA' assert response.data['manufacturer']['id'] == str(manufacturer.id) @@ -31,6 +31,6 @@ def test_create_detector_type_missing_name(): 'url': 'http://typea.com', 'description': 'Test type' } - response = client.post('/api/detector-type/', data, format='json') + response = client.post('/api/detector-types/', data, format='json') assert response.status_code == 400 assert 'name' in response.data diff --git a/backend/DOSPORTAL/tests/api/test_detectortype_detail.py b/backend/DOSPORTAL/tests/api/test_detectortype_detail.py index 52e9345..f8d3e5e 100644 --- a/backend/DOSPORTAL/tests/api/test_detectortype_detail.py +++ b/backend/DOSPORTAL/tests/api/test_detectortype_detail.py @@ -10,7 +10,7 @@ def test_get_detector_type_detail_success(): dtype = DetectorType.objects.create(name='TypeA', manufacturer=manufacturer) client = APIClient() client.force_authenticate(user=user) - response = client.get(f'/api/detector-type/{dtype.id}/') + response = client.get(f'/api/detector-types/{dtype.id}/') assert response.status_code == 200 assert response.data['id'] == str(dtype.id) assert response.data['name'] == 'TypeA' @@ -23,6 +23,6 @@ def test_get_detector_type_detail_not_found(): client.force_authenticate(user=user) import uuid fake_id = uuid.uuid4() - response = client.get(f'/api/detector-type/{fake_id}/') + response = client.get(f'/api/detector-types/{fake_id}/') assert response.status_code == 404 assert 'detail' in response.data diff --git a/backend/DOSPORTAL/tests/api/test_file_get.py b/backend/DOSPORTAL/tests/api/test_file_get.py index fa80c39..10fce35 100644 --- a/backend/DOSPORTAL/tests/api/test_file_get.py +++ b/backend/DOSPORTAL/tests/api/test_file_get.py @@ -86,26 +86,24 @@ def sample_file(db, org_with_members, owner_user): class TestFileDetail: def test_requires_authentication(self, api_client, sample_file): - response = api_client.get(f'/api/file/{sample_file.id}/') + response = api_client.get(f'/api/files/{sample_file.id}/') assert response.status_code == status.HTTP_401_UNAUTHORIZED def test_file_not_found(self, api_client, owner_user): api_client.force_authenticate(user=owner_user) - response = api_client.get('/api/file/00000000-0000-0000-0000-000000000000/') + response = api_client.get('/api/files/00000000-0000-0000-0000-000000000000/') assert response.status_code == status.HTTP_404_NOT_FOUND - assert 'not found' in response.data['error'].lower() def test_member_can_access_org_file(self, api_client, member_user, sample_file): api_client.force_authenticate(user=member_user) - response = api_client.get(f'/api/file/{sample_file.id}/') + response = api_client.get(f'/api/files/{sample_file.id}/') assert response.status_code == status.HTTP_200_OK assert response.data['filename'] == 'test.txt' def test_outsider_cannot_access_org_file(self, api_client, outsider_user, sample_file): api_client.force_authenticate(user=outsider_user) - response = api_client.get(f'/api/file/{sample_file.id}/') - assert response.status_code == status.HTTP_403_FORBIDDEN - assert 'permission' in response.data['error'].lower() + response = api_client.get(f'/api/files/{sample_file.id}/') + assert response.status_code == status.HTTP_404_NOT_FOUND def test_uploader_can_access_own_file_without_org(self, api_client, owner_user): api_client.force_authenticate(user=owner_user) @@ -118,7 +116,7 @@ def test_uploader_can_access_own_file_without_org(self, api_client, owner_user): owner=None, size=8 ) - response = api_client.get(f'/api/file/{personal_file.id}/') + response = api_client.get(f'/api/files/{personal_file.id}/') assert response.status_code == status.HTTP_200_OK assert response.data['filename'] == 'personal.txt' @@ -127,21 +125,21 @@ def test_uploader_can_access_own_file_without_org(self, api_client, owner_user): class TestFileList: def test_requires_authentication(self, api_client): - response = api_client.get('/api/file/') + response = api_client.get('/api/files/') assert response.status_code == status.HTTP_401_UNAUTHORIZED def test_member_sees_org_files(self, api_client, member_user, sample_file): api_client.force_authenticate(user=member_user) - response = api_client.get('/api/file/') + response = api_client.get('/api/files/') assert response.status_code == status.HTTP_200_OK - assert len(response.data) == 1 - assert response.data[0]['id'] == str(sample_file.id) + assert len(response.data['results']) == 1 + assert response.data['results'][0]['id'] == str(sample_file.id) def test_outsider_does_not_see_org_files(self, api_client, outsider_user, sample_file): api_client.force_authenticate(user=outsider_user) - response = api_client.get('/api/file/') + response = api_client.get('/api/files/') assert response.status_code == status.HTTP_200_OK - assert len(response.data) == 0 + assert len(response.data['results']) == 0 def test_filter_by_organization(self, api_client, owner_user, org_with_members): api_client.force_authenticate(user=owner_user) @@ -165,10 +163,10 @@ def test_filter_by_organization(self, api_client, owner_user, org_with_members): size=5 ) - response = api_client.get(f'/api/file/?org_id={org_with_members.id}') + response = api_client.get(f'/api/files/?owner={org_with_members.id}') assert response.status_code == status.HTTP_200_OK - assert len(response.data) == 1 - assert response.data[0]['id'] == str(file1.id) + assert len(response.data['results']) == 1 + assert response.data['results'][0]['id'] == str(file1.id) def test_filter_by_file_type(self, api_client, owner_user, org_with_members): api_client.force_authenticate(user=owner_user) @@ -190,7 +188,7 @@ def test_filter_by_file_type(self, api_client, owner_user, org_with_members): size=3 ) - response = api_client.get('/api/file/?file_type=log') + response = api_client.get('/api/files/?file_type=log') assert response.status_code == status.HTTP_200_OK - assert len(response.data) == 1 - assert response.data[0]['file_type'] == 'log' + assert len(response.data['results']) == 1 + assert response.data['results'][0]['file_type'] == 'log' diff --git a/backend/DOSPORTAL/tests/api/test_file_upload.py b/backend/DOSPORTAL/tests/api/test_file_upload.py index 31db415..de9c6b4 100644 --- a/backend/DOSPORTAL/tests/api/test_file_upload.py +++ b/backend/DOSPORTAL/tests/api/test_file_upload.py @@ -82,49 +82,25 @@ def org_with_members(db, organization, owner_user, admin_user, member_user): @pytest.mark.django_db class TestFileUploadAPI: - def test_requires_authentication(self, api_client): + def test_requires_authentication(self, api_client, organization): file_content = SimpleUploadedFile("test.txt", b"test", content_type="text/plain") response = api_client.post( - '/api/file/upload/', + '/api/files/', {'filename': 'test.txt', 'file': file_content, 'file_type': 'log'}, format='multipart' ) assert response.status_code == status.HTTP_401_UNAUTHORIZED - def test_upload_without_organization(self, api_client, owner_user): - api_client.force_authenticate(user=owner_user) - file_content = SimpleUploadedFile("test.txt", b"test content", content_type="text/plain") - - response = api_client.post( - '/api/file/upload/', - {'filename': 'test.txt', 'file': file_content, 'file_type': 'log'}, - format='multipart' - ) - - assert response.status_code == status.HTTP_201_CREATED - assert response.data['filename'] == 'test.txt' - assert response.data['file_type'] == 'log' - assert response.data['size'] > 0 - - file_obj = File.objects.get(id=response.data['id']) - assert file_obj.author == owner_user - assert file_obj.owner is None - def test_owner_can_upload_to_organization(self, api_client, owner_user, org_with_members): api_client.force_authenticate(user=owner_user) file_content = SimpleUploadedFile("org_file.txt", b"org content", content_type="text/plain") - + response = api_client.post( - '/api/file/upload/', - { - 'filename': 'org_file.txt', - 'file': file_content, - 'file_type': 'log', - 'owner': str(org_with_members.id) - }, + '/api/files/', + {'filename': 'org_file.txt', 'file': file_content, 'file_type': 'log', 'owner': str(org_with_members.id)}, format='multipart' ) - + assert response.status_code == status.HTTP_201_CREATED file_obj = File.objects.get(id=response.data['id']) assert file_obj.owner == org_with_members @@ -132,70 +108,55 @@ def test_owner_can_upload_to_organization(self, api_client, owner_user, org_with def test_admin_can_upload_to_organization(self, api_client, admin_user, org_with_members): api_client.force_authenticate(user=admin_user) file_content = SimpleUploadedFile("admin_file.txt", b"admin", content_type="text/plain") - + response = api_client.post( - '/api/file/upload/', - { - 'filename': 'admin_file.txt', - 'file': file_content, - 'file_type': 'document', - 'owner': str(org_with_members.id) - }, + '/api/files/', + {'filename': 'admin_file.txt', 'file': file_content, 'file_type': 'document', 'owner': str(org_with_members.id)}, format='multipart' ) - + assert response.status_code == status.HTTP_201_CREATED def test_member_cannot_upload_to_organization(self, api_client, member_user, org_with_members): api_client.force_authenticate(user=member_user) file_content = SimpleUploadedFile("member_file.txt", b"member", content_type="text/plain") - + response = api_client.post( - '/api/file/upload/', - { - 'filename': 'member_file.txt', - 'file': file_content, - 'file_type': 'log', - 'owner': str(org_with_members.id) - }, + '/api/files/', + {'filename': 'member_file.txt', 'file': file_content, 'file_type': 'log', 'owner': str(org_with_members.id)}, format='multipart' ) - + assert response.status_code == status.HTTP_403_FORBIDDEN - assert 'permission' in response.data['error'].lower() + assert 'permission' in response.data['detail'].lower() def test_outsider_cannot_upload_to_organization(self, api_client, outsider_user, org_with_members): api_client.force_authenticate(user=outsider_user) file_content = SimpleUploadedFile("outsider.txt", b"outsider", content_type="text/plain") - + response = api_client.post( - '/api/file/upload/', - { - 'filename': 'outsider.txt', - 'file': file_content, - 'file_type': 'log', - 'owner': str(org_with_members.id) - }, + '/api/files/', + {'filename': 'outsider.txt', 'file': file_content, 'file_type': 'log', 'owner': str(org_with_members.id)}, format='multipart' ) - + assert response.status_code == status.HTTP_403_FORBIDDEN - def test_missing_file(self, api_client, owner_user): + def test_missing_file(self, api_client, owner_user, org_with_members): api_client.force_authenticate(user=owner_user) - + response = api_client.post( - '/api/file/upload/', - {'filename': 'missing.txt', 'file_type': 'log'}, + '/api/files/', + {'filename': 'missing.txt', 'file_type': 'log', 'owner': str(org_with_members.id)}, format='multipart' ) - + assert response.status_code == status.HTTP_400_BAD_REQUEST assert 'no file' in response.data['error'].lower() - def test_multiple_file_types(self, api_client, owner_user): + def test_multiple_file_types(self, api_client, owner_user, org_with_members): api_client.force_authenticate(user=owner_user) - + for file_type in ['log', 'trajectory', 'document']: file_content = SimpleUploadedFile( f"{file_type}.txt", @@ -203,8 +164,8 @@ def test_multiple_file_types(self, api_client, owner_user): content_type="text/plain" ) response = api_client.post( - '/api/file/upload/', - {'filename': f'{file_type}.txt', 'file': file_content, 'file_type': file_type}, + '/api/files/', + {'filename': f'{file_type}.txt', 'file': file_content, 'file_type': file_type, 'owner': str(org_with_members.id)}, format='multipart' ) assert response.status_code == status.HTTP_201_CREATED diff --git a/backend/DOSPORTAL/tests/api/test_measurement_detail.py b/backend/DOSPORTAL/tests/api/test_measurement_detail.py index 2e6a982..c6c4702 100644 --- a/backend/DOSPORTAL/tests/api/test_measurement_detail.py +++ b/backend/DOSPORTAL/tests/api/test_measurement_detail.py @@ -29,7 +29,7 @@ def test_measurement_detail_unauthenticated(api_client, user1, org1): """Test that unauthenticated users get 401.""" m1 = Measurement.objects.create(name="Measurement 1", author=user1, owner=org1) - response = api_client.get(f"/api/measurement/{m1.id}/") + response = api_client.get(f"/api/measurements/{m1.id}/") assert response.status_code == 401 @@ -38,9 +38,8 @@ def test_measurement_detail_not_found(api_client, user1): """Test that non-existent measurement returns 404.""" api_client.force_authenticate(user=user1) - response = api_client.get("/api/measurement/00000000-0000-0000-0000-000000000000/") + response = api_client.get("/api/measurements/00000000-0000-0000-0000-000000000000/") assert response.status_code == 404 - assert 'not found' in response.data['error'].lower() @pytest.mark.django_db @@ -54,7 +53,7 @@ def test_measurement_detail_member_can_access(api_client, user1, user2, org1): # user1 should have access (as member) api_client.force_authenticate(user=user1) - response = api_client.get(f"/api/measurement/{m1.id}/") + response = api_client.get(f"/api/measurements/{m1.id}/") assert response.status_code == 200 assert response.data['name'] == "Measurement 1" assert response.data['id'] == str(m1.id) @@ -71,7 +70,7 @@ def test_measurement_detail_author_can_access(api_client, user1, user2, org1): # user2 should have access (as author) api_client.force_authenticate(user=user2) - response = api_client.get(f"/api/measurement/{m1.id}/") + response = api_client.get(f"/api/measurements/{m1.id}/") assert response.status_code == 200 assert response.data['name'] == "Measurement 1" @@ -87,9 +86,8 @@ def test_measurement_detail_outsider_cannot_access(api_client, user1, user2, org # user2 is NOT member and NOT author - should NOT have access api_client.force_authenticate(user=user2) - response = api_client.get(f"/api/measurement/{m1.id}/") - assert response.status_code == 403 - assert 'permission' in response.data['error'].lower() + response = api_client.get(f"/api/measurements/{m1.id}/") + assert response.status_code == 404 @pytest.mark.django_db @@ -109,7 +107,7 @@ def test_measurement_detail_all_member_types_can_access(api_client, org1): # All three org members should see the measurement for user in [owner_user, admin_user, member_user]: api_client.force_authenticate(user=user) - response = api_client.get(f"/api/measurement/{m1.id}/") + response = api_client.get(f"/api/measurements/{m1.id}/") assert response.status_code == 200 assert response.data['id'] == str(m1.id) @@ -122,11 +120,11 @@ def test_measurement_detail_without_owner(api_client, user1, user2): # user1 (author) should have access api_client.force_authenticate(user=user1) - response = api_client.get(f"/api/measurement/{m1.id}/") + response = api_client.get(f"/api/measurements/{m1.id}/") assert response.status_code == 200 assert response.data['id'] == str(m1.id) # user2 should NOT have access api_client.force_authenticate(user=user2) - response = api_client.get(f"/api/measurement/{m1.id}/") - assert response.status_code == 403 + response = api_client.get(f"/api/measurements/{m1.id}/") + assert response.status_code == 404 diff --git a/backend/DOSPORTAL/tests/api/test_measurement_segments.py b/backend/DOSPORTAL/tests/api/test_measurement_segments.py new file mode 100644 index 0000000..8d126ae --- /dev/null +++ b/backend/DOSPORTAL/tests/api/test_measurement_segments.py @@ -0,0 +1,93 @@ +import pytest +from rest_framework.test import APIClient +from django.contrib.auth.models import User + +from DOSPORTAL.models import Measurement, MeasurementSegment +from DOSPORTAL.models.spectrals import SpectralRecord + + +@pytest.fixture +def api_client(): + return APIClient() + + +@pytest.fixture +def user(db): + return User.objects.create_user(username="owner", password="pass") + + +@pytest.fixture +def other_user(db): + return User.objects.create_user(username="other", password="pass") + + +@pytest.fixture +def measurement(db, user): + return Measurement.objects.create(name="Test measurement", author=user) + + +@pytest.fixture +def spectral_record(db, user): + return SpectralRecord.objects.create(name="Record A", author=user) + + +@pytest.fixture +def segment(db, measurement, spectral_record): + return MeasurementSegment.objects.create( + measurement=measurement, + spectral_record=spectral_record, + position=0, + ) + + +@pytest.mark.django_db +def test_patch_segment_updates_time_range(api_client, user, segment): + api_client.force_authenticate(user=user) + response = api_client.patch( + f"/api/measurement-segments/{segment.id}/", + {"time_from": "2024-01-01T10:00:00Z", "time_to": "2024-01-01T11:00:00Z"}, + format="json", + ) + assert response.status_code == 200 + segment.refresh_from_db() + assert str(segment.time_from) != str(None) + assert str(segment.time_to) != str(None) + + +@pytest.mark.django_db +def test_delete_segment(api_client, user, segment): + api_client.force_authenticate(user=user) + segment_id = segment.id + response = api_client.delete(f"/api/measurement-segments/{segment_id}/") + assert response.status_code == 204 + assert not MeasurementSegment.objects.filter(id=segment_id).exists() + + +@pytest.mark.django_db +def test_delete_segment_forbidden_for_non_author(api_client, other_user, segment): + api_client.force_authenticate(user=other_user) + response = api_client.delete(f"/api/measurement-segments/{segment.id}/") + assert response.status_code in (403, 404) + assert MeasurementSegment.objects.filter(id=segment.id).exists() + + +@pytest.mark.django_db +def test_list_segments_filtered_by_measurement( + api_client, user, measurement, spectral_record +): + other_measurement = Measurement.objects.create(name="Other", author=user) + seg_a = MeasurementSegment.objects.create( + measurement=measurement, spectral_record=spectral_record, position=0 + ) + seg_b = MeasurementSegment.objects.create( + measurement=other_measurement, spectral_record=spectral_record, position=0 + ) + + api_client.force_authenticate(user=user) + response = api_client.get( + f"/api/measurement-segments/?measurement={measurement.id}" + ) + assert response.status_code == 200 + ids = {s["id"] for s in response.json()["results"]} + assert str(seg_a.id) in ids + assert str(seg_b.id) not in ids diff --git a/backend/DOSPORTAL/tests/api/test_measurements.py b/backend/DOSPORTAL/tests/api/test_measurements.py index 18ce670..1024931 100644 --- a/backend/DOSPORTAL/tests/api/test_measurements.py +++ b/backend/DOSPORTAL/tests/api/test_measurements.py @@ -57,9 +57,9 @@ def test_measurements_filtered_by_organization_membership(api_client, user1, use # user1 should see m1 and m2 (from org1 and org2) api_client.force_authenticate(user=user1) - response = api_client.get("/api/measurement/") + response = api_client.get("/api/measurements/") assert response.status_code == 200 - data = response.json() + data = response.json()['results'] measurement_ids = {m['id'] for m in data} assert str(m1.id) in measurement_ids assert str(m2.id) in measurement_ids @@ -67,9 +67,9 @@ def test_measurements_filtered_by_organization_membership(api_client, user1, use # user2 should see only m3 (from org3) api_client.force_authenticate(user=user2) - response = api_client.get("/api/measurement/") + response = api_client.get("/api/measurements/") assert response.status_code == 200 - data = response.json() + data = response.json()['results'] measurement_ids = {m['id'] for m in data} assert str(m1.id) not in measurement_ids assert str(m2.id) not in measurement_ids @@ -90,18 +90,18 @@ def test_measurements_user_sees_own_authored(api_client, user1, user2, org1): # user2 should still see m1 because they are the author api_client.force_authenticate(user=user2) - response = api_client.get("/api/measurement/") + response = api_client.get("/api/measurements/") assert response.status_code == 200 - data = response.json() + data = response.json()['results'] measurement_ids = {m['id'] for m in data} assert str(m1.id) in measurement_ids assert str(m2.id) not in measurement_ids # user1 should see both (member of org1) api_client.force_authenticate(user=user1) - response = api_client.get("/api/measurement/") + response = api_client.get("/api/measurements/") assert response.status_code == 200 - data = response.json() + data = response.json()['results'] measurement_ids = {m['id'] for m in data} assert str(m1.id) in measurement_ids assert str(m2.id) in measurement_ids @@ -122,9 +122,9 @@ def test_measurements_all_member_types_have_access(api_client, org1): # All three should see the measurement for user in [owner_user, admin_user, member_user]: api_client.force_authenticate(user=user) - response = api_client.get("/api/measurement/") + response = api_client.get("/api/measurements/") assert response.status_code == 200 - data = response.json() + data = response.json()['results'] measurement_ids = {m['id'] for m in data} assert str(m1.id) in measurement_ids @@ -132,14 +132,14 @@ def test_measurements_all_member_types_have_access(api_client, org1): @pytest.mark.django_db def test_measurements_no_organizations(api_client, user1): api_client.force_authenticate(user=user1) - response = api_client.get("/api/measurement/") + response = api_client.get("/api/measurements/") assert response.status_code == 200 - assert response.json() == [] + assert response.json()['results'] == [] @pytest.mark.django_db def test_measurements_unauthenticated(api_client): - response = api_client.get("/api/measurement/") + response = api_client.get("/api/measurements/") assert response.status_code == 401 @@ -152,17 +152,17 @@ def test_measurements_without_owner(api_client, user1, user2): # user1 (author) should see it api_client.force_authenticate(user=user1) - response = api_client.get("/api/measurement/") + response = api_client.get("/api/measurements/") assert response.status_code == 200 - data = response.json() + data = response.json()['results'] measurement_ids = {m['id'] for m in data} assert str(m1.id) in measurement_ids # user2 should not see it api_client.force_authenticate(user=user2) - response = api_client.get("/api/measurement/") + response = api_client.get("/api/measurements/") assert response.status_code == 200 - data = response.json() + data = response.json()['results'] measurement_ids = {m['id'] for m in data} assert str(m1.id) not in measurement_ids @@ -176,11 +176,10 @@ def test_measurements_ordered_by_most_recent(api_client, user1, org1): m3 = Measurement.objects.create(name="Measurement 3", author=user1, owner=org1) api_client.force_authenticate(user=user1) - response = api_client.get("/api/measurement/") + response = api_client.get("/api/measurements/") assert response.status_code == 200 - data = response.json() + data = response.json()['results'] - # Should be ordered newest first (m3, m2, m1) assert len(data) == 3 assert data[0]['id'] == str(m3.id) assert data[1]['id'] == str(m2.id) diff --git a/backend/DOSPORTAL/tests/api/test_organization_member.py b/backend/DOSPORTAL/tests/api/test_organization_member.py index 7eff943..ceeb926 100644 --- a/backend/DOSPORTAL/tests/api/test_organization_member.py +++ b/backend/DOSPORTAL/tests/api/test_organization_member.py @@ -50,13 +50,14 @@ def setUp(self): user=self.member_user, organization=self.org, user_type="ME" ) - self.url = f"/api/organizations/{self.org.id}/member/" + self.members_url = f"/api/organizations/{self.org.id}/members/" + self.member_url = lambda u: f"/api/organizations/{self.org.id}/members/{u}/" def test_add_member_as_owner(self): """Owner should be able to add new members.""" self.client.force_authenticate(user=self.owner_user) response = self.client.post( - self.url, {"username": "newuser", "user_type": "ME"} + self.members_url, {"username": "newuser", "user_type": "ME"} ) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertTrue( @@ -69,7 +70,7 @@ def test_add_member_as_admin(self): """Admin should be able to add new members.""" self.client.force_authenticate(user=self.admin_user) response = self.client.post( - self.url, {"username": "newuser", "user_type": "ME"} + self.members_url, {"username": "newuser", "user_type": "ME"} ) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertTrue( @@ -82,7 +83,7 @@ def test_add_member_as_regular_member(self): """Regular member should NOT be able to add new members.""" self.client.force_authenticate(user=self.member_user) response = self.client.post( - self.url, {"username": "newuser", "user_type": "ME"} + self.members_url, {"username": "newuser", "user_type": "ME"} ) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertFalse( @@ -94,7 +95,7 @@ def test_add_member_as_regular_member(self): def test_add_member_unauthenticated(self): """Unauthenticated users should not be able to add members.""" response = self.client.post( - self.url, {"username": "newuser", "user_type": "ME"} + self.members_url, {"username": "newuser", "user_type": "ME"} ) self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) @@ -102,14 +103,14 @@ def test_add_nonexistent_user(self): """Adding a non-existent user should fail.""" self.client.force_authenticate(user=self.owner_user) response = self.client.post( - self.url, {"username": "doesnotexist", "user_type": "ME"} + self.members_url, {"username": "doesnotexist", "user_type": "ME"} ) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_add_duplicate_member(self): """Adding a user who is already a member should fail.""" self.client.force_authenticate(user=self.owner_user) - response = self.client.post(self.url, {"username": "member", "user_type": "ME"}) + response = self.client.post(self.members_url, {"username": "member", "user_type": "ME"}) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertIn("already a member", response.data["detail"].lower()) @@ -117,7 +118,7 @@ def test_add_member_with_owner_role(self): """Adding a member with OW role should fail.""" self.client.force_authenticate(user=self.owner_user) response = self.client.post( - self.url, {"username": "newuser", "user_type": "OW"} + self.members_url, {"username": "newuser", "user_type": "OW"} ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @@ -125,7 +126,7 @@ def test_add_member_with_invalid_role(self): """Adding a member with invalid role should fail.""" self.client.force_authenticate(user=self.owner_user) response = self.client.post( - self.url, {"username": "newuser", "user_type": "INVALID"} + self.members_url, {"username": "newuser", "user_type": "INVALID"} ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @@ -133,7 +134,7 @@ def test_add_member_as_admin_role(self): """Owner should be able to add a new admin.""" self.client.force_authenticate(user=self.owner_user) response = self.client.post( - self.url, {"username": "newuser", "user_type": "AD"} + self.members_url, {"username": "newuser", "user_type": "AD"} ) self.assertEqual(response.status_code, status.HTTP_201_CREATED) org_user = OrganizationUser.objects.get( @@ -144,7 +145,7 @@ def test_add_member_as_admin_role(self): def test_change_member_role_as_owner(self): """Owner should be able to change member roles.""" self.client.force_authenticate(user=self.owner_user) - response = self.client.put(self.url, {"username": "member", "user_type": "AD"}) + response = self.client.put(self.member_url("member"), {"user_type": "AD"}) self.assertEqual(response.status_code, status.HTTP_200_OK) org_user = OrganizationUser.objects.get( user=self.member_user, organization=self.org @@ -154,27 +155,27 @@ def test_change_member_role_as_owner(self): def test_change_member_role_as_admin(self): """Admin should be able to change member roles.""" self.client.force_authenticate(user=self.admin_user) - response = self.client.put(self.url, {"username": "member", "user_type": "AD"}) + response = self.client.put(self.member_url("member"), {"user_type": "AD"}) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_change_member_role_as_regular_member(self): """Regular member should NOT be able to change roles.""" self.client.force_authenticate(user=self.member_user) - response = self.client.put(self.url, {"username": "member", "user_type": "AD"}) + response = self.client.put(self.member_url("member"), {"user_type": "AD"}) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_change_role_to_invalid_value(self): """Changing role to invalid value should fail.""" self.client.force_authenticate(user=self.owner_user) response = self.client.put( - self.url, {"username": "member", "user_type": "INVALID"} + self.member_url("member"), {"user_type": "INVALID"} ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_remove_member_as_owner(self): """Owner should be able to remove members.""" self.client.force_authenticate(user=self.owner_user) - response = self.client.delete(self.url, {"username": "member"}) + response = self.client.delete(self.member_url("member")) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertFalse( OrganizationUser.objects.filter( @@ -185,19 +186,19 @@ def test_remove_member_as_owner(self): def test_remove_member_as_admin(self): """Admin should be able to remove members.""" self.client.force_authenticate(user=self.admin_user) - response = self.client.delete(self.url, {"username": "member"}) + response = self.client.delete(self.member_url("member")) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_remove_member_as_regular_member(self): """Regular member should NOT be able to remove other members.""" self.client.force_authenticate(user=self.member_user) - response = self.client.delete(self.url, {"username": "admin"}) + response = self.client.delete(self.member_url("admin")) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_remove_self(self): """Any member should be able to remove themselves.""" self.client.force_authenticate(user=self.member_user) - response = self.client.delete(self.url, {"username": "member"}) + response = self.client.delete(self.member_url("member")) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertFalse( OrganizationUser.objects.filter( @@ -208,7 +209,7 @@ def test_remove_self(self): def test_remove_owner(self): """Removing the owner should fail.""" self.client.force_authenticate(user=self.admin_user) - response = self.client.delete(self.url, {"username": "owner"}) + response = self.client.delete(self.member_url("owner")) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertTrue( OrganizationUser.objects.filter( @@ -219,46 +220,44 @@ def test_remove_owner(self): def test_remove_non_member(self): """Removing a non-member should fail.""" self.client.force_authenticate(user=self.owner_user) - response = self.client.delete(self.url, {"username": "unrelated"}) + response = self.client.delete(self.member_url("unrelated")) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_operations_on_nonexistent_organization(self): """Operations on non-existent organization should fail.""" self.client.force_authenticate(user=self.owner_user) - fake_url = "/api/organizations/00000000-0000-0000-0000-000000000000/member/" + fake_members_url = "/api/organizations/00000000-0000-0000-0000-000000000000/members/" + fake_member_url = "/api/organizations/00000000-0000-0000-0000-000000000000/members/member/" - # Try to add response = self.client.post( - fake_url, {"username": "newuser", "user_type": "ME"} + fake_members_url, {"username": "newuser", "user_type": "ME"} ) - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - # Try to update - response = self.client.put(fake_url, {"username": "member", "user_type": "AD"}) - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + response = self.client.put(fake_member_url, {"user_type": "AD"}) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - # Try to delete - response = self.client.delete(fake_url, {"username": "member"}) - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + response = self.client.delete(fake_member_url) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_missing_username_parameter(self): """Request without username should fail.""" self.client.force_authenticate(user=self.owner_user) - response = self.client.post(self.url, {"user_type": "ME"}) + response = self.client.post(self.members_url, {"user_type": "ME"}) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_unrelated_user_cannot_add_members(self): """User not in organization should not be able to add members.""" self.client.force_authenticate(user=self.unrelated_user) response = self.client.post( - self.url, {"username": "newuser", "user_type": "ME"} + self.members_url, {"username": "newuser", "user_type": "ME"} ) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_owner_cannot_add_to_different_org(self): """Owner of one organization should not be able to add members to a different organization.""" self.client.force_authenticate(user=self.owner_user) - other_org_url = f"/api/organizations/{self.other_org.id}/member/" + other_org_url = f"/api/organizations/{self.other_org.id}/members/" response = self.client.post( other_org_url, {"username": "newuser", "user_type": "ME"} ) diff --git a/backend/DOSPORTAL/tests/api/test_schema.py b/backend/DOSPORTAL/tests/api/test_schema.py index 5c2ae6d..6e4b82b 100644 --- a/backend/DOSPORTAL/tests/api/test_schema.py +++ b/backend/DOSPORTAL/tests/api/test_schema.py @@ -38,7 +38,7 @@ def test_openapi_schema_contains_endpoints(): "/api/organizations/{org_id}/" in paths ), "Organization detail endpoint should be documented" assert ( - "/api/organizations/{org_id}/member/" in paths + "/api/organizations/{org_id}/members/" in paths ), "Organization member endpoint should be documented" # Test login endpoint has proper documentation diff --git a/backend/DOSPORTAL/tests/api/test_spectral_record.py b/backend/DOSPORTAL/tests/api/test_spectral_record.py index ede799d..8ccf8ab 100644 --- a/backend/DOSPORTAL/tests/api/test_spectral_record.py +++ b/backend/DOSPORTAL/tests/api/test_spectral_record.py @@ -175,33 +175,33 @@ def completed_spectral_record_with_artifact(db, spectral_record): class TestSpectralRecordListEndpoint: def test_list_requires_authentication(self, api_client): - response = api_client.get('/api/spectral-record/') + response = api_client.get('/api/spectral-records/') assert response.status_code == status.HTTP_401_UNAUTHORIZED def test_member_sees_org_records(self, api_client, member_user, spectral_record, org_with_members): api_client.force_authenticate(user=member_user) - response = api_client.get('/api/spectral-record/') + response = api_client.get('/api/spectral-records/') assert response.status_code == status.HTTP_200_OK - assert len(response.data) == 1 - assert response.data[0]['id'] == str(spectral_record.id) + assert len(response.data['results']) == 1 + assert response.data['results'][0]['id'] == str(spectral_record.id) def test_outsider_does_not_see_org_records(self, api_client, outsider_user, spectral_record): api_client.force_authenticate(user=outsider_user) - response = api_client.get('/api/spectral-record/') + response = api_client.get('/api/spectral-records/') assert response.status_code == status.HTTP_200_OK - assert len(response.data) == 0 + assert len(response.data['results']) == 0 def test_list_authenticated(self, api_client, user_with_org, spectral_record): api_client.force_authenticate(user=user_with_org) - response = api_client.get('/api/spectral-record/') + response = api_client.get('/api/spectral-records/') assert response.status_code == status.HTTP_200_OK - assert len(response.data) == 1 - assert response.data[0]['id'] == str(spectral_record.id) - assert response.data[0]['name'] == 'Test Spectral Record' - assert response.data[0]['processing_status'] == SpectralRecord.PROCESSING_PENDING - assert response.data[0]['artifacts_count'] == 0 + assert len(response.data['results']) == 1 + assert response.data['results'][0]['id'] == str(spectral_record.id) + assert response.data['results'][0]['name'] == 'Test Spectral Record' + assert response.data['results'][0]['processing_status'] == SpectralRecord.PROCESSING_PENDING + assert response.data['results'][0]['artifacts_count'] == 0 def test_list_multiple_records(self, api_client, user_with_org, log_file, organization): from django.utils import timezone @@ -220,15 +220,15 @@ def test_list_multiple_records(self, api_client, user_with_org, log_file, organi ) records.append(record) - response = api_client.get('/api/spectral-record/') + response = api_client.get('/api/spectral-records/') assert response.status_code == status.HTTP_200_OK - assert len(response.data) == 3 + assert len(response.data['results']) == 3 - statuses = [item['processing_status'] for item in response.data] + statuses = [item['processing_status'] for item in response.data['results']] assert SpectralRecord.PROCESSING_PENDING in statuses assert SpectralRecord.PROCESSING_COMPLETED in statuses - + def test_owner_field_returns_spectral_record_owner_name(self, api_client, user_with_org, organization, sample_candy_log): from django.utils import timezone @@ -251,14 +251,14 @@ def test_owner_field_returns_spectral_record_owner_name(self, api_client, user_w time_start=timezone.now() ) - response = api_client.get('/api/spectral-record/') + response = api_client.get('/api/spectral-records/') assert response.status_code == status.HTTP_200_OK - assert len(response.data) >= 1 + assert len(response.data['results']) >= 1 - record_data = next((r for r in response.data if r['id'] == str(spectral_record.id)), None) + record_data = next((r for r in response.data['results'] if r['id'] == str(spectral_record.id)), None) assert record_data is not None - assert record_data['owner'] == organization.name + assert record_data['owner']['name'] == organization.name def test_owner_field_null_when_no_spectral_record_owner(self, api_client, user_with_org, sample_candy_log): from django.utils import timezone @@ -281,11 +281,11 @@ def test_owner_field_null_when_no_spectral_record_owner(self, api_client, user_w time_start=timezone.now() ) - response = api_client.get('/api/spectral-record/') + response = api_client.get('/api/spectral-records/') assert response.status_code == status.HTTP_200_OK - record_data = next((r for r in response.data if r['id'] == str(spectral_record.id)), None) + record_data = next((r for r in response.data['results'] if r['id'] == str(spectral_record.id)), None) assert record_data is not None assert record_data['owner'] is None @@ -293,81 +293,82 @@ def test_owner_field_null_when_no_spectral_record_owner(self, api_client, user_w @pytest.mark.django_db class TestSpectralRecordCreateEndpoint: - def test_create_unauthenticated(self, api_client, log_file): - response = api_client.post('/api/spectral-record/create/', { + def test_create_unauthenticated(self, api_client, log_file, organization): + response = api_client.post('/api/spectral-records/', { 'name': 'Test Record', - 'raw_file_id': str(log_file.id) + 'raw_file': str(log_file.id) }) assert response.status_code == status.HTTP_401_UNAUTHORIZED - def test_create_success(self, api_client, user_with_org, log_file): + def test_create_success(self, api_client, user_with_org, log_file, organization): api_client.force_authenticate(user=user_with_org) - + data = { 'name': 'New Spectral Record', - 'raw_file_id': str(log_file.id), + 'raw_file': str(log_file.id), + 'owner': str(organization.id), 'description': 'Test description' } - - response = api_client.post('/api/spectral-record/create/', data) - + + response = api_client.post('/api/spectral-records/', data) + assert response.status_code == status.HTTP_201_CREATED assert response.data['name'] == 'New Spectral Record' assert response.data['processing_status'] == SpectralRecord.PROCESSING_PENDING assert 'message' in response.data - + record = SpectralRecord.objects.get(id=response.data['id']) assert record.name == 'New Spectral Record' assert record.raw_file == log_file assert record.author == user_with_org - assert record.owner == log_file.owner + assert record.owner == organization - def test_create_missing_file_id(self, api_client, user_with_org): + def test_create_missing_file(self, api_client, user_with_org, organization): api_client.force_authenticate(user=user_with_org) - - data = {'name': 'Test Record'} - - response = api_client.post('/api/spectral-record/create/', data) - + + data = {'name': 'Test Record', 'owner': str(organization.id)} + + response = api_client.post('/api/spectral-records/', data) + assert response.status_code == status.HTTP_400_BAD_REQUEST - assert 'raw_file_id is required' in response.data['error'] + assert 'raw_file' in response.data - def test_create_invalid_file_id(self, api_client, user_with_org): + def test_create_invalid_file_id(self, api_client, user_with_org, organization): api_client.force_authenticate(user=user_with_org) - + from uuid import uuid4 - data = {'name': 'Test Record', 'raw_file_id': str(uuid4())} - - response = api_client.post('/api/spectral-record/create/', data) - - assert response.status_code == status.HTTP_404_NOT_FOUND - assert 'not found' in response.data['error'].lower() + data = {'name': 'Test Record', 'raw_file': str(uuid4()), 'owner': str(organization.id)} + + response = api_client.post('/api/spectral-records/', data) + + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert 'raw_file' in response.data def test_create_with_unauthorized_owner(self, api_client, outsider_user, log_file, organization): api_client.force_authenticate(user=outsider_user) - + data = { 'name': 'Test Record', - 'raw_file_id': str(log_file.id), - 'owner': str(organization.id) + 'raw_file': str(log_file.id), + 'owner': str(organization.id), } - - response = api_client.post('/api/spectral-record/create/', data) - + + response = api_client.post('/api/spectral-records/', data) + assert response.status_code == status.HTTP_403_FORBIDDEN - assert 'permission' in response.data['error'].lower() + assert 'permission' in response.data['detail'].lower() def test_create_member_cannot_set_owner(self, api_client, member_user, log_file, org_with_members): api_client.force_authenticate(user=member_user) - + data = { 'name': 'Test Record', - 'raw_file_id': str(log_file.id), - 'owner': str(org_with_members.id) + 'raw_file': str(log_file.id), + 'owner': str(org_with_members.id), } - - response = api_client.post('/api/spectral-record/create/', data) - + + response = api_client.post('/api/spectral-records/', data) + assert response.status_code == status.HTTP_403_FORBIDDEN @@ -379,14 +380,14 @@ class TestSpectralRecordEvolutionEndpoint: def test_evolution_requires_authentication(self, api_client, completed_spectral_record_with_artifact): record = completed_spectral_record_with_artifact - response = api_client.get(f'/api/spectral-record/{record.id}/evolution/') + response = api_client.get(f'/api/spectral-records/{record.id}/evolution/') assert response.status_code == status.HTTP_401_UNAUTHORIZED def test_evolution_success(self, api_client, completed_spectral_record_with_artifact, user_with_org): record = completed_spectral_record_with_artifact api_client.force_authenticate(user=user_with_org) - response = api_client.get(f'/api/spectral-record/{record.id}/evolution/') + response = api_client.get(f'/api/spectral-records/{record.id}/evolution/') assert response.status_code == status.HTTP_200_OK assert 'evolution_values' in response.data @@ -402,19 +403,19 @@ def test_evolution_success(self, api_client, completed_spectral_record_with_arti def test_evolution_record_not_found(self, api_client, user_with_org): from uuid import uuid4 api_client.force_authenticate(user=user_with_org) - response = api_client.get(f'/api/spectral-record/{uuid4()}/evolution/') + response = api_client.get(f'/api/spectral-records/{uuid4()}/evolution/') assert response.status_code == status.HTTP_404_NOT_FOUND def test_evolution_processing_not_completed(self, api_client, spectral_record, user_with_org): api_client.force_authenticate(user=user_with_org) - response = api_client.get(f'/api/spectral-record/{spectral_record.id}/evolution/') + response = api_client.get(f'/api/spectral-records/{spectral_record.id}/evolution/') assert response.status_code == status.HTTP_425_TOO_EARLY def test_evolution_permission_denied(self, api_client, completed_spectral_record_with_artifact, outsider_user): record = completed_spectral_record_with_artifact api_client.force_authenticate(user=outsider_user) - response = api_client.get(f'/api/spectral-record/{record.id}/evolution/') - assert response.status_code == status.HTTP_403_FORBIDDEN + response = api_client.get(f'/api/spectral-records/{record.id}/evolution/') + assert response.status_code == status.HTTP_404_NOT_FOUND @pytest.mark.django_db @@ -422,14 +423,14 @@ class TestSpectralRecordSpectrumEndpoint: def test_spectrum_requires_authentication(self, api_client, completed_spectral_record_with_artifact): record = completed_spectral_record_with_artifact - response = api_client.get(f'/api/spectral-record/{record.id}/spectrum/') + response = api_client.get(f'/api/spectral-records/{record.id}/spectrum/') assert response.status_code == status.HTTP_401_UNAUTHORIZED def test_spectrum_success(self, api_client, completed_spectral_record_with_artifact, user_with_org): record = completed_spectral_record_with_artifact api_client.force_authenticate(user=user_with_org) - response = api_client.get(f'/api/spectral-record/{record.id}/spectrum/') + response = api_client.get(f'/api/spectral-records/{record.id}/spectrum/') assert response.status_code == status.HTTP_200_OK assert 'spectrum_values' in response.data @@ -447,16 +448,16 @@ def test_spectrum_success(self, api_client, completed_spectral_record_with_artif def test_spectrum_record_not_found(self, api_client, user_with_org): from uuid import uuid4 api_client.force_authenticate(user=user_with_org) - response = api_client.get(f'/api/spectral-record/{uuid4()}/spectrum/') + response = api_client.get(f'/api/spectral-records/{uuid4()}/spectrum/') assert response.status_code == status.HTTP_404_NOT_FOUND def test_spectrum_processing_not_completed(self, api_client, spectral_record, user_with_org): api_client.force_authenticate(user=user_with_org) - response = api_client.get(f'/api/spectral-record/{spectral_record.id}/spectrum/') + response = api_client.get(f'/api/spectral-records/{spectral_record.id}/spectrum/') assert response.status_code == status.HTTP_425_TOO_EARLY def test_spectrum_permission_denied(self, api_client, completed_spectral_record_with_artifact, outsider_user): record = completed_spectral_record_with_artifact api_client.force_authenticate(user=outsider_user) - response = api_client.get(f'/api/spectral-record/{record.id}/spectrum/') - assert response.status_code == status.HTTP_403_FORBIDDEN + response = api_client.get(f'/api/spectral-records/{record.id}/spectrum/') + assert response.status_code == status.HTTP_404_NOT_FOUND diff --git a/backend/DOSPORTAL/tests/conftest.py b/backend/DOSPORTAL/tests/conftest.py new file mode 100644 index 0000000..eeacab6 --- /dev/null +++ b/backend/DOSPORTAL/tests/conftest.py @@ -0,0 +1,18 @@ +import boto3 +import pytest +from moto import mock_aws + + +@pytest.fixture(autouse=True) +def mock_s3_storage(settings): + settings.AWS_ACCESS_KEY_ID = "testing" + settings.AWS_SECRET_ACCESS_KEY = "testing" + settings.AWS_STORAGE_BUCKET_NAME = "dosportal-test-bucket" + settings.AWS_S3_REGION_NAME = "us-east-1" + settings.AWS_S3_ENDPOINT_URL = "https://s3.amazonaws.com" + settings.MINIO_PUBLIC_URL = None + + with mock_aws(): + s3 = boto3.client("s3", region_name=settings.AWS_S3_REGION_NAME) + s3.create_bucket(Bucket=settings.AWS_STORAGE_BUCKET_NAME) + yield diff --git a/backend/DOSPORTAL/tests/test_soft_delete.py b/backend/DOSPORTAL/tests/test_soft_delete.py new file mode 100644 index 0000000..b2a2695 --- /dev/null +++ b/backend/DOSPORTAL/tests/test_soft_delete.py @@ -0,0 +1,75 @@ +import pytest +from django.contrib.auth.models import User +from DOSPORTAL.models import Organization, Measurement + + +@pytest.fixture +def user(db): + return User.objects.create_user(username="testuser", password="testpass") + + +@pytest.fixture +def org(db): + return Organization.objects.create(name="Test Org") + + +@pytest.fixture +def measurement(db, user, org): + return Measurement.objects.create(name="Test Measurement", author=user, owner=org) + + +@pytest.mark.django_db +def test_soft_delete_sets_flags(measurement, user): + """soft_delete() sets is_deleted=True, deleted_at and deleted_by.""" + measurement.soft_delete(deleted_by=user) + + # Use objects_default to bypass the active-only manager + m = Measurement.objects_default.get(pk=measurement.pk) + assert m.is_deleted is True + assert m.deleted_at is not None + assert m.deleted_by == user + + +@pytest.mark.django_db +def test_soft_deleted_object_hidden_from_default_manager(measurement, user): + """Soft-deleted objects must NOT appear in Model.objects (default manager).""" + assert Measurement.objects.filter(pk=measurement.pk).exists() + + measurement.soft_delete(deleted_by=user) + + assert not Measurement.objects.filter(pk=measurement.pk).exists() + + +@pytest.mark.django_db +def test_objects_default_returns_deleted(measurement, user): + """objects_default must still return soft-deleted records.""" + measurement.soft_delete(deleted_by=user) + + assert Measurement.objects_default.filter(pk=measurement.pk).exists() + + +@pytest.mark.django_db +def test_restore_clears_flags(measurement, user): + """restore() resets is_deleted, deleted_at and deleted_by.""" + measurement.soft_delete(deleted_by=user) + measurement.restore() + + m = Measurement.objects.get(pk=measurement.pk) + assert m.is_deleted is False + assert m.deleted_at is None + assert m.deleted_by is None + + +@pytest.mark.django_db +def test_queryset_bulk_delete_soft_deletes(user, org): + """QuerySet.delete() on SoftDeleteModel performs soft delete, not hard delete.""" + m1 = Measurement.objects.create(name="M1", author=user, owner=org) + m2 = Measurement.objects.create(name="M2", author=user, owner=org) + + Measurement.objects.filter(owner=org).delete() + + # Both rows still exist in DB + assert Measurement.objects_default.filter(pk=m1.pk).exists() + assert Measurement.objects_default.filter(pk=m2.pk).exists() + # But are hidden from the default manager + assert not Measurement.objects.filter(owner=org).exists() diff --git a/backend/api/permissions.py b/backend/api/permissions.py new file mode 100644 index 0000000..76b048a --- /dev/null +++ b/backend/api/permissions.py @@ -0,0 +1,80 @@ +from rest_framework.permissions import BasePermission, SAFE_METHODS + +from DOSPORTAL.models import OrganizationUser + + +class IsOrganizationMember(BasePermission): + """ + User must be a member (OW, AD, ME) of the organization + identified by 'org_id' in URL kwargs. + """ + + message = "You do not have permission to perform this action." + + def has_permission(self, request, view): + org_id = view.kwargs.get("org_id") + if not org_id: + return False + return OrganizationUser.objects.filter( + user=request.user, + organization_id=org_id, + user_type__in=["OW", "AD", "ME"], + ).exists() + + @staticmethod + def user_is_member(user, org): + """Check if user is a member (OW/AD/ME) of the given org object.""" + return OrganizationUser.objects.filter( + user=user, + organization=org, + user_type__in=["OW", "AD", "ME"], + ).exists() + + +class IsOrganizationAdmin(BasePermission): + """ + User must be an admin or owner (OW, AD) of the organization + identified by 'org_id' in URL kwargs. + """ + + message = "You do not have permission to perform this action." + + def has_permission(self, request, view): + org_id = view.kwargs.get("org_id") + if not org_id: + return False + return OrganizationUser.objects.filter( + user=request.user, + organization_id=org_id, + user_type__in=["OW", "AD"], + ).exists() + + @staticmethod + def user_is_admin(user, org): + """Check if user is an admin or owner (OW/AD) of the given org object.""" + return OrganizationUser.objects.filter( + user=user, + organization=org, + user_type__in=["OW", "AD"], + ).exists() + + +class IsOrganizationAdminOrReadOnly(BasePermission): + """ + Read-only (safe) methods are allowed to any authenticated user. + Write methods require OW/AD of the organization in URL kwargs. + """ + + message = "You do not have permission to perform this action." + + def has_permission(self, request, view): + if request.method in SAFE_METHODS: + return True + org_id = view.kwargs.get("org_id") + if not org_id: + return False + return OrganizationUser.objects.filter( + user=request.user, + organization_id=org_id, + user_type__in=["OW", "AD"], + ).exists() diff --git a/backend/api/serializers/__init__.py b/backend/api/serializers/__init__.py index b89a557..a957e34 100644 --- a/backend/api/serializers/__init__.py +++ b/backend/api/serializers/__init__.py @@ -25,6 +25,7 @@ DetectorManufacturerSerializer, DetectorTypeSerializer, DetectorSerializer, + DetectorWriteRequestSerializer, DetectorLogbookSerializer, ) @@ -60,6 +61,7 @@ "DetectorManufacturerSerializer", "DetectorTypeSerializer", "DetectorSerializer", + "DetectorWriteRequestSerializer", "DetectorLogbookSerializer", # Measurements "MeasurementsSerializer", diff --git a/backend/api/serializers/detectors.py b/backend/api/serializers/detectors.py index 70b5529..66c27c4 100644 --- a/backend/api/serializers/detectors.py +++ b/backend/api/serializers/detectors.py @@ -6,6 +6,7 @@ DetectorType, Detector, DetectorLogbook, + Organization, ) from .organizations import OrganizationSummarySerializer, UserSummarySerializer @@ -40,6 +41,12 @@ def to_representation(self, instance): class DetectorSerializer(serializers.ModelSerializer): owner = OrganizationSummarySerializer(read_only=True) + owner_id = serializers.PrimaryKeyRelatedField( + source="owner", + queryset=Organization.objects.all(), + required=True, + write_only=False, + ) type = DetectorTypeSerializer(read_only=True) type_id = serializers.PrimaryKeyRelatedField( source="type", @@ -47,6 +54,8 @@ class DetectorSerializer(serializers.ModelSerializer): required=True, write_only=False, ) + image = serializers.ImageField(required=False, allow_null=True, use_url=True) + data = serializers.JSONField(required=False, default=dict) class Meta: model = Detector @@ -56,13 +65,54 @@ class Meta: def to_representation(self, instance): rep = super().to_representation(instance) rep["type_id"] = str(instance.type.id) if instance.type else None - rep["owner"] = str(instance.owner.id) if instance.owner else None + rep["owner_id"] = str(instance.owner.id) if instance.owner else None return rep +class DetectorWriteRequestSerializer(serializers.ModelSerializer): + """Schema serializer for multipart write requests.""" + + owner_id = serializers.PrimaryKeyRelatedField( + source="owner", + queryset=Organization.objects.all(), + required=True, + write_only=False, + ) + type_id = serializers.PrimaryKeyRelatedField( + source="type", + queryset=DetectorType.objects.all(), + required=True, + write_only=False, + ) + image = serializers.ImageField(required=False, allow_null=True, use_url=True) + data = serializers.CharField( + required=False, + allow_blank=True, + help_text="Detector metadata encoded as JSON string for multipart/form-data requests.", + ) + + class Meta: + model = Detector + fields = ( + "owner_id", + "type_id", + "image", + "is_deleted", + "deleted_at", + "sn", + "name", + "manufactured_date", + "data", + "deleted_by", + "calib", + "access", + ) + + class DetectorLogbookSerializer(serializers.ModelSerializer): author = UserSummarySerializer(read_only=True) modified_by = UserSummarySerializer(read_only=True) + metadata = serializers.JSONField(required=False, default=dict) class Meta: model = DetectorLogbook diff --git a/backend/api/serializers/measurements.py b/backend/api/serializers/measurements.py index b60b3ba..4810b77 100644 --- a/backend/api/serializers/measurements.py +++ b/backend/api/serializers/measurements.py @@ -1,7 +1,7 @@ """Measurements relatedserializers.""" from rest_framework import serializers -from DOSPORTAL.models import Measurement, File, SpectrumData +from DOSPORTAL.models import Measurement, File, SpectrumData, MeasurementSegment, Organization from DOSPORTAL.models.spectrals import SpectralRecord, SpectralRecordArtifact from DOSPORTAL.models.flights import Flight, Airports from .organizations import OrganizationSummarySerializer, UserSummarySerializer @@ -64,17 +64,25 @@ class Meta: class SpectralRecordArtifactSerializer(serializers.ModelSerializer): """Serializer for spectral record artifacts.""" + artifact = FileSerializer(read_only=True) + class Meta: model = SpectralRecordArtifact - fields = '__all__' + fields = ('id', 'artifact_type', 'artifact', 'spectral_record', 'created_at') read_only_fields = ('id', 'created_at') class SpectralRecordSerializer(serializers.ModelSerializer): """Serializer for spectral records.""" artifacts = SpectralRecordArtifactSerializer(many=True, read_only=True) + artifacts_count = serializers.SerializerMethodField() raw_file = FileSerializer(read_only=True) - + owner = OrganizationSummarySerializer(read_only=True) + author = UserSummarySerializer(read_only=True) + + def get_artifacts_count(self, obj): + return obj.artifacts.count() + class Meta: model = SpectralRecord fields = '__all__' @@ -83,12 +91,48 @@ class Meta: class SpectralRecordCreateSerializer(serializers.ModelSerializer): """Serializer for creating spectral records.""" + raw_file = serializers.PrimaryKeyRelatedField( + queryset=File.objects.all(), + required=True, + ) + class Meta: model = SpectralRecord - fields = ('name', 'raw_file', 'detector', 'description', 'owner', 'author') - + fields = ('name', 'raw_file', 'detector', 'description', 'owner', 'metadata') + def validate_raw_file(self, value): - """Validate that the file is of log type.""" if value and value.file_type != File.FILE_TYPE_LOG: raise serializers.ValidationError("Raw file must be of type 'log'") return value + + +class SpectralRecordUpdateSerializer(serializers.ModelSerializer): + + class Meta: + model = SpectralRecord + fields = ('name', 'description', 'metadata') + + +class MeasurementSegmentSerializer(serializers.ModelSerializer): + class Meta: + model = MeasurementSegment + fields = ('id', 'measurement', 'spectral_record', 'time_from', 'time_to', 'position') + read_only_fields = ('id',) + + +class MeasurementCreateSerializer(serializers.ModelSerializer): + owner_id = serializers.PrimaryKeyRelatedField( + source="owner", + queryset=Organization.objects.all(), + required=False, + allow_null=True, + ) + + class Meta: + model = Measurement + fields = ( + "name", "measurement_type", "description", "public", + "time_start", "time_end", + "base_location_lat", "base_location_lon", "base_location_alt", + "owner_id", + ) diff --git a/backend/api/urls.py b/backend/api/urls.py index a9416c4..6d3dff2 100644 --- a/backend/api/urls.py +++ b/backend/api/urls.py @@ -1,58 +1,57 @@ -from django.urls import path +from django.urls import path, include +from rest_framework.routers import SimpleRouter from . import views -from .views import spectrals +from .viewsets import ( + OrganizationViewSet, + InviteViewSet, + DetectorManufacturerViewSet, + DetectorTypeViewSet, + DetectorViewSet, + DetectorLogbookViewSet, + MeasurementViewSet, + MeasurementSegmentViewSet, + FileViewSet, + SpectralRecordViewSet, + SpectralRecordArtifactViewSet, + FlightViewSet, + AirportsViewSet, +) from drf_spectacular.views import ( SpectacularAPIView, SpectacularSwaggerView, SpectacularRedocView, ) +router = SimpleRouter() +router.register(r"organizations", OrganizationViewSet, basename="organization") +router.register(r"invites", InviteViewSet, basename="invite") +router.register(r"detector-manufacturers", DetectorManufacturerViewSet, basename="detector-manufacturer") +router.register(r"detector-types", DetectorTypeViewSet, basename="detector-type") +router.register(r"detectors", DetectorViewSet, basename="detector") +router.register(r"logbooks", DetectorLogbookViewSet, basename="logbook") +router.register(r"measurements", MeasurementViewSet, basename="measurement") +router.register(r"measurement-segments", MeasurementSegmentViewSet, basename="measurement-segment") +router.register(r"files", FileViewSet, basename="file") +router.register(r"spectral-records", SpectralRecordViewSet, basename="spectral-record") +router.register(r"spectral-record-artifacts", SpectralRecordArtifactViewSet, basename="spectral-record-artifact") +router.register(r"flights", FlightViewSet, basename="flight") +router.register(r"airports", AirportsViewSet, basename="airport") + urlpatterns = [ + path("", include(router.urls)), + path("version/", views.Version), # auth path("login/", views.Login), path("signup/", views.Signup), path("logout/", views.Logout), - # measurements - path("measurement/", views.MeasurementsGet), - path("measurement/add/", views.MeasurementsPost), - path("measurement//", views.MeasurementDetail), - # File endpoints - path("file/", views.FileList), - path("file//", views.FileDetail), - path("file/upload/", views.FileUpload), - # Spectral Record endpoints - path("spectral-record/", spectrals.SpectralRecordList), - path("spectral-record/create/", spectrals.SpectralRecordCreate), - path("spectral-record//", spectrals.SpectralRecordDetail), - path("spectral-record//evolution/", spectrals.SpectralRecordEvolution), - path("spectral-record//spectrum/", spectrals.SpectralRecordSpectrum), - path("spectral-record-artifact/", spectrals.SpectralRecordArtifactList), - # Detectors - path("detector/", views.DetectorGet), - path("detector//qr/", views.DetectorQRCode), - path("detector-manufacturer/", views.detector_manufacturer_list), - path( - "detector-manufacturer//", - views.detector_manufacturer_detail, - ), - path("detector-type/", views.DetectorTypeList), - path("detector-type//", views.DetectorTypeDetail), - # Detector logbooks - path("logbook/", views.DetectorLogbookGet), - path("logbook/add/", views.DetectorLogbookPost), - path("logbook//", views.DetectorLogbookPut), + # Detector QR code (custom, stays as FBV) + path("detectors//qr/", views.DetectorQRCode), # organizations / users path("user/profile/", views.UserProfile), path("user//", views.UserDetail), path("user/organizations/", views.UserOrganizations), path("user/organizations/owned/", views.UserOrganizationsOwned), - path("organizations/", views.Organizations), - path("organizations//", views.OrganizationDetail), - path("organizations//member/", views.OrganizationMember), - path("organizations//invites/", views.CreateOrganizationInvite), - path("invites//accept/", views.AcceptOrganizationInvite), - path("invites//", views.GetOrganizationInviteDetails), # API documentation path("schema/", SpectacularAPIView.as_view(), name="schema"), path("docs/", SpectacularSwaggerView.as_view(url_name="schema"), name="swagger-ui"), diff --git a/backend/api/views/__init__.py b/backend/api/views/__init__.py index efa61eb..6c511c4 100644 --- a/backend/api/views/__init__.py +++ b/backend/api/views/__init__.py @@ -2,53 +2,14 @@ from .auth import Login, Signup, Logout, Version # Detector views -from .detectors import ( - detector_manufacturer_list, - detector_manufacturer_detail, - DetectorTypeList, - DetectorTypeDetail, - DetectorGet, - DetectorLogbookGet, - DetectorLogbookPost, - DetectorLogbookPut, - DetectorQRCode, -) +from .detectors_qr import DetectorQRCode # Organization views from .organizations import ( - Organizations, - OrganizationDetail, - OrganizationMember, UserDetail, UserProfile, UserOrganizations, UserOrganizationsOwned, - CreateOrganizationInvite, - AcceptOrganizationInvite, - GetOrganizationInviteDetails, -) - -# Measurement views -from .measurements import ( - MeasurementsGet, - MeasurementsPost, - MeasurementDetail, -) - -# File views -from .files import ( - FileList, - FileDetail, - FileUpload, -) - -# Spectral views -from .spectrals import ( - SpectralRecordList, - SpectralRecordCreate, - SpectralRecordDetail, - SpectralRecordEvolution, - SpectralRecordSpectrum, ) __all__ = [ @@ -58,38 +19,10 @@ "Logout", "Version", # Detectors - "detector_manufacturer_list", - "detector_manufacturer_detail", - "DetectorTypeList", - "DetectorTypeDetail", - "DetectorGet", - "DetectorLogbookGet", - "DetectorLogbookPost", - "DetectorLogbookPut", "DetectorQRCode", # Organizations - "Organizations", - "OrganizationDetail", - "OrganizationMember", "UserProfile", "UserDetail", "UserOrganizations", "UserOrganizationsOwned", - "CreateOrganizationInvite", - "AcceptOrganizationInvite", - "GetOrganizationInviteDetails", - # Measurements - "MeasurementsGet", - "MeasurementsPost", - "MeasurementDetail", - # Files - "FileList", - "FileDetail", - "FileUpload", - # Spectrals - "SpectralRecordList", - "SpectralRecordCreate", - "SpectralRecordDetail", - "SpectralRecordEvolution", - "SpectralRecordSpectrum", ] diff --git a/backend/api/views/detectors.py b/backend/api/views/detectors.py deleted file mode 100644 index 10a0458..0000000 --- a/backend/api/views/detectors.py +++ /dev/null @@ -1,426 +0,0 @@ -from django.utils.dateparse import parse_datetime -from django.http import HttpResponse -import logging - -from rest_framework.response import Response -from rest_framework.permissions import AllowAny, IsAuthenticated -from rest_framework.decorators import api_view, permission_classes -from rest_framework import status - -from drf_spectacular.utils import extend_schema, OpenApiParameter -from drf_spectacular.types import OpenApiTypes - -from DOSPORTAL.models import ( - Detector, - DetectorManufacturer, - DetectorType, - DetectorLogbook, - Organization, -) -from ..serializers import ( - DetectorSerializer, - DetectorTypeSerializer, - DetectorManufacturerSerializer, - DetectorLogbookSerializer, -) -from ..qr_utils import generate_qr_code, generate_qr_detector_with_label - -logger = logging.getLogger("api.detectors") - - -def check_org_admin_permission(user, org): - """ - Check if user is admin or owner of the organization. - Returns (has_permission: bool, org_user: OrganizationUser|None) - """ - from DOSPORTAL.models import OrganizationUser - - org_user = OrganizationUser.objects.filter(user=user, organization=org).first() - has_permission = org_user and org_user.user_type in ["OW", "AD"] - return has_permission, org_user - - -@extend_schema( - responses={200: DetectorManufacturerSerializer(many=True)}, - request=DetectorManufacturerSerializer, - description="Get all detector manufacturers or create a new manufacturer", - tags=["Detectors"], -) -@api_view(["GET", "POST"]) -@permission_classes((AllowAny,)) -def detector_manufacturer_list(request): - """Get all detector manufacturers or add a new one.""" - if request.method == "GET": - items = DetectorManufacturer.objects.all() - serializer = DetectorManufacturerSerializer(items, many=True) - return Response(serializer.data) - elif request.method == "POST": - serializer = DetectorManufacturerSerializer(data=request.data) - if serializer.is_valid(): - serializer.save() - return Response(serializer.data, status=201) - return Response(serializer.errors, status=400) - - -@extend_schema( - responses={200: DetectorManufacturerSerializer}, - description="Get detector manufacturer by ID", - tags=["Detectors"], - parameters=[ - OpenApiParameter( - name="manufacturer_id", - type=OpenApiTypes.UUID, - location=OpenApiParameter.PATH, - description="Detector manufacturer ID", - ) - ], -) -@api_view(["GET"]) -@permission_classes((AllowAny,)) -def detector_manufacturer_detail(request, manufacturer_id): - """Get detector manufacturer by id.""" - try: - item = DetectorManufacturer.objects.get(id=manufacturer_id) - except DetectorManufacturer.DoesNotExist: - return Response({"detail": "Not found."}, status=404) - serializer = DetectorManufacturerSerializer(item) - return Response(serializer.data) - - -@extend_schema( - responses={200: DetectorTypeSerializer(many=True)}, - request=DetectorTypeSerializer, - description="Get all detector types or create a new detector type", - tags=["Detectors"], -) -@api_view(["GET", "POST"]) -@permission_classes((IsAuthenticated,)) -def DetectorTypeList(request): - """Get all detector types or create a new one.""" - if request.method == "GET": - items = DetectorType.objects.select_related("manufacturer").all() - serializer = DetectorTypeSerializer(items, many=True) - return Response(serializer.data) - elif request.method == "POST": - serializer = DetectorTypeSerializer(data=request.data) - if serializer.is_valid(): - dtype = serializer.save() - return Response( - DetectorTypeSerializer(dtype).data, status=status.HTTP_201_CREATED - ) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - -@extend_schema( - responses={200: DetectorTypeSerializer}, - description="Get detector type by ID", - tags=["Detectors"], - parameters=[ - OpenApiParameter( - name="type_id", - type=OpenApiTypes.UUID, - location=OpenApiParameter.PATH, - description="Detector type ID", - ) - ], -) -@api_view(["GET"]) -@permission_classes((IsAuthenticated,)) -def DetectorTypeDetail(request, type_id): - """Get detector type by id.""" - try: - item = DetectorType.objects.get(id=type_id) - except DetectorType.DoesNotExist: - return Response({"detail": "Not found."}, status=404) - serializer = DetectorTypeSerializer(item, context={"request": request}) - return Response(serializer.data) - - -@extend_schema( - responses={200: DetectorSerializer(many=True)}, - request=DetectorSerializer, - description="Get all detectors or create a new detector", - tags=["Detectors"], -) -@api_view(["GET", "POST"]) -@permission_classes((IsAuthenticated,)) -def DetectorGet(request): - logger.info( - "DetectorGet user=%s auth=%s header=%s", - request.user, - request.auth, - "present" if request.headers.get("Authorization") else "missing", - ) - if request.method == "GET": - items = Detector.objects.select_related("type__manufacturer", "owner").all() - - # Filter by owner organization if provided - owner_id = request.GET.get('owner') - if owner_id: - items = items.filter(owner_id=owner_id) - - serializer = DetectorSerializer(items, many=True) - return Response(serializer.data) - elif request.method == "POST": - data = request.data.copy() - owner_id = data.get("owner") - if not owner_id: - return Response( - {"detail": "Owner organization is required."}, - status=status.HTTP_400_BAD_REQUEST, - ) - try: - org = Organization.objects.get(id=owner_id) - except Organization.DoesNotExist: - return Response( - {"detail": "Organization not found."}, status=status.HTTP_404_NOT_FOUND - ) - has_permission, _ = check_org_admin_permission(request.user, org) - if not has_permission: - return Response( - { - "detail": "You do not have permission to add detectors to this organization." - }, - status=status.HTTP_403_FORBIDDEN, - ) - - # Ensure owner is in access - access_ids = set() - if "access" in data and isinstance(data["access"], list): - access_ids = set(str(a) for a in data["access"]) - owner_id_str = str(owner_id) - access_ids.add(owner_id_str) - data["access"] = list(access_ids) - - serializer = DetectorSerializer(data=data) - if serializer.is_valid(): - detector = serializer.save(owner=org) - return Response( - DetectorSerializer(detector).data, status=status.HTTP_201_CREATED - ) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - else: - return Response( - {"detail": "Method not allowed."}, - status=status.HTTP_405_METHOD_NOT_ALLOWED, - ) - - -@extend_schema( - responses={200: DetectorLogbookSerializer(many=True)}, - description="Get detector logbook entries with optional filters by detector, type, or date range", - tags=["Detectors"], - parameters=[ - OpenApiParameter( - name="detector", - type=OpenApiTypes.UUID, - location=OpenApiParameter.QUERY, - description="Filter by detector ID", - ), - OpenApiParameter( - name="entry_type", - type=OpenApiTypes.STR, - location=OpenApiParameter.QUERY, - description="Filter by entry type", - ), - OpenApiParameter( - name="date_from", - type=OpenApiTypes.DATETIME, - location=OpenApiParameter.QUERY, - description="Filter entries from this date (ISO 8601 format)", - ), - OpenApiParameter( - name="date_to", - type=OpenApiTypes.DATETIME, - location=OpenApiParameter.QUERY, - description="Filter entries until this date (ISO 8601 format)", - ), - ], -) -@api_view(["GET"]) -@permission_classes((IsAuthenticated,)) -def DetectorLogbookGet(request): - items = DetectorLogbook.objects.select_related("detector", "author").all() - - detector_id = request.query_params.get("detector") - if detector_id: - items = items.filter(detector_id=detector_id) - - entry_type = request.query_params.get("entry_type") - if entry_type: - items = items.filter(entry_type=entry_type) - - date_from = request.query_params.get("date_from") - date_to = request.query_params.get("date_to") - - if date_from: - parsed_from = parse_datetime(date_from) - if parsed_from: - items = items.filter(created__gte=parsed_from) - - if date_to: - parsed_to = parse_datetime(date_to) - if parsed_to: - items = items.filter(created__lte=parsed_to) - - serializer = DetectorLogbookSerializer(items, many=True) - return Response(serializer.data) - - -@extend_schema( - request=DetectorLogbookSerializer, - responses={201: DetectorLogbookSerializer}, - description="Create a new detector logbook entry", - tags=["Detectors"], -) -@api_view(["POST"]) -@permission_classes((IsAuthenticated,)) -def DetectorLogbookPost(request): - detector_id = request.data.get("detector") - if detector_id: - try: - detector = Detector.objects.get(id=detector_id) - user_has_access = ( - detector.owner and request.user in detector.owner.users.all() - ) or detector.access.filter(users=request.user).exists() - - if not user_has_access: - return Response( - {"detail": "Access to the detector denied."}, - status=status.HTTP_403_FORBIDDEN, - ) - except Detector.DoesNotExist: - return Response( - {"detail": "Detektor not found."}, status=status.HTTP_404_NOT_FOUND - ) - - serializer = DetectorLogbookSerializer(data=request.data) - if serializer.is_valid(): - serializer.save(author=request.user) - return Response(serializer.data, status=status.HTTP_201_CREATED) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - -@extend_schema( - request=DetectorLogbookSerializer, - responses={200: DetectorLogbookSerializer}, - description="Update a detector logbook entry", - tags=["Detectors"], - parameters=[ - OpenApiParameter( - name="entry_id", - type=OpenApiTypes.UUID, - location=OpenApiParameter.PATH, - description="Logbook entry ID", - ) - ], -) -@api_view(["PUT"]) -@permission_classes((IsAuthenticated,)) -def DetectorLogbookPut(request, entry_id): - try: - entry = DetectorLogbook.objects.get(id=entry_id) - except DetectorLogbook.DoesNotExist: - return Response( - {"detail": "Logbook entry not found."}, status=status.HTTP_404_NOT_FOUND - ) - - # Check if user has access to modify this entry - detector = entry.detector - user_has_access = ( - detector.owner and request.user in detector.owner.users.all() - ) or detector.access.filter(users=request.user).exists() - - if not user_has_access: - return Response( - {"detail": "Access to the detector denied."}, - status=status.HTTP_403_FORBIDDEN, - ) - - # Only allow updating specific fields - allowed_fields = [ - "text", - "entry_type", - "latitude", - "longitude", - "altitude", - "location_text", - "public", - ] - update_data = {k: v for k, v in request.data.items() if k in allowed_fields} - - serializer = DetectorLogbookSerializer(entry, data=update_data, partial=True) - if serializer.is_valid(): - serializer.save(modified_by=request.user) - return Response(serializer.data, status=status.HTTP_200_OK) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - -@extend_schema( - description="Generate QR code for a specific detector", - tags=["Detectors"], - parameters=[ - OpenApiParameter( - name="detector_id", - type=OpenApiTypes.UUID, - location=OpenApiParameter.PATH, - description="Detector ID", - ), - OpenApiParameter( - name="label", - type=OpenApiTypes.STR, - location=OpenApiParameter.QUERY, - description="Include detector label (name and serial number) - true/false", - ), - ], -) -@api_view(["GET"]) -@permission_classes((IsAuthenticated,)) -def DetectorQRCode(request, detector_id): - """ - Generate QR code for a specific detector. - - Query params: - - label: 'true' to include detector name and serial number - """ - try: - detector = Detector.objects.select_related("type").get(id=detector_id) - except Detector.DoesNotExist: - return Response( - {"detail": "Detector not found."}, status=status.HTTP_404_NOT_FOUND - ) - - # Build the logbook creation URL - base_url = request.build_absolute_uri("/").rstrip("/") - logbook_url = f"{base_url}/logbook/{detector.id}/create" - - # Get query parameters - include_label = request.query_params.get("label", "false").lower() == "true" - - # Generate QR code - try: - if include_label: - qr_buffer = generate_qr_detector_with_label( - url=logbook_url, detector_name=detector.name, serial_number=detector.sn - ) - else: - qr_buffer = generate_qr_code(url=logbook_url) - - response = HttpResponse(qr_buffer.read(), content_type="image/png") - filename = f"detector_{detector.sn}_qr.png" - response["Content-Disposition"] = f'inline; filename="{filename}"' - - return response - - except Exception as e: - logger.error( - "DetectorQRCode user=%s auth=%s header=%s error=%s", - request.user, - request.auth, - "present" if request.headers.get("Authorization") else "missing", - str(e), - ) - return Response( - {"detail": "Error generating QR code."}, - status=status.HTTP_500_INTERNAL_SERVER_ERROR, - ) diff --git a/backend/api/views/detectors_qr.py b/backend/api/views/detectors_qr.py new file mode 100644 index 0000000..d429b62 --- /dev/null +++ b/backend/api/views/detectors_qr.py @@ -0,0 +1,85 @@ +from django.http import HttpResponse +import logging + +from rest_framework.response import Response +from rest_framework.permissions import IsAuthenticated +from rest_framework.decorators import api_view, permission_classes +from rest_framework import status + +from drf_spectacular.utils import extend_schema, OpenApiParameter +from drf_spectacular.types import OpenApiTypes + +from DOSPORTAL.models import Detector +from ..qr_utils import generate_qr_code, generate_qr_detector_with_label + +logger = logging.getLogger("api.detectors") + + +@extend_schema( + description="Generate QR code for a specific detector", + tags=["Detectors"], + parameters=[ + OpenApiParameter( + name="detector_id", + type=OpenApiTypes.UUID, + location=OpenApiParameter.PATH, + description="Detector ID", + ), + OpenApiParameter( + name="label", + type=OpenApiTypes.STR, + location=OpenApiParameter.QUERY, + description="Include detector label (name and serial number) - true/false", + ), + ], +) +@api_view(["GET"]) +@permission_classes((IsAuthenticated,)) +def DetectorQRCode(request, detector_id): + """ + Generate QR code for a specific detector. + + Query params: + - label: 'true' to include detector name and serial number + """ + try: + detector = Detector.objects.select_related("type").get(id=detector_id) + except Detector.DoesNotExist: + return Response( + {"detail": "Detector not found."}, status=status.HTTP_404_NOT_FOUND + ) + + # Build the logbook creation URL + base_url = request.build_absolute_uri("/").rstrip("/") + logbook_url = f"{base_url}/logbook/{detector.id}/create" + + # Get query parameters + include_label = request.query_params.get("label", "false").lower() == "true" + + # Generate QR code + try: + if include_label: + qr_buffer = generate_qr_detector_with_label( + url=logbook_url, detector_name=detector.name, serial_number=detector.sn + ) + else: + qr_buffer = generate_qr_code(url=logbook_url) + + response = HttpResponse(qr_buffer.read(), content_type="image/png") + filename = f"detector_{detector.sn}_qr.png" + response["Content-Disposition"] = f'inline; filename="{filename}"' + + return response + + except Exception as e: + logger.error( + "DetectorQRCode user=%s auth=%s header=%s error=%s", + request.user, + request.auth, + "present" if request.headers.get("Authorization") else "missing", + str(e), + ) + return Response( + {"detail": "Error generating QR code."}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR, + ) diff --git a/backend/api/views/files.py b/backend/api/views/files.py deleted file mode 100644 index 20b586d..0000000 --- a/backend/api/views/files.py +++ /dev/null @@ -1,191 +0,0 @@ -"""File management endpoints.""" - -from rest_framework.response import Response -from rest_framework.permissions import IsAuthenticated -from rest_framework.decorators import api_view, permission_classes -from rest_framework import status - -from drf_spectacular.utils import extend_schema, OpenApiParameter -from drf_spectacular.types import OpenApiTypes - -from DOSPORTAL.models import File, OrganizationUser -from ..serializers import FileSerializer, FileUploadSerializer -from .organizations import check_org_member_permission - -import logging - -logger = logging.getLogger(__name__) - -def check_org_member_permission_file(user, file_obj): - """ - Check if user has permission of member (or higher). - Returns (has_permission: bool, org_user: OrganizationUser|None) - """ - if not file_obj.owner: - # Files without organization can be accessed by uploader only - return user == file_obj.author, None - else: - return check_org_member_permission(user, file_obj.owner) - - -@extend_schema( - responses={200: FileSerializer(many=True)}, - description="Get list of files (filtered by user's organizations)", - tags=["Files"], - parameters=[ - OpenApiParameter( - name="org_id", - type=OpenApiTypes.UUID, - location=OpenApiParameter.QUERY, - description="Filter by organization ID", - required=False, - ), - OpenApiParameter( - name="file_type", - type=OpenApiTypes.STR, - location=OpenApiParameter.QUERY, - description="Filter by file type (log, trajectory, document, etc.)", - required=False, - ), - ], -) -@api_view(["GET"]) -@permission_classes([IsAuthenticated]) -def FileList(request): - """ - Get list of files that the user has access to. - User can only see files from organizations where they are owner or admin. - """ - # Get organizations where user is member - user_orgs = OrganizationUser.objects.filter( - user=request.user, - user_type__in=["OW", "AD", "ME"] - ).values_list('organization_id', flat=True) - - # Base queryset: files from user's organizations or uploaded by user - queryset = File.objects.filter( - owner__in=user_orgs - ) | File.objects.filter(author=request.user) - - # Apply filters - org_id = request.GET.get('org_id') - if org_id: - queryset = queryset.filter(owner_id=org_id) - - file_type = request.GET.get('file_type') - if file_type: - queryset = queryset.filter(file_type=file_type) - - # Order by most recent first - queryset = queryset.order_by('-created_at').distinct() - - serializer = FileSerializer(queryset, many=True) - return Response(serializer.data) - - -@extend_schema( - responses={200: FileSerializer}, - description="Get file details by ID", - tags=["Files"], - parameters=[ - OpenApiParameter( - name="file_id", - type=OpenApiTypes.UUID, - location=OpenApiParameter.PATH, - description="File ID", - ) - ], -) -@api_view(["GET"]) -@permission_classes([IsAuthenticated]) -def FileDetail(request, file_id): - """ - Get detailed information about a specific file. - User must be owner or admin of the file's organization. - """ - try: - file_obj = File.objects.get(id=file_id) - except File.DoesNotExist: - return Response( - {'error': 'File not found'}, - status=status.HTTP_404_NOT_FOUND - ) - - # Check permission - has_permission, _ = check_org_member_permission_file(request.user, file_obj) - if not has_permission: - return Response( - {'error': 'You do not have permission to access this file'}, - status=status.HTTP_403_FORBIDDEN - ) - - serializer = FileSerializer(file_obj) - return Response(serializer.data) - - -@extend_schema( - request=FileUploadSerializer, - responses={201: FileSerializer}, - description="Upload a new file", - tags=["Files"], -) -@api_view(["POST"]) -@permission_classes([IsAuthenticated]) -def FileUpload(request): - """ - Upload a file and create File record. - User must be owner or admin of the target organization. - """ - try: - # Validate file presence - if 'file' not in request.FILES: - return Response( - {'error': 'No file was submitted'}, - status=status.HTTP_400_BAD_REQUEST - ) - - # Check organization permission if owner is specified - owner_id = request.data.get('owner') - if owner_id: - org_user = OrganizationUser.objects.filter( - user=request.user, - organization_id=owner_id, - user_type__in=["OW", "AD"] - ).first() - - if not org_user: - return Response( - {'error': 'You do not have permission to upload files to this organization'}, - status=status.HTTP_403_FORBIDDEN - ) - - data = { - 'filename': request.data.get('filename'), - 'file_type': request.data.get('file_type', 'log'), - 'metadata': request.data.get('metadata', {}), - 'file': request.FILES['file'], # Add file directly for validation - } - - # Add owner if provided - if owner_id: - data['owner'] = owner_id - - serializer = FileUploadSerializer(data=data, context={'request': request}) - if serializer.is_valid(): - file_obj = serializer.save(author=request.user) - return Response({ - 'id': str(file_obj.id), - 'filename': file_obj.filename, - 'file_type': file_obj.file_type, - 'size': file_obj.size, - 'created_at': file_obj.created_at.isoformat(), - }, status=status.HTTP_201_CREATED) - - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - except Exception as e: - logger.exception(f"File upload failed: {str(e)}") - return Response( - {'error': 'Upload failed.'}, - status=status.HTTP_500_INTERNAL_SERVER_ERROR - ) diff --git a/backend/api/views/measurements.py b/backend/api/views/measurements.py deleted file mode 100644 index cb0b446..0000000 --- a/backend/api/views/measurements.py +++ /dev/null @@ -1,87 +0,0 @@ -from rest_framework.response import Response -from rest_framework.permissions import AllowAny, IsAuthenticated -from rest_framework.decorators import api_view, permission_classes -from rest_framework import status - -from drf_spectacular.utils import extend_schema, OpenApiParameter -from drf_spectacular.types import OpenApiTypes - -from DOSPORTAL.models import Measurement -from ..serializers import MeasurementsSerializer -from .organizations import get_user_organizations, check_org_member_permission - - -@extend_schema( - tags=["Measurements"], - description="Get list of measurements accessible to the current user (filtered by organization membership)" -) -@api_view(["GET"]) -@permission_classes([IsAuthenticated]) -def MeasurementsGet(request): - # Filter: measurements from user's organizations OR authored by user - user_orgs = get_user_organizations(request.user) - queryset = Measurement.objects.filter( - owner__in=user_orgs - ) | Measurement.objects.filter(author=request.user) - - # Order by most recent first - queryset = queryset.order_by('-time_created').distinct() - - serializer = MeasurementsSerializer(queryset, many=True) - return Response(serializer.data) - - -@extend_schema(tags=["Measurements"]) -@api_view(["POST"]) -@permission_classes((AllowAny,)) -def MeasurementsPost(request): - serializer = MeasurementsSerializer(data=request.data) - if serializer.is_valid(): - serializer.save() - return Response(serializer.data) - - -@extend_schema( - responses={200: MeasurementsSerializer}, - description="Get measurement detail by ID", - tags=["Measurements"], - parameters=[ - OpenApiParameter( - name="measurement_id", - type=OpenApiTypes.UUID, - location=OpenApiParameter.PATH, - description="Measurement ID", - ) - ], -) -@api_view(["GET"]) -@permission_classes([IsAuthenticated]) -def MeasurementDetail(request, measurement_id): - """ - Get detailed information about a specific measurement. - User must be a member of the measurement's organization or the author. - """ - try: - measurement = Measurement.objects.get(id=measurement_id) - except Measurement.DoesNotExist: - return Response( - {'error': 'Measurement not found'}, - status=status.HTTP_404_NOT_FOUND - ) - - # Check permission: user is author OR member of owner organization - if measurement.author == request.user: - # Author always has access - serializer = MeasurementsSerializer(measurement) - return Response(serializer.data) - - if measurement.owner: - has_permission, _ = check_org_member_permission(request.user, measurement.owner) - if has_permission: - serializer = MeasurementsSerializer(measurement) - return Response(serializer.data) - - return Response( - {'error': 'You do not have permission to access this measurement'}, - status=status.HTTP_403_FORBIDDEN - ) \ No newline at end of file diff --git a/backend/api/views/organizations.py b/backend/api/views/organizations.py index a5331db..f50a8ea 100644 --- a/backend/api/views/organizations.py +++ b/backend/api/views/organizations.py @@ -1,56 +1,22 @@ -from django.db import transaction -from django.utils import timezone - from rest_framework.response import Response -from rest_framework.permissions import AllowAny, IsAuthenticated +from rest_framework.permissions import IsAuthenticated from rest_framework.decorators import api_view, permission_classes from rest_framework import status -from drf_spectacular.utils import extend_schema, OpenApiParameter -from drf_spectacular.types import OpenApiTypes +from drf_spectacular.utils import extend_schema from django.contrib.auth.models import User as DjangoUser from DOSPORTAL.models import ( - Organization, OrganizationUser, - OrganizationInvite, ) from ..serializers import ( UserProfileSerializer, UserSummarySerializer, OrganizationUserSerializer, - OrganizationDetailSerializer, OrganizationSummarySerializer, - AddOrganizationMemberRequestSerializer, - CreateOrganizationRequestSerializer, - CreateInviteRequestSerializer, - CreateInviteResponseSerializer, ) -import logging - -logger = logging.getLogger(__name__) - - -def check_org_admin_permission(user, org): - """ - Check if user is admin or owner of the organization. - Returns (has_permission: bool, org_user: OrganizationUser|None) - """ - org_user = OrganizationUser.objects.filter(user=user, organization=org).first() - has_permission = org_user and org_user.user_type in ["OW", "AD"] - return has_permission, org_user - -def check_org_member_permission(user, org): - """ - Check if user has permission of member (or higher). - Returns (has_permission: bool, org_user: OrganizationUser|None) - """ - org_user = OrganizationUser.objects.filter(user=user, organization=org).first() - has_permission = org_user and org_user.user_type in ["OW", "AD", "ME"] - return has_permission, org_user - def get_user_organizations(user, user_types=None): """ @@ -72,215 +38,6 @@ def get_user_organizations(user, user_types=None): ).values_list('organization_id', flat=True) -@extend_schema( - request=CreateOrganizationRequestSerializer, - responses={201: OrganizationDetailSerializer}, - description="Create a new organization (creator becomes owner)", - tags=["Organizations"], -) -@api_view(["POST"]) -@permission_classes((IsAuthenticated,)) -def Organizations(request): - if request.method == "POST": - name = request.data.get("name") - data_policy = request.data.get("data_policy", "PU") - website = request.data.get("website", "") - contact_email = request.data.get("contact_email", "") - description = request.data.get("description", "") - - if not name: - return Response( - {"detail": "Organization name is required."}, - status=status.HTTP_400_BAD_REQUEST, - ) - - try: - org = Organization.objects.create( - name=name, - data_policy=data_policy, - website=website, - contact_email=contact_email, - description=description, - ) - OrganizationUser.objects.create( - user=request.user, organization=org, user_type="OW" - ) - serializer = OrganizationDetailSerializer(org) - logger.exception("Error creating organization") - return Response(serializer.data, status=status.HTTP_201_CREATED) - except Exception: - return Response( - {"detail": "An error occurred while creating the organization."}, - status=status.HTTP_400_BAD_REQUEST, - ) - - -@extend_schema( - responses={200: OrganizationDetailSerializer}, - request=OrganizationDetailSerializer, - description="Get or update organization details", - tags=["Organizations"], - parameters=[ - OpenApiParameter( - name="org_id", - type=OpenApiTypes.UUID, - location=OpenApiParameter.PATH, - description="Organization ID", - ) - ], -) -@api_view(["GET", "PUT"]) -@permission_classes((IsAuthenticated,)) -def OrganizationDetail(request, org_id): - try: - org = Organization.objects.get(id=org_id) - except Organization.DoesNotExist: - return Response( - {"detail": "Organization not found."}, status=status.HTTP_404_NOT_FOUND - ) - - if request.method == "GET": - serializer = OrganizationDetailSerializer(org) - return Response(serializer.data) - - elif request.method == "PUT": - # Check if user is owner or admin - has_permission, _ = check_org_admin_permission(request.user, org) - if not has_permission: - return Response( - {"detail": "You do not have permission to edit this organization."}, - status=status.HTTP_403_FORBIDDEN, - ) - - allowed_fields = [ - "name", - "data_policy", - "website", - "contact_email", - "description", - ] - update_data = {k: v for k, v in request.data.items() if k in allowed_fields} - - serializer = OrganizationDetailSerializer(org, data=update_data, partial=True) - if serializer.is_valid(): - serializer.save() - return Response(serializer.data, status=status.HTTP_200_OK) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - -@extend_schema( - request=AddOrganizationMemberRequestSerializer, - responses={ - 201: {"description": "User added successfully"}, - 200: {"description": "User role updated or user removed"}, - 400: {"description": "Bad request (invalid data, duplicate member, etc.)"}, - 403: {"description": "Permission denied"}, - 404: {"description": "Organization or user not found"}, - }, - description="Manage organization members (add, update role, remove)", - tags=["Organizations"], - parameters=[ - OpenApiParameter( - name="org_id", - type=OpenApiTypes.UUID, - location=OpenApiParameter.PATH, - description="Organization ID", - ) - ], -) -@api_view(["POST", "PUT", "DELETE"]) -@permission_classes((IsAuthenticated,)) -def OrganizationMember(request, org_id): - """ - Permissions: Only owner/admin can do this. - POST: Add a user to an organization by username. - PUT: Change a user's role to an organization by username. - DELETE: Remove a user from an organization by username. - """ - username = request.data.get("username") - user_type = request.data.get("user_type", "ME") - if not username: - return Response({"detail": "Username required."}, status=400) - try: - org = Organization.objects.get(id=org_id) - except Organization.DoesNotExist: - return Response({"detail": "Organization not found."}, status=404) - - if request.method == "POST": - has_permission, _ = check_org_admin_permission(request.user, org) - if not has_permission: - return Response( - {"detail": "You do not have permission to add members."}, status=403 - ) - # Only allow adding Member or Admin roles - if user_type not in ["ME", "AD"]: - return Response( - {"detail": "Invalid user_type. Only ME or AD allowed."}, status=400 - ) - try: - user = DjangoUser.objects.get(username=username) - except DjangoUser.DoesNotExist: - return Response({"detail": "User not found."}, status=404) - if OrganizationUser.objects.filter(user=user, organization=org).exists(): - return Response({"detail": "User already a member."}, status=400) - OrganizationUser.objects.create( - user=user, organization=org, user_type=user_type - ) - return Response({"detail": "User added."}, status=201) - elif request.method == "PUT": - # Only allow owner/admin to change role - has_permission, _ = check_org_admin_permission(request.user, org) - if not has_permission: - return Response( - {"detail": "You do not have permission to change roles."}, status=403 - ) - try: - user = DjangoUser.objects.get(username=username) - except DjangoUser.DoesNotExist: - return Response({"detail": "User not found."}, status=404) - org_member = OrganizationUser.objects.filter( - user=user, organization=org - ).first() - if not org_member: - return Response( - {"detail": "User is not a member of this organization."}, status=404 - ) - if user_type not in ["ME", "AD"]: - return Response({"detail": "Invalid role."}, status=400) - org_member.user_type = user_type - org_member.save() - return Response({"detail": f"Role updated to {user_type}."}, status=200) - elif request.method == "DELETE": - try: - user = DjangoUser.objects.get(username=username) - except DjangoUser.DoesNotExist: - return Response({"detail": "User not found."}, status=404) - - # Only allow owner/admin to remove member OR self to remove self - if user != request.user: # can remove self - has_permission, _ = check_org_admin_permission(request.user, org) - if not has_permission: - return Response( - {"detail": "You do not have permission to remove this member."}, - status=403, - ) - - org_member = OrganizationUser.objects.filter( - user=user, organization=org - ).first() - if not org_member: - return Response( - {"detail": "User is not a member of this organization."}, status=404 - ) - if org_member.user_type == "OW": - return Response( - {"detail": "You cannot remove the owner from the organization."}, - status=403, - ) - org_member.delete() - return Response({"detail": "User removed from organization."}, status=200) - - @extend_schema( responses={200: UserProfileSerializer}, request=UserProfileSerializer, @@ -359,148 +116,3 @@ def UserOrganizationsOwned(request): organizations = [ou.organization for ou in org_users] serializer = OrganizationSummarySerializer(organizations, many=True) return Response(serializer.data) - - -@extend_schema( - request=CreateInviteRequestSerializer, - responses={201: CreateInviteResponseSerializer}, - description="Create a one-time invite link for an organization (owner/admin only)", - tags=["Organizations"], - parameters=[ - OpenApiParameter( - name="org_id", - type=OpenApiTypes.UUID, - location=OpenApiParameter.PATH, - description="Organization ID", - ) - ], -) -@api_view(["POST"]) -@permission_classes((IsAuthenticated,)) -def CreateOrganizationInvite(request, org_id): - """Create a one-time invite link for an organization (owner/admin only).""" - user_type = request.data.get("user_type", "ME") - expires_hours = int(request.data.get("expires_hours", 24)) - expires_hours = min(max(expires_hours, 1), 168) # Clamp time to 1-168 hours - try: - org = Organization.objects.get(id=org_id) - except Organization.DoesNotExist: - return Response({"detail": "Organization not found."}, status=404) - has_permission, _ = check_org_admin_permission(request.user, org) - if not has_permission: - return Response( - {"detail": "You do not have permission to create invites."}, status=403 - ) - if user_type not in ["ME", "AD"]: - return Response({"detail": "Invalid user_type."}, status=400) - - # Generate token and hash - token = OrganizationInvite.generate_token() - token_hash = OrganizationInvite.hash_token(token) - expires_at = timezone.now() + timezone.timedelta(hours=expires_hours) - invite = OrganizationInvite.objects.create( - organization=org, - token_hash=token_hash, - user_type=user_type, - created_by=request.user, - expires_at=expires_at, - ) - invite_url = f"/invite/{token}/" - return Response( - { - "invite_url": invite_url, - "expires_at": invite.expires_at, - "user_type": invite.user_type, - }, - status=201, - ) - - -@extend_schema( - description="Accept an organization invite using a one-time token", - tags=["Organizations"], - parameters=[ - OpenApiParameter( - name="token", - type=OpenApiTypes.STR, - location=OpenApiParameter.PATH, - description="One-time invite token", - ) - ], -) -@api_view(["POST"]) -@permission_classes((IsAuthenticated,)) -def AcceptOrganizationInvite(request, token): - """Accept an invite link (one-time).""" - token_hash = OrganizationInvite.hash_token(token) - try: - with transaction.atomic(): - invite = OrganizationInvite.objects.select_for_update().get( - token_hash=token_hash - ) - if not invite.is_active: - return Response( - {"detail": "Invite is not active (expired, used, or revoked)."}, - status=400, - ) - if OrganizationUser.objects.filter( - user=request.user, organization=invite.organization - ).exists(): - return Response( - {"detail": "You are already a member of this organization."}, - status=400, - ) - OrganizationUser.objects.create( - user=request.user, - organization=invite.organization, - user_type=invite.user_type, - ) - invite.used_at = timezone.now() - invite.used_by = request.user - invite.save() - return Response( - { - "detail": "Joined.", - "organization_id": str(invite.organization.id), - "user_type": invite.user_type, - }, - status=200, - ) - except OrganizationInvite.DoesNotExist: - return Response({"detail": "Invalid invite token."}, status=404) - - -@extend_schema( - description="Get details about an organization invite for preview before joining", - tags=["Organizations"], - parameters=[ - OpenApiParameter( - name="token", - type=OpenApiTypes.STR, - location=OpenApiParameter.PATH, - description="One-time invite token", - ) - ], -) -@api_view(["GET"]) -@permission_classes((AllowAny,)) -def GetOrganizationInviteDetails(request, token): - """Get details about an invite and its organization for preview before joining.""" - token_hash = OrganizationInvite.hash_token(token) - try: - invite = OrganizationInvite.objects.select_related("organization").get( - token_hash=token_hash - ) - org = invite.organization - org_data = OrganizationDetailSerializer(org).data - return Response( - { - "organization": org_data, - "user_type": invite.user_type, - "expires_at": invite.expires_at, - "is_active": invite.is_active, - }, - status=200, - ) - except OrganizationInvite.DoesNotExist: - return Response({"detail": "Invalid invite token."}, status=404) diff --git a/backend/api/views/spectrals.py b/backend/api/views/spectrals.py deleted file mode 100644 index 7547153..0000000 --- a/backend/api/views/spectrals.py +++ /dev/null @@ -1,371 +0,0 @@ -""" -API views for SpectralRecord management with Parquet support. -""" -from rest_framework.decorators import api_view, permission_classes -from rest_framework.response import Response -from rest_framework.permissions import IsAuthenticated -from rest_framework import status -import pandas as pd -import numpy as np - -import logging -from DOSPORTAL.models import File, OrganizationUser -from DOSPORTAL.models.detectors import Detector -from DOSPORTAL.models.spectrals import SpectralRecord, SpectralRecordArtifact -from .organizations import check_org_member_permission -from ..serializers.organizations import UserSummarySerializer -from ..serializers.measurements import FileSerializer - -logger = logging.getLogger(__name__) - -@api_view(['GET']) -@permission_classes([IsAuthenticated]) -def SpectralRecordList(request): - """List spectral records filtered by user's organization membership.""" - try: - user_orgs = OrganizationUser.objects.filter( - user=request.user, - user_type__in=["OW", "AD", "ME"] - ).values_list('organization_id', flat=True) - - queryset = SpectralRecord.objects.filter( - owner__in=user_orgs - ) | SpectralRecord.objects.filter(author=request.user) - - queryset = queryset.select_related('raw_file', 'author', 'owner').distinct() - - data = [] - for record in queryset: - data.append({ - 'id': str(record.id), - 'name': record.name, - 'processing_status': record.processing_status, - 'created': record.created.isoformat(), - 'author': record.author.username if record.author else None, - 'owner': record.owner.name if record.owner else None, - 'raw_file_id': str(record.raw_file.id) if record.raw_file else None, - 'artifacts_count': record.artifacts.count() - }) - - return Response(data) - - except Exception as e: - logger.exception(f"Failed to list spectral records: {str(e)}") - return Response( - {'error': 'Failed to list spectral records'}, - status=status.HTTP_500_INTERNAL_SERVER_ERROR - ) - -@api_view(['POST']) -@permission_classes([IsAuthenticated]) -def SpectralRecordCreate(request): - """Create a new SpectralRecord (triggers async processing).""" - try: - data = request.data - - # Get raw file - raw_file_id = data.get('raw_file_id') - if not raw_file_id: - return Response( - {'error': 'raw_file_id is required'}, - status=status.HTTP_400_BAD_REQUEST - ) - - try: - raw_file = File.objects.get(id=raw_file_id, file_type=File.FILE_TYPE_LOG) - except File.DoesNotExist: - return Response( - {'error': 'Raw file not found or not a log file'}, - status=status.HTTP_404_NOT_FOUND - ) - - # Check if user wants to set explicit owner - owner_id = data.get('owner') - if owner_id: - # Check if user has permission to create records in this organization - org_user = OrganizationUser.objects.filter( - user=request.user, - organization_id=owner_id, - user_type__in=["OW", "AD"] - ).first() - - if not org_user: - return Response( - {'error': 'You do not have permission to create records in this organization'}, - status=status.HTTP_403_FORBIDDEN - ) - owner = org_user.organization - else: - # Use raw file's owner by default - owner = raw_file.owner - - record = SpectralRecord.objects.create( - name=data.get('name', 'Spectral Record'), - raw_file=raw_file, - author=request.user, - owner=owner, - description=data.get('description', ''), - processing_status=SpectralRecord.PROCESSING_PENDING - ) - - # Optionally attach a detector - detector_id = data.get('detector') - if detector_id: - try: - detector = Detector.objects.get(id=detector_id) - record.detector = detector - record.save(update_fields=['detector']) - except Detector.DoesNotExist as e: - logger.info(f"detector was not attached to spectral record {str(record.id)}: {str(e)}") - - return Response({ - 'id': str(record.id), - 'name': record.name, - 'processing_status': record.processing_status, - 'message': 'SpectralRecord created, async processing scheduled' - }, status=status.HTTP_201_CREATED) - - except Exception as e: - logger.exception(f'Failed to create spectral record: {str(e)}') - return Response( - {'error': 'Failed to create spectral record.'}, - status=status.HTTP_500_INTERNAL_SERVER_ERROR - ) - -def check_spectral_record_permission(user, record): - """Check if user has access to spectral record.""" - if not record.owner: - return user == record.author, None - else: - return check_org_member_permission(user, record.owner) - - -@api_view(['GET']) -@permission_classes([IsAuthenticated]) -def SpectralRecordDetail(request, record_id): - """Get details of a single spectral record.""" - try: - try: - record = SpectralRecord.objects.select_related('raw_file', 'author', 'owner', 'detector').get(id=record_id) - except SpectralRecord.DoesNotExist: - return Response( - {'error': 'SpectralRecord not found'}, - status=status.HTTP_404_NOT_FOUND - ) - - has_permission, _ = check_spectral_record_permission(request.user, record) - if not has_permission: - return Response( - {'error': 'You do not have permission to access this record'}, - status=status.HTTP_403_FORBIDDEN - ) - - data = { - 'id': str(record.id), - 'name': record.name, - 'processing_status': record.processing_status, - 'created': record.created.isoformat(), - 'author': UserSummarySerializer(record.author).data if record.author else None, - 'owner': record.owner.name if record.owner else None, - 'raw_file_id': str(record.raw_file.id) if record.raw_file else None, - 'artifacts_count': record.artifacts.count(), - 'description': record.description, - 'detector': {'id': str(record.detector.id), 'name': record.detector.name} if record.detector else None, - } - - return Response(data) - - except Exception as e: - logger.exception(f'Failed to get spectral record: {str(e)}') - return Response( - {'error': 'Failed to get spectral record.'}, - status=status.HTTP_500_INTERNAL_SERVER_ERROR - ) - - -@api_view(['GET']) -@permission_classes([IsAuthenticated]) -def SpectralRecordArtifactList(request): - try: - # Get query parameters - record_id = request.GET.get('record_id') - artifact_type = request.GET.get('artifact_type') - - if not record_id: - return Response( - {'error': 'record_id parameter is required'}, - status=status.HTTP_400_BAD_REQUEST - ) - - try: - record = SpectralRecord.objects.get(id=record_id) - except SpectralRecord.DoesNotExist: - return Response( - {'error': 'SpectralRecord not found'}, - status=status.HTTP_404_NOT_FOUND - ) - - has_permission, _ = check_spectral_record_permission(request.user, record) - if not has_permission: - return Response( - {'error': 'You do not have permission to access this record'}, - status=status.HTTP_403_FORBIDDEN - ) - - # Build queryset with filters - queryset = SpectralRecordArtifact.objects.filter( - spectral_record=record - ).select_related('artifact', 'artifact__author', 'artifact__owner') - - if artifact_type: - queryset = queryset.filter(artifact_type=artifact_type) - - queryset = queryset.order_by('created_at') - - data = [] - for artifact in queryset: - artifact_data = { - 'id': str(artifact.id), - 'artifact_type': artifact.artifact_type, - 'created_at': artifact.created_at.isoformat(), - 'file': FileSerializer(artifact.artifact).data if artifact.artifact else None - } - data.append(artifact_data) - - return Response(data) - - except Exception as e: - return Response( - {'error': f'Failed to list spectral record artifacts: {str(e)}'}, - status=status.HTTP_500_INTERNAL_SERVER_ERROR - ) - - -def _load_spectral_parquet(record): - """Load Parquet DataFrame from a completed SpectralRecord's artifact. - Returns (df, error_response). If error_response is not None, return it directly. - """ - if record.processing_status != SpectralRecord.PROCESSING_COMPLETED: - return None, Response( - {'error': f'Processing not completed. Status: {record.processing_status}'}, - status=status.HTTP_425_TOO_EARLY - ) - - try: - artifact = SpectralRecordArtifact.objects.get( - spectral_record=record, - artifact_type=SpectralRecordArtifact.SPECTRAL_FILE - ) - except SpectralRecordArtifact.DoesNotExist: - return None, Response( - {'error': 'Parquet artifact not found'}, - status=status.HTTP_404_NOT_FOUND - ) - - artifact.artifact.file.open('rb') - df = pd.read_parquet(artifact.artifact.file, engine='fastparquet') - artifact.artifact.file.close() - - channel_cols = [col for col in df.columns if col.startswith('channel_')] - df[channel_cols] = df[channel_cols].fillna(0) - return df, None - - -@api_view(['GET']) -@permission_classes([IsAuthenticated]) -def SpectralRecordEvolution(request, record_id): - """Get counts-per-second evolution over time from Parquet artifact. - - Returns {evolution_values: [[time_ms, cps], ...], total_time: float} - """ - try: - - try: - record = SpectralRecord.objects.select_related('calib').get(id=record_id) - except SpectralRecord.DoesNotExist: - return Response({'error': 'SpectralRecord not found'}, status=status.HTTP_404_NOT_FOUND) - - has_permission, _ = check_spectral_record_permission(request.user, record) - if not has_permission: - return Response({'error': 'You do not have permission to access this record'}, status=status.HTTP_403_FORBIDDEN) - - df, err = _load_spectral_parquet(record) - if err: - return err - - channel_columns = [col for col in df.columns if col.startswith('channel_')] - - total_time = float(df['time_ms'].max() - df['time_ms'].min()) - if total_time == 0 or np.isnan(total_time) or np.isinf(total_time): - total_time = 1.0 # avoid division by zero for single-row data - - row_sums = df[channel_columns].sum(axis=1) - counts_per_second = row_sums / total_time - - # Replace any NaN/inf with 0 to ensure JSON serialization - counts_per_second = counts_per_second.replace([np.inf, -np.inf], 0).fillna(0) - time_series = df['time_ms'].replace([np.inf, -np.inf], 0).fillna(0) - - evolution_values = list(zip(time_series.astype(float).tolist(), counts_per_second.tolist())) - - return Response({ - 'evolution_values': evolution_values, - 'total_time': total_time, - }) - - except Exception as e: - print(f'Failed to generate evolution. {str(e)}') - return Response({'error': 'Failed to generate evolution data.'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) - - -@api_view(['GET']) -@permission_classes([IsAuthenticated]) -def SpectralRecordSpectrum(request, record_id): - """Get energy/channel spectrum (sum over all exposures) from Parquet artifact. - - Returns {spectrum_values: [[channel_or_keV, cps], ...], total_time: float, calib: bool} - """ - try: - try: - record = SpectralRecord.objects.select_related('calib').get(id=record_id) - except SpectralRecord.DoesNotExist: - return Response({'error': 'SpectralRecord not found'}, status=status.HTTP_404_NOT_FOUND) - - has_permission, _ = check_spectral_record_permission(request.user, record) - if not has_permission: - return Response({'error': 'You do not have permission to access this record'}, status=status.HTTP_403_FORBIDDEN) - - df, err = _load_spectral_parquet(record) - if err: - return err - - channel_columns = [col for col in df.columns if col.startswith('channel_')] - - total_time = float(df['time_ms'].max() - df['time_ms'].min()) - if total_time == 0: - total_time = 1.0 - - # Sum all rows per channel → total counts, then divide by time → cps - channel_sums = df[channel_columns].sum(axis=0) / total_time - channel_sums = channel_sums.fillna(0) - - has_calib = record.calib is not None - spectrum_values = [] - for col in channel_columns: - channel_num = int(col.replace('channel_', '')) - cps = float(channel_sums[col]) - if has_calib: - x_val = (record.calib.coef0 + channel_num * record.calib.coef1) / 1000 # keV - else: - x_val = channel_num - spectrum_values.append([x_val, cps]) - - return Response({ - 'spectrum_values': spectrum_values, - 'total_time': total_time, - 'calib': has_calib, - }) - - except Exception as e: - print(f'Failed to generate spectrum. {str(e)}') - return Response({'error': 'Failed to generate spectrum data.'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) \ No newline at end of file diff --git a/backend/api/viewsets/__init__.py b/backend/api/viewsets/__init__.py new file mode 100644 index 0000000..7d0d020 --- /dev/null +++ b/backend/api/viewsets/__init__.py @@ -0,0 +1,28 @@ +from .organizations import OrganizationViewSet +from .invites import InviteViewSet +from .detectors import ( + DetectorManufacturerViewSet, + DetectorTypeViewSet, + DetectorViewSet, + DetectorLogbookViewSet, +) +from .measurements import MeasurementViewSet, MeasurementSegmentViewSet +from .files import FileViewSet +from .spectrals import SpectralRecordViewSet, SpectralRecordArtifactViewSet +from .flights import FlightViewSet, AirportsViewSet + +__all__ = [ + "OrganizationViewSet", + "InviteViewSet", + "DetectorManufacturerViewSet", + "DetectorTypeViewSet", + "DetectorViewSet", + "DetectorLogbookViewSet", + "MeasurementViewSet", + "MeasurementSegmentViewSet", + "FileViewSet", + "SpectralRecordViewSet", + "SpectralRecordArtifactViewSet", + "FlightViewSet", + "AirportsViewSet", +] diff --git a/backend/api/viewsets/detectors.py b/backend/api/viewsets/detectors.py new file mode 100644 index 0000000..41f4af8 --- /dev/null +++ b/backend/api/viewsets/detectors.py @@ -0,0 +1,214 @@ +from django.utils.dateparse import parse_datetime +from rest_framework.permissions import IsAuthenticated, AllowAny +from rest_framework.viewsets import ModelViewSet +from rest_framework.parsers import MultiPartParser, FormParser, JSONParser +from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiParameter, OpenApiRequest +from drf_spectacular.types import OpenApiTypes +from rest_framework.exceptions import PermissionDenied, NotFound + +from DOSPORTAL.models import ( + DetectorManufacturer, + DetectorType, + Detector, + DetectorLogbook, + OrganizationUser, +) +from ..serializers import ( + DetectorManufacturerSerializer, + DetectorTypeSerializer, + DetectorSerializer, + DetectorWriteRequestSerializer, + DetectorLogbookSerializer, +) +from ..viewsets_base import SoftDeleteModelViewSet + + +@extend_schema_view( + list=extend_schema(description="List all detector manufacturers.", tags=["Detectors"]), + create=extend_schema(description="Create a detector manufacturer.", tags=["Detectors"]), + retrieve=extend_schema(description="Get detector manufacturer by ID.", tags=["Detectors"]), + update=extend_schema(description="Update a detector manufacturer.", tags=["Detectors"]), + partial_update=extend_schema(description="Partially update a detector manufacturer.", tags=["Detectors"]), + destroy=extend_schema(description="Delete a detector manufacturer.", tags=["Detectors"]), +) +class DetectorManufacturerViewSet(ModelViewSet): + queryset = DetectorManufacturer.objects.all().order_by("name") + serializer_class = DetectorManufacturerSerializer + + def get_permissions(self): + if self.action in ("list", "retrieve"): + return [AllowAny()] + return [IsAuthenticated()] + + +@extend_schema_view( + list=extend_schema(description="List all detector types.", tags=["Detectors"]), + create=extend_schema(description="Create a detector type.", tags=["Detectors"]), + retrieve=extend_schema(description="Get detector type by ID.", tags=["Detectors"]), + update=extend_schema(description="Update a detector type.", tags=["Detectors"]), + partial_update=extend_schema(description="Partially update a detector type.", tags=["Detectors"]), + destroy=extend_schema(description="Delete a detector type.", tags=["Detectors"]), +) +class DetectorTypeViewSet(ModelViewSet): + queryset = DetectorType.objects.select_related("manufacturer").order_by("name") + serializer_class = DetectorTypeSerializer + permission_classes = [IsAuthenticated] + + +@extend_schema_view( + list=extend_schema( + description="List detectors accessible to the current user (filtered by org membership).", + tags=["Detectors"], + parameters=[ + OpenApiParameter( + name="owner", + type=OpenApiTypes.UUID, + location=OpenApiParameter.QUERY, + description="Filter by organization ID", + required=False, + ), + ], + ), + create=extend_schema( + description="Create a detector. The owner org must be one where the user is admin/owner.", + tags=["Detectors"], + request=OpenApiRequest( + request=DetectorWriteRequestSerializer, + encoding={"data": {"contentType": "application/json"}}, + ), + ), + retrieve=extend_schema(description="Get detector detail by ID.", tags=["Detectors"]), + update=extend_schema( + description="Update a detector (org admin/owner only).", + tags=["Detectors"], + request=OpenApiRequest( + request=DetectorWriteRequestSerializer, + encoding={"data": {"contentType": "application/json"}}, + ), + ), + partial_update=extend_schema( + description="Partially update a detector (org admin/owner only).", + tags=["Detectors"], + request=OpenApiRequest( + request=DetectorWriteRequestSerializer, + encoding={"data": {"contentType": "application/json"}}, + ), + ), + destroy=extend_schema(description="Soft-delete a detector (org admin/owner only).", tags=["Detectors"]), +) +class DetectorViewSet(SoftDeleteModelViewSet): + + serializer_class = DetectorSerializer + permission_classes = [IsAuthenticated] + parser_classes = [MultiPartParser, FormParser, JSONParser] + http_method_names = ["get", "post", "put", "patch", "delete", "head", "options"] + + def get_queryset(self): + user = self.request.user + user_orgs = OrganizationUser.objects.filter( + user=user, user_type__in=["OW", "AD", "ME"] + ).values_list("organization_id", flat=True) + qs = Detector.objects.filter(owner__in=user_orgs).select_related( + "type__manufacturer", "owner" + ).order_by("-created") + owner_id = self.request.query_params.get("owner") + if owner_id: + qs = qs.filter(owner_id=owner_id) + return qs + + def perform_create(self, serializer): + owner = serializer.validated_data.get("owner") + if not OrganizationUser.objects.filter( + user=self.request.user, + organization=owner, + user_type__in=["OW", "AD"], + ).exists(): + raise PermissionDenied() + serializer.save() + + def _user_is_org_admin(self, detector): + if not detector.owner: + return False + return OrganizationUser.objects.filter( + user=self.request.user, + organization=detector.owner, + user_type__in=["OW", "AD"], + ).exists() + + def perform_update(self, serializer): + if not self._user_is_org_admin(serializer.instance): + raise PermissionDenied() + serializer.save() + + def perform_destroy(self, instance): + if not self._user_is_org_admin(instance): + raise PermissionDenied() + instance.soft_delete(deleted_by=self.request.user) + + +@extend_schema_view( + list=extend_schema( + description="List detector logbook entries with optional filters.", + tags=["Detectors"], + parameters=[ + OpenApiParameter("detector", OpenApiTypes.UUID, OpenApiParameter.QUERY, required=False), + OpenApiParameter("entry_type", OpenApiTypes.STR, OpenApiParameter.QUERY, required=False), + OpenApiParameter("date_from", OpenApiTypes.DATETIME, OpenApiParameter.QUERY, required=False), + OpenApiParameter("date_to", OpenApiTypes.DATETIME, OpenApiParameter.QUERY, required=False), + ], + ), + create=extend_schema(description="Create a logbook entry.", tags=["Detectors"]), + retrieve=extend_schema(description="Get a logbook entry by ID.", tags=["Detectors"]), + update=extend_schema(description="Update a logbook entry.", tags=["Detectors"]), + partial_update=extend_schema(description="Partially update a logbook entry.", tags=["Detectors"]), + destroy=extend_schema(description="Soft-delete a logbook entry.", tags=["Detectors"]), +) +class DetectorLogbookViewSet(SoftDeleteModelViewSet): + serializer_class = DetectorLogbookSerializer + permission_classes = [IsAuthenticated] + + def get_queryset(self): + qs = DetectorLogbook.objects.select_related("detector", "author").all() + detector_id = self.request.query_params.get("detector") + if detector_id: + qs = qs.filter(detector_id=detector_id) + entry_type = self.request.query_params.get("entry_type") + if entry_type: + qs = qs.filter(entry_type=entry_type) + date_from = self.request.query_params.get("date_from") + if date_from: + parsed = parse_datetime(date_from) + if parsed: + qs = qs.filter(created__gte=parsed) + date_to = self.request.query_params.get("date_to") + if date_to: + parsed = parse_datetime(date_to) + if parsed: + qs = qs.filter(created__lte=parsed) + return qs + + def _has_detector_access(self, detector): + return ( + detector.owner and self.request.user in detector.owner.users.all() + ) or detector.access.filter(users=self.request.user).exists() + + def perform_create(self, serializer): + detector_id = self.request.data.get("detector") + if detector_id: + try: + detector = Detector.objects.get(id=detector_id) + except Detector.DoesNotExist: + raise NotFound("Detector not found.") + if not self._has_detector_access(detector): + raise PermissionDenied("Access to the detector denied.") + serializer.save(author=self.request.user) + + def perform_update(self, serializer): + if not self._has_detector_access(serializer.instance.detector): + raise PermissionDenied("Access to the detector denied.") + serializer.save(modified_by=self.request.user) + + def perform_destroy(self, instance): + if not self._has_detector_access(instance.detector): + raise PermissionDenied("Access to the detector denied.") + instance.soft_delete(deleted_by=self.request.user) diff --git a/backend/api/viewsets/files.py b/backend/api/viewsets/files.py new file mode 100644 index 0000000..bb2ae1b --- /dev/null +++ b/backend/api/viewsets/files.py @@ -0,0 +1,95 @@ +import logging + +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response +from rest_framework.exceptions import PermissionDenied +from rest_framework import status +from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiParameter +from drf_spectacular.types import OpenApiTypes + +from DOSPORTAL.models import File, OrganizationUser +from ..serializers import FileSerializer, FileUploadSerializer +from ..viewsets_base import SoftDeleteModelViewSet + +logger = logging.getLogger(__name__) + + +@extend_schema_view( + list=extend_schema( + description="List files accessible to the current user.", + tags=["Files"], + parameters=[ + OpenApiParameter("owner", OpenApiTypes.UUID, OpenApiParameter.QUERY, required=False, description="Filter by organization ID"), + OpenApiParameter("file_type", OpenApiTypes.STR, OpenApiParameter.QUERY, required=False, description="Filter by file type"), + ], + ), + retrieve=extend_schema(description="Get file detail by ID.", tags=["Files"]), + create=extend_schema( + description="Upload a file. Supply owner (org UUID) to assign to an organization (user must be admin/owner).", + tags=["Files"], + request=FileUploadSerializer, + responses={201: FileSerializer}, + ), + destroy=extend_schema(description="Soft-delete a file (org admin/owner only).", tags=["Files"]), +) +class FileViewSet(SoftDeleteModelViewSet): + permission_classes = [IsAuthenticated] + http_method_names = ["get", "post", "delete", "head", "options"] + + def get_serializer_class(self): + if self.action == "create": + return FileUploadSerializer + return FileSerializer + + def get_queryset(self): + user = self.request.user + user_orgs = OrganizationUser.objects.filter( + user=user, user_type__in=["OW", "AD", "ME"] + ).values_list("organization_id", flat=True) + qs = ( + File.objects.filter(owner__in=user_orgs) | File.objects.filter(author=user) + ).order_by("-created_at").distinct() + + owner_id = self.request.query_params.get("owner") + if owner_id: + qs = qs.filter(owner_id=owner_id) + file_type = self.request.query_params.get("file_type") + if file_type: + qs = qs.filter(file_type=file_type) + return qs + + def create(self, request, *args, **kwargs): + if "file" not in request.FILES: + return Response( + {"error": "No file was submitted"}, status=status.HTTP_400_BAD_REQUEST + ) + owner_id = request.data.get("owner") + if owner_id: + if not OrganizationUser.objects.filter( + user=request.user, + organization_id=owner_id, + user_type__in=["OW", "AD"], + ).exists(): + raise PermissionDenied( + "You do not have permission to upload to this organization." + ) + serializer = FileUploadSerializer(data=request.data, context={"request": request}) + if serializer.is_valid(): + try: + file_obj = serializer.save(author=request.user) + return Response(FileSerializer(file_obj).data, status=status.HTTP_201_CREATED) + except Exception as e: + logger.exception(f"File upload failed: {str(e)}") + return Response({"error": "Upload failed."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + def perform_destroy(self, instance): + is_org_admin = instance.owner and OrganizationUser.objects.filter( + user=self.request.user, + organization=instance.owner, + user_type__in=["OW", "AD"], + ).exists() + is_author = instance.author == self.request.user + if not (is_org_admin or is_author): + raise PermissionDenied("You do not have permission to delete this file.") + instance.soft_delete(deleted_by=self.request.user) \ No newline at end of file diff --git a/backend/api/viewsets/flights.py b/backend/api/viewsets/flights.py new file mode 100644 index 0000000..1f03398 --- /dev/null +++ b/backend/api/viewsets/flights.py @@ -0,0 +1,28 @@ +"""ViewSets for Flight and Airports.""" +from drf_spectacular.utils import extend_schema, extend_schema_view +from rest_framework.mixins import ListModelMixin, RetrieveModelMixin +from rest_framework.permissions import IsAuthenticated +from rest_framework.viewsets import GenericViewSet + +from DOSPORTAL.models.flights import Airports, Flight +from ..serializers.measurements import AirportSerializer, FlightSerializer + + +@extend_schema_view( + list=extend_schema(description="List airports.", tags=["Flights"]), + retrieve=extend_schema(description="Get airport detail.", tags=["Flights"]), +) +class AirportsViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): + permission_classes = [IsAuthenticated] + serializer_class = AirportSerializer + queryset = Airports.objects.all().order_by("name") + + +@extend_schema_view( + list=extend_schema(description="List flights.", tags=["Flights"]), + retrieve=extend_schema(description="Get flight detail.", tags=["Flights"]), +) +class FlightViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): + permission_classes = [IsAuthenticated] + serializer_class = FlightSerializer + queryset = Flight.objects.select_related("takeoff", "land").all().order_by("departure_time") diff --git a/backend/api/viewsets/invites.py b/backend/api/viewsets/invites.py new file mode 100644 index 0000000..77858e9 --- /dev/null +++ b/backend/api/viewsets/invites.py @@ -0,0 +1,99 @@ +from django.db import transaction +from django.utils import timezone + +from rest_framework.viewsets import GenericViewSet +from rest_framework.mixins import RetrieveModelMixin +from rest_framework.permissions import AllowAny, IsAuthenticated +from rest_framework.decorators import action +from rest_framework.response import Response +from rest_framework.exceptions import NotFound +from drf_spectacular.utils import extend_schema, extend_schema_view + +from DOSPORTAL.models import OrganizationInvite, OrganizationUser +from ..serializers import OrganizationDetailSerializer + + +@extend_schema_view( + retrieve=extend_schema( + description="Get invite details by token (public, no authentication required).", + tags=["Organizations"], + ), +) +class InviteViewSet(RetrieveModelMixin, GenericViewSet): + + lookup_field = "token" + permission_classes = [AllowAny] + + def get_queryset(self): + return OrganizationInvite.objects.select_related("organization").all() + + def get_object(self): + token = self.kwargs["token"] + token_hash = OrganizationInvite.hash_token(token) + try: + return OrganizationInvite.objects.select_related("organization").get( + token_hash=token_hash + ) + except OrganizationInvite.DoesNotExist: + raise NotFound("Invalid invite token.") + + def retrieve(self, request, *args, **kwargs): + invite = self.get_object() + org_data = OrganizationDetailSerializer(invite.organization).data + return Response( + { + "organization": org_data, + "user_type": invite.user_type, + "expires_at": invite.expires_at, + "is_active": invite.is_active, + } + ) + + @extend_schema( + description="Accept an invite and join the organization. Requires authentication.", + tags=["Organizations"], + responses={200: {"description": "Successfully joined the organization"}}, + ) + @action( + detail=True, + methods=["post"], + url_path="accept", + permission_classes=[IsAuthenticated], + ) + def accept(self, request, token=None): + token_hash = OrganizationInvite.hash_token(token) + try: + with transaction.atomic(): + invite = OrganizationInvite.objects.select_for_update().get( + token_hash=token_hash + ) + if not invite.is_active: + return Response( + {"detail": "Invite is not active (expired, used, or revoked)."}, + status=400, + ) + if OrganizationUser.objects.filter( + user=request.user, organization=invite.organization + ).exists(): + return Response( + {"detail": "You are already a member of this organization."}, + status=400, + ) + OrganizationUser.objects.create( + user=request.user, + organization=invite.organization, + user_type=invite.user_type, + ) + invite.used_at = timezone.now() + invite.used_by = request.user + invite.save() + return Response( + { + "detail": "Joined.", + "organization_id": str(invite.organization.id), + "user_type": invite.user_type, + }, + status=200, + ) + except OrganizationInvite.DoesNotExist: + return Response({"detail": "Invalid invite token."}, status=404) diff --git a/backend/api/viewsets/measurements.py b/backend/api/viewsets/measurements.py new file mode 100644 index 0000000..e27bc78 --- /dev/null +++ b/backend/api/viewsets/measurements.py @@ -0,0 +1,264 @@ +from rest_framework.viewsets import ModelViewSet +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response +from rest_framework.decorators import action +from rest_framework.exceptions import PermissionDenied +from rest_framework import status +from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiParameter +from drf_spectacular.types import OpenApiTypes + +from django.db import transaction +from DOSPORTAL.models import Measurement, MeasurementSegment, OrganizationUser, MeasurementArtifact +from ..serializers import MeasurementsSerializer +from ..serializers.measurements import MeasurementCreateSerializer, MeasurementSegmentSerializer +from ..viewsets_base import SoftDeleteModelViewSet +import pandas as pd +import numpy as np +from django_q.tasks import async_task + + +def _load_spectral_parquet(measurement): + """Load Parquet DataFrame from a completed Measurement's artifact. + Returns (df, error_response). If error_response is not None, return it directly. + """ + if measurement.processing_status == Measurement.PROCESSING_PENDING: + return None, Response( + {"detail": "Measurement artifact not found."}, + status=status.HTTP_404_NOT_FOUND, + ) + + if measurement.processing_status == Measurement.PROCESSING_IN_PROGRESS: + return None, Response( + {"detail": "Measurement artifact is still being processed."}, + status=status.HTTP_425_TOO_EARLY, + ) + + if measurement.processing_status != Measurement.PROCESSING_COMPLETED: + return None, Response( + {"detail": f"Artifact not ready. Status: {measurement.processing_status}"}, + status=status.HTTP_425_TOO_EARLY, + ) + + try: + artifact = MeasurementArtifact.objects.get( + measurement=measurement, + ) + except MeasurementArtifact.DoesNotExist: + return None, Response( + {"detail": "Parquet artifact not found"}, + status=status.HTTP_404_NOT_FOUND, + ) + + artifact.artifact.file.open("rb") + df = pd.read_parquet(artifact.artifact.file, engine="fastparquet") + artifact.artifact.file.close() + + channel_cols = [col for col in df.columns if col.startswith("channel_")] + df[channel_cols] = df[channel_cols].fillna(0) + return df, None + + +@extend_schema_view( + list=extend_schema(description="List measurements accessible to the current user.", tags=["Measurements"]), + retrieve=extend_schema(description="Get measurement detail by ID.", tags=["Measurements"]), + create=extend_schema( + description="Create a measurement. Supply owner_id to assign to an organization (user must be a member).", + tags=["Measurements"], + ), + destroy=extend_schema(description="Soft-delete a measurement (author or org admin/owner only).", tags=["Measurements"]), +) +class MeasurementViewSet(SoftDeleteModelViewSet): + permission_classes = [IsAuthenticated] + http_method_names = ["get", "post", "delete", "head", "options"] + + def get_serializer_class(self): + if self.action == "create": + return MeasurementCreateSerializer + return MeasurementsSerializer + + def get_queryset(self): + user = self.request.user + user_orgs = OrganizationUser.objects.filter( + user=user, user_type__in=["OW", "AD", "ME"] + ).values_list("organization_id", flat=True) + return ( + Measurement.objects.filter(owner__in=user_orgs) + | Measurement.objects.filter(author=user) + ).select_related("owner", "author", "flight").order_by("-time_created").distinct() + + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + self.perform_create(serializer) + return Response( + MeasurementsSerializer(serializer.instance).data, + status=status.HTTP_201_CREATED, + ) + + def perform_create(self, serializer): + owner = serializer.validated_data.get("owner") + if owner: + if not OrganizationUser.objects.filter( + user=self.request.user, + organization=owner, + user_type__in=["OW", "AD", "ME"], + ).exists(): + raise PermissionDenied( + "You do not have permission to create measurements for this organization." + ) + serializer.save(author=self.request.user) + + def perform_destroy(self, instance): + is_author = instance.author == self.request.user + is_org_admin = instance.owner and OrganizationUser.objects.filter( + user=self.request.user, + organization=instance.owner, + user_type__in=["OW", "AD"], + ).exists() + if not (is_author or is_org_admin): + raise PermissionDenied("You do not have permission to delete this measurement.") + instance.soft_delete(deleted_by=self.request.user) + + @action(detail=True, methods=["get"]) + def evolution(self, request, pk=None): + """Get counts-per-second evolution over time from Parquet artifact.""" + measurement = self.get_object() + df, err = _load_spectral_parquet(measurement) + if err: + return err + + channel_columns = [col for col in df.columns if col.startswith("channel_")] + total_time = float(df["time_ms"].max() - df["time_ms"].min()) + if total_time == 0 or np.isnan(total_time) or np.isinf(total_time): + total_time = 1.0 + + row_sums = df[channel_columns].sum(axis=1) + counts_per_second = row_sums / total_time + counts_per_second = counts_per_second.replace([np.inf, -np.inf], 0).fillna(0) + time_series = df["time_ms"].replace([np.inf, -np.inf], 0).fillna(0) + + evolution_values = list( + zip(time_series.astype(float).tolist(), counts_per_second.tolist()) + ) + return Response({"evolution_values": evolution_values, "total_time": total_time}) + + @action(detail=True, methods=["get"]) + def spectrum(self, request, pk=None): + """Get energy/channel spectrum (sum over all exposures) from Parquet artifact.""" + measurement = self.get_object() + df, err = _load_spectral_parquet(measurement) + if err: + return err + + channel_columns = [col for col in df.columns if col.startswith("channel_")] + total_time = float(df["time_ms"].max() - df["time_ms"].min()) + if total_time == 0: + total_time = 1.0 + + channel_sums = df[channel_columns].sum(axis=0) / total_time + channel_sums = channel_sums.fillna(0) + + # has_calib = measurement.calib is not None + spectrum_values = [] + for col in channel_columns: + channel_num = int(col.replace("channel_", "")) + cps = float(channel_sums[col]) + # if has_calib: + # x_val = (measurement.calib.coef0 + channel_num * measurement.calib.coef1) / 1000 + # else: + x_val = channel_num + spectrum_values.append([x_val, cps]) + + return Response( + {"spectrum_values": spectrum_values, "total_time": total_time} + ) + + @action(detail=True, methods=["post"]) + def finalize(self, request, pk=None): + measurement = self.get_object() + + if not measurement.segments.exists(): + return Response({"error": "No segments found."}, status=400) + + if measurement.processing_status == Measurement.PROCESSING_IN_PROGRESS: + return Response({"error": "Already processing."}, status=400) + + measurement.processing_status = Measurement.PROCESSING_IN_PROGRESS + measurement.save(update_fields=["processing_status"]) + + transaction.on_commit( + lambda: async_task('DOSPORTAL.tasks.create_measurement_artifact', measurement.id) + ) + return Response({"status": "processing"}) + +@extend_schema_view( + list=extend_schema( + description="List measurement segments accessible to the current user. Filter by ?measurement=.", + tags=["Measurements"], + parameters=[ + OpenApiParameter( + name="measurement", + type=OpenApiTypes.UUID, + location=OpenApiParameter.QUERY, + description="Filter segments by measurement ID.", + required=False, + ) + ], + ), + retrieve=extend_schema(description="Get measurement segment detail.", tags=["Measurements"]), + create=extend_schema( + description="Create a measurement segment. User must be a member of the measurement's organization.", + tags=["Measurements"], + ), + partial_update=extend_schema( + description="Partially update a segment (e.g. time_from, time_to, position).", + tags=["Measurements"], + ), + destroy=extend_schema( + description="Delete a measurement segment. Only accessible to the measurement author or org admin/owner.", + tags=["Measurements"], + ), +) +class MeasurementSegmentViewSet(ModelViewSet): + serializer_class = MeasurementSegmentSerializer + permission_classes = [IsAuthenticated] + http_method_names = ["get", "post", "patch", "delete", "head", "options"] + + def get_queryset(self): + user = self.request.user + user_orgs = OrganizationUser.objects.filter( + user=user, user_type__in=["OW", "AD", "ME"] + ).values_list("organization_id", flat=True) + qs = ( + MeasurementSegment.objects.filter(measurement__owner__in=user_orgs) + | MeasurementSegment.objects.filter(measurement__author=user) + ).select_related("measurement", "spectral_record").distinct().order_by("position") + + measurement_id = self.request.query_params.get("measurement") + if measurement_id: + qs = qs.filter(measurement__id=measurement_id) + + return qs + + def _check_measurement_permission(self, measurement): + if measurement.owner: + if not OrganizationUser.objects.filter( + user=self.request.user, + organization=measurement.owner, + user_type__in=["OW", "AD", "ME"], + ).exists(): + raise PermissionDenied("You do not have permission to modify segments of this measurement.") + elif measurement.author != self.request.user: + raise PermissionDenied("You do not have access to this measurement.") + + def perform_create(self, serializer): + self._check_measurement_permission(serializer.validated_data["measurement"]) + serializer.save() + + def perform_update(self, serializer): + self._check_measurement_permission(serializer.instance.measurement) + serializer.save() + + def perform_destroy(self, instance): + self._check_measurement_permission(instance.measurement) + instance.delete() diff --git a/backend/api/viewsets/organizations.py b/backend/api/viewsets/organizations.py new file mode 100644 index 0000000..5ce9e31 --- /dev/null +++ b/backend/api/viewsets/organizations.py @@ -0,0 +1,235 @@ +from django.contrib.auth.models import User as DjangoUser +from django.utils import timezone + +from rest_framework.permissions import IsAuthenticated +from rest_framework.decorators import action +from rest_framework.response import Response +from drf_spectacular.utils import extend_schema, extend_schema_view + +from DOSPORTAL.models import Organization, OrganizationUser, OrganizationInvite +from ..serializers import ( + OrganizationDetailSerializer, + OrganizationInviteSerializer, +) +from ..permissions import IsOrganizationAdmin, IsOrganizationMember +from ..viewsets_base import SoftDeleteModelViewSet + + +@extend_schema_view( + list=extend_schema( + description="List all organizations (any authenticated user).", + tags=["Organizations"], + ), + create=extend_schema( + description="Create a new organization. The creator automatically becomes owner.", + tags=["Organizations"], + ), + retrieve=extend_schema( + description="Get organization detail by ID.", + tags=["Organizations"], + ), + update=extend_schema( + description="Update organization (owner/admin only).", + tags=["Organizations"], + ), + partial_update=extend_schema( + description="Partially update organization (owner/admin only).", + tags=["Organizations"], + ), + destroy=extend_schema( + description="Soft-delete an organization (owner/admin only).", + tags=["Organizations"], + ), + members=extend_schema( + description="GET: List all members. POST: Add a member (admin/owner only).", + tags=["Organizations"], + ), + member_detail=extend_schema( + description="PUT: Update a member's role (admin/owner only). DELETE: Remove a member.", + tags=["Organizations"], + ), + invites=extend_schema( + description="GET: List organization invites (admin/owner only). POST: Create a new invite (admin/owner only).", + tags=["Organizations"], + ), + revoke_invite=extend_schema( + description="Revoke an active invite by its UUID (admin/owner only).", + tags=["Organizations"], + ), +) +class OrganizationViewSet(SoftDeleteModelViewSet): + + serializer_class = OrganizationDetailSerializer + # Keeps 'org_id' as URL kwarg so IsOrganizationAdmin permission class works. + lookup_url_kwarg = "org_id" + + def get_queryset(self): + return Organization.objects.all() + + def get_permissions(self): + admin_actions = ( + "update", "partial_update", "destroy", + "invites", "revoke_invite", + ) + if self.action in admin_actions: + return [IsAuthenticated(), IsOrganizationAdmin()] + if self.action == "member_detail": + # DELETE: any member can remove themselves; admin required for others + # PUT: admin required — but IsOrganizationMember gates entry, admin check is in the view + return [IsAuthenticated(), IsOrganizationMember()] + if self.action == "members" and self.request.method == "POST": + return [IsAuthenticated(), IsOrganizationAdmin()] + return [IsAuthenticated()] + + def perform_create(self, serializer): + org = serializer.save() + OrganizationUser.objects.create( + user=self.request.user, organization=org, user_type="OW" + ) + + # ------------------------------------------------------------------ members + + @action(detail=True, url_path="members", methods=["get", "post"]) + def members(self, request, org_id=None): + org = self.get_object() + + if request.method == "GET": + org_users = OrganizationUser.objects.filter( + organization=org + ).select_related("user") + data = [ + { + "id": ou.user.id, + "username": ou.user.username, + "first_name": ou.user.first_name, + "last_name": ou.user.last_name, + "user_type": ou.user_type, + } + for ou in org_users + ] + return Response(data) + + # POST — add member (IsOrganizationAdmin already enforced) + username = request.data.get("username") + user_type = request.data.get("user_type", "ME") + if not username: + return Response({"detail": "Username required."}, status=400) + if user_type not in ["ME", "AD"]: + return Response({"detail": "Invalid user_type. Only ME or AD allowed."}, status=400) + try: + user = DjangoUser.objects.get(username=username) + except DjangoUser.DoesNotExist: + return Response({"detail": "User not found."}, status=404) + if OrganizationUser.objects.filter(user=user, organization=org).exists(): + return Response({"detail": "User already a member."}, status=400) + OrganizationUser.objects.create(user=user, organization=org, user_type=user_type) + return Response({"detail": "User added."}, status=201) + + @action( + detail=True, + url_path=r"members/(?P[^/.]+)", + methods=["put", "delete"], + ) + def member_detail(self, request, org_id=None, username=None): + org = self.get_object() + try: + target_user = DjangoUser.objects.get(username=username) + except DjangoUser.DoesNotExist: + return Response({"detail": "User not found."}, status=404) + + if request.method == "PUT": + # Admin/owner only (checked via get_permissions + explicit guard) + if not IsOrganizationAdmin.user_is_admin(request.user, org): + return Response({"detail": "You do not have permission to change roles."}, status=403) + user_type = request.data.get("user_type", "ME") + if user_type not in ["ME", "AD"]: + return Response({"detail": "Invalid role."}, status=400) + org_member = OrganizationUser.objects.filter( + user=target_user, organization=org + ).first() + if not org_member: + return Response( + {"detail": "User is not a member of this organization."}, status=404 + ) + org_member.user_type = user_type + org_member.save() + return Response({"detail": f"Role updated to {user_type}."}, status=200) + + # DELETE — any member can remove themselves; admin required for others + if target_user != request.user and not IsOrganizationAdmin.user_is_admin( + request.user, org + ): + return Response( + {"detail": "You do not have permission to remove this member."}, + status=403, + ) + org_member = OrganizationUser.objects.filter( + user=target_user, organization=org + ).first() + if not org_member: + return Response( + {"detail": "User is not a member of this organization."}, status=404 + ) + if org_member.user_type == "OW": + return Response( + {"detail": "You cannot remove the owner from the organization."}, + status=403, + ) + org_member.delete() + return Response({"detail": "User removed from organization."}, status=200) + + # ------------------------------------------------------------------ invites + + @action(detail=True, url_path="invites", methods=["get", "post"]) + def invites(self, request, org_id=None): + org = self.get_object() + + if request.method == "GET": + org_invites = OrganizationInvite.objects.filter( + organization=org + ).order_by("-created_at") + serializer = OrganizationInviteSerializer(org_invites, many=True) + return Response(serializer.data) + + # POST — create invite + user_type = request.data.get("user_type", "ME") + expires_hours = int(request.data.get("expires_hours", 24)) + expires_hours = min(max(expires_hours, 1), 168) + if user_type not in ["ME", "AD"]: + return Response({"detail": "Invalid user_type."}, status=400) + token = OrganizationInvite.generate_token() + token_hash = OrganizationInvite.hash_token(token) + expires_at = timezone.now() + timezone.timedelta(hours=expires_hours) + invite = OrganizationInvite.objects.create( + organization=org, + token_hash=token_hash, + user_type=user_type, + created_by=request.user, + expires_at=expires_at, + ) + invite_url = f"/invite/{token}/" + return Response( + { + "invite_url": invite_url, + "expires_at": invite.expires_at, + "user_type": invite.user_type, + }, + status=201, + ) + + @action( + detail=True, + url_path=r"invites/(?P[^/.]+)", + methods=["delete"], + ) + def revoke_invite(self, request, org_id=None, invite_id=None): + org = self.get_object() + try: + invite = OrganizationInvite.objects.get(id=invite_id, organization=org) + except OrganizationInvite.DoesNotExist: + return Response({"detail": "Invite not found."}, status=404) + if not invite.is_active: + return Response({"detail": "Invite is already inactive."}, status=400) + invite.revoked_at = timezone.now() + invite.save(update_fields=["revoked_at"]) + return Response({"detail": "Invite revoked."}, status=200) diff --git a/backend/api/viewsets/spectrals.py b/backend/api/viewsets/spectrals.py new file mode 100644 index 0000000..7098b06 --- /dev/null +++ b/backend/api/viewsets/spectrals.py @@ -0,0 +1,271 @@ +import logging + +import numpy as np +import pandas as pd +from drf_spectacular.utils import OpenApiParameter, extend_schema, extend_schema_view +from drf_spectacular.types import OpenApiTypes +from rest_framework import status +from rest_framework.decorators import action +from rest_framework.exceptions import PermissionDenied +from rest_framework.mixins import ListModelMixin, RetrieveModelMixin +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response +from rest_framework.viewsets import GenericViewSet + +from DOSPORTAL.models import OrganizationUser +from DOSPORTAL.models.spectrals import SpectralRecord, SpectralRecordArtifact +from ..serializers.measurements import ( + SpectralRecordArtifactSerializer, + SpectralRecordCreateSerializer, + SpectralRecordSerializer, + SpectralRecordUpdateSerializer, +) +from ..viewsets_base import SoftDeleteModelViewSet + +logger = logging.getLogger(__name__) + + +def _load_spectral_parquet(record): + """Load Parquet DataFrame from a completed SpectralRecord's artifact. + Returns (df, error_response). If error_response is not None, return it directly. + """ + if record.processing_status != SpectralRecord.PROCESSING_COMPLETED: + return None, Response( + {"detail": f"Processing not completed. Status: {record.processing_status}"}, + status=status.HTTP_425_TOO_EARLY, + ) + + try: + artifact = SpectralRecordArtifact.objects.get( + spectral_record=record, + artifact_type=SpectralRecordArtifact.SPECTRAL_FILE, + ) + except SpectralRecordArtifact.DoesNotExist: + return None, Response( + {"detail": "Parquet artifact not found"}, + status=status.HTTP_404_NOT_FOUND, + ) + + artifact.artifact.file.open("rb") + df = pd.read_parquet(artifact.artifact.file, engine="fastparquet") + artifact.artifact.file.close() + + channel_cols = [col for col in df.columns if col.startswith("channel_")] + df[channel_cols] = df[channel_cols].fillna(0) + return df, None + + +@extend_schema_view( + list=extend_schema( + description="List spectral records accessible to the current user.", + tags=["Spectral Records"], + parameters=[ + OpenApiParameter( + "processing_status", + OpenApiTypes.STR, + OpenApiParameter.QUERY, + required=False, + description="Filter by processing status (pending/processing/completed/failed)", + ) + ], + ), + retrieve=extend_schema(description="Get spectral record detail.", tags=["Spectral Records"]), + create=extend_schema( + description="Create a spectral record. Supply owner (org UUID) — user must be admin/owner of the organization.", + tags=["Spectral Records"], + ), + evolution=extend_schema( + description="Get counts-per-second evolution over time from Parquet artifact.", + tags=["Spectral Records"], + ), + spectrum=extend_schema( + description="Get energy/channel spectrum (sum over all exposures) from Parquet artifact.", + tags=["Spectral Records"], + ), + destroy=extend_schema(description="Soft-delete a spectral record (org admin/owner only).", tags=["Spectral Records"]), + partial_update=extend_schema( + description="Update editable fields of a spectral record.", + tags=["Spectral Records"], + ), +) +class SpectralRecordViewSet(SoftDeleteModelViewSet): + permission_classes = [IsAuthenticated] + http_method_names = ["get", "post", "patch", "delete", "head", "options"] + + def get_serializer_class(self): + if self.action == "create": + return SpectralRecordCreateSerializer + if self.action == "partial_update": + return SpectralRecordUpdateSerializer + return SpectralRecordSerializer + + def get_queryset(self): + user = self.request.user + user_orgs = OrganizationUser.objects.filter( + user=user, user_type__in=["OW", "AD", "ME"] + ).values_list("organization_id", flat=True) + + qs = ( + SpectralRecord.objects.filter(owner__in=user_orgs) + | SpectralRecord.objects.filter(author=user) + ).select_related("raw_file", "author", "owner", "detector", "calib").distinct() + + processing_status = self.request.query_params.get("processing_status") + if processing_status: + qs = qs.filter(processing_status=processing_status.lower()) + + return qs.order_by("-created") + + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + self.perform_create(serializer) + return Response( + { + **SpectralRecordSerializer(serializer.instance).data, + "message": "SpectralRecord created, async processing scheduled", + }, + status=status.HTTP_201_CREATED, + ) + + def perform_create(self, serializer): + owner = serializer.validated_data.get("owner") + if owner: + if not OrganizationUser.objects.filter( + user=self.request.user, + organization=owner, + user_type__in=["OW", "AD"], + ).exists(): + raise PermissionDenied( + "You do not have permission to create spectral records for this organization." + ) + serializer.save(author=self.request.user) + + def perform_update(self, serializer): + instance = serializer.instance + is_org_member = instance.owner and OrganizationUser.objects.filter( + user=self.request.user, + organization=instance.owner, + user_type__in=["OW", "AD", "ME"], + ).exists() + is_author = instance.author == self.request.user + if not (is_org_member or is_author): + raise PermissionDenied("You do not have permission to edit this spectral record.") + serializer.save() + + def perform_destroy(self, instance): + is_org_admin = instance.owner and OrganizationUser.objects.filter( + user=self.request.user, + organization=instance.owner, + user_type__in=["OW", "AD"], + ).exists() + is_author = instance.author == self.request.user + if not (is_org_admin or is_author): + raise PermissionDenied("You do not have permission to delete this spectral record.") + instance.soft_delete(deleted_by=self.request.user) + + @action(detail=True, methods=["get"]) + def evolution(self, request, pk=None): + """Get counts-per-second evolution over time from Parquet artifact.""" + record = self.get_object() + df, err = _load_spectral_parquet(record) + if err: + return err + + channel_columns = [col for col in df.columns if col.startswith("channel_")] + total_time = float(df["time_ms"].max() - df["time_ms"].min()) + if total_time == 0 or np.isnan(total_time) or np.isinf(total_time): + total_time = 1.0 + + row_sums = df[channel_columns].sum(axis=1) + counts_per_second = row_sums / total_time + counts_per_second = counts_per_second.replace([np.inf, -np.inf], 0).fillna(0) + time_series = df["time_ms"].replace([np.inf, -np.inf], 0).fillna(0) + + evolution_values = list( + zip(time_series.astype(float).tolist(), counts_per_second.tolist()) + ) + return Response({"evolution_values": evolution_values, "total_time": total_time}) + + @action(detail=True, methods=["get"]) + def spectrum(self, request, pk=None): + """Get energy/channel spectrum (sum over all exposures) from Parquet artifact.""" + record = self.get_object() + df, err = _load_spectral_parquet(record) + if err: + return err + + channel_columns = [col for col in df.columns if col.startswith("channel_")] + total_time = float(df["time_ms"].max() - df["time_ms"].min()) + if total_time == 0: + total_time = 1.0 + + channel_sums = df[channel_columns].sum(axis=0) / total_time + channel_sums = channel_sums.fillna(0) + + has_calib = record.calib is not None + spectrum_values = [] + for col in channel_columns: + channel_num = int(col.replace("channel_", "")) + cps = float(channel_sums[col]) + if has_calib: + x_val = (record.calib.coef0 + channel_num * record.calib.coef1) / 1000 + else: + x_val = channel_num + spectrum_values.append([x_val, cps]) + + return Response( + {"spectrum_values": spectrum_values, "total_time": total_time, "calib": has_calib} + ) + + +@extend_schema_view( + list=extend_schema( + description="List spectral record artifacts accessible to the current user.", + tags=["Spectral Records"], + parameters=[ + OpenApiParameter( + "spectral_record", + OpenApiTypes.UUID, + OpenApiParameter.QUERY, + required=False, + description="Filter by spectral record ID", + ), + OpenApiParameter( + "artifact_type", + OpenApiTypes.STR, + OpenApiParameter.QUERY, + required=False, + ), + ], + ), + retrieve=extend_schema(description="Get spectral record artifact detail.", tags=["Spectral Records"]), +) +class SpectralRecordArtifactViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): + permission_classes = [IsAuthenticated] + serializer_class = SpectralRecordArtifactSerializer + + def get_queryset(self): + user = self.request.user + user_orgs = OrganizationUser.objects.filter( + user=user, user_type__in=["OW", "AD", "ME"] + ).values_list("organization_id", flat=True) + + accessible_records = ( + SpectralRecord.objects.filter(owner__in=user_orgs) + | SpectralRecord.objects.filter(author=user) + ).distinct() + + qs = SpectralRecordArtifact.objects.filter( + spectral_record__in=accessible_records + ).select_related("artifact", "spectral_record").order_by("created_at") + + spectral_record = self.request.query_params.get("spectral_record") + if spectral_record: + qs = qs.filter(spectral_record_id=spectral_record) + + artifact_type = self.request.query_params.get("artifact_type") + if artifact_type: + qs = qs.filter(artifact_type=artifact_type) + + return qs diff --git a/backend/api/viewsets_base.py b/backend/api/viewsets_base.py new file mode 100644 index 0000000..bb79838 --- /dev/null +++ b/backend/api/viewsets_base.py @@ -0,0 +1,10 @@ +from rest_framework.viewsets import ModelViewSet + + +class SoftDeleteModelViewSet(ModelViewSet): + """ + Routes DELETE to soft_delete() instead of hard delete. + """ + + def perform_destroy(self, instance): + instance.soft_delete(deleted_by=self.request.user) diff --git a/frontend/.gitignore b/frontend/.gitignore index a547bf3..7c1f03f 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -1,5 +1,5 @@ # Logs -logs +# logs *.log npm-debug.log* yarn-debug.log* diff --git a/frontend/components.json b/frontend/components.json new file mode 100644 index 0000000..5c23ec4 --- /dev/null +++ b/frontend/components.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "radix-nova", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/index.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "rtl": false, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "menuColor": "default", + "menuAccent": "subtle", + "registries": {} +} diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js index 5e6b472..2d9c69b 100644 --- a/frontend/eslint.config.js +++ b/frontend/eslint.config.js @@ -20,4 +20,10 @@ export default defineConfig([ globals: globals.browser, }, }, + { + files: ['src/components/ui/**/*.{ts,tsx}'], + rules: { + 'react-refresh/only-export-components': 'off', + }, + }, ]) diff --git a/frontend/index.html b/frontend/index.html index 131399f..64eefb7 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2,7 +2,7 @@ - + DOSPORTAL diff --git a/frontend/orval.config.ts b/frontend/orval.config.ts new file mode 100644 index 0000000..a1e98f4 --- /dev/null +++ b/frontend/orval.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from 'orval'; + +export default defineConfig({ + myApi: { + input: { + target: 'http://backend:8000/api/schema', + }, + output: { + mode: 'tags-split', + target: 'src/api', + schemas: 'src/api/model', + client: 'react-query', + httpClient: 'axios', + clean: true, // clean-up of old files before gen. new + }, + }, +}); \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ae6b471..4252259 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,26 +1,43 @@ { - "name": "frontend", + "name": "dosportal-rect", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "frontend", + "name": "dosportal-rect", "version": "0.0.0", "dependencies": { + "@dnd-kit/react": "^0.3.2", + "@fontsource-variable/geist": "^5.2.8", + "@monaco-editor/react": "^4.7.0", + "@tailwindcss/vite": "^4.2.2", + "@tanstack/react-query": "^5.90.21", + "axios": "^1.13.5", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", "echarts": "^6.0.0", "echarts-for-react": "^3.0.6", "leaflet": "^1.9.4", + "lucide-react": "^0.577.0", + "next-themes": "^0.4.6", + "radix-ui": "^1.4.3", "react": "^19.2.0", "react-dom": "^19.2.0", "react-leaflet": "^5.0.0", "react-markdown": "^10.1.0", - "react-router-dom": "^7.12.0" + "react-router-dom": "^7.12.0", + "react-select": "^5.10.2", + "shadcn": "^4.1.0", + "sonner": "^2.0.7", + "tailwind-merge": "^3.5.0", + "tailwindcss": "^4.2.2", + "tw-animate-css": "^1.4.0" }, "devDependencies": { "@eslint/js": "^9.39.1", "@types/leaflet": "^1.9.14", - "@types/node": "^24.10.1", + "@types/node": "^24.12.0", "@types/react": "^19.2.5", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.1.1", @@ -28,16 +45,117 @@ "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.4.24", "globals": "^16.5.0", + "orval": "^7.21.0", "typescript": "~5.9.3", "typescript-eslint": "^8.46.4", "vite": "npm:rolldown-vite@7.2.5" } }, + "node_modules/@apidevtools/json-schema-ref-parser": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-14.0.1.tgz", + "integrity": "sha512-Oc96zvmxx1fqoSEdUmfmvvb59/KDOnUoJ7s2t7bISyAn0XEz57LCCw8k2Y4Pf3mwKaZLMciESALORLgfe2frCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.15", + "js-yaml": "^4.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/philsturgeon" + } + }, + "node_modules/@apidevtools/openapi-schemas": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", + "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@apidevtools/swagger-methods": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", + "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@apidevtools/swagger-parser": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-12.1.0.tgz", + "integrity": "sha512-e5mJoswsnAX0jG+J09xHFYQXb/bUc5S3pLpMxUuRUA2H8T2kni3yEoyz2R3Dltw5f4A6j6rPNMpWTK+iVDFlng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "14.0.1", + "@apidevtools/openapi-schemas": "^2.1.0", + "@apidevtools/swagger-methods": "^3.0.2", + "ajv": "^8.17.1", + "ajv-draft-04": "^1.0.0", + "call-me-maybe": "^1.0.2" + }, + "peerDependencies": { + "openapi-types": ">=7" + } + }, + "node_modules/@apidevtools/swagger-parser/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@apidevtools/swagger-parser/node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/@apidevtools/swagger-parser/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@asyncapi/specs": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-6.11.1.tgz", + "integrity": "sha512-A3WBLqAKGoJ2+6FWFtpjBlCQ1oFCcs4GxF7zsIGvNqp/klGUHjlA3aAcZ9XMMpLGE8zPeYDz2x9FmO6DSuKraQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.11" + } + }, "node_modules/@babel/code-frame": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", @@ -52,7 +170,6 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -62,7 +179,6 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", @@ -93,7 +209,6 @@ "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==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.29.0", @@ -106,11 +221,22 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-compilation-targets": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.28.6", @@ -123,21 +249,53 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", + "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/helper-globals": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-module-imports": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.28.6", @@ -151,7 +309,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.28.6", @@ -165,21 +322,61 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-plugin-utils": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", + "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -189,7 +386,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -199,7 +395,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -209,7 +404,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", @@ -223,7 +417,6 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.29.0" @@ -235,6 +428,52 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", + "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-react-jsx-self": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", @@ -267,11 +506,57 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz", + "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", + "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.28.6", @@ -286,7 +571,6 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", @@ -305,7 +589,6 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -315,976 +598,1105 @@ "node": ">=6.9.0" } }, - "node_modules/@emnapi/core": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", - "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", + "node_modules/@commander-js/extra-typings": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@commander-js/extra-typings/-/extra-typings-14.0.0.tgz", + "integrity": "sha512-hIn0ncNaJRLkZrxBIp5AsW/eXEHNKYQBh0aPdoUqNgD+Io3NIykQqpKFyKcuasZhicGaEZJX/JBSIkZ4e5x8Dg==", "dev": true, "license": "MIT", - "optional": true, + "peerDependencies": { + "commander": "~14.0.0" + } + }, + "node_modules/@dnd-kit/abstract": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@dnd-kit/abstract/-/abstract-0.3.2.tgz", + "integrity": "sha512-uvPVK+SZYD6Viddn9M0K0JQdXknuVSxA/EbMlFRanve3P/XTc18oLa5zGftKSGjfQGmuzkZ34E26DSbly1zi3Q==", + "license": "MIT", "dependencies": { - "@emnapi/wasi-threads": "1.1.0", - "tslib": "^2.4.0" + "@dnd-kit/geometry": "^0.3.2", + "@dnd-kit/state": "^0.3.2", + "tslib": "^2.6.2" } }, - "node_modules/@emnapi/core/node_modules/tslib": { + "node_modules/@dnd-kit/abstract/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 + "license": "0BSD" }, - "node_modules/@emnapi/runtime": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", - "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", - "dev": true, + "node_modules/@dnd-kit/collision": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@dnd-kit/collision/-/collision-0.3.2.tgz", + "integrity": "sha512-pNmNSLCI8S9fNQ7QJ3fBCDjiT0sqBhUFcKgmyYaGvGCAU+kq0AP8OWlh0JSisc9k5mFyxmRpmFQcnJpILz/RPA==", "license": "MIT", - "optional": true, "dependencies": { - "tslib": "^2.4.0" + "@dnd-kit/abstract": "^0.3.2", + "@dnd-kit/geometry": "^0.3.2", + "tslib": "^2.6.2" } }, - "node_modules/@emnapi/runtime/node_modules/tslib": { + "node_modules/@dnd-kit/collision/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 + "license": "0BSD" }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", - "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", - "dev": true, + "node_modules/@dnd-kit/dom": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@dnd-kit/dom/-/dom-0.3.2.tgz", + "integrity": "sha512-cIUAVgt2szQyz6JRy7I+0r+xeyOAGH21Y15hb5bIyHoDEaZBvIDH+OOlD9eoLjCbsxDLN9WloU2CBi3OE6LYDg==", "license": "MIT", - "optional": true, "dependencies": { - "tslib": "^2.4.0" + "@dnd-kit/abstract": "^0.3.2", + "@dnd-kit/collision": "^0.3.2", + "@dnd-kit/geometry": "^0.3.2", + "@dnd-kit/state": "^0.3.2", + "tslib": "^2.6.2" } }, - "node_modules/@emnapi/wasi-threads/node_modules/tslib": { + "node_modules/@dnd-kit/dom/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 + "license": "0BSD" }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, + "node_modules/@dnd-kit/geometry": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@dnd-kit/geometry/-/geometry-0.3.2.tgz", + "integrity": "sha512-3UBPuIS7E3oGiHxOE8h810QA+0pnrnCtGxl4Os1z3yy5YkC/BEYGY+TxWPTQaY1/OMV7GCX7ZNMlama2QN3n3w==", "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "@dnd-kit/state": "^0.3.2", + "tslib": "^2.6.2" + } + }, + "node_modules/@dnd-kit/geometry/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@dnd-kit/react": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@dnd-kit/react/-/react-0.3.2.tgz", + "integrity": "sha512-1Opg1xw6I75Z95c+rF2NJa0pdGb8rLAENtuopKtJ1J0PudWlz+P6yL137xy/6DV43uaRmNGtsdbMbR0yRYJ72g==", + "license": "MIT", + "dependencies": { + "@dnd-kit/abstract": "^0.3.2", + "@dnd-kit/dom": "^0.3.2", + "@dnd-kit/state": "^0.3.2", + "tslib": "^2.6.2" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } + "node_modules/@dnd-kit/react/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, + "node_modules/@dnd-kit/state": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@dnd-kit/state/-/state-0.3.2.tgz", + "integrity": "sha512-dLUIkoYrIJhGXfF2wGLTfb46vUokEsO/OoE21TSfmahYrx7ysTmnwbePsznFaHlwgZhQEh6AlLvthLCeY21b1A==", "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "dependencies": { + "@preact/signals-core": "^1.10.0", + "tslib": "^2.6.2" } }, - "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@dnd-kit/state/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@dotenvx/dotenvx": { + "version": "1.57.0", + "resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.57.0.tgz", + "integrity": "sha512-WsTEcqfHzKmLFZh3jLGd7o4iCkrIupp+qFH2FJUJtQXUh2GcOnLXD00DcrhlO4H8QSmaKnW9lugOEbrdpu25kA==", + "license": "BSD-3-Clause", "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.2" + "commander": "^11.1.0", + "dotenv": "^17.2.1", + "eciesjs": "^0.4.10", + "execa": "^5.1.1", + "fdir": "^6.2.0", + "ignore": "^5.3.0", + "object-treeify": "1.1.33", + "picomatch": "^4.0.2", + "which": "^4.0.0" }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "bin": { + "dotenvx": "src/cli/dotenvx.js" + }, + "funding": { + "url": "https://dotenvx.com" } }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0" - }, + "node_modules/@dotenvx/dotenvx/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=16" } }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, + "node_modules/@dotenvx/dotenvx/node_modules/isexe": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", + "license": "BlueOak-1.0.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", - "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", - "dev": true, - "license": "MIT", + "node_modules/@dotenvx/dotenvx/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "license": "ISC", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "isexe": "^3.1.1" }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "bin": { + "node-which": "bin/which.js" }, - "funding": { - "url": "https://opencollective.com/eslint" + "engines": { + "node": "^16.13.0 || >=18.0.0" } }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, + "node_modules/@ecies/ciphers": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@ecies/ciphers/-/ciphers-0.2.5.tgz", + "integrity": "sha512-GalEZH4JgOMHYYcYmVqnFirFsjZHeoGMDt9IxEnM9F7GRUUyUksJ7Ou53L83WHJq3RWKD3AcBpo0iQh0oMpf8A==", "license": "MIT", "engines": { - "node": ">=18" + "bun": ">=1", + "deno": ">=2", + "node": ">=16" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@noble/ciphers": "^1.0.0" } }, - "node_modules/@eslint/js": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", - "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", - "dev": true, + "node_modules/@emnapi/core": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", + "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" } }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } + "node_modules/@emnapi/core/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "license": "MIT", + "optional": true, "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "tslib": "^2.4.0" } }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } + "node_modules/@emnapi/runtime/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "license": "MIT", + "optional": true, "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" + "tslib": "^2.4.0" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } + "node_modules/@emnapi/wasi-threads/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", "license": "MIT", - "engines": { - "node": ">=6.0.0" + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", "license": "MIT" }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "peerDependencies": { + "react": ">=16.8.0" } }, - "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, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], "license": "MIT", "optional": true, - "dependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1", - "@tybys/wasm-util": "^0.10.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" + "os": [ + "aix" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@oxc-project/runtime": { - "version": "0.97.0", - "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.97.0.tgz", - "integrity": "sha512-yH0zw7z+jEws4dZ4IUKoix5Lh3yhqIJWF9Dc8PWvhpo7U7O+lJrv7ZZL4BeRO0la8LBQFwcCewtLBnVV7hPe/w==", - "dev": true, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18" } }, - "node_modules/@oxc-project/types": { - "version": "0.97.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.97.0.tgz", - "integrity": "sha512-lxmZK4xFrdvU0yZiDwgVQTCvh2gHWBJCBk5ALsrtsBWhs0uDIi+FTOnXRQeQfs304imdvTdaakT/lqwQ8hkOXQ==", - "dev": true, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@react-leaflet/core": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz", - "integrity": "sha512-3EWmekh4Nz+pGcr+xjf0KNyYfC3U2JjnkWsh0zcqaexYqmmB5ZhH37kz41JXGmKzpaMZCnPofBBm64i+YrEvGQ==", - "license": "Hippocratic-2.1", - "peerDependencies": { - "leaflet": "^1.9.0", - "react": "^19.0.0", - "react-dom": "^19.0.0" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-beta.50", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.50.tgz", - "integrity": "sha512-XlEkrOIHLyGT3avOgzfTFSjG+f+dZMw+/qd+Y3HLN86wlndrB/gSimrJCk4gOhr1XtRtEKfszpadI3Md4Z4/Ag==", + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ - "arm64" + "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18" } }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-beta.50", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.50.tgz", - "integrity": "sha512-+JRqKJhoFlt5r9q+DecAGPLZ5PxeLva+wCMtAuoFMWPoZzgcYrr599KQ+Ix0jwll4B4HGP43avu9My8KtSOR+w==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18" } }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-beta.50", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.50.tgz", - "integrity": "sha512-fFXDjXnuX7/gQZQm/1FoivVtRcyAzdjSik7Eo+9iwPQ9EgtA5/nB2+jmbzaKtMGG3q+BnZbdKHCtOacmNrkIDA==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18" } }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-beta.50", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.50.tgz", - "integrity": "sha512-F1b6vARy49tjmT/hbloplzgJS7GIvwWZqt+tAHEstCh0JIh9sa8FAMVqEmYxDviqKBaAI8iVvUREm/Kh/PD26Q==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18" } }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-beta.50", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.50.tgz", - "integrity": "sha512-U6cR76N8T8M6lHj7EZrQ3xunLPxSvYYxA8vJsBKZiFZkT8YV4kjgCO3KwMJL0NOjQCPGKyiXO07U+KmJzdPGRw==", + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18" } }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-beta.50", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.50.tgz", - "integrity": "sha512-ONgyjofCrrE3bnh5GZb8EINSFyR/hmwTzZ7oVuyUB170lboza1VMCnb8jgE6MsyyRgHYmN8Lb59i3NKGrxrYjw==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18" } }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-beta.50", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.50.tgz", - "integrity": "sha512-L0zRdH2oDPkmB+wvuTl+dJbXCsx62SkqcEqdM+79LOcB+PxbAxxjzHU14BuZIQdXcAVDzfpMfaHWzZuwhhBTcw==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ - "arm64" + "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18" } }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-beta.50", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.50.tgz", - "integrity": "sha512-gyoI8o/TGpQd3OzkJnh1M2kxy1Bisg8qJ5Gci0sXm9yLFzEXIFdtc4EAzepxGvrT2ri99ar5rdsmNG0zP0SbIg==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ - "x64" + "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18" } }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-beta.50", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.50.tgz", - "integrity": "sha512-zti8A7M+xFDpKlghpcCAzyOi+e5nfUl3QhU023ce5NCgUxRG5zGP2GR9LTydQ1rnIPwZUVBWd4o7NjZDaQxaXA==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ - "x64" + "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18" } }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-beta.50", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.50.tgz", - "integrity": "sha512-eZUssog7qljrrRU9Mi0eqYEPm3Ch0UwB+qlWPMKSUXHNqhm3TvDZarJQdTevGEfu3EHAXJvBIe0YFYr0TPVaMA==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ - "arm64" + "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "openharmony" + "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18" } }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-beta.50", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.50.tgz", - "integrity": "sha512-nmCN0nIdeUnmgeDXiQ+2HU6FT162o+rxnF7WMkBm4M5Ds8qTU7Dzv2Wrf22bo4ftnlrb2hKK6FSwAJSAe2FWLg==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ - "wasm32" + "riscv64" ], - "dev": true, "license": "MIT", "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^1.0.7" - }, + "os": [ + "linux" + ], "engines": { - "node": ">=14.0.0" + "node": ">=18" } }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-beta.50", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.50.tgz", - "integrity": "sha512-7kcNLi7Ua59JTTLvbe1dYb028QEPaJPJQHqkmSZ5q3tJueUeb6yjRtx8mw4uIqgWZcnQHAR3PrLN4XRJxvgIkA==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ - "arm64" + "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18" } }, - "node_modules/@rolldown/binding-win32-ia32-msvc": { - "version": "1.0.0-beta.50", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.50.tgz", - "integrity": "sha512-lL70VTNvSCdSZkDPPVMwWn/M2yQiYvSoXw9hTLgdIWdUfC3g72UaruezusR6ceRuwHCY1Ayu2LtKqXkBO5LIwg==", + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ - "ia32" + "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18" } }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-beta.50", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.50.tgz", - "integrity": "sha512-4qU4x5DXWB4JPjyTne/wBNPqkbQU8J45bl21geERBKtEittleonioACBL1R0PsBu0Aq21SwMK5a9zdBkWSlQtQ==", + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "netbsd" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18" } }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.3", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", - "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==", - "dev": true, - "license": "MIT" + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", - "dev": true, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], "license": "MIT", "optional": true, - "dependencies": { - "tslib": "^2.4.0" + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@tybys/wasm-util/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 - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], "license": "MIT", - "dependencies": { - "@types/ms": "*" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "license": "MIT" - }, - "node_modules/@types/estree-jsx": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", - "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@types/estree": "*" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/geojson": { - "version": "7946.0.16", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", - "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, - "license": "MIT" - }, - "node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", "license": "MIT", "dependencies": { - "@types/unist": "*" + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/leaflet": { - "version": "1.9.21", - "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.21.tgz", - "integrity": "sha512-TbAd9DaPGSnzp6QvtYngntMZgcRk+igFELwR2N99XZn7RXUdKgsXMR+28bUO0rPsWp8MIu/f47luLIQuSLYv/w==", + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", - "dependencies": { - "@types/geojson": "*" + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, "license": "MIT", - "dependencies": { - "@types/unist": "*" + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "24.10.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.13.tgz", - "integrity": "sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg==", + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "undici-types": "~7.16.0" + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", - "license": "MIT", + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "csstype": "^3.2.2" + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.2.0" + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.0.tgz", - "integrity": "sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==", + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/type-utils": "8.56.0", - "@typescript-eslint/utils": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.56.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typescript-eslint/parser": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.0.tgz", - "integrity": "sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==", + "node_modules/@eslint/js": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", "dev": true, "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", - "debug": "^4.4.3" - }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "url": "https://eslint.org/donate" } }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.0.tgz", - "integrity": "sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==", + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.56.0", - "@typescript-eslint/types": "^8.56.0", - "debug": "^4.4.3" - }, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.0.tgz", - "integrity": "sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==", + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0" + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@exodus/schemasafe": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.3.0.tgz", + "integrity": "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==", + "dev": true, + "license": "MIT" + }, + "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": { + "@floating-ui/utils": "^0.2.11" + } + }, + "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": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.6" }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "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/@fontsource-variable/geist": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource-variable/geist/-/geist-5.2.8.tgz", + "integrity": "sha512-cJ6m9e+8MQ5dCYJsLylfZrgBh6KkG4bOLckB35Tr9J/EqdkEM6QllH5PxqP1dhTvFup+HtMRPuz9xOjxXJggxw==", + "license": "OFL-1.1", "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/ayuhito" } }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.0.tgz", - "integrity": "sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==", + "node_modules/@gerrit0/mini-shiki": { + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.22.0.tgz", + "integrity": "sha512-jMpciqEVUBKE1QwU64S4saNMzpsSza6diNCk4MWAeCxO2+LFi2FIFmL2S0VDLzEJCxuvCbU783xi8Hp/gkM5CQ==", "dev": true, "license": "MIT", + "dependencies": { + "@shikijs/engine-oniguruma": "^3.22.0", + "@shikijs/langs": "^3.22.0", + "@shikijs/themes": "^3.22.0", + "@shikijs/types": "^3.22.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@hono/node-server": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz", + "integrity": "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==", + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=18.14.1" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "hono": "^4" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.0.tgz", - "integrity": "sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==", + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0", - "@typescript-eslint/utils": "8.56.0", - "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@typescript-eslint/types": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", - "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18.18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.0.tgz", - "integrity": "sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==", + "node_modules/@ibm-cloud/openapi-ruleset": { + "version": "1.33.7", + "resolved": "https://registry.npmjs.org/@ibm-cloud/openapi-ruleset/-/openapi-ruleset-1.33.7.tgz", + "integrity": "sha512-xAhFrqqIEl7MIeb7otM33CVFBB8qHkyNp68ac/PJfA8zKg1LkZIJINntRUxC54gKHmz45rUYXNEBVvpyi/N6sg==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@typescript-eslint/project-service": "8.56.0", - "@typescript-eslint/tsconfig-utils": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", - "debug": "^4.4.3", - "minimatch": "^9.0.5", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" + "@ibm-cloud/openapi-ruleset-utilities": "1.9.0", + "@stoplight/spectral-formats": "^1.8.2", + "@stoplight/spectral-functions": "^1.9.3", + "@stoplight/spectral-rulesets": "^1.21.3", + "chalk": "^4.1.2", + "inflected": "^2.1.0", + "jsonschema": "^1.5.0", + "lodash": "^4.17.23", + "loglevel": "^1.9.2", + "loglevel-plugin-prefix": "0.8.4", + "minimatch": "^6.2.0", + "validator": "^13.15.23" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "node": ">=16.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "node_modules/@ibm-cloud/openapi-ruleset-utilities": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@ibm-cloud/openapi-ruleset-utilities/-/openapi-ruleset-utilities-1.9.0.tgz", + "integrity": "sha512-AoFbSarOqFBYH+1TZ9Ahkm2IWYSi5v0pBk88fpV+5b3qGJukypX8PwvCWADjuyIccKg48/F73a6hTTkBzDQ2UA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@ibm-cloud/openapi-ruleset/node_modules/brace-expansion": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", @@ -1294,2611 +1706,11498 @@ "balanced-match": "^1.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "node_modules/@ibm-cloud/openapi-ruleset/node_modules/minimatch": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-6.2.1.tgz", + "integrity": "sha512-C5ir1Ql7cVnkJLOtpgK9vf2P4ufJu9Hm9fwTznllGARCWOqBf+UB48yZwQyban6r7Lesm05ZOzO6JyVOzItjZQ==", "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, + "node_modules/@inquirer/ansi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@typescript-eslint/utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.0.tgz", - "integrity": "sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==", - "dev": true, + "node_modules/@inquirer/confirm": { + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=18" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.0.tgz", - "integrity": "sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==", - "dev": true, + "node_modules/@inquirer/core": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.0", - "eslint-visitor-keys": "^5.0.0" + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.3" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", - "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", - "dev": true, - "license": "Apache-2.0", + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "node": ">=14" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "license": "ISC" - }, - "node_modules/@vitejs/plugin-react": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz", - "integrity": "sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA==", - "dev": true, + "node_modules/@inquirer/core/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "license": "MIT", "dependencies": { - "@babel/core": "^7.29.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-rc.3", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.18.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + "node": ">=8" } }, - "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==", - "dev": true, + "node_modules/@inquirer/figures": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, "engines": { - "node": ">=0.4.0" + "node": ">=18" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, + "node_modules/@inquirer/type": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", "license": "MIT", + "engines": { + "node": ">=18" + }, "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, + "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": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "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": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/bail": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "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", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", - "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, "engines": { "node": ">=6.0.0" } }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, + "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": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "node_modules/@jsep-plugin/assignment": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", + "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" - }, - "bin": { - "browserslist": "cli.js" - }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/@jsep-plugin/regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", + "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001770", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001770.tgz", - "integrity": "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==", + "node_modules/@jsep-plugin/ternary": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@jsep-plugin/ternary/-/ternary-1.1.4.tgz", + "integrity": "sha512-ck5wiqIbqdMX6WRQztBL7ASDty9YLgJ3sSAK5ZpBzXeySvFGCzIvM6UiAI4hTZ22fEcYQVV/zhUbNscggW+Ukg==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.27.1", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.27.1.tgz", + "integrity": "sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" + "zod": { + "optional": false } - ], - "license": "CC-BY-4.0" + } }, - "node_modules/ccount": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, "funding": { "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "node_modules/@modelcontextprotocol/sdk/node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ajv": "^8.0.0" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "ajv": "^8.0.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, - "node_modules/character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/@monaco-editor/loader": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.7.0.tgz", + "integrity": "sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA==", + "license": "MIT", + "dependencies": { + "state-local": "^1.0.6" } }, - "node_modules/character-entities-html4": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", - "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "node_modules/@monaco-editor/react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.7.0.tgz", + "integrity": "sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==", "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "dependencies": { + "@monaco-editor/loader": "^1.5.0" + }, + "peerDependencies": { + "monaco-editor": ">= 0.25.0 < 1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/character-entities-legacy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "node_modules/@mswjs/interceptors": { + "version": "0.41.3", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.41.3.tgz", + "integrity": "sha512-cXu86tF4VQVfwz8W1SPbhoRyHJkti6mjH/XJIxp40jhO4j2k1m4KYrEykxqWPkFF3vrK4rgQppBh//AwyGSXPA==", + "license": "MIT", + "dependencies": { + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/logger": "^0.3.0", + "@open-draft/until": "^2.0.0", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "strict-event-emitter": "^0.5.1" + }, + "engines": { + "node": ">=18" + } + }, + "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==", "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" + }, "funding": { "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/character-reference-invalid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", - "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@noble/hashes": "1.8.0" }, "engines": { - "node": ">=7.0.0" + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/comma-separated-tokens": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } }, - "node_modules/cookie": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", - "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "license": "MIT", "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": ">= 8" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { "node": ">= 8" } }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "node_modules/@open-draft/deferred-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", + "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", "license": "MIT" }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/@open-draft/logger": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", + "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", "license": "MIT", "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" } }, - "node_modules/decode-named-character-reference": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", - "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "node_modules/@open-draft/until": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", + "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", + "license": "MIT" + }, + "node_modules/@orval/angular": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@orval/angular/-/angular-7.21.0.tgz", + "integrity": "sha512-AGelR1FfuimtIBBVccUI9MyjNOalLEyJFog8a94thFiqRGtz0JFIPnd8+IqRcmw3wE370PKQQMCqZl1WkjZi8w==", + "dev": true, "license": "MIT", "dependencies": { - "character-entities": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "@orval/core": "7.21.0" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "node_modules/@orval/axios": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@orval/axios/-/axios-7.21.0.tgz", + "integrity": "sha512-0t2PqMSdjJ7No6Ng5gTEpqyILmngz1mDw7OQ2TPwOiAEepNfeDgE6NtRh3zbZvrH/H5I+W8dgn+wGYueZQCNjw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@orval/core": "7.21.0" + } }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "node_modules/@orval/core": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@orval/core/-/core-7.21.0.tgz", + "integrity": "sha512-dUkggESlHq1pEUoNMF1ssRSzat5Y+G+pwtah8YoKW4wY3pTB7CNjGtGlD+a9dv3rCHUqYUqKaQD1UWRWWpF+VQ==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "@apidevtools/swagger-parser": "^12.1.0", + "@ibm-cloud/openapi-ruleset": "^1.33.1", + "@stoplight/spectral-core": "^1.20.0", + "acorn": "^8.15.0", + "chalk": "^4.1.2", + "compare-versions": "^6.1.1", + "debug": "^4.4.3", + "esbuild": "^0.25.11", + "esutils": "2.0.3", + "fs-extra": "^11.3.1", + "globby": "11.1.0", + "lodash.isempty": "^4.4.0", + "lodash.uniq": "^4.5.0", + "lodash.uniqby": "^4.7.0", + "lodash.uniqwith": "^4.5.0", + "micromatch": "^4.0.8", + "openapi3-ts": "4.5.0", + "swagger2openapi": "^7.0.8", + "typedoc": "^0.28.14" } }, - "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==", + "node_modules/@orval/fetch": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@orval/fetch/-/fetch-7.21.0.tgz", + "integrity": "sha512-e5YrZeZGoZhqj9Gzp2ANJx3/36ueMRXxwLwX0C1ps+rmMsFNa26lmQ8FHIscDQTwwULSGEGNUcunfO6X6f8t4w==", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" + "license": "MIT", + "dependencies": { + "@orval/core": "7.21.0", + "openapi3-ts": "4.5.0" } }, - "node_modules/devlop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "node_modules/@orval/hono": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@orval/hono/-/hono-7.21.0.tgz", + "integrity": "sha512-XF5hdzUjDVUjZC2Fd/ROJsp8Us+j2dCSocqfrJmOrjSO1ReTTYy2sKv3c2wk7+TUAojz/0VdTtISf8LZTM+ETQ==", + "dev": true, "license": "MIT", "dependencies": { - "dequal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "@orval/core": "7.21.0", + "@orval/zod": "7.21.0", + "fs-extra": "^11.3.2", + "lodash.uniq": "^4.5.0", + "openapi3-ts": "4.5.0" } }, - "node_modules/echarts": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/echarts/-/echarts-6.0.0.tgz", - "integrity": "sha512-Tte/grDQRiETQP4xz3iZWSvoHrkCQtwqd6hs+mifXcjrCuo2iKWbajFObuLJVBlDIJlOzgQPd1hsaKt/3+OMkQ==", - "license": "Apache-2.0", + "node_modules/@orval/mcp": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@orval/mcp/-/mcp-7.21.0.tgz", + "integrity": "sha512-4VQjdj1IDgximy+YWOwA7NzXjSvQ8lb2b6BlkKQk8wtrUW//xfquBmR7TRrtf2HKRx3UGtHsxayx4LP0dIqZgQ==", + "dev": true, + "license": "MIT", "dependencies": { - "tslib": "2.3.0", - "zrender": "6.0.0" + "@orval/core": "7.21.0", + "@orval/fetch": "7.21.0", + "@orval/zod": "7.21.0", + "openapi3-ts": "4.5.0" } }, - "node_modules/echarts-for-react": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/echarts-for-react/-/echarts-for-react-3.0.6.tgz", - "integrity": "sha512-4zqLgTGWS3JvkQDXjzkR1k1CHRdpd6by0988TWMJgnvDytegWLbeP/VNZmMa+0VJx2eD7Y632bi2JquXDgiGJg==", + "node_modules/@orval/mock": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@orval/mock/-/mock-7.21.0.tgz", + "integrity": "sha512-KgzGfG9JrrX1ciO7c0niyumncWYU9nuUg0CqMf0S2/SrAj+xunydQVja1HEB/eNB/E269pp4KG+S/d6ofe94yQ==", + "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.3", - "size-sensor": "^1.0.1" - }, - "peerDependencies": { - "echarts": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", - "react": "^15.0.0 || >=16.0.0" + "@orval/core": "7.21.0", + "openapi3-ts": "4.5.0" } }, - "node_modules/electron-to-chromium": { - "version": "1.5.302", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz", - "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==", + "node_modules/@orval/query": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@orval/query/-/query-7.21.0.tgz", + "integrity": "sha512-4An6IcqRMRReSurHVw2izLHOAX4ZkHPlaK9LubkOH1Nxzymm2ihw4eamt2XKuZ1eF83R3rzYcKwMPK3t+GzeVg==", "dev": true, - "license": "ISC" + "license": "MIT", + "dependencies": { + "@orval/core": "7.21.0", + "@orval/fetch": "7.21.0", + "chalk": "^4.1.2", + "lodash.omitby": "^4.6.0" + } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "node_modules/@orval/swr": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@orval/swr/-/swr-7.21.0.tgz", + "integrity": "sha512-aHa6WFldrpN8gQYuXfl51ogC+QpFtVzL/u9DQa+hEUAf9MXieMVVDV5w9fR9XJ4nMpV1fSCbeRd7xxqNVtd/Nw==", "dev": true, "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "@orval/core": "7.21.0", + "@orval/fetch": "7.21.0" } }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/@orval/zod": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@orval/zod/-/zod-7.21.0.tgz", + "integrity": "sha512-bTMAxdtJ8/KxDusTRL0u57YN7H0VWim8pbWj5eQYwo3xABs+puYdF3kKZ2c2biB/jUwgJJEnVkwbZV8XjxaWYw==", "dev": true, "license": "MIT", + "dependencies": { + "@orval/core": "7.21.0", + "lodash.uniq": "^4.5.0", + "openapi3-ts": "4.5.0" + } + }, + "node_modules/@oxc-project/runtime": { + "version": "0.97.0", + "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.97.0.tgz", + "integrity": "sha512-yH0zw7z+jEws4dZ4IUKoix5Lh3yhqIJWF9Dc8PWvhpo7U7O+lJrv7ZZL4BeRO0la8LBQFwcCewtLBnVV7hPe/w==", + "license": "MIT", "engines": { - "node": ">=10" - }, + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.97.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.97.0.tgz", + "integrity": "sha512-lxmZK4xFrdvU0yZiDwgVQTCvh2gHWBJCBk5ALsrtsBWhs0uDIi+FTOnXRQeQfs304imdvTdaakT/lqwQ8hkOXQ==", + "license": "MIT", "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/eslint": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", - "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", - "dev": true, + "node_modules/@preact/signals-core": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.13.0.tgz", + "integrity": "sha512-slT6XeTCAbdql61GVLlGU4x7XHI7kCZV5Um5uhE4zLX4ApgiiXc0UYFvVOKq06xcovzp7p+61l68oPi563ARKg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accessible-icon": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accessible-icon/-/react-accessible-icon-1.1.7.tgz", + "integrity": "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==", "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.2", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" + "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { - "jiti": "*" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { - "jiti": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { "optional": true } } }, - "node_modules/eslint-plugin-react-hooks": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", - "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", - "dev": true, + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", + "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", "license": "MIT", "dependencies": { - "@babel/core": "^7.24.4", - "@babel/parser": "^7.24.4", - "hermes-parser": "^0.25.1", - "zod": "^3.25.0 || ^4.0.0", - "zod-validation-error": "^3.5.0 || ^4.0.0" - }, - "engines": { - "node": ">=18" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.26", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz", - "integrity": "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==", - "dev": true, + "node_modules/@radix-ui/react-alert-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz", + "integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==", "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, "peerDependencies": { - "eslint": ">=8.40" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "@radix-ui/react-primitive": "2.1.3" }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node_modules/@radix-ui/react-aspect-ratio": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.7.tgz", + "integrity": "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.10.tgz", + "integrity": "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==", + "license": "MIT", "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/@radix-ui/react-checkbox": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", + "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", + "license": "MIT", "dependencies": { - "estraverse": "^5.1.0" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" }, - "engines": { - "node": ">=0.10" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", + "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", + "license": "MIT", "dependencies": { - "estraverse": "^5.2.0" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1" }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/estree-util-is-identifier-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", - "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, "peerDependencies": { - "picomatch": "^3 || ^4" + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { - "picomatch": { + "@types/react": { "optional": true } } }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, + "node_modules/@radix-ui/react-context-menu": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.16.tgz", + "integrity": "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==", "license": "MIT", "dependencies": { - "flat-cache": "^4.0.0" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" }, - "engines": { - "node": ">=16.0.0" - } + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "engines": { - "node": ">=16" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", + "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", "dependencies": { - "is-glob": "^4.0.3" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" }, - "engines": { - "node": ">=10.13.0" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/globals": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", - "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", - "dev": true, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", "license": "MIT", - "engines": { - "node": ">=18" + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/hast-util-to-jsx-runtime": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", - "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "node_modules/@radix-ui/react-form": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.8.tgz", + "integrity": "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ==", "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "hast-util-whitespace": "^3.0.0", - "mdast-util-mdx-expression": "^2.0.0", - "mdast-util-mdx-jsx": "^3.0.0", - "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-js": "^1.0.0", - "unist-util-position": "^5.0.0", - "vfile-message": "^4.0.0" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-label": "2.1.7", + "@radix-ui/react-primitive": "2.1.3" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/hast-util-whitespace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", - "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "node_modules/@radix-ui/react-hover-card": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.15.tgz", + "integrity": "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==", "license": "MIT", "dependencies": { - "@types/hast": "^3.0.0" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/hermes-estree": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", - "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", - "dev": true, - "license": "MIT" - }, - "node_modules/hermes-parser": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", - "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", - "dev": true, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", "license": "MIT", "dependencies": { - "hermes-estree": "0.25.1" + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/html-url-attributes": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", - "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "node_modules/@radix-ui/react-label": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz", + "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==", "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" + "node_modules/@radix-ui/react-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", + "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, + "node_modules/@radix-ui/react-menubar": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.16.tgz", + "integrity": "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==", "license": "MIT", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" }, - "engines": { - "node": ">=6" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.14.tgz", + "integrity": "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==", "license": "MIT", - "engines": { - "node": ">=0.8.19" + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/inline-style-parser": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", - "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", - "license": "MIT" - }, - "node_modules/is-alphabetical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", - "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "node_modules/@radix-ui/react-one-time-password-field": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-one-time-password-field/-/react-one-time-password-field-0.1.8.tgz", + "integrity": "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg==", "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/is-alphanumerical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", - "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "node_modules/@radix-ui/react-password-toggle-field": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-password-toggle-field/-/react-password-toggle-field-0.1.3.tgz", + "integrity": "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw==", "license": "MIT", "dependencies": { - "is-alphabetical": "^2.0.0", - "is-decimal": "^2.0.0" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-is-hydrated": "0.1.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/is-decimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", - "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/@radix-ui/react-popover": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", + "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" }, - "engines": { - "node": ">=0.10.0" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/is-hexadecimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", - "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "@radix-ui/react-slot": "1.2.3" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.7.tgz", + "integrity": "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==", "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, + "node_modules/@radix-ui/react-radio-group": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.8.tgz", + "integrity": "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==", "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" }, - "engines": { - "node": ">=6" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", "license": "MIT", - "bin": { - "json5": "lib/cli.js" + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" }, - "engines": { - "node": ">=6" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", + "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", "license": "MIT", "dependencies": { - "json-buffer": "3.0.1" + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/leaflet": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", - "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", - "license": "BSD-2-Clause" + "node_modules/@radix-ui/react-select": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", + "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz", + "integrity": "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==", "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "@radix-ui/react-primitive": "2.1.3" }, - "engines": { - "node": ">= 0.8.0" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/lightningcss": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", - "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", - "dev": true, - "license": "MPL-2.0", + "node_modules/@radix-ui/react-slider": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.3.6.tgz", + "integrity": "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==", + "license": "MIT", "dependencies": { - "detect-libc": "^2.0.3" + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" }, - "engines": { - "node": ">= 12.0.0" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", + "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.15.tgz", + "integrity": "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz", + "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.11.tgz", + "integrity": "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-toggle": "1.1.10", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toolbar": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toolbar/-/react-toolbar-1.1.11.tgz", + "integrity": "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-separator": "1.1.7", + "@radix-ui/react-toggle-group": "1.1.11" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", + "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", + "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, + "node_modules/@react-leaflet/core": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz", + "integrity": "sha512-3EWmekh4Nz+pGcr+xjf0KNyYfC3U2JjnkWsh0zcqaexYqmmB5ZhH37kz41JXGmKzpaMZCnPofBBm64i+YrEvGQ==", + "license": "Hippocratic-2.1", + "peerDependencies": { + "leaflet": "^1.9.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.50.tgz", + "integrity": "sha512-XlEkrOIHLyGT3avOgzfTFSjG+f+dZMw+/qd+Y3HLN86wlndrB/gSimrJCk4gOhr1XtRtEKfszpadI3Md4Z4/Ag==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.50.tgz", + "integrity": "sha512-+JRqKJhoFlt5r9q+DecAGPLZ5PxeLva+wCMtAuoFMWPoZzgcYrr599KQ+Ix0jwll4B4HGP43avu9My8KtSOR+w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.50.tgz", + "integrity": "sha512-fFXDjXnuX7/gQZQm/1FoivVtRcyAzdjSik7Eo+9iwPQ9EgtA5/nB2+jmbzaKtMGG3q+BnZbdKHCtOacmNrkIDA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.50.tgz", + "integrity": "sha512-F1b6vARy49tjmT/hbloplzgJS7GIvwWZqt+tAHEstCh0JIh9sa8FAMVqEmYxDviqKBaAI8iVvUREm/Kh/PD26Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.50.tgz", + "integrity": "sha512-U6cR76N8T8M6lHj7EZrQ3xunLPxSvYYxA8vJsBKZiFZkT8YV4kjgCO3KwMJL0NOjQCPGKyiXO07U+KmJzdPGRw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.50.tgz", + "integrity": "sha512-ONgyjofCrrE3bnh5GZb8EINSFyR/hmwTzZ7oVuyUB170lboza1VMCnb8jgE6MsyyRgHYmN8Lb59i3NKGrxrYjw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.50.tgz", + "integrity": "sha512-L0zRdH2oDPkmB+wvuTl+dJbXCsx62SkqcEqdM+79LOcB+PxbAxxjzHU14BuZIQdXcAVDzfpMfaHWzZuwhhBTcw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.50.tgz", + "integrity": "sha512-gyoI8o/TGpQd3OzkJnh1M2kxy1Bisg8qJ5Gci0sXm9yLFzEXIFdtc4EAzepxGvrT2ri99ar5rdsmNG0zP0SbIg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.50.tgz", + "integrity": "sha512-zti8A7M+xFDpKlghpcCAzyOi+e5nfUl3QhU023ce5NCgUxRG5zGP2GR9LTydQ1rnIPwZUVBWd4o7NjZDaQxaXA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.50.tgz", + "integrity": "sha512-eZUssog7qljrrRU9Mi0eqYEPm3Ch0UwB+qlWPMKSUXHNqhm3TvDZarJQdTevGEfu3EHAXJvBIe0YFYr0TPVaMA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.50.tgz", + "integrity": "sha512-nmCN0nIdeUnmgeDXiQ+2HU6FT162o+rxnF7WMkBm4M5Ds8qTU7Dzv2Wrf22bo4ftnlrb2hKK6FSwAJSAe2FWLg==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.0.7" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.50.tgz", + "integrity": "sha512-7kcNLi7Ua59JTTLvbe1dYb028QEPaJPJQHqkmSZ5q3tJueUeb6yjRtx8mw4uIqgWZcnQHAR3PrLN4XRJxvgIkA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-ia32-msvc": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.50.tgz", + "integrity": "sha512-lL70VTNvSCdSZkDPPVMwWn/M2yQiYvSoXw9hTLgdIWdUfC3g72UaruezusR6ceRuwHCY1Ayu2LtKqXkBO5LIwg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.50.tgz", + "integrity": "sha512-4qU4x5DXWB4JPjyTne/wBNPqkbQU8J45bl21geERBKtEittleonioACBL1R0PsBu0Aq21SwMK5a9zdBkWSlQtQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", + "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "license": "MIT" + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.22.0.tgz", + "integrity": "sha512-DyXsOG0vGtNtl7ygvabHd7Mt5EY8gCNqR9Y7Lpbbd/PbJvgWrqaKzH1JW6H6qFkuUa8aCxoiYVv8/YfFljiQxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.22.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.22.0.tgz", + "integrity": "sha512-x/42TfhWmp6H00T6uwVrdTJGKgNdFbrEdhaDwSR5fd5zhQ1Q46bHq9EO61SCEWJR0HY7z2HNDMaBZp8JRmKiIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.22.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.22.0.tgz", + "integrity": "sha512-o+tlOKqsr6FE4+mYJG08tfCFDS+3CG20HbldXeVoyP+cYSUxDhrFf3GPjE60U55iOkkjbpY2uC3It/eeja35/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.22.0" + } + }, + "node_modules/@shikijs/types": { + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.22.0.tgz", + "integrity": "sha512-491iAekgKDBFE67z70Ok5a8KBMsQ2IJwOWw3us/7ffQkIBCyOQfm/aNwVMBUriP02QshIfgHCBSIYAl3u2eWjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@stoplight/json": { + "version": "3.21.7", + "resolved": "https://registry.npmjs.org/@stoplight/json/-/json-3.21.7.tgz", + "integrity": "sha512-xcJXgKFqv/uCEgtGlPxy3tPA+4I+ZI4vAuMJ885+ThkTHFVkC+0Fm58lA9NlsyjnkpxFh4YiQWpH+KefHdbA0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@stoplight/ordered-object-literal": "^1.0.3", + "@stoplight/path": "^1.3.2", + "@stoplight/types": "^13.6.0", + "jsonc-parser": "~2.2.1", + "lodash": "^4.17.21", + "safe-stable-stringify": "^1.1" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/@stoplight/json-ref-readers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@stoplight/json-ref-readers/-/json-ref-readers-1.2.2.tgz", + "integrity": "sha512-nty0tHUq2f1IKuFYsLM4CXLZGHdMn+X/IwEUIpeSOXt0QjMUbL0Em57iJUDzz+2MkWG83smIigNZ3fauGjqgdQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-fetch": "^2.6.0", + "tslib": "^1.14.1" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/@stoplight/json-ref-readers/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@stoplight/json-ref-resolver": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@stoplight/json-ref-resolver/-/json-ref-resolver-3.1.6.tgz", + "integrity": "sha512-YNcWv3R3n3U6iQYBsFOiWSuRGE5su1tJSiX6pAPRVk7dP0L7lqCteXGzuVRQ0gMZqUl8v1P0+fAKxF6PLo9B5A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@stoplight/json": "^3.21.0", + "@stoplight/path": "^1.3.2", + "@stoplight/types": "^12.3.0 || ^13.0.0", + "@types/urijs": "^1.19.19", + "dependency-graph": "~0.11.0", + "fast-memoize": "^2.5.2", + "immer": "^9.0.6", + "lodash": "^4.17.21", + "tslib": "^2.6.0", + "urijs": "^1.19.11" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/@stoplight/json-ref-resolver/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" + }, + "node_modules/@stoplight/ordered-object-literal": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@stoplight/ordered-object-literal/-/ordered-object-literal-1.0.5.tgz", + "integrity": "sha512-COTiuCU5bgMUtbIFBuyyh2/yVVzlr5Om0v5utQDgBCuQUOPgU1DwoffkTfg4UBQOvByi5foF4w4T+H9CoRe5wg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/@stoplight/path": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@stoplight/path/-/path-1.3.2.tgz", + "integrity": "sha512-lyIc6JUlUA8Ve5ELywPC8I2Sdnh1zc1zmbYgVarhXIp9YeAB0ReeqmGEOWNtlHkbP2DAA1AL65Wfn2ncjK/jtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/@stoplight/spectral-core": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.21.0.tgz", + "integrity": "sha512-oj4e/FrDLUhBRocIW+lRMKlJ/q/rDZw61HkLbTFsdMd+f/FTkli2xHNB1YC6n1mrMKjjvy7XlUuFkC7XxtgbWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@stoplight/better-ajv-errors": "1.0.3", + "@stoplight/json": "~3.21.0", + "@stoplight/path": "1.3.2", + "@stoplight/spectral-parsers": "^1.0.0", + "@stoplight/spectral-ref-resolver": "^1.0.4", + "@stoplight/spectral-runtime": "^1.1.2", + "@stoplight/types": "~13.6.0", + "@types/es-aggregate-error": "^1.0.2", + "@types/json-schema": "^7.0.11", + "ajv": "^8.17.1", + "ajv-errors": "~3.0.0", + "ajv-formats": "~2.1.1", + "es-aggregate-error": "^1.0.7", + "jsonpath-plus": "^10.3.0", + "lodash": "~4.17.23", + "lodash.topath": "^4.5.2", + "minimatch": "3.1.2", + "nimma": "0.2.3", + "pony-cause": "^1.1.1", + "simple-eval": "1.0.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^16.20 || ^18.18 || >= 20.17" + } + }, + "node_modules/@stoplight/spectral-core/node_modules/@stoplight/better-ajv-errors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stoplight/better-ajv-errors/-/better-ajv-errors-1.0.3.tgz", + "integrity": "sha512-0p9uXkuB22qGdNfy3VeEhxkU5uwvp/KrBTAbrLBURv6ilxIVwanKwjMc41lQfIVgPGcOkmLbTolfFrSsueu7zA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jsonpointer": "^5.0.0", + "leven": "^3.1.0" + }, + "engines": { + "node": "^12.20 || >= 14.13" + }, + "peerDependencies": { + "ajv": ">=8" + } + }, + "node_modules/@stoplight/spectral-core/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@stoplight/spectral-core/node_modules/ajv-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", + "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^8.0.1" + } + }, + "node_modules/@stoplight/spectral-core/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@stoplight/spectral-core/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" + }, + "node_modules/@stoplight/spectral-formats": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-formats/-/spectral-formats-1.8.2.tgz", + "integrity": "sha512-c06HB+rOKfe7tuxg0IdKDEA5XnjL2vrn/m/OVIIxtINtBzphZrOgtRn7epQ5bQF5SWp84Ue7UJWaGgDwVngMFw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@stoplight/json": "^3.17.0", + "@stoplight/spectral-core": "^1.19.2", + "@types/json-schema": "^7.0.7", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^16.20 || ^18.18 || >= 20.17" + } + }, + "node_modules/@stoplight/spectral-formats/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" + }, + "node_modules/@stoplight/spectral-functions": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-functions/-/spectral-functions-1.10.1.tgz", + "integrity": "sha512-obu8ZfoHxELOapfGsCJixKZXZcffjg+lSoNuttpmUFuDzVLT3VmH8QkPXfOGOL5Pz80BR35ClNAToDkdnYIURg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@stoplight/better-ajv-errors": "1.0.3", + "@stoplight/json": "^3.17.1", + "@stoplight/spectral-core": "^1.19.4", + "@stoplight/spectral-formats": "^1.8.1", + "@stoplight/spectral-runtime": "^1.1.2", + "ajv": "^8.17.1", + "ajv-draft-04": "~1.0.0", + "ajv-errors": "~3.0.0", + "ajv-formats": "~2.1.1", + "lodash": "~4.17.21", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^16.20 || ^18.18 || >= 20.17" + } + }, + "node_modules/@stoplight/spectral-functions/node_modules/@stoplight/better-ajv-errors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stoplight/better-ajv-errors/-/better-ajv-errors-1.0.3.tgz", + "integrity": "sha512-0p9uXkuB22qGdNfy3VeEhxkU5uwvp/KrBTAbrLBURv6ilxIVwanKwjMc41lQfIVgPGcOkmLbTolfFrSsueu7zA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jsonpointer": "^5.0.0", + "leven": "^3.1.0" + }, + "engines": { + "node": "^12.20 || >= 14.13" + }, + "peerDependencies": { + "ajv": ">=8" + } + }, + "node_modules/@stoplight/spectral-functions/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@stoplight/spectral-functions/node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/@stoplight/spectral-functions/node_modules/ajv-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", + "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^8.0.1" + } + }, + "node_modules/@stoplight/spectral-functions/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@stoplight/spectral-functions/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" + }, + "node_modules/@stoplight/spectral-parsers": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-parsers/-/spectral-parsers-1.0.5.tgz", + "integrity": "sha512-ANDTp2IHWGvsQDAY85/jQi9ZrF4mRrA5bciNHX+PUxPr4DwS6iv4h+FVWJMVwcEYdpyoIdyL+SRmHdJfQEPmwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@stoplight/json": "~3.21.0", + "@stoplight/types": "^14.1.1", + "@stoplight/yaml": "~4.3.0", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^16.20 || ^18.18 || >= 20.17" + } + }, + "node_modules/@stoplight/spectral-parsers/node_modules/@stoplight/types": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-14.1.1.tgz", + "integrity": "sha512-/kjtr+0t0tjKr+heVfviO9FrU/uGLc+QNX3fHJc19xsCNYqU7lVhaXxDmEID9BZTjG+/r9pK9xP/xU02XGg65g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.4", + "utility-types": "^3.10.0" + }, + "engines": { + "node": "^12.20 || >=14.13" + } + }, + "node_modules/@stoplight/spectral-parsers/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" + }, + "node_modules/@stoplight/spectral-ref-resolver": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-ref-resolver/-/spectral-ref-resolver-1.0.5.tgz", + "integrity": "sha512-gj3TieX5a9zMW29z3mBlAtDOCgN3GEc1VgZnCVlr5irmR4Qi5LuECuFItAq4pTn5Zu+sW5bqutsCH7D4PkpyAA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@stoplight/json-ref-readers": "1.2.2", + "@stoplight/json-ref-resolver": "~3.1.6", + "@stoplight/spectral-runtime": "^1.1.2", + "dependency-graph": "0.11.0", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^16.20 || ^18.18 || >= 20.17" + } + }, + "node_modules/@stoplight/spectral-ref-resolver/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" + }, + "node_modules/@stoplight/spectral-rulesets": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-rulesets/-/spectral-rulesets-1.22.0.tgz", + "integrity": "sha512-l2EY2jiKKLsvnPfGy+pXC0LeGsbJzcQP5G/AojHgf+cwN//VYxW1Wvv4WKFx/CLmLxc42mJYF2juwWofjWYNIQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@asyncapi/specs": "^6.8.0", + "@stoplight/better-ajv-errors": "1.0.3", + "@stoplight/json": "^3.17.0", + "@stoplight/spectral-core": "^1.19.4", + "@stoplight/spectral-formats": "^1.8.1", + "@stoplight/spectral-functions": "^1.9.1", + "@stoplight/spectral-runtime": "^1.1.2", + "@stoplight/types": "^13.6.0", + "@types/json-schema": "^7.0.7", + "ajv": "^8.17.1", + "ajv-formats": "~2.1.1", + "json-schema-traverse": "^1.0.0", + "leven": "3.1.0", + "lodash": "~4.17.21", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^16.20 || ^18.18 || >= 20.17" + } + }, + "node_modules/@stoplight/spectral-rulesets/node_modules/@stoplight/better-ajv-errors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stoplight/better-ajv-errors/-/better-ajv-errors-1.0.3.tgz", + "integrity": "sha512-0p9uXkuB22qGdNfy3VeEhxkU5uwvp/KrBTAbrLBURv6ilxIVwanKwjMc41lQfIVgPGcOkmLbTolfFrSsueu7zA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jsonpointer": "^5.0.0", + "leven": "^3.1.0" + }, + "engines": { + "node": "^12.20 || >= 14.13" + }, + "peerDependencies": { + "ajv": ">=8" + } + }, + "node_modules/@stoplight/spectral-rulesets/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@stoplight/spectral-rulesets/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@stoplight/spectral-rulesets/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" + }, + "node_modules/@stoplight/spectral-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-runtime/-/spectral-runtime-1.1.4.tgz", + "integrity": "sha512-YHbhX3dqW0do6DhiPSgSGQzr6yQLlWybhKwWx0cqxjMwxej3TqLv3BXMfIUYFKKUqIwH4Q2mV8rrMM8qD2N0rQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@stoplight/json": "^3.20.1", + "@stoplight/path": "^1.3.2", + "@stoplight/types": "^13.6.0", + "abort-controller": "^3.0.0", + "lodash": "^4.17.21", + "node-fetch": "^2.7.0", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^16.20 || ^18.18 || >= 20.17" + } + }, + "node_modules/@stoplight/spectral-runtime/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" + }, + "node_modules/@stoplight/types": { + "version": "13.6.0", + "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.6.0.tgz", + "integrity": "sha512-dzyuzvUjv3m1wmhPfq82lCVYGcXG0xUYgqnWfCq3PCVR4BKFhjdkHrnJ+jIDoMKvXb05AZP/ObQF6+NpDo29IQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.4", + "utility-types": "^3.10.0" + }, + "engines": { + "node": "^12.20 || >=14.13" + } + }, + "node_modules/@stoplight/yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@stoplight/yaml/-/yaml-4.3.0.tgz", + "integrity": "sha512-JZlVFE6/dYpP9tQmV0/ADfn32L9uFarHWxfcRhReKUnljz1ZiUM5zpX+PH8h5CJs6lao3TuFqnPm9IJJCEkE2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@stoplight/ordered-object-literal": "^1.0.5", + "@stoplight/types": "^14.1.1", + "@stoplight/yaml-ast-parser": "0.0.50", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=10.8" + } + }, + "node_modules/@stoplight/yaml-ast-parser": { + "version": "0.0.50", + "resolved": "https://registry.npmjs.org/@stoplight/yaml-ast-parser/-/yaml-ast-parser-0.0.50.tgz", + "integrity": "sha512-Pb6M8TDO9DtSVla9yXSTAxmo9GVEouq5P40DWXdOie69bXogZTkgvopCq+yEvTMA0F6PEvdJmbtTV3ccIp11VQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@stoplight/yaml/node_modules/@stoplight/types": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-14.1.1.tgz", + "integrity": "sha512-/kjtr+0t0tjKr+heVfviO9FrU/uGLc+QNX3fHJc19xsCNYqU7lVhaXxDmEID9BZTjG+/r9pK9xP/xU02XGg65g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.4", + "utility-types": "^3.10.0" + }, + "engines": { + "node": "^12.20 || >=14.13" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.2.tgz", + "integrity": "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.19.0", + "jiti": "^2.6.1", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.2.2" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.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/@tailwindcss/node/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" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/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" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/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" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/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" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/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" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/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" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/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" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/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" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/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" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/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" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/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" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.2.tgz", + "integrity": "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==", + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.2.2", + "@tailwindcss/oxide-darwin-arm64": "4.2.2", + "@tailwindcss/oxide-darwin-x64": "4.2.2", + "@tailwindcss/oxide-freebsd-x64": "4.2.2", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", + "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", + "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", + "@tailwindcss/oxide-linux-x64-musl": "4.2.2", + "@tailwindcss/oxide-wasm32-wasi": "4.2.2", + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", + "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.2.tgz", + "integrity": "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.2.tgz", + "integrity": "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.2.tgz", + "integrity": "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.2.tgz", + "integrity": "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.2.tgz", + "integrity": "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.2.tgz", + "integrity": "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.2.tgz", + "integrity": "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.2.tgz", + "integrity": "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.2.tgz", + "integrity": "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.2.tgz", + "integrity": "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.8.1", + "@emnapi/runtime": "^1.8.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.1", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.2.tgz", + "integrity": "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.2.tgz", + "integrity": "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.2.tgz", + "integrity": "sha512-mEiF5HO1QqCLXoNEfXVA1Tzo+cYsrqV7w9Juj2wdUFyW07JRenqMG225MvPwr3ZD9N1bFQj46X7r33iHxLUW0w==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.2.2", + "@tailwindcss/oxide": "4.2.2", + "tailwindcss": "4.2.2" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7 || ^8" + } + }, + "node_modules/@tanstack/query-core": { + "version": "5.90.20", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.20.tgz", + "integrity": "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.90.21", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.21.tgz", + "integrity": "sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.90.20" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@ts-morph/common": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.27.0.tgz", + "integrity": "sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==", + "license": "MIT", + "dependencies": { + "fast-glob": "^3.3.3", + "minimatch": "^10.0.1", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@ts-morph/common/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@ts-morph/common/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@ts-morph/common/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tybys/wasm-util/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/es-aggregate-error": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/es-aggregate-error/-/es-aggregate-error-1.0.6.tgz", + "integrity": "sha512-qJ7LIFp06h1QE1aVxbVd+zJP2wdaugYXYfd6JxsyRMrYHaxb6itXPogW2tz+ylUJ1n1b+JF1PHyYCfYHm0dvUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/leaflet": { + "version": "1.9.21", + "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.21.tgz", + "integrity": "sha512-TbAd9DaPGSnzp6QvtYngntMZgcRk+igFELwR2N99XZn7RXUdKgsXMR+28bUO0rPsWp8MIu/f47luLIQuSLYv/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.12.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.0.tgz", + "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/statuses": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.6.tgz", + "integrity": "sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==", + "license": "MIT" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@types/urijs": { + "version": "1.19.26", + "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.26.tgz", + "integrity": "sha512-wkXrVzX5yoqLnndOwFsieJA7oKM8cNkOKJtf/3vVGSUFkWDKZvFHpIl9Pvqb/T9UsawBBFMTTD8xu7sK5MWuvg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/validate-npm-package-name": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/validate-npm-package-name/-/validate-npm-package-name-4.0.2.tgz", + "integrity": "sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.0.tgz", + "integrity": "sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.56.0", + "@typescript-eslint/type-utils": "8.56.0", + "@typescript-eslint/utils": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.56.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.0.tgz", + "integrity": "sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/typescript-estree": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.0.tgz", + "integrity": "sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.56.0", + "@typescript-eslint/types": "^8.56.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.0.tgz", + "integrity": "sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.0.tgz", + "integrity": "sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.0.tgz", + "integrity": "sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/typescript-estree": "8.56.0", + "@typescript-eslint/utils": "8.56.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", + "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.0.tgz", + "integrity": "sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.56.0", + "@typescript-eslint/tsconfig-utils": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.0.tgz", + "integrity": "sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/typescript-estree": "8.56.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.0.tgz", + "integrity": "sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", + "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz", + "integrity": "sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.29.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-rc.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "dev": true, + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/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/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", + "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/body-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001770", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001770.tgz", + "integrity": "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/code-block-writer": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", + "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "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/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "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/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/diff": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz", + "integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dompurify": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", + "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==", + "license": "(MPL-2.0 OR Apache-2.0)", + "peer": true, + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/dotenv": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz", + "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "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/echarts": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-6.0.0.tgz", + "integrity": "sha512-Tte/grDQRiETQP4xz3iZWSvoHrkCQtwqd6hs+mifXcjrCuo2iKWbajFObuLJVBlDIJlOzgQPd1hsaKt/3+OMkQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "2.3.0", + "zrender": "6.0.0" + } + }, + "node_modules/echarts-for-react": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/echarts-for-react/-/echarts-for-react-3.0.6.tgz", + "integrity": "sha512-4zqLgTGWS3JvkQDXjzkR1k1CHRdpd6by0988TWMJgnvDytegWLbeP/VNZmMa+0VJx2eD7Y632bi2JquXDgiGJg==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "size-sensor": "^1.0.1" + }, + "peerDependencies": { + "echarts": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", + "react": "^15.0.0 || >=16.0.0" + } + }, + "node_modules/eciesjs": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/eciesjs/-/eciesjs-0.4.18.tgz", + "integrity": "sha512-wG99Zcfcys9fZux7Cft8BAX/YrOJLJSZ3jyYPfhZHqN2E+Ffx+QXBDsv3gubEgPtV6dTzJMSQUwk1H98/t/0wQ==", + "license": "MIT", + "dependencies": { + "@ecies/ciphers": "^0.2.5", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "^1.9.7", + "@noble/hashes": "^1.8.0" + }, + "engines": { + "bun": ">=1", + "deno": ">=2", + "node": ">=16" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.302", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz", + "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", + "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", + "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-aggregate-error": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/es-aggregate-error/-/es-aggregate-error-1.0.14.tgz", + "integrity": "sha512-3YxX6rVb07B5TV11AV5wsL7nQCHXNwoHPsQC8S4AmBiqYhyNCJ5BRKXkXyDJvs8QzXN20NgRtxe3dEEQD9NLHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "globalthis": "^1.0.4", + "has-property-descriptors": "^1.0.2", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "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/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "devOptional": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", + "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz", + "integrity": "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.3.1.tgz", + "integrity": "sha512-D1dKN+cmyPWuvB+G2SREQDzPY1agpBIcTa9sJxOPMCNeH3gwzhqJRDWCXW3gg0y//+LQ/8j52JbMROWyrKdMdw==", + "license": "MIT", + "dependencies": { + "ip-address": "10.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-memoize": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz", + "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "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/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-extra": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", + "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fuzzysort": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fuzzysort/-/fuzzysort-3.1.0.tgz", + "integrity": "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==", + "license": "MIT" + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", + "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-own-enumerable-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-own-enumerable-keys/-/get-own-enumerable-keys-1.0.0.tgz", + "integrity": "sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/graphql": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.13.1.tgz", + "integrity": "sha512-gGgrVCoDKlIZ8fIqXBBb0pPKqDgki0Z/FSKNiQzSGj2uEYHr1tq5wmBegGwJx6QB5S5cM0khSBpi/JFHMCvsmQ==", + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/headers-polyfill": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.3.tgz", + "integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==", + "license": "MIT" + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hono": { + "version": "4.12.8", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.8.tgz", + "integrity": "sha512-VJCEvtrezO1IAR+kqEYnxUOoStaQPGrCmX3j4wDTNOcD1uRPFpGlwQUIW8niPuvHXaTUxeOUl5MMDGrl+tmO9A==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/html-url-attributes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http2-client": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz", + "integrity": "sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==", + "dev": true, + "license": "MIT" + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflected": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/inflected/-/inflected-2.1.0.tgz", + "integrity": "sha512-hAEKNxvHf2Iq3H60oMBHkB4wl5jn3TPF3+fXek/sRwAB5gP9xWs4r7aweSF95f99HFoz69pnZTcu8f0SIHV18w==", + "dev": true, + "license": "MIT" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "license": "MIT" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ip-address": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-node-process": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", + "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", + "license": "MIT" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-3.0.0.tgz", + "integrity": "sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regexp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-3.1.0.tgz", + "integrity": "sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/jose": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.2.tgz", + "integrity": "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsep": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", + "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.16.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": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.2.1.tgz", + "integrity": "sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonpath-plus": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.4.0.tgz", + "integrity": "sha512-T92WWatJXmhBbKsgH/0hl+jxjdXrifi5IKeMY02DWggRxX0UElcbVzPlmgLTbvsPeW1PasQ6xE2Q75stkhGbsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jsep-plugin/assignment": "^1.3.0", + "@jsep-plugin/regex": "^1.0.4", + "jsep": "^1.4.0" + }, + "bin": { + "jsonpath": "bin/jsonpath-cli.js", + "jsonpath-plus": "bin/jsonpath-cli.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jsonschema": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.5.0.tgz", + "integrity": "sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leaflet": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", + "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", + "license": "BSD-2-Clause" + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", + "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.31.1", + "lightningcss-darwin-arm64": "1.31.1", + "lightningcss-darwin-x64": "1.31.1", + "lightningcss-freebsd-x64": "1.31.1", + "lightningcss-linux-arm-gnueabihf": "1.31.1", + "lightningcss-linux-arm64-gnu": "1.31.1", + "lightningcss-linux-arm64-musl": "1.31.1", + "lightningcss-linux-x64-gnu": "1.31.1", + "lightningcss-linux-x64-musl": "1.31.1", + "lightningcss-win32-arm64-msvc": "1.31.1", + "lightningcss-win32-x64-msvc": "1.31.1" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", + "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", + "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", + "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", + "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", + "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", + "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", + "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", + "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", + "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", + "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", + "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isempty": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz", + "integrity": "sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.omitby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.omitby/-/lodash.omitby-4.6.0.tgz", + "integrity": "sha512-5OrRcIVR75M288p4nbI2WLAf3ndw2GD9fyNv3Bc15+WCxJDdZ4lYndSxGd7hnG6PVjiJTeJE2dHEGhIuKGicIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.topath": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.topath/-/lodash.topath-4.5.2.tgz", + "integrity": "sha512-1/W4dM+35DwvE/iEd1M9ekewOSTlpFekhw9mhAtrwjVqUr83/ilQiyAvmg4tVX7Unkcfl1KC+i9WdaT4B6aQcg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniqby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", + "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniqwith": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz", + "integrity": "sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loglevel": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz", + "integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, + "node_modules/loglevel-plugin-prefix": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/loglevel-plugin-prefix/-/loglevel-plugin-prefix-0.8.4.tgz", + "integrity": "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.577.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.577.0.tgz", + "integrity": "sha512-4LjoFv2eEPwYDPg/CUdBJQSDfPyzXCRrVW1X7jrx/trgxnxkHFjnVZINbzvzxjN70dxychOfg+FTYwBiS3pQ5A==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true, + "license": "MIT" + }, + "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" + } + }, + "node_modules/markdown-it": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/marked": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", + "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==", + "license": "MIT", + "peer": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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" + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/monaco-editor": { + "version": "0.55.1", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz", + "integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==", + "license": "MIT", + "peer": true, + "dependencies": { + "dompurify": "3.2.7", + "marked": "14.0.0" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/msw": { + "version": "2.12.13", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.12.13.tgz", + "integrity": "sha512-9CV2mXT9+z0J26MQDfEZZkj/psJ5Er/w0w+t95FWdaGH/DTlhNZBx8vBO5jSYv8AZEnl3ouX+AaTT68KXdAIag==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@inquirer/confirm": "^5.0.0", + "@mswjs/interceptors": "^0.41.2", + "@open-draft/deferred-promise": "^2.2.0", + "@types/statuses": "^2.0.6", + "cookie": "^1.0.2", + "graphql": "^16.12.0", + "headers-polyfill": "^4.0.2", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "path-to-regexp": "^6.3.0", + "picocolors": "^1.1.1", + "rettime": "^0.10.1", + "statuses": "^2.0.2", + "strict-event-emitter": "^0.5.1", + "tough-cookie": "^6.0.0", + "type-fest": "^5.2.0", + "until-async": "^3.0.2", + "yargs": "^17.7.2" + }, + "bin": { + "msw": "cli/index.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mswjs" + }, + "peerDependencies": { + "typescript": ">= 4.8.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.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" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/next-themes": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", + "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/nimma": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/nimma/-/nimma-0.2.3.tgz", + "integrity": "sha512-1ZOI8J+1PKKGceo/5CT5GfQOG6H8I2BencSK06YarZ2wXwH37BSSUWldqJmMJYA5JfqDqffxDXynt6f11AyKcA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsep-plugin/regex": "^1.0.1", + "@jsep-plugin/ternary": "^1.0.2", + "astring": "^1.8.1", + "jsep": "^1.2.0" + }, + "engines": { + "node": "^12.20 || >=14.13" + }, + "optionalDependencies": { + "jsonpath-plus": "^6.0.1 || ^10.1.0", + "lodash.topath": "^4.5.2" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch-h2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz", + "integrity": "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "http2-client": "^1.2.5" + }, + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/node-readfiles": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/node-readfiles/-/node-readfiles-0.2.0.tgz", + "integrity": "sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es6-promise": "^3.2.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "license": "MIT" + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/oas-kit-common": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/oas-kit-common/-/oas-kit-common-1.0.8.tgz", + "integrity": "sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "fast-safe-stringify": "^2.0.7" + } + }, + "node_modules/oas-linter": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/oas-linter/-/oas-linter-3.2.2.tgz", + "integrity": "sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@exodus/schemasafe": "^1.0.0-rc.2", + "should": "^13.2.1", + "yaml": "^1.10.0" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-linter/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/oas-resolver": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/oas-resolver/-/oas-resolver-2.5.6.tgz", + "integrity": "sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "node-fetch-h2": "^2.3.0", + "oas-kit-common": "^1.0.8", + "reftools": "^1.1.9", + "yaml": "^1.10.0", + "yargs": "^17.0.1" + }, + "bin": { + "resolve": "resolve.js" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-resolver/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/oas-schema-walker": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/oas-schema-walker/-/oas-schema-walker-1.1.5.tgz", + "integrity": "sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ==", + "dev": true, + "license": "BSD-3-Clause", + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-validator": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/oas-validator/-/oas-validator-5.0.8.tgz", + "integrity": "sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "call-me-maybe": "^1.0.1", + "oas-kit-common": "^1.0.8", + "oas-linter": "^3.2.2", + "oas-resolver": "^2.5.6", + "oas-schema-walker": "^1.1.5", + "reftools": "^1.1.9", + "should": "^13.2.1", + "yaml": "^1.10.0" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-validator/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-treeify": { + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz", + "integrity": "sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", + "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", + "license": "MIT", + "dependencies": { + "default-browser": "^5.4.0", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.1.0", + "wsl-utils": "^0.3.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/openapi3-ts": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/openapi3-ts/-/openapi3-ts-4.5.0.tgz", + "integrity": "sha512-jaL+HgTq2Gj5jRcfdutgRGLosCy/hT8sQf6VOy+P+g36cZOjI1iukdPnijC+4CmeRzg/jEllJUboEic2FhxhtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yaml": "^2.8.0" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/ora/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/orval": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/orval/-/orval-7.21.0.tgz", + "integrity": "sha512-gG6aihg/BUiOgapn0qXsx3mgKU3L6iuzWtQJmvzdXavasyS0i+9e5j7kIpbdbeCYIEQX05kjBIzz5ZQlqzXCDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apidevtools/swagger-parser": "^12.1.0", + "@commander-js/extra-typings": "^14.0.0", + "@orval/angular": "7.21.0", + "@orval/axios": "7.21.0", + "@orval/core": "7.21.0", + "@orval/fetch": "7.21.0", + "@orval/hono": "7.21.0", + "@orval/mcp": "7.21.0", + "@orval/mock": "7.21.0", + "@orval/query": "7.21.0", + "@orval/swr": "7.21.0", + "@orval/zod": "7.21.0", + "chalk": "^4.1.2", + "chokidar": "^4.0.3", + "commander": "^14.0.1", + "enquirer": "^2.4.1", + "execa": "^5.1.1", + "find-up": "5.0.0", + "fs-extra": "^11.3.2", + "jiti": "^2.6.1", + "js-yaml": "4.1.1", + "lodash.uniq": "^4.5.0", + "openapi3-ts": "4.5.0", + "string-argv": "^0.3.2", + "tsconfck": "^2.1.2", + "typedoc": "^0.28.14", + "typedoc-plugin-coverage": "^4.0.2", + "typedoc-plugin-markdown": "^4.9.0" + }, + "bin": { + "orval": "dist/bin/orval.js" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/outvariant": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", + "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==", + "license": "MIT" + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.31.1", - "lightningcss-darwin-arm64": "1.31.1", - "lightningcss-darwin-x64": "1.31.1", - "lightningcss-freebsd-x64": "1.31.1", - "lightningcss-linux-arm-gnueabihf": "1.31.1", - "lightningcss-linux-arm64-gnu": "1.31.1", - "lightningcss-linux-arm64-musl": "1.31.1", - "lightningcss-linux-x64-gnu": "1.31.1", - "lightningcss-linux-x64-musl": "1.31.1", - "lightningcss-win32-arm64-msvc": "1.31.1", - "lightningcss-win32-x64-msvc": "1.31.1" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/lightningcss-android-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", - "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, "engines": { - "node": ">= 12.0.0" + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", - "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", - "cpu": [ - "arm64" - ], + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], + "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", - "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", - "cpu": [ - "x64" - ], + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/pony-cause": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-1.1.1.tgz", + "integrity": "sha512-PxkIc/2ZpLiEzQXu5YRDOUgBlfGYBY8156HY5ZcRAwwonMk5W/MrJP2LLkG/hF7GEQzaHo2aS7ho6ZLCOvf+6g==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" + "license": "0BSD", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "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": ">= 12.0.0" + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "license": "MIT", + "engines": { + "node": ">=20" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", - "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", - "cpu": [ - "x64" - ], + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], + "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-ms": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", + "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prompts/node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "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" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" } }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", - "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", - "cpu": [ - "arm" - ], + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">=6" } }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", - "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "node_modules/qs": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", + "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, "engines": { - "node": ">= 12.0.0" + "node": ">=0.6" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", - "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } ], - "engines": { - "node": ">= 12.0.0" + "license": "MIT" + }, + "node_modules/radix-ui": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.4.3.tgz", + "integrity": "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-accessible-icon": "1.1.7", + "@radix-ui/react-accordion": "1.2.12", + "@radix-ui/react-alert-dialog": "1.1.15", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-aspect-ratio": "1.1.7", + "@radix-ui/react-avatar": "1.1.10", + "@radix-ui/react-checkbox": "1.3.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-context-menu": "2.2.16", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-dropdown-menu": "2.1.16", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-form": "0.1.8", + "@radix-ui/react-hover-card": "1.1.15", + "@radix-ui/react-label": "2.1.7", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-menubar": "1.1.16", + "@radix-ui/react-navigation-menu": "1.2.14", + "@radix-ui/react-one-time-password-field": "0.1.8", + "@radix-ui/react-password-toggle-field": "0.1.3", + "@radix-ui/react-popover": "1.1.15", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-progress": "1.1.7", + "@radix-ui/react-radio-group": "1.3.8", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-scroll-area": "1.2.10", + "@radix-ui/react-select": "2.2.6", + "@radix-ui/react-separator": "1.1.7", + "@radix-ui/react-slider": "1.3.6", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-switch": "1.2.6", + "@radix-ui/react-tabs": "1.1.13", + "@radix-ui/react-toast": "1.2.15", + "@radix-ui/react-toggle": "1.1.10", + "@radix-ui/react-toggle-group": "1.1.11", + "@radix-ui/react-toolbar": "1.1.11", + "@radix-ui/react-tooltip": "1.2.8", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-escape-keydown": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", - "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "engines": { + "node": ">= 0.10" } }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", - "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "peerDependencies": { + "react": "^19.2.4" } }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", - "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-leaflet": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-5.0.0.tgz", + "integrity": "sha512-CWbTpr5vcHw5bt9i4zSlPEVQdTVcML390TjeDG0cK59z1ylexpqC6M1PJFjV8jD7CF+ACBFsLIDs6DRMoLEofw==", + "license": "Hippocratic-2.1", + "dependencies": { + "@react-leaflet/core": "^3.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "peerDependencies": { + "leaflet": "^1.9.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" } }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", - "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" + "node_modules/react-markdown": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", + "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" } }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", "dev": true, "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" }, "engines": { "node": ">=10" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/longest-streak": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", - "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", "dependencies": { - "yallist": "^3.0.2" + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/mdast-util-from-markdown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", - "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "node_modules/react-router": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.0.tgz", + "integrity": "sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==", "license": "MIT", "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } } }, - "node_modules/mdast-util-mdx-expression": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", - "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "node_modules/react-router-dom": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.0.tgz", + "integrity": "sha512-5CO/l5Yahi2SKC6rGZ+HDEjpjkGaG/ncEP7eWFTvFxbHP8yeeI0PxTDjimtpXYlR3b3i9/WIL4VJttPrESIf2g==", "license": "MIT", "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" + "react-router": "7.13.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" } }, - "node_modules/mdast-util-mdx-jsx": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", - "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "node_modules/react-select": { + "version": "5.10.2", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.10.2.tgz", + "integrity": "sha512-Z33nHdEFWq9tfnfVXaiM12rbJmk+QjFEztWLtmXqQhz6Al4UZZ9xc0wiatmGtUOCCnHN0WizL3tCMYRENX4rVQ==", "license": "MIT", "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "ccount": "^2.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-stringify-position": "^4.0.0", - "vfile-message": "^4.0.0" + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.2.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/mdast-util-mdxjs-esm": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", - "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", "license": "MIT", "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/mdast-util-phrasing": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", - "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", - "license": "MIT", + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", "dependencies": { - "@types/mdast": "^4.0.0", - "unist-util-is": "^6.0.0" + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" } }, - "node_modules/mdast-util-to-hast": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", - "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@ungap/structured-clone": "^1.0.0", - "devlop": "^1.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "trim-lines": "^3.0.0", - "unist-util-position": "^5.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" + "engines": { + "node": ">= 14.18.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/mdast-util-to-markdown": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", - "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "node_modules/recast": { + "version": "0.23.11", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", + "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==", "license": "MIT", "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "longest-streak": "^3.0.0", - "mdast-util-phrasing": "^4.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "unist-util-visit": "^5.0.0", - "zwitch": "^2.0.0" + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">= 4" } }, - "node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "node_modules/recast/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==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, "license": "MIT", "dependencies": { - "@types/mdast": "^4.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/micromark": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", - "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "node_modules/reftools": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.9.tgz", + "integrity": "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==", + "dev": true, + "license": "BSD-3-Clause", + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" } }, - "node_modules/micromark-core-commonmark": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", - "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, "license": "MIT", "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/micromark-factory-destination": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", - "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", "license": "MIT", "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-factory-label": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", - "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", "license": "MIT", "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/micromark-factory-title": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", - "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/micromark-factory-whitespace": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", - "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "license": "MIT", "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "engines": { + "node": ">=4" } }, - "node_modules/micromark-util-chunked": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", - "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "license": "MIT", "dependencies": { - "micromark-util-symbol": "^2.0.0" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/micromark-util-classify-character": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", - "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", "license": "MIT", "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/micromark-util-combine-extensions": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", - "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rettime": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/rettime/-/rettime-0.10.1.tgz", + "integrity": "sha512-uyDrIlUEH37cinabq0AX4QbgV4HbFZ/gqoiunWQ1UqBtRvTTytwhNYjE++pO/MjPTZL5KQCf2bEoJ/BJNVQ5Kw==", + "license": "MIT" + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.50.tgz", + "integrity": "sha512-JFULvCNl/anKn99eKjOSEubi0lLmNqQDAjyEMME2T4CwezUDL0i6t1O9xZsu2OMehPnV2caNefWpGF+8TnzB6A==", "license": "MIT", "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" + "@oxc-project/types": "=0.97.0", + "@rolldown/pluginutils": "1.0.0-beta.50" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-beta.50", + "@rolldown/binding-darwin-arm64": "1.0.0-beta.50", + "@rolldown/binding-darwin-x64": "1.0.0-beta.50", + "@rolldown/binding-freebsd-x64": "1.0.0-beta.50", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.50", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.50", + "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.50", + "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.50", + "@rolldown/binding-linux-x64-musl": "1.0.0-beta.50", + "@rolldown/binding-openharmony-arm64": "1.0.0-beta.50", + "@rolldown/binding-wasm32-wasi": "1.0.0-beta.50", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.50", + "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.50", + "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.50" } }, - "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", - "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.50.tgz", + "integrity": "sha512-5e76wQiQVeL1ICOZVUg4LSOVYg9jyhGCin+icYozhsUzM+fHE7kddi1bdiE0jwVqTfkjba3jUFbEkoC9WkdvyA==", + "license": "MIT" + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "license": "MIT", "dependencies": { - "micromark-util-symbol": "^2.0.0" + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" } }, - "node_modules/micromark-util-decode-string": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", - "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/router/node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/micromark-util-encode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", - "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/micromark-util-html-tag-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", - "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "funding": [ { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" + "type": "github", + "url": "https://github.com/sponsors/feross" }, { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", - "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" + "type": "patreon", + "url": "https://www.patreon.com/feross" }, { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" + "type": "consulting", + "url": "https://feross.org/support" } ], "license": "MIT", "dependencies": { - "micromark-util-symbol": "^2.0.0" + "queue-microtask": "^1.2.2" } }, - "node_modules/micromark-util-resolve-all": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", - "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, "license": "MIT", "dependencies": { - "micromark-util-types": "^2.0.0" + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", - "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, "license": "MIT", "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/micromark-util-subtokenize": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", - "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, "license": "MIT", "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/safe-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz", + "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==", + "dev": true, "license": "MIT" }, - "node_modules/micromark-util-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", - "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" }, "engines": { - "node": "*" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" + "node_modules/send/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/send/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" + "dependencies": { + "mime-db": "^1.54.0" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", "license": "MIT" }, - "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, "license": "MIT", "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 0.4" } }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", "dev": true, "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=10" + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shadcn": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/shadcn/-/shadcn-4.1.0.tgz", + "integrity": "sha512-3zETJ+0Ezj69FS6RL0HOkLKKAR5yXisXx1iISJdfLQfrUqj/VIQlanQi1Ukk+9OE+XHZVj4FQNTBSfbr2CyCYg==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/plugin-transform-typescript": "^7.28.0", + "@babel/preset-typescript": "^7.27.1", + "@dotenvx/dotenvx": "^1.48.4", + "@modelcontextprotocol/sdk": "^1.26.0", + "@types/validate-npm-package-name": "^4.0.2", + "browserslist": "^4.26.2", + "commander": "^14.0.0", + "cosmiconfig": "^9.0.0", + "dedent": "^1.6.0", + "deepmerge": "^4.3.1", + "diff": "^8.0.2", + "execa": "^9.6.0", + "fast-glob": "^3.3.3", + "fs-extra": "^11.3.1", + "fuzzysort": "^3.1.0", + "https-proxy-agent": "^7.0.6", + "kleur": "^4.1.5", + "msw": "^2.10.4", + "node-fetch": "^3.3.2", + "open": "^11.0.0", + "ora": "^8.2.0", + "postcss": "^8.5.6", + "postcss-selector-parser": "^7.1.0", + "prompts": "^2.4.2", + "recast": "^0.23.11", + "stringify-object": "^5.0.0", + "tailwind-merge": "^3.0.1", + "ts-morph": "^26.0.0", + "tsconfig-paths": "^4.2.0", + "validate-npm-package-name": "^7.0.1", + "zod": "^3.24.1", + "zod-to-json-schema": "^3.24.6" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "bin": { + "shadcn": "dist/index.js" } }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, + "node_modules/shadcn/node_modules/cosmiconfig": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", "license": "MIT", "dependencies": { - "p-limit": "^3.0.2" + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, + "node_modules/shadcn/node_modules/execa": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", + "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", "license": "MIT", "dependencies": { - "callsites": "^3.0.0" + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.6", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.2.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.1.1" }, "engines": { - "node": ">=6" + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/parse-entities": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", - "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "node_modules/shadcn/node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "character-entities-legacy": "^3.0.0", - "character-reference-invalid": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "is-alphanumerical": "^2.0.0", - "is-decimal": "^2.0.0", - "is-hexadecimal": "^2.0.0" + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse-entities/node_modules/@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", - "license": "MIT" + "node_modules/shadcn/node_modules/human-signals": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, + "node_modules/shadcn/node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, + "node_modules/shadcn/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" } }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, + "node_modules/shadcn/node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/shadcn/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "engines": { + "node": ">=12" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/shadcn/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", "engines": { - "node": "^10 || ^12 || >=14" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, + "node_modules/shadcn/node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", "license": "MIT", "engines": { - "node": ">= 0.8.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/property-information": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", - "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "node_modules/shadcn/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/colinhacks" } }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "node_modules/should": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", + "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", + "dev": true, "license": "MIT", "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.4" + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" } }, - "node_modules/react-leaflet": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-5.0.0.tgz", - "integrity": "sha512-CWbTpr5vcHw5bt9i4zSlPEVQdTVcML390TjeDG0cK59z1ylexpqC6M1PJFjV8jD7CF+ACBFsLIDs6DRMoLEofw==", - "license": "Hippocratic-2.1", + "node_modules/should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", + "dev": true, + "license": "MIT", "dependencies": { - "@react-leaflet/core": "^3.0.0" - }, - "peerDependencies": { - "leaflet": "^1.9.0", - "react": "^19.0.0", - "react-dom": "^19.0.0" + "should-type": "^1.4.0" } }, - "node_modules/react-markdown": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", - "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", + "node_modules/should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==", + "dev": true, "license": "MIT", "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "hast-util-to-jsx-runtime": "^2.0.0", - "html-url-attributes": "^3.0.0", - "mdast-util-to-hast": "^13.0.0", - "remark-parse": "^11.0.0", - "remark-rehype": "^11.0.0", - "unified": "^11.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "@types/react": ">=18", - "react": ">=18" + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" + } + }, + "node_modules/should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/should-type-adaptors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", + "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" } }, - "node_modules/react-refresh": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", - "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "node_modules/should-util": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", + "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", "dev": true, + "license": "MIT" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-router": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.0.tgz", - "integrity": "sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==", + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "license": "MIT", "dependencies": { - "cookie": "^1.0.1", - "set-cookie-parser": "^2.6.0" + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" }, "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-router-dom": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.0.tgz", - "integrity": "sha512-5CO/l5Yahi2SKC6rGZ+HDEjpjkGaG/ncEP7eWFTvFxbHP8yeeI0PxTDjimtpXYlR3b3i9/WIL4VJttPrESIf2g==", + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "license": "MIT", "dependencies": { - "react-router": "7.13.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" }, "engines": { - "node": ">=20.0.0" + "node": ">= 0.4" }, - "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/remark-parse": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", - "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "license": "MIT", "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unified": "^11.0.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/remark-rehype": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", - "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/simple-eval": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-eval/-/simple-eval-1.0.1.tgz", + "integrity": "sha512-LH7FpTAkeD+y5xQC4fzS+tFtaNlvt3Ib1zKzvhjv/Y+cioV4zIuw4IZr2yhRLu67CWL7FR9/6KXKnjRoZTvGGQ==", + "dev": true, "license": "MIT", "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "mdast-util-to-hast": "^13.0.0", - "unified": "^11.0.0", - "vfile": "^6.0.0" + "jsep": "^1.3.6" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=12" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/size-sensor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/size-sensor/-/size-sensor-1.0.3.tgz", + "integrity": "sha512-+k9mJ2/rQMiRmQUcjn+qznch260leIXY8r4FyYKKyRBO/s5UoeMAHGkCJyE1R/4wrIhTJONfyloY55SkE7ve3A==", + "license": "ISC" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/rolldown": { - "version": "1.0.0-beta.50", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.50.tgz", - "integrity": "sha512-JFULvCNl/anKn99eKjOSEubi0lLmNqQDAjyEMME2T4CwezUDL0i6t1O9xZsu2OMehPnV2caNefWpGF+8TnzB6A==", - "dev": true, + "node_modules/sonner": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz", + "integrity": "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==", "license": "MIT", - "dependencies": { - "@oxc-project/types": "=0.97.0", - "@rolldown/pluginutils": "1.0.0-beta.50" - }, - "bin": { - "rolldown": "bin/cli.mjs" - }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-beta.50", - "@rolldown/binding-darwin-arm64": "1.0.0-beta.50", - "@rolldown/binding-darwin-x64": "1.0.0-beta.50", - "@rolldown/binding-freebsd-x64": "1.0.0-beta.50", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.50", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.50", - "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.50", - "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.50", - "@rolldown/binding-linux-x64-musl": "1.0.0-beta.50", - "@rolldown/binding-openharmony-arm64": "1.0.0-beta.50", - "@rolldown/binding-wasm32-wasi": "1.0.0-beta.50", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.50", - "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.50", - "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.50" + "node": ">=0.10.0" } }, - "node_modules/rolldown/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.50", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.50.tgz", - "integrity": "sha512-5e76wQiQVeL1ICOZVUg4LSOVYg9jyhGCin+icYozhsUzM+fHE7kddi1bdiE0jwVqTfkjba3jUFbEkoC9WkdvyA==", - "dev": true, - "license": "MIT" + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/state-local": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", + "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==", "license": "MIT" }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/set-cookie-parser": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", - "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "node_modules/strict-event-emitter": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", + "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", "license": "MIT" }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", "dev": true, "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" } }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/size-sensor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/size-sensor/-/size-sensor-1.0.3.tgz", - "integrity": "sha512-+k9mJ2/rQMiRmQUcjn+qznch260leIXY8r4FyYKKyRBO/s5UoeMAHGkCJyE1R/4wrIhTJONfyloY55SkE7ve3A==", - "license": "ISC" + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/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==", + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/space-separated-tokens": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-5.0.0.tgz", + "integrity": "sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==", + "license": "BSD-2-Clause", + "dependencies": { + "get-own-enumerable-keys": "^1.0.0", + "is-obj": "^3.0.0", + "is-regexp": "^3.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/yeoman/stringify-object?sponsor=1" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "engines": { + "node": ">=4" } }, - "node_modules/stringify-entities": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", - "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "license": "MIT", - "dependencies": { - "character-entities-html4": "^2.0.0", - "character-entities-legacy": "^3.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "engines": { + "node": ">=6" } }, "node_modules/strip-json-comments": { @@ -3932,6 +13231,12 @@ "inline-style-parser": "0.2.7" } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3945,11 +13250,107 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/swagger2openapi": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.8.tgz", + "integrity": "sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "call-me-maybe": "^1.0.1", + "node-fetch": "^2.6.1", + "node-fetch-h2": "^2.3.0", + "node-readfiles": "^0.2.0", + "oas-kit-common": "^1.0.8", + "oas-resolver": "^2.5.6", + "oas-schema-walker": "^1.1.5", + "oas-validator": "^5.0.8", + "reftools": "^1.1.9", + "yaml": "^1.10.0", + "yargs": "^17.0.1" + }, + "bin": { + "boast": "boast.js", + "oas-validate": "oas-validate.js", + "swagger2openapi": "swagger2openapi.js" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/swagger2openapi/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tailwind-merge": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.5.0.tgz", + "integrity": "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz", + "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -3962,6 +13363,64 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tldts": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.27.tgz", + "integrity": "sha512-I4FZcVFcqCRuT0ph6dCDpPuO4Xgzvh+spkcTr1gK7peIvxWauoloVO0vuy1FQnijT63ss6AsHB6+OIM4aXHbPg==", + "license": "MIT", + "dependencies": { + "tldts-core": "^7.0.27" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.27.tgz", + "integrity": "sha512-YQ7uPjgWUibIK6DW5lrKujGwUKhLevU4hcGbP5O6TcIUb+oTjJYJVWPS4nZsIHrEEEG6myk/oqAJUEQmpZrHsg==", + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", + "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -3988,37 +13447,312 @@ "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=18.12" + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-morph": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-26.0.0.tgz", + "integrity": "sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==", + "license": "MIT", + "dependencies": { + "@ts-morph/common": "~0.27.0", + "code-block-writer": "^13.0.3" + } + }, + "node_modules/tsconfck": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-2.1.2.tgz", + "integrity": "sha512-ghqN1b0puy3MhhviwO2kGF8SeMDNhEbnKxjK7h6+fvY9JAxqvXi8y5NAHSQv687OVboS2uZIByzGd45/YxrRHg==", + "dev": true, + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^14.13.1 || ^16 || >=18" + }, + "peerDependencies": { + "typescript": "^4.3.5 || ^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "license": "0BSD" + }, + "node_modules/tw-animate-css": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz", + "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Wombosvideo" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.5.0.tgz", + "integrity": "sha512-PlBfpQwiUvGViBNX84Yxwjsdhd1TUlXr6zjX7eoirtCPIr08NAmxwa+fcYBTeRQxHo9YC9wwF3m9i700sHma8g==", + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedoc": { + "version": "0.28.17", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.17.tgz", + "integrity": "sha512-ZkJ2G7mZrbxrKxinTQMjFqsCoYY6a5Luwv2GKbTnBCEgV2ihYm5CflA9JnJAwH0pZWavqfYxmDkFHPt4yx2oDQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@gerrit0/mini-shiki": "^3.17.0", + "lunr": "^2.3.9", + "markdown-it": "^14.1.0", + "minimatch": "^9.0.5", + "yaml": "^2.8.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 18", + "pnpm": ">= 10" + }, + "peerDependencies": { + "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x" + } + }, + "node_modules/typedoc-plugin-coverage": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/typedoc-plugin-coverage/-/typedoc-plugin-coverage-4.0.2.tgz", + "integrity": "sha512-mfn0e7NCqB8x2PfvhXrtmd7KWlsNf1+B2N9y8gR/jexXBLrXl/0e+b2HdG5HaTXGi7i0t2pyQY2VRmq7gtdEHQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "typedoc": "0.28.x" + } + }, + "node_modules/typedoc-plugin-markdown": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-4.10.0.tgz", + "integrity": "sha512-psrg8Rtnv4HPWCsoxId+MzEN8TVK5jeKCnTbnGAbTBqcDapR9hM41bJT/9eAyKn9C2MDG9Qjh3MkltAYuLDoXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "typedoc": "0.28.x" + } + }, + "node_modules/typedoc/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/typedoc/node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" }, - "peerDependencies": { - "typescript": ">=4.8.4" + "engines": { + "node": "18 || 20 || >=22" } }, - "node_modules/tslib": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", - "license": "0BSD" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/typedoc/node_modules/minimatch": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.6.tgz", + "integrity": "sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "prelude-ls": "^1.2.1" + "brace-expansion": "^5.0.2" }, "engines": { - "node": ">= 0.8.0" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -4052,13 +13786,51 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/undici-types": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true, + "devOptional": true, "license": "MIT" }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/unified": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", @@ -4146,11 +13918,37 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/until-async": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/until-async/-/until-async-3.0.2.tgz", + "integrity": "sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/kettanaito" + } + }, "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, "funding": [ { "type": "opencollective", @@ -4187,6 +13985,123 @@ "punycode": "^2.1.0" } }, + "node_modules/urijs": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz", + "integrity": "sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/validate-npm-package-name": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz", + "integrity": "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==", + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/validator": { + "version": "13.15.26", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz", + "integrity": "sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", @@ -4220,7 +14135,6 @@ "version": "7.2.5", "resolved": "https://registry.npmjs.org/rolldown-vite/-/rolldown-vite-7.2.5.tgz", "integrity": "sha512-u09tdk/huMiN8xwoiBbig197jKdCamQTtOruSalOzbqGje3jdHiV0njQlAW0YvzoahkirFePNQ4RYlfnRQpXZA==", - "dev": true, "license": "MIT", "dependencies": { "@oxc-project/runtime": "0.97.0", @@ -4292,11 +14206,37 @@ } } }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -4308,6 +14248,95 @@ "node": ">= 8" } }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -4318,13 +14347,103 @@ "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/wsl-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", + "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==", + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "devOptional": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -4338,16 +14457,48 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zod": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } }, + "node_modules/zod-to-json-schema": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25 || ^4" + } + }, "node_modules/zod-validation-error": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index ae0e815..158e595 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -7,22 +7,40 @@ "dev": "vite", "build": "tsc -b && vite build", "lint": "eslint .", - "preview": "vite preview" + "preview": "vite preview", + "generate-api": "orval" }, "dependencies": { + "@dnd-kit/react": "^0.3.2", + "@fontsource-variable/geist": "^5.2.8", + "@monaco-editor/react": "^4.7.0", + "@tailwindcss/vite": "^4.2.2", + "@tanstack/react-query": "^5.90.21", + "axios": "^1.13.5", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", "echarts": "^6.0.0", "echarts-for-react": "^3.0.6", "leaflet": "^1.9.4", + "lucide-react": "^0.577.0", + "next-themes": "^0.4.6", + "radix-ui": "^1.4.3", "react": "^19.2.0", "react-dom": "^19.2.0", "react-leaflet": "^5.0.0", "react-markdown": "^10.1.0", - "react-router-dom": "^7.12.0" + "react-router-dom": "^7.12.0", + "react-select": "^5.10.2", + "shadcn": "^4.1.0", + "sonner": "^2.0.7", + "tailwind-merge": "^3.5.0", + "tailwindcss": "^4.2.2", + "tw-animate-css": "^1.4.0" }, "devDependencies": { "@eslint/js": "^9.39.1", "@types/leaflet": "^1.9.14", - "@types/node": "^24.10.1", + "@types/node": "^24.12.0", "@types/react": "^19.2.5", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.1.1", @@ -30,6 +48,7 @@ "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.4.24", "globals": "^16.5.0", + "orval": "^7.21.0", "typescript": "~5.9.3", "typescript-eslint": "^8.46.4", "vite": "npm:rolldown-vite@7.2.5" diff --git a/frontend/public/images/favicon.ico b/frontend/public/images/favicon.ico new file mode 100644 index 0000000..a3e1471 Binary files /dev/null and b/frontend/public/images/favicon.ico differ diff --git a/frontend/public/vite.svg b/frontend/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/frontend/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/App.css b/frontend/src/App.css index de76197..2ef6f71 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -1,3 +1,9 @@ +/* + * Temporary legacy stylesheet. + * This file is being migrated incrementally to Tailwind utility classes. + * Add only critical fixes here; prefer styling in components with Tailwind. + */ + :root { --bg: #ffffff; --card: #ffffff; @@ -170,7 +176,6 @@ button.primary:disabled { } .success { - margin-top: 0.75rem; color: var(--green); } @@ -249,47 +254,6 @@ button.primary:disabled { margin: 0; } -/* Navbar */ -.navbar { - position: fixed; - top: 0; - left: 0; - right: 0; - height: 56px; - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 1.25rem; - background: #ffffff; - border-bottom: 1px solid var(--border); - z-index: 20; -} - -.nav-left, .nav-right { - display: flex; - align-items: center; - gap: 0.75rem; -} - -.nav-brand { - font-weight: 700; - letter-spacing: 0.03em; - color: var(--text); -} - -.nav-link { - color: var(--muted); - text-decoration: none; - padding: 0.35rem 0.65rem; - border-radius: 8px; - transition: background 0.15s ease, color 0.15s ease; -} - -.nav-link:hover { - background: rgba(13,110,253,0.08); - color: var(--text); -} - .pill { color: #ffffff; text-decoration: none; diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx deleted file mode 100644 index a10e558..0000000 --- a/frontend/src/App.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom' -import './App.css' -import { Layout } from './components/Layout' -import { useAuth } from './hooks/useAuth' -import { HomePage } from './pages/HomePage' -import { LoginPage } from './pages/LoginPage' -import { SignupPage } from './pages/SignupPage' -import { SignupSuccessPage } from './pages/SignupSuccessPage' -import { LogbooksPage } from './pages/LogbooksPage' -import { DetectorLogbookPage } from './pages/DetectorLogbookPage' -import { LogbookEntryPage } from './pages/LogbookEntryPage' -import { ProfilePage } from './pages/ProfilePage' -import { CreateOrganizationPage } from './pages/CreateOrganizationPage' -import { OrganizationDetailPage } from './pages/OrganizationDetailPage' -import { InviteAcceptPage } from './pages/InviteAcceptPage'; -import { DetectorCreatePage } from './pages/DetectorCreatePage'; -import { LogsUploadPage } from './pages/LogsUploadPage'; -import { MeasurementsPage } from './pages/MeasurementsPage'; -import { MeasurementDetailPage } from './pages/MeasurementDetailPage'; -import { LogsPage } from './pages/LogsPage'; -import { SpectralRecordStatusPage } from './pages/SpectralRecordStatusPage'; -import { SpectralRecordDetailPage } from './pages/SpectralRecordDetailPage'; -import { AirportDetailPage } from './pages/AirportDetailPage'; -import { UserDetailPage } from './pages/UserDetailPage'; - -function App() { - const { API_BASE, ORIGIN_BASE, isAuthed, login, signup, logout, getAuthHeader } = useAuth() - - return ( - - - - : } - /> - : } - /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - - - ) -} - -export default App diff --git a/frontend/src/api/authentication/authentication.ts b/frontend/src/api/authentication/authentication.ts new file mode 100644 index 0000000..7e50195 --- /dev/null +++ b/frontend/src/api/authentication/authentication.ts @@ -0,0 +1,541 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import { + useMutation, + useQuery +} from '@tanstack/react-query'; +import type { + DataTag, + DefinedInitialDataOptions, + DefinedUseQueryResult, + MutationFunction, + QueryClient, + QueryFunction, + QueryKey, + UndefinedInitialDataOptions, + UseMutationOptions, + UseMutationResult, + UseQueryOptions, + UseQueryResult +} from '@tanstack/react-query'; + +import * as axios from 'axios'; +import type { + AxiosError, + AxiosRequestConfig, + AxiosResponse +} from 'axios'; + +import type { + LoginRequestRequest, + LoginResponse, + OrganizationSummary, + OrganizationUser, + SignupRequestRequest, + SignupResponse, + UserProfile, + UserProfileRequest +} from '.././model'; + + + + + +/** + * Authenticate user and return authentication token + */ +export const loginCreate = ( + loginRequestRequest: LoginRequestRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.post( + `/api/login/`, + loginRequestRequest,options + ); + } + + + +export const getLoginCreateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: LoginRequestRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{data: LoginRequestRequest}, TContext> => { + +const mutationKey = ['loginCreate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {data: LoginRequestRequest}> = (props) => { + const {data} = props ?? {}; + + return loginCreate(data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type LoginCreateMutationResult = NonNullable>> + export type LoginCreateMutationBody = LoginRequestRequest + export type LoginCreateMutationError = AxiosError + + export const useLoginCreate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: LoginRequestRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {data: LoginRequestRequest}, + TContext + > => { + + const mutationOptions = getLoginCreateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * API logout endpoint. Delete the token. + */ +export const logoutCreate = ( + options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.post( + `/api/logout/`,undefined,options + ); + } + + + +export const getLogoutCreateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,void, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,void, TContext> => { + +const mutationKey = ['logoutCreate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, void> = () => { + + + return logoutCreate(axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type LogoutCreateMutationResult = NonNullable>> + + export type LogoutCreateMutationError = AxiosError + + export const useLogoutCreate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,void, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + void, + TContext + > => { + + const mutationOptions = getLogoutCreateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Create a new user account + */ +export const signupCreate = ( + signupRequestRequest: SignupRequestRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.post( + `/api/signup/`, + signupRequestRequest,options + ); + } + + + +export const getSignupCreateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: SignupRequestRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{data: SignupRequestRequest}, TContext> => { + +const mutationKey = ['signupCreate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {data: SignupRequestRequest}> = (props) => { + const {data} = props ?? {}; + + return signupCreate(data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type SignupCreateMutationResult = NonNullable>> + export type SignupCreateMutationBody = SignupRequestRequest + export type SignupCreateMutationError = AxiosError + + export const useSignupCreate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: SignupRequestRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {data: SignupRequestRequest}, + TContext + > => { + + const mutationOptions = getSignupCreateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Get all organizations that the current user is a member of + */ +export const userOrganizationsList = ( + options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/user/organizations/`,options + ); + } + + + + +export const getUserOrganizationsListQueryKey = () => { + return [ + `/api/user/organizations/` + ] as const; + } + + +export const getUserOrganizationsListQueryOptions = >, TError = AxiosError>( options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getUserOrganizationsListQueryKey(); + + + + const queryFn: QueryFunction>> = ({ signal }) => userOrganizationsList({ signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type UserOrganizationsListQueryResult = NonNullable>> +export type UserOrganizationsListQueryError = AxiosError + + +export function useUserOrganizationsList>, TError = AxiosError>( + options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useUserOrganizationsList>, TError = AxiosError>( + options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useUserOrganizationsList>, TError = AxiosError>( + options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useUserOrganizationsList>, TError = AxiosError>( + options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getUserOrganizationsListQueryOptions(options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Get all organizations where the current user is Admin or Owner + */ +export const userOrganizationsOwnedList = ( + options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/user/organizations/owned/`,options + ); + } + + + + +export const getUserOrganizationsOwnedListQueryKey = () => { + return [ + `/api/user/organizations/owned/` + ] as const; + } + + +export const getUserOrganizationsOwnedListQueryOptions = >, TError = AxiosError>( options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getUserOrganizationsOwnedListQueryKey(); + + + + const queryFn: QueryFunction>> = ({ signal }) => userOrganizationsOwnedList({ signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type UserOrganizationsOwnedListQueryResult = NonNullable>> +export type UserOrganizationsOwnedListQueryError = AxiosError + + +export function useUserOrganizationsOwnedList>, TError = AxiosError>( + options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useUserOrganizationsOwnedList>, TError = AxiosError>( + options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useUserOrganizationsOwnedList>, TError = AxiosError>( + options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useUserOrganizationsOwnedList>, TError = AxiosError>( + options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getUserOrganizationsOwnedListQueryOptions(options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Get or update current user profile information + */ +export const userProfileRetrieve = ( + options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/user/profile/`,options + ); + } + + + + +export const getUserProfileRetrieveQueryKey = () => { + return [ + `/api/user/profile/` + ] as const; + } + + +export const getUserProfileRetrieveQueryOptions = >, TError = AxiosError>( options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getUserProfileRetrieveQueryKey(); + + + + const queryFn: QueryFunction>> = ({ signal }) => userProfileRetrieve({ signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type UserProfileRetrieveQueryResult = NonNullable>> +export type UserProfileRetrieveQueryError = AxiosError + + +export function useUserProfileRetrieve>, TError = AxiosError>( + options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useUserProfileRetrieve>, TError = AxiosError>( + options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useUserProfileRetrieve>, TError = AxiosError>( + options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useUserProfileRetrieve>, TError = AxiosError>( + options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getUserProfileRetrieveQueryOptions(options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Get or update current user profile information + */ +export const userProfileUpdate = ( + userProfileRequest: UserProfileRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.put( + `/api/user/profile/`, + userProfileRequest,options + ); + } + + + +export const getUserProfileUpdateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: UserProfileRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{data: UserProfileRequest}, TContext> => { + +const mutationKey = ['userProfileUpdate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {data: UserProfileRequest}> = (props) => { + const {data} = props ?? {}; + + return userProfileUpdate(data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type UserProfileUpdateMutationResult = NonNullable>> + export type UserProfileUpdateMutationBody = UserProfileRequest + export type UserProfileUpdateMutationError = AxiosError + + export const useUserProfileUpdate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: UserProfileRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {data: UserProfileRequest}, + TContext + > => { + + const mutationOptions = getUserProfileUpdateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + \ No newline at end of file diff --git a/frontend/src/api/detectors/detectors.ts b/frontend/src/api/detectors/detectors.ts new file mode 100644 index 0000000..5481e47 --- /dev/null +++ b/frontend/src/api/detectors/detectors.ts @@ -0,0 +1,1889 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import { + useMutation, + useQuery +} from '@tanstack/react-query'; +import type { + DataTag, + DefinedInitialDataOptions, + DefinedUseQueryResult, + MutationFunction, + QueryClient, + QueryFunction, + QueryKey, + UndefinedInitialDataOptions, + UseMutationOptions, + UseMutationResult, + UseQueryOptions, + UseQueryResult +} from '@tanstack/react-query'; + +import * as axios from 'axios'; +import type { + AxiosError, + AxiosRequestConfig, + AxiosResponse +} from 'axios'; + +import type { + Detector, + DetectorLogbook, + DetectorLogbookRequest, + DetectorManufacturer, + DetectorManufacturerRequest, + DetectorManufacturersListParams, + DetectorType, + DetectorTypeRequest, + DetectorTypesListParams, + DetectorWriteRequestRequest, + DetectorsListParams, + DetectorsQrRetrieveParams, + LogbooksListParams, + PaginatedDetectorList, + PaginatedDetectorLogbookList, + PaginatedDetectorManufacturerList, + PaginatedDetectorTypeList, + PatchedDetectorLogbookRequest, + PatchedDetectorManufacturerRequest, + PatchedDetectorTypeRequest, + PatchedDetectorWriteRequestRequest +} from '.././model'; + + + + + +/** + * List all detector manufacturers. + */ +export const detectorManufacturersList = ( + params?: DetectorManufacturersListParams, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/detector-manufacturers/`,{ + ...options, + params: {...params, ...options?.params},} + ); + } + + + + +export const getDetectorManufacturersListQueryKey = (params?: DetectorManufacturersListParams,) => { + return [ + `/api/detector-manufacturers/`, ...(params ? [params]: []) + ] as const; + } + + +export const getDetectorManufacturersListQueryOptions = >, TError = AxiosError>(params?: DetectorManufacturersListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getDetectorManufacturersListQueryKey(params); + + + + const queryFn: QueryFunction>> = ({ signal }) => detectorManufacturersList(params, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type DetectorManufacturersListQueryResult = NonNullable>> +export type DetectorManufacturersListQueryError = AxiosError + + +export function useDetectorManufacturersList>, TError = AxiosError>( + params: undefined | DetectorManufacturersListParams, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useDetectorManufacturersList>, TError = AxiosError>( + params?: DetectorManufacturersListParams, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useDetectorManufacturersList>, TError = AxiosError>( + params?: DetectorManufacturersListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useDetectorManufacturersList>, TError = AxiosError>( + params?: DetectorManufacturersListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getDetectorManufacturersListQueryOptions(params,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Create a detector manufacturer. + */ +export const detectorManufacturersCreate = ( + detectorManufacturerRequest: DetectorManufacturerRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.post( + `/api/detector-manufacturers/`, + detectorManufacturerRequest,options + ); + } + + + +export const getDetectorManufacturersCreateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: DetectorManufacturerRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{data: DetectorManufacturerRequest}, TContext> => { + +const mutationKey = ['detectorManufacturersCreate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {data: DetectorManufacturerRequest}> = (props) => { + const {data} = props ?? {}; + + return detectorManufacturersCreate(data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type DetectorManufacturersCreateMutationResult = NonNullable>> + export type DetectorManufacturersCreateMutationBody = DetectorManufacturerRequest + export type DetectorManufacturersCreateMutationError = AxiosError + + export const useDetectorManufacturersCreate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: DetectorManufacturerRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {data: DetectorManufacturerRequest}, + TContext + > => { + + const mutationOptions = getDetectorManufacturersCreateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Get detector manufacturer by ID. + */ +export const detectorManufacturersRetrieve = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/detector-manufacturers/${id}/`,options + ); + } + + + + +export const getDetectorManufacturersRetrieveQueryKey = (id?: string,) => { + return [ + `/api/detector-manufacturers/${id}/` + ] as const; + } + + +export const getDetectorManufacturersRetrieveQueryOptions = >, TError = AxiosError>(id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getDetectorManufacturersRetrieveQueryKey(id); + + + + const queryFn: QueryFunction>> = ({ signal }) => detectorManufacturersRetrieve(id, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(id), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type DetectorManufacturersRetrieveQueryResult = NonNullable>> +export type DetectorManufacturersRetrieveQueryError = AxiosError + + +export function useDetectorManufacturersRetrieve>, TError = AxiosError>( + id: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useDetectorManufacturersRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useDetectorManufacturersRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useDetectorManufacturersRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getDetectorManufacturersRetrieveQueryOptions(id,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Update a detector manufacturer. + */ +export const detectorManufacturersUpdate = ( + id: string, + detectorManufacturerRequest: DetectorManufacturerRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.put( + `/api/detector-manufacturers/${id}/`, + detectorManufacturerRequest,options + ); + } + + + +export const getDetectorManufacturersUpdateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: DetectorManufacturerRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string;data: DetectorManufacturerRequest}, TContext> => { + +const mutationKey = ['detectorManufacturersUpdate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string;data: DetectorManufacturerRequest}> = (props) => { + const {id,data} = props ?? {}; + + return detectorManufacturersUpdate(id,data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type DetectorManufacturersUpdateMutationResult = NonNullable>> + export type DetectorManufacturersUpdateMutationBody = DetectorManufacturerRequest + export type DetectorManufacturersUpdateMutationError = AxiosError + + export const useDetectorManufacturersUpdate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: DetectorManufacturerRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string;data: DetectorManufacturerRequest}, + TContext + > => { + + const mutationOptions = getDetectorManufacturersUpdateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Partially update a detector manufacturer. + */ +export const detectorManufacturersPartialUpdate = ( + id: string, + patchedDetectorManufacturerRequest: PatchedDetectorManufacturerRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.patch( + `/api/detector-manufacturers/${id}/`, + patchedDetectorManufacturerRequest,options + ); + } + + + +export const getDetectorManufacturersPartialUpdateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: PatchedDetectorManufacturerRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string;data: PatchedDetectorManufacturerRequest}, TContext> => { + +const mutationKey = ['detectorManufacturersPartialUpdate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string;data: PatchedDetectorManufacturerRequest}> = (props) => { + const {id,data} = props ?? {}; + + return detectorManufacturersPartialUpdate(id,data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type DetectorManufacturersPartialUpdateMutationResult = NonNullable>> + export type DetectorManufacturersPartialUpdateMutationBody = PatchedDetectorManufacturerRequest + export type DetectorManufacturersPartialUpdateMutationError = AxiosError + + export const useDetectorManufacturersPartialUpdate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: PatchedDetectorManufacturerRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string;data: PatchedDetectorManufacturerRequest}, + TContext + > => { + + const mutationOptions = getDetectorManufacturersPartialUpdateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Delete a detector manufacturer. + */ +export const detectorManufacturersDestroy = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.delete( + `/api/detector-manufacturers/${id}/`,options + ); + } + + + +export const getDetectorManufacturersDestroyMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string}, TContext> => { + +const mutationKey = ['detectorManufacturersDestroy']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string}> = (props) => { + const {id} = props ?? {}; + + return detectorManufacturersDestroy(id,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type DetectorManufacturersDestroyMutationResult = NonNullable>> + + export type DetectorManufacturersDestroyMutationError = AxiosError + + export const useDetectorManufacturersDestroy = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string}, + TContext + > => { + + const mutationOptions = getDetectorManufacturersDestroyMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * List all detector types. + */ +export const detectorTypesList = ( + params?: DetectorTypesListParams, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/detector-types/`,{ + ...options, + params: {...params, ...options?.params},} + ); + } + + + + +export const getDetectorTypesListQueryKey = (params?: DetectorTypesListParams,) => { + return [ + `/api/detector-types/`, ...(params ? [params]: []) + ] as const; + } + + +export const getDetectorTypesListQueryOptions = >, TError = AxiosError>(params?: DetectorTypesListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getDetectorTypesListQueryKey(params); + + + + const queryFn: QueryFunction>> = ({ signal }) => detectorTypesList(params, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type DetectorTypesListQueryResult = NonNullable>> +export type DetectorTypesListQueryError = AxiosError + + +export function useDetectorTypesList>, TError = AxiosError>( + params: undefined | DetectorTypesListParams, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useDetectorTypesList>, TError = AxiosError>( + params?: DetectorTypesListParams, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useDetectorTypesList>, TError = AxiosError>( + params?: DetectorTypesListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useDetectorTypesList>, TError = AxiosError>( + params?: DetectorTypesListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getDetectorTypesListQueryOptions(params,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Create a detector type. + */ +export const detectorTypesCreate = ( + detectorTypeRequest: DetectorTypeRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.post( + `/api/detector-types/`, + detectorTypeRequest,options + ); + } + + + +export const getDetectorTypesCreateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: DetectorTypeRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{data: DetectorTypeRequest}, TContext> => { + +const mutationKey = ['detectorTypesCreate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {data: DetectorTypeRequest}> = (props) => { + const {data} = props ?? {}; + + return detectorTypesCreate(data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type DetectorTypesCreateMutationResult = NonNullable>> + export type DetectorTypesCreateMutationBody = DetectorTypeRequest + export type DetectorTypesCreateMutationError = AxiosError + + export const useDetectorTypesCreate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: DetectorTypeRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {data: DetectorTypeRequest}, + TContext + > => { + + const mutationOptions = getDetectorTypesCreateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Get detector type by ID. + */ +export const detectorTypesRetrieve = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/detector-types/${id}/`,options + ); + } + + + + +export const getDetectorTypesRetrieveQueryKey = (id?: string,) => { + return [ + `/api/detector-types/${id}/` + ] as const; + } + + +export const getDetectorTypesRetrieveQueryOptions = >, TError = AxiosError>(id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getDetectorTypesRetrieveQueryKey(id); + + + + const queryFn: QueryFunction>> = ({ signal }) => detectorTypesRetrieve(id, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(id), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type DetectorTypesRetrieveQueryResult = NonNullable>> +export type DetectorTypesRetrieveQueryError = AxiosError + + +export function useDetectorTypesRetrieve>, TError = AxiosError>( + id: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useDetectorTypesRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useDetectorTypesRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useDetectorTypesRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getDetectorTypesRetrieveQueryOptions(id,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Update a detector type. + */ +export const detectorTypesUpdate = ( + id: string, + detectorTypeRequest: DetectorTypeRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.put( + `/api/detector-types/${id}/`, + detectorTypeRequest,options + ); + } + + + +export const getDetectorTypesUpdateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: DetectorTypeRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string;data: DetectorTypeRequest}, TContext> => { + +const mutationKey = ['detectorTypesUpdate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string;data: DetectorTypeRequest}> = (props) => { + const {id,data} = props ?? {}; + + return detectorTypesUpdate(id,data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type DetectorTypesUpdateMutationResult = NonNullable>> + export type DetectorTypesUpdateMutationBody = DetectorTypeRequest + export type DetectorTypesUpdateMutationError = AxiosError + + export const useDetectorTypesUpdate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: DetectorTypeRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string;data: DetectorTypeRequest}, + TContext + > => { + + const mutationOptions = getDetectorTypesUpdateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Partially update a detector type. + */ +export const detectorTypesPartialUpdate = ( + id: string, + patchedDetectorTypeRequest: PatchedDetectorTypeRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.patch( + `/api/detector-types/${id}/`, + patchedDetectorTypeRequest,options + ); + } + + + +export const getDetectorTypesPartialUpdateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: PatchedDetectorTypeRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string;data: PatchedDetectorTypeRequest}, TContext> => { + +const mutationKey = ['detectorTypesPartialUpdate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string;data: PatchedDetectorTypeRequest}> = (props) => { + const {id,data} = props ?? {}; + + return detectorTypesPartialUpdate(id,data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type DetectorTypesPartialUpdateMutationResult = NonNullable>> + export type DetectorTypesPartialUpdateMutationBody = PatchedDetectorTypeRequest + export type DetectorTypesPartialUpdateMutationError = AxiosError + + export const useDetectorTypesPartialUpdate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: PatchedDetectorTypeRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string;data: PatchedDetectorTypeRequest}, + TContext + > => { + + const mutationOptions = getDetectorTypesPartialUpdateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Delete a detector type. + */ +export const detectorTypesDestroy = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.delete( + `/api/detector-types/${id}/`,options + ); + } + + + +export const getDetectorTypesDestroyMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string}, TContext> => { + +const mutationKey = ['detectorTypesDestroy']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string}> = (props) => { + const {id} = props ?? {}; + + return detectorTypesDestroy(id,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type DetectorTypesDestroyMutationResult = NonNullable>> + + export type DetectorTypesDestroyMutationError = AxiosError + + export const useDetectorTypesDestroy = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string}, + TContext + > => { + + const mutationOptions = getDetectorTypesDestroyMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * List detectors accessible to the current user (filtered by org membership). + */ +export const detectorsList = ( + params?: DetectorsListParams, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/detectors/`,{ + ...options, + params: {...params, ...options?.params},} + ); + } + + + + +export const getDetectorsListQueryKey = (params?: DetectorsListParams,) => { + return [ + `/api/detectors/`, ...(params ? [params]: []) + ] as const; + } + + +export const getDetectorsListQueryOptions = >, TError = AxiosError>(params?: DetectorsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getDetectorsListQueryKey(params); + + + + const queryFn: QueryFunction>> = ({ signal }) => detectorsList(params, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type DetectorsListQueryResult = NonNullable>> +export type DetectorsListQueryError = AxiosError + + +export function useDetectorsList>, TError = AxiosError>( + params: undefined | DetectorsListParams, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useDetectorsList>, TError = AxiosError>( + params?: DetectorsListParams, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useDetectorsList>, TError = AxiosError>( + params?: DetectorsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useDetectorsList>, TError = AxiosError>( + params?: DetectorsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getDetectorsListQueryOptions(params,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Create a detector. The owner org must be one where the user is admin/owner. + */ +export const detectorsCreate = ( + detectorWriteRequestRequest: DetectorWriteRequestRequest, options?: AxiosRequestConfig + ): Promise> => { + + const formData = new FormData(); +formData.append(`owner_id`, detectorWriteRequestRequest.owner_id) +formData.append(`type_id`, detectorWriteRequestRequest.type_id) +if(detectorWriteRequestRequest.image !== undefined && detectorWriteRequestRequest.image !== null) { + formData.append(`image`, detectorWriteRequestRequest.image) + } +if(detectorWriteRequestRequest.is_deleted !== undefined) { + formData.append(`is_deleted`, detectorWriteRequestRequest.is_deleted.toString()) + } +if(detectorWriteRequestRequest.deleted_at !== undefined && detectorWriteRequestRequest.deleted_at !== null) { + formData.append(`deleted_at`, detectorWriteRequestRequest.deleted_at) + } +formData.append(`sn`, detectorWriteRequestRequest.sn) +formData.append(`name`, detectorWriteRequestRequest.name) +if(detectorWriteRequestRequest.manufactured_date !== undefined && detectorWriteRequestRequest.manufactured_date !== null) { + formData.append(`manufactured_date`, detectorWriteRequestRequest.manufactured_date) + } +if(detectorWriteRequestRequest.data !== undefined) { + formData.append(`data`, detectorWriteRequestRequest.data) + } +if(detectorWriteRequestRequest.deleted_by !== undefined && detectorWriteRequestRequest.deleted_by !== null) { + formData.append(`deleted_by`, detectorWriteRequestRequest.deleted_by.toString()) + } +if(detectorWriteRequestRequest.calib !== undefined) { + detectorWriteRequestRequest.calib.forEach(value => formData.append(`calib`, value)); + } +if(detectorWriteRequestRequest.access !== undefined) { + detectorWriteRequestRequest.access.forEach(value => formData.append(`access`, value)); + } + + return axios.default.post( + `/api/detectors/`, + formData,options + ); + } + + + +export const getDetectorsCreateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: DetectorWriteRequestRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{data: DetectorWriteRequestRequest}, TContext> => { + +const mutationKey = ['detectorsCreate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {data: DetectorWriteRequestRequest}> = (props) => { + const {data} = props ?? {}; + + return detectorsCreate(data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type DetectorsCreateMutationResult = NonNullable>> + export type DetectorsCreateMutationBody = DetectorWriteRequestRequest + export type DetectorsCreateMutationError = AxiosError + + export const useDetectorsCreate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: DetectorWriteRequestRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {data: DetectorWriteRequestRequest}, + TContext + > => { + + const mutationOptions = getDetectorsCreateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Generate QR code for a specific detector + */ +export const detectorsQrRetrieve = ( + detectorId: string, + params?: DetectorsQrRetrieveParams, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/detectors/${detectorId}/qr/`,{ + ...options, + params: {...params, ...options?.params},} + ); + } + + + + +export const getDetectorsQrRetrieveQueryKey = (detectorId?: string, + params?: DetectorsQrRetrieveParams,) => { + return [ + `/api/detectors/${detectorId}/qr/`, ...(params ? [params]: []) + ] as const; + } + + +export const getDetectorsQrRetrieveQueryOptions = >, TError = AxiosError>(detectorId: string, + params?: DetectorsQrRetrieveParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getDetectorsQrRetrieveQueryKey(detectorId,params); + + + + const queryFn: QueryFunction>> = ({ signal }) => detectorsQrRetrieve(detectorId,params, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(detectorId), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type DetectorsQrRetrieveQueryResult = NonNullable>> +export type DetectorsQrRetrieveQueryError = AxiosError + + +export function useDetectorsQrRetrieve>, TError = AxiosError>( + detectorId: string, + params: undefined | DetectorsQrRetrieveParams, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useDetectorsQrRetrieve>, TError = AxiosError>( + detectorId: string, + params?: DetectorsQrRetrieveParams, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useDetectorsQrRetrieve>, TError = AxiosError>( + detectorId: string, + params?: DetectorsQrRetrieveParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useDetectorsQrRetrieve>, TError = AxiosError>( + detectorId: string, + params?: DetectorsQrRetrieveParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getDetectorsQrRetrieveQueryOptions(detectorId,params,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Get detector detail by ID. + */ +export const detectorsRetrieve = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/detectors/${id}/`,options + ); + } + + + + +export const getDetectorsRetrieveQueryKey = (id?: string,) => { + return [ + `/api/detectors/${id}/` + ] as const; + } + + +export const getDetectorsRetrieveQueryOptions = >, TError = AxiosError>(id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getDetectorsRetrieveQueryKey(id); + + + + const queryFn: QueryFunction>> = ({ signal }) => detectorsRetrieve(id, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(id), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type DetectorsRetrieveQueryResult = NonNullable>> +export type DetectorsRetrieveQueryError = AxiosError + + +export function useDetectorsRetrieve>, TError = AxiosError>( + id: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useDetectorsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useDetectorsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useDetectorsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getDetectorsRetrieveQueryOptions(id,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Update a detector (org admin/owner only). + */ +export const detectorsUpdate = ( + id: string, + detectorWriteRequestRequest: DetectorWriteRequestRequest, options?: AxiosRequestConfig + ): Promise> => { + + const formData = new FormData(); +formData.append(`owner_id`, detectorWriteRequestRequest.owner_id) +formData.append(`type_id`, detectorWriteRequestRequest.type_id) +if(detectorWriteRequestRequest.image !== undefined && detectorWriteRequestRequest.image !== null) { + formData.append(`image`, detectorWriteRequestRequest.image) + } +if(detectorWriteRequestRequest.is_deleted !== undefined) { + formData.append(`is_deleted`, detectorWriteRequestRequest.is_deleted.toString()) + } +if(detectorWriteRequestRequest.deleted_at !== undefined && detectorWriteRequestRequest.deleted_at !== null) { + formData.append(`deleted_at`, detectorWriteRequestRequest.deleted_at) + } +formData.append(`sn`, detectorWriteRequestRequest.sn) +formData.append(`name`, detectorWriteRequestRequest.name) +if(detectorWriteRequestRequest.manufactured_date !== undefined && detectorWriteRequestRequest.manufactured_date !== null) { + formData.append(`manufactured_date`, detectorWriteRequestRequest.manufactured_date) + } +if(detectorWriteRequestRequest.data !== undefined) { + formData.append(`data`, detectorWriteRequestRequest.data) + } +if(detectorWriteRequestRequest.deleted_by !== undefined && detectorWriteRequestRequest.deleted_by !== null) { + formData.append(`deleted_by`, detectorWriteRequestRequest.deleted_by.toString()) + } +if(detectorWriteRequestRequest.calib !== undefined) { + detectorWriteRequestRequest.calib.forEach(value => formData.append(`calib`, value)); + } +if(detectorWriteRequestRequest.access !== undefined) { + detectorWriteRequestRequest.access.forEach(value => formData.append(`access`, value)); + } + + return axios.default.put( + `/api/detectors/${id}/`, + formData,options + ); + } + + + +export const getDetectorsUpdateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: DetectorWriteRequestRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string;data: DetectorWriteRequestRequest}, TContext> => { + +const mutationKey = ['detectorsUpdate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string;data: DetectorWriteRequestRequest}> = (props) => { + const {id,data} = props ?? {}; + + return detectorsUpdate(id,data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type DetectorsUpdateMutationResult = NonNullable>> + export type DetectorsUpdateMutationBody = DetectorWriteRequestRequest + export type DetectorsUpdateMutationError = AxiosError + + export const useDetectorsUpdate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: DetectorWriteRequestRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string;data: DetectorWriteRequestRequest}, + TContext + > => { + + const mutationOptions = getDetectorsUpdateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Partially update a detector (org admin/owner only). + */ +export const detectorsPartialUpdate = ( + id: string, + patchedDetectorWriteRequestRequest: PatchedDetectorWriteRequestRequest, options?: AxiosRequestConfig + ): Promise> => { + + const formData = new FormData(); +if(patchedDetectorWriteRequestRequest.owner_id !== undefined) { + formData.append(`owner_id`, patchedDetectorWriteRequestRequest.owner_id) + } +if(patchedDetectorWriteRequestRequest.type_id !== undefined) { + formData.append(`type_id`, patchedDetectorWriteRequestRequest.type_id) + } +if(patchedDetectorWriteRequestRequest.image !== undefined && patchedDetectorWriteRequestRequest.image !== null) { + formData.append(`image`, patchedDetectorWriteRequestRequest.image) + } +if(patchedDetectorWriteRequestRequest.is_deleted !== undefined) { + formData.append(`is_deleted`, patchedDetectorWriteRequestRequest.is_deleted.toString()) + } +if(patchedDetectorWriteRequestRequest.deleted_at !== undefined && patchedDetectorWriteRequestRequest.deleted_at !== null) { + formData.append(`deleted_at`, patchedDetectorWriteRequestRequest.deleted_at) + } +if(patchedDetectorWriteRequestRequest.sn !== undefined) { + formData.append(`sn`, patchedDetectorWriteRequestRequest.sn) + } +if(patchedDetectorWriteRequestRequest.name !== undefined) { + formData.append(`name`, patchedDetectorWriteRequestRequest.name) + } +if(patchedDetectorWriteRequestRequest.manufactured_date !== undefined && patchedDetectorWriteRequestRequest.manufactured_date !== null) { + formData.append(`manufactured_date`, patchedDetectorWriteRequestRequest.manufactured_date) + } +if(patchedDetectorWriteRequestRequest.data !== undefined) { + formData.append(`data`, patchedDetectorWriteRequestRequest.data) + } +if(patchedDetectorWriteRequestRequest.deleted_by !== undefined && patchedDetectorWriteRequestRequest.deleted_by !== null) { + formData.append(`deleted_by`, patchedDetectorWriteRequestRequest.deleted_by.toString()) + } +if(patchedDetectorWriteRequestRequest.calib !== undefined) { + patchedDetectorWriteRequestRequest.calib.forEach(value => formData.append(`calib`, value)); + } +if(patchedDetectorWriteRequestRequest.access !== undefined) { + patchedDetectorWriteRequestRequest.access.forEach(value => formData.append(`access`, value)); + } + + return axios.default.patch( + `/api/detectors/${id}/`, + formData,options + ); + } + + + +export const getDetectorsPartialUpdateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: PatchedDetectorWriteRequestRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string;data: PatchedDetectorWriteRequestRequest}, TContext> => { + +const mutationKey = ['detectorsPartialUpdate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string;data: PatchedDetectorWriteRequestRequest}> = (props) => { + const {id,data} = props ?? {}; + + return detectorsPartialUpdate(id,data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type DetectorsPartialUpdateMutationResult = NonNullable>> + export type DetectorsPartialUpdateMutationBody = PatchedDetectorWriteRequestRequest + export type DetectorsPartialUpdateMutationError = AxiosError + + export const useDetectorsPartialUpdate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: PatchedDetectorWriteRequestRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string;data: PatchedDetectorWriteRequestRequest}, + TContext + > => { + + const mutationOptions = getDetectorsPartialUpdateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Soft-delete a detector (org admin/owner only). + */ +export const detectorsDestroy = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.delete( + `/api/detectors/${id}/`,options + ); + } + + + +export const getDetectorsDestroyMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string}, TContext> => { + +const mutationKey = ['detectorsDestroy']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string}> = (props) => { + const {id} = props ?? {}; + + return detectorsDestroy(id,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type DetectorsDestroyMutationResult = NonNullable>> + + export type DetectorsDestroyMutationError = AxiosError + + export const useDetectorsDestroy = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string}, + TContext + > => { + + const mutationOptions = getDetectorsDestroyMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * List detector logbook entries with optional filters. + */ +export const logbooksList = ( + params?: LogbooksListParams, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/logbooks/`,{ + ...options, + params: {...params, ...options?.params},} + ); + } + + + + +export const getLogbooksListQueryKey = (params?: LogbooksListParams,) => { + return [ + `/api/logbooks/`, ...(params ? [params]: []) + ] as const; + } + + +export const getLogbooksListQueryOptions = >, TError = AxiosError>(params?: LogbooksListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getLogbooksListQueryKey(params); + + + + const queryFn: QueryFunction>> = ({ signal }) => logbooksList(params, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type LogbooksListQueryResult = NonNullable>> +export type LogbooksListQueryError = AxiosError + + +export function useLogbooksList>, TError = AxiosError>( + params: undefined | LogbooksListParams, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useLogbooksList>, TError = AxiosError>( + params?: LogbooksListParams, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useLogbooksList>, TError = AxiosError>( + params?: LogbooksListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useLogbooksList>, TError = AxiosError>( + params?: LogbooksListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getLogbooksListQueryOptions(params,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Create a logbook entry. + */ +export const logbooksCreate = ( + detectorLogbookRequest: DetectorLogbookRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.post( + `/api/logbooks/`, + detectorLogbookRequest,options + ); + } + + + +export const getLogbooksCreateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: DetectorLogbookRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{data: DetectorLogbookRequest}, TContext> => { + +const mutationKey = ['logbooksCreate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {data: DetectorLogbookRequest}> = (props) => { + const {data} = props ?? {}; + + return logbooksCreate(data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type LogbooksCreateMutationResult = NonNullable>> + export type LogbooksCreateMutationBody = DetectorLogbookRequest + export type LogbooksCreateMutationError = AxiosError + + export const useLogbooksCreate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: DetectorLogbookRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {data: DetectorLogbookRequest}, + TContext + > => { + + const mutationOptions = getLogbooksCreateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Get a logbook entry by ID. + */ +export const logbooksRetrieve = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/logbooks/${id}/`,options + ); + } + + + + +export const getLogbooksRetrieveQueryKey = (id?: string,) => { + return [ + `/api/logbooks/${id}/` + ] as const; + } + + +export const getLogbooksRetrieveQueryOptions = >, TError = AxiosError>(id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getLogbooksRetrieveQueryKey(id); + + + + const queryFn: QueryFunction>> = ({ signal }) => logbooksRetrieve(id, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(id), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type LogbooksRetrieveQueryResult = NonNullable>> +export type LogbooksRetrieveQueryError = AxiosError + + +export function useLogbooksRetrieve>, TError = AxiosError>( + id: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useLogbooksRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useLogbooksRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useLogbooksRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getLogbooksRetrieveQueryOptions(id,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Update a logbook entry. + */ +export const logbooksUpdate = ( + id: string, + detectorLogbookRequest: DetectorLogbookRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.put( + `/api/logbooks/${id}/`, + detectorLogbookRequest,options + ); + } + + + +export const getLogbooksUpdateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: DetectorLogbookRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string;data: DetectorLogbookRequest}, TContext> => { + +const mutationKey = ['logbooksUpdate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string;data: DetectorLogbookRequest}> = (props) => { + const {id,data} = props ?? {}; + + return logbooksUpdate(id,data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type LogbooksUpdateMutationResult = NonNullable>> + export type LogbooksUpdateMutationBody = DetectorLogbookRequest + export type LogbooksUpdateMutationError = AxiosError + + export const useLogbooksUpdate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: DetectorLogbookRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string;data: DetectorLogbookRequest}, + TContext + > => { + + const mutationOptions = getLogbooksUpdateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Partially update a logbook entry. + */ +export const logbooksPartialUpdate = ( + id: string, + patchedDetectorLogbookRequest: PatchedDetectorLogbookRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.patch( + `/api/logbooks/${id}/`, + patchedDetectorLogbookRequest,options + ); + } + + + +export const getLogbooksPartialUpdateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: PatchedDetectorLogbookRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string;data: PatchedDetectorLogbookRequest}, TContext> => { + +const mutationKey = ['logbooksPartialUpdate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string;data: PatchedDetectorLogbookRequest}> = (props) => { + const {id,data} = props ?? {}; + + return logbooksPartialUpdate(id,data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type LogbooksPartialUpdateMutationResult = NonNullable>> + export type LogbooksPartialUpdateMutationBody = PatchedDetectorLogbookRequest + export type LogbooksPartialUpdateMutationError = AxiosError + + export const useLogbooksPartialUpdate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: PatchedDetectorLogbookRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string;data: PatchedDetectorLogbookRequest}, + TContext + > => { + + const mutationOptions = getLogbooksPartialUpdateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Soft-delete a logbook entry. + */ +export const logbooksDestroy = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.delete( + `/api/logbooks/${id}/`,options + ); + } + + + +export const getLogbooksDestroyMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string}, TContext> => { + +const mutationKey = ['logbooksDestroy']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string}> = (props) => { + const {id} = props ?? {}; + + return logbooksDestroy(id,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type LogbooksDestroyMutationResult = NonNullable>> + + export type LogbooksDestroyMutationError = AxiosError + + export const useLogbooksDestroy = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string}, + TContext + > => { + + const mutationOptions = getLogbooksDestroyMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + \ No newline at end of file diff --git a/frontend/src/api/files/files.ts b/frontend/src/api/files/files.ts new file mode 100644 index 0000000..7c58cbe --- /dev/null +++ b/frontend/src/api/files/files.ts @@ -0,0 +1,336 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import { + useMutation, + useQuery +} from '@tanstack/react-query'; +import type { + DataTag, + DefinedInitialDataOptions, + DefinedUseQueryResult, + MutationFunction, + QueryClient, + QueryFunction, + QueryKey, + UndefinedInitialDataOptions, + UseMutationOptions, + UseMutationResult, + UseQueryOptions, + UseQueryResult +} from '@tanstack/react-query'; + +import * as axios from 'axios'; +import type { + AxiosError, + AxiosRequestConfig, + AxiosResponse +} from 'axios'; + +import type { + File, + FileUploadRequest, + FilesListParams, + PaginatedFileList +} from '.././model'; + + + + + +/** + * List files accessible to the current user. + */ +export const filesList = ( + params?: FilesListParams, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/files/`,{ + ...options, + params: {...params, ...options?.params},} + ); + } + + + + +export const getFilesListQueryKey = (params?: FilesListParams,) => { + return [ + `/api/files/`, ...(params ? [params]: []) + ] as const; + } + + +export const getFilesListQueryOptions = >, TError = AxiosError>(params?: FilesListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getFilesListQueryKey(params); + + + + const queryFn: QueryFunction>> = ({ signal }) => filesList(params, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type FilesListQueryResult = NonNullable>> +export type FilesListQueryError = AxiosError + + +export function useFilesList>, TError = AxiosError>( + params: undefined | FilesListParams, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useFilesList>, TError = AxiosError>( + params?: FilesListParams, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useFilesList>, TError = AxiosError>( + params?: FilesListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useFilesList>, TError = AxiosError>( + params?: FilesListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getFilesListQueryOptions(params,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Upload a file. Supply owner (org UUID) to assign to an organization (user must be admin/owner). + */ +export const filesCreate = ( + fileUploadRequest: FileUploadRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.post( + `/api/files/`, + fileUploadRequest,options + ); + } + + + +export const getFilesCreateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: FileUploadRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{data: FileUploadRequest}, TContext> => { + +const mutationKey = ['filesCreate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {data: FileUploadRequest}> = (props) => { + const {data} = props ?? {}; + + return filesCreate(data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type FilesCreateMutationResult = NonNullable>> + export type FilesCreateMutationBody = FileUploadRequest + export type FilesCreateMutationError = AxiosError + + export const useFilesCreate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: FileUploadRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {data: FileUploadRequest}, + TContext + > => { + + const mutationOptions = getFilesCreateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Get file detail by ID. + */ +export const filesRetrieve = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/files/${id}/`,options + ); + } + + + + +export const getFilesRetrieveQueryKey = (id?: string,) => { + return [ + `/api/files/${id}/` + ] as const; + } + + +export const getFilesRetrieveQueryOptions = >, TError = AxiosError>(id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getFilesRetrieveQueryKey(id); + + + + const queryFn: QueryFunction>> = ({ signal }) => filesRetrieve(id, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(id), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type FilesRetrieveQueryResult = NonNullable>> +export type FilesRetrieveQueryError = AxiosError + + +export function useFilesRetrieve>, TError = AxiosError>( + id: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useFilesRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useFilesRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useFilesRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getFilesRetrieveQueryOptions(id,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Soft-delete a file (org admin/owner only). + */ +export const filesDestroy = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.delete( + `/api/files/${id}/`,options + ); + } + + + +export const getFilesDestroyMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string}, TContext> => { + +const mutationKey = ['filesDestroy']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string}> = (props) => { + const {id} = props ?? {}; + + return filesDestroy(id,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type FilesDestroyMutationResult = NonNullable>> + + export type FilesDestroyMutationError = AxiosError + + export const useFilesDestroy = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string}, + TContext + > => { + + const mutationOptions = getFilesDestroyMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + \ No newline at end of file diff --git a/frontend/src/api/flights/flights.ts b/frontend/src/api/flights/flights.ts new file mode 100644 index 0000000..960094e --- /dev/null +++ b/frontend/src/api/flights/flights.ts @@ -0,0 +1,394 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import { + useQuery +} from '@tanstack/react-query'; +import type { + DataTag, + DefinedInitialDataOptions, + DefinedUseQueryResult, + QueryClient, + QueryFunction, + QueryKey, + UndefinedInitialDataOptions, + UseQueryOptions, + UseQueryResult +} from '@tanstack/react-query'; + +import * as axios from 'axios'; +import type { + AxiosError, + AxiosRequestConfig, + AxiosResponse +} from 'axios'; + +import type { + Airport, + AirportsListParams, + Flight, + FlightsListParams, + PaginatedAirportList, + PaginatedFlightList +} from '.././model'; + + + + + +/** + * List airports. + */ +export const airportsList = ( + params?: AirportsListParams, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/airports/`,{ + ...options, + params: {...params, ...options?.params},} + ); + } + + + + +export const getAirportsListQueryKey = (params?: AirportsListParams,) => { + return [ + `/api/airports/`, ...(params ? [params]: []) + ] as const; + } + + +export const getAirportsListQueryOptions = >, TError = AxiosError>(params?: AirportsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getAirportsListQueryKey(params); + + + + const queryFn: QueryFunction>> = ({ signal }) => airportsList(params, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type AirportsListQueryResult = NonNullable>> +export type AirportsListQueryError = AxiosError + + +export function useAirportsList>, TError = AxiosError>( + params: undefined | AirportsListParams, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useAirportsList>, TError = AxiosError>( + params?: AirportsListParams, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useAirportsList>, TError = AxiosError>( + params?: AirportsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useAirportsList>, TError = AxiosError>( + params?: AirportsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getAirportsListQueryOptions(params,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Get airport detail. + */ +export const airportsRetrieve = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/airports/${id}/`,options + ); + } + + + + +export const getAirportsRetrieveQueryKey = (id?: string,) => { + return [ + `/api/airports/${id}/` + ] as const; + } + + +export const getAirportsRetrieveQueryOptions = >, TError = AxiosError>(id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getAirportsRetrieveQueryKey(id); + + + + const queryFn: QueryFunction>> = ({ signal }) => airportsRetrieve(id, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(id), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type AirportsRetrieveQueryResult = NonNullable>> +export type AirportsRetrieveQueryError = AxiosError + + +export function useAirportsRetrieve>, TError = AxiosError>( + id: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useAirportsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useAirportsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useAirportsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getAirportsRetrieveQueryOptions(id,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * List flights. + */ +export const flightsList = ( + params?: FlightsListParams, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/flights/`,{ + ...options, + params: {...params, ...options?.params},} + ); + } + + + + +export const getFlightsListQueryKey = (params?: FlightsListParams,) => { + return [ + `/api/flights/`, ...(params ? [params]: []) + ] as const; + } + + +export const getFlightsListQueryOptions = >, TError = AxiosError>(params?: FlightsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getFlightsListQueryKey(params); + + + + const queryFn: QueryFunction>> = ({ signal }) => flightsList(params, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type FlightsListQueryResult = NonNullable>> +export type FlightsListQueryError = AxiosError + + +export function useFlightsList>, TError = AxiosError>( + params: undefined | FlightsListParams, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useFlightsList>, TError = AxiosError>( + params?: FlightsListParams, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useFlightsList>, TError = AxiosError>( + params?: FlightsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useFlightsList>, TError = AxiosError>( + params?: FlightsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getFlightsListQueryOptions(params,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Get flight detail. + */ +export const flightsRetrieve = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/flights/${id}/`,options + ); + } + + + + +export const getFlightsRetrieveQueryKey = (id?: string,) => { + return [ + `/api/flights/${id}/` + ] as const; + } + + +export const getFlightsRetrieveQueryOptions = >, TError = AxiosError>(id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getFlightsRetrieveQueryKey(id); + + + + const queryFn: QueryFunction>> = ({ signal }) => flightsRetrieve(id, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(id), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type FlightsRetrieveQueryResult = NonNullable>> +export type FlightsRetrieveQueryError = AxiosError + + +export function useFlightsRetrieve>, TError = AxiosError>( + id: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useFlightsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useFlightsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useFlightsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getFlightsRetrieveQueryOptions(id,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + diff --git a/frontend/src/api/measurements/measurements.ts b/frontend/src/api/measurements/measurements.ts new file mode 100644 index 0000000..dea17f9 --- /dev/null +++ b/frontend/src/api/measurements/measurements.ts @@ -0,0 +1,925 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import { + useMutation, + useQuery +} from '@tanstack/react-query'; +import type { + DataTag, + DefinedInitialDataOptions, + DefinedUseQueryResult, + MutationFunction, + QueryClient, + QueryFunction, + QueryKey, + UndefinedInitialDataOptions, + UseMutationOptions, + UseMutationResult, + UseQueryOptions, + UseQueryResult +} from '@tanstack/react-query'; + +import * as axios from 'axios'; +import type { + AxiosError, + AxiosRequestConfig, + AxiosResponse +} from 'axios'; + +import type { + MeasurementCreate, + MeasurementCreateRequest, + MeasurementSegment, + MeasurementSegmentRequest, + MeasurementSegmentsListParams, + Measurements, + MeasurementsListParams, + MeasurementsRequest, + PaginatedMeasurementSegmentList, + PaginatedMeasurementsList, + PatchedMeasurementSegmentRequest +} from '.././model'; + + + + + +/** + * List measurement segments accessible to the current user. Filter by ?measurement=. + */ +export const measurementSegmentsList = ( + params?: MeasurementSegmentsListParams, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/measurement-segments/`,{ + ...options, + params: {...params, ...options?.params},} + ); + } + + + + +export const getMeasurementSegmentsListQueryKey = (params?: MeasurementSegmentsListParams,) => { + return [ + `/api/measurement-segments/`, ...(params ? [params]: []) + ] as const; + } + + +export const getMeasurementSegmentsListQueryOptions = >, TError = AxiosError>(params?: MeasurementSegmentsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getMeasurementSegmentsListQueryKey(params); + + + + const queryFn: QueryFunction>> = ({ signal }) => measurementSegmentsList(params, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type MeasurementSegmentsListQueryResult = NonNullable>> +export type MeasurementSegmentsListQueryError = AxiosError + + +export function useMeasurementSegmentsList>, TError = AxiosError>( + params: undefined | MeasurementSegmentsListParams, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useMeasurementSegmentsList>, TError = AxiosError>( + params?: MeasurementSegmentsListParams, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useMeasurementSegmentsList>, TError = AxiosError>( + params?: MeasurementSegmentsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useMeasurementSegmentsList>, TError = AxiosError>( + params?: MeasurementSegmentsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getMeasurementSegmentsListQueryOptions(params,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Create a measurement segment. User must be a member of the measurement's organization. + */ +export const measurementSegmentsCreate = ( + measurementSegmentRequest: MeasurementSegmentRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.post( + `/api/measurement-segments/`, + measurementSegmentRequest,options + ); + } + + + +export const getMeasurementSegmentsCreateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: MeasurementSegmentRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{data: MeasurementSegmentRequest}, TContext> => { + +const mutationKey = ['measurementSegmentsCreate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {data: MeasurementSegmentRequest}> = (props) => { + const {data} = props ?? {}; + + return measurementSegmentsCreate(data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type MeasurementSegmentsCreateMutationResult = NonNullable>> + export type MeasurementSegmentsCreateMutationBody = MeasurementSegmentRequest + export type MeasurementSegmentsCreateMutationError = AxiosError + + export const useMeasurementSegmentsCreate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: MeasurementSegmentRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {data: MeasurementSegmentRequest}, + TContext + > => { + + const mutationOptions = getMeasurementSegmentsCreateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Get measurement segment detail. + */ +export const measurementSegmentsRetrieve = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/measurement-segments/${id}/`,options + ); + } + + + + +export const getMeasurementSegmentsRetrieveQueryKey = (id?: string,) => { + return [ + `/api/measurement-segments/${id}/` + ] as const; + } + + +export const getMeasurementSegmentsRetrieveQueryOptions = >, TError = AxiosError>(id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getMeasurementSegmentsRetrieveQueryKey(id); + + + + const queryFn: QueryFunction>> = ({ signal }) => measurementSegmentsRetrieve(id, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(id), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type MeasurementSegmentsRetrieveQueryResult = NonNullable>> +export type MeasurementSegmentsRetrieveQueryError = AxiosError + + +export function useMeasurementSegmentsRetrieve>, TError = AxiosError>( + id: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useMeasurementSegmentsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useMeasurementSegmentsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useMeasurementSegmentsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getMeasurementSegmentsRetrieveQueryOptions(id,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Partially update a segment (e.g. time_from, time_to, position). + */ +export const measurementSegmentsPartialUpdate = ( + id: string, + patchedMeasurementSegmentRequest: PatchedMeasurementSegmentRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.patch( + `/api/measurement-segments/${id}/`, + patchedMeasurementSegmentRequest,options + ); + } + + + +export const getMeasurementSegmentsPartialUpdateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: PatchedMeasurementSegmentRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string;data: PatchedMeasurementSegmentRequest}, TContext> => { + +const mutationKey = ['measurementSegmentsPartialUpdate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string;data: PatchedMeasurementSegmentRequest}> = (props) => { + const {id,data} = props ?? {}; + + return measurementSegmentsPartialUpdate(id,data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type MeasurementSegmentsPartialUpdateMutationResult = NonNullable>> + export type MeasurementSegmentsPartialUpdateMutationBody = PatchedMeasurementSegmentRequest + export type MeasurementSegmentsPartialUpdateMutationError = AxiosError + + export const useMeasurementSegmentsPartialUpdate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: PatchedMeasurementSegmentRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string;data: PatchedMeasurementSegmentRequest}, + TContext + > => { + + const mutationOptions = getMeasurementSegmentsPartialUpdateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Delete a measurement segment. Only accessible to the measurement author or org admin/owner. + */ +export const measurementSegmentsDestroy = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.delete( + `/api/measurement-segments/${id}/`,options + ); + } + + + +export const getMeasurementSegmentsDestroyMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string}, TContext> => { + +const mutationKey = ['measurementSegmentsDestroy']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string}> = (props) => { + const {id} = props ?? {}; + + return measurementSegmentsDestroy(id,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type MeasurementSegmentsDestroyMutationResult = NonNullable>> + + export type MeasurementSegmentsDestroyMutationError = AxiosError + + export const useMeasurementSegmentsDestroy = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string}, + TContext + > => { + + const mutationOptions = getMeasurementSegmentsDestroyMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * List measurements accessible to the current user. + */ +export const measurementsList = ( + params?: MeasurementsListParams, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/measurements/`,{ + ...options, + params: {...params, ...options?.params},} + ); + } + + + + +export const getMeasurementsListQueryKey = (params?: MeasurementsListParams,) => { + return [ + `/api/measurements/`, ...(params ? [params]: []) + ] as const; + } + + +export const getMeasurementsListQueryOptions = >, TError = AxiosError>(params?: MeasurementsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getMeasurementsListQueryKey(params); + + + + const queryFn: QueryFunction>> = ({ signal }) => measurementsList(params, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type MeasurementsListQueryResult = NonNullable>> +export type MeasurementsListQueryError = AxiosError + + +export function useMeasurementsList>, TError = AxiosError>( + params: undefined | MeasurementsListParams, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useMeasurementsList>, TError = AxiosError>( + params?: MeasurementsListParams, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useMeasurementsList>, TError = AxiosError>( + params?: MeasurementsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useMeasurementsList>, TError = AxiosError>( + params?: MeasurementsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getMeasurementsListQueryOptions(params,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Create a measurement. Supply owner_id to assign to an organization (user must be a member). + */ +export const measurementsCreate = ( + measurementCreateRequest: MeasurementCreateRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.post( + `/api/measurements/`, + measurementCreateRequest,options + ); + } + + + +export const getMeasurementsCreateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: MeasurementCreateRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{data: MeasurementCreateRequest}, TContext> => { + +const mutationKey = ['measurementsCreate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {data: MeasurementCreateRequest}> = (props) => { + const {data} = props ?? {}; + + return measurementsCreate(data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type MeasurementsCreateMutationResult = NonNullable>> + export type MeasurementsCreateMutationBody = MeasurementCreateRequest + export type MeasurementsCreateMutationError = AxiosError + + export const useMeasurementsCreate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: MeasurementCreateRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {data: MeasurementCreateRequest}, + TContext + > => { + + const mutationOptions = getMeasurementsCreateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Get measurement detail by ID. + */ +export const measurementsRetrieve = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/measurements/${id}/`,options + ); + } + + + + +export const getMeasurementsRetrieveQueryKey = (id?: string,) => { + return [ + `/api/measurements/${id}/` + ] as const; + } + + +export const getMeasurementsRetrieveQueryOptions = >, TError = AxiosError>(id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getMeasurementsRetrieveQueryKey(id); + + + + const queryFn: QueryFunction>> = ({ signal }) => measurementsRetrieve(id, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(id), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type MeasurementsRetrieveQueryResult = NonNullable>> +export type MeasurementsRetrieveQueryError = AxiosError + + +export function useMeasurementsRetrieve>, TError = AxiosError>( + id: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useMeasurementsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useMeasurementsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useMeasurementsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getMeasurementsRetrieveQueryOptions(id,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Soft-delete a measurement (author or org admin/owner only). + */ +export const measurementsDestroy = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.delete( + `/api/measurements/${id}/`,options + ); + } + + + +export const getMeasurementsDestroyMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string}, TContext> => { + +const mutationKey = ['measurementsDestroy']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string}> = (props) => { + const {id} = props ?? {}; + + return measurementsDestroy(id,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type MeasurementsDestroyMutationResult = NonNullable>> + + export type MeasurementsDestroyMutationError = AxiosError + + export const useMeasurementsDestroy = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string}, + TContext + > => { + + const mutationOptions = getMeasurementsDestroyMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Get counts-per-second evolution over time from Parquet artifact. + */ +export const measurementsEvolutionRetrieve = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/measurements/${id}/evolution/`,options + ); + } + + + + +export const getMeasurementsEvolutionRetrieveQueryKey = (id?: string,) => { + return [ + `/api/measurements/${id}/evolution/` + ] as const; + } + + +export const getMeasurementsEvolutionRetrieveQueryOptions = >, TError = AxiosError>(id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getMeasurementsEvolutionRetrieveQueryKey(id); + + + + const queryFn: QueryFunction>> = ({ signal }) => measurementsEvolutionRetrieve(id, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(id), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type MeasurementsEvolutionRetrieveQueryResult = NonNullable>> +export type MeasurementsEvolutionRetrieveQueryError = AxiosError + + +export function useMeasurementsEvolutionRetrieve>, TError = AxiosError>( + id: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useMeasurementsEvolutionRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useMeasurementsEvolutionRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useMeasurementsEvolutionRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getMeasurementsEvolutionRetrieveQueryOptions(id,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Routes DELETE to soft_delete() instead of hard delete. + */ +export const measurementsFinalizeCreate = ( + id: string, + measurementsRequest: MeasurementsRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.post( + `/api/measurements/${id}/finalize/`, + measurementsRequest,options + ); + } + + + +export const getMeasurementsFinalizeCreateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: MeasurementsRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string;data: MeasurementsRequest}, TContext> => { + +const mutationKey = ['measurementsFinalizeCreate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string;data: MeasurementsRequest}> = (props) => { + const {id,data} = props ?? {}; + + return measurementsFinalizeCreate(id,data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type MeasurementsFinalizeCreateMutationResult = NonNullable>> + export type MeasurementsFinalizeCreateMutationBody = MeasurementsRequest + export type MeasurementsFinalizeCreateMutationError = AxiosError + + export const useMeasurementsFinalizeCreate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: MeasurementsRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string;data: MeasurementsRequest}, + TContext + > => { + + const mutationOptions = getMeasurementsFinalizeCreateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Get energy/channel spectrum (sum over all exposures) from Parquet artifact. + */ +export const measurementsSpectrumRetrieve = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/measurements/${id}/spectrum/`,options + ); + } + + + + +export const getMeasurementsSpectrumRetrieveQueryKey = (id?: string,) => { + return [ + `/api/measurements/${id}/spectrum/` + ] as const; + } + + +export const getMeasurementsSpectrumRetrieveQueryOptions = >, TError = AxiosError>(id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getMeasurementsSpectrumRetrieveQueryKey(id); + + + + const queryFn: QueryFunction>> = ({ signal }) => measurementsSpectrumRetrieve(id, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(id), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type MeasurementsSpectrumRetrieveQueryResult = NonNullable>> +export type MeasurementsSpectrumRetrieveQueryError = AxiosError + + +export function useMeasurementsSpectrumRetrieve>, TError = AxiosError>( + id: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useMeasurementsSpectrumRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useMeasurementsSpectrumRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useMeasurementsSpectrumRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getMeasurementsSpectrumRetrieveQueryOptions(id,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + diff --git a/frontend/src/api/model/airport.ts b/frontend/src/api/model/airport.ts new file mode 100644 index 0000000..1f61ff1 --- /dev/null +++ b/frontend/src/api/model/airport.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface Airport { + readonly id: string; + name: string; + /** @nullable */ + code_iata?: string | null; + /** @nullable */ + code_icao?: string | null; + /** @nullable */ + municipality?: string | null; +} diff --git a/frontend/src/api/model/airportRequest.ts b/frontend/src/api/model/airportRequest.ts new file mode 100644 index 0000000..22fcd96 --- /dev/null +++ b/frontend/src/api/model/airportRequest.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface AirportRequest { + /** @minLength 1 */ + name: string; + /** + * @minLength 1 + * @nullable + */ + code_iata?: string | null; + /** + * @minLength 1 + * @nullable + */ + code_icao?: string | null; + /** + * @minLength 1 + * @nullable + */ + municipality?: string | null; +} diff --git a/frontend/src/api/model/airportsListParams.ts b/frontend/src/api/model/airportsListParams.ts new file mode 100644 index 0000000..fbf7190 --- /dev/null +++ b/frontend/src/api/model/airportsListParams.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export type AirportsListParams = { +/** + * A page number within the paginated result set. + */ +page?: number; +}; diff --git a/frontend/src/api/model/artifactTypeEnum.ts b/frontend/src/api/model/artifactTypeEnum.ts new file mode 100644 index 0000000..5131483 --- /dev/null +++ b/frontend/src/api/model/artifactTypeEnum.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +/** + * * `spectral` - Processed log file into spectral file (Parquet) + */ +export type ArtifactTypeEnum = typeof ArtifactTypeEnum[keyof typeof ArtifactTypeEnum]; + + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const ArtifactTypeEnum = { + spectral: 'spectral', +} as const; diff --git a/frontend/src/api/model/dataPolicyEnum.ts b/frontend/src/api/model/dataPolicyEnum.ts new file mode 100644 index 0000000..7368872 --- /dev/null +++ b/frontend/src/api/model/dataPolicyEnum.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +/** + * * `PR` - Private +* `PU` - Public +* `NV` - Non-public + */ +export type DataPolicyEnum = typeof DataPolicyEnum[keyof typeof DataPolicyEnum]; + + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const DataPolicyEnum = { + PR: 'PR', + PU: 'PU', + NV: 'NV', +} as const; diff --git a/frontend/src/api/model/detector.ts b/frontend/src/api/model/detector.ts new file mode 100644 index 0000000..f11787c --- /dev/null +++ b/frontend/src/api/model/detector.ts @@ -0,0 +1,39 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { OrganizationSummary } from './organizationSummary'; +import type { DetectorType } from './detectorType'; + +export interface Detector { + readonly id: string; + readonly owner: OrganizationSummary; + owner_id: string; + readonly type: DetectorType; + type_id: string; + /** @nullable */ + image?: string | null; + data?: unknown; + is_deleted?: boolean; + /** @nullable */ + deleted_at?: string | null; + /** @maxLength 80 */ + sn: string; + /** @maxLength 150 */ + name: string; + /** + * Date when detector was manufactured + * @nullable + */ + manufactured_date?: string | null; + /** @nullable */ + readonly created: string | null; + /** @nullable */ + deleted_by?: number | null; + /** Detector calibration */ + calib?: string[]; + access?: string[]; +} diff --git a/frontend/src/api/model/detectorLogbook.ts b/frontend/src/api/model/detectorLogbook.ts new file mode 100644 index 0000000..48d70d6 --- /dev/null +++ b/frontend/src/api/model/detectorLogbook.ts @@ -0,0 +1,69 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { UserSummary } from './userSummary'; +import type { EntryTypeEnum } from './entryTypeEnum'; +import type { SourceEnum } from './sourceEnum'; + +export interface DetectorLogbook { + readonly id: string; + readonly author: UserSummary; + readonly modified_by: UserSummary; + metadata?: unknown; + is_deleted?: boolean; + /** @nullable */ + deleted_at?: string | null; + readonly created: string; + /** @nullable */ + readonly modified: string | null; + /** Detailed description of activity made on the detector. */ + text: string; + /** Private logbook will be visible for maintainers of detector and for dosportal admins. */ + public?: boolean; + /** Category of the logbook entry. + +* `reset` - Reset +* `sync` - Sync +* `maintenance` - Maintenance +* `note` - Note +* `location_update` - Location update +* `calibration` - Calibration +* `other` - Other */ + entry_type?: EntryTypeEnum; + /** Origin of the logbook entry. + +* `web` - Web +* `api` - API +* `qr` - QR +* `auto` - Automatic +* `other` - Other */ + source?: SourceEnum; + /** + * GPS latitude of the location + * @nullable + */ + latitude?: number | null; + /** + * GPS longitude of the location + * @nullable + */ + longitude?: number | null; + /** + * Altitude of the location in meters + * @nullable + */ + altitude?: number | null; + /** + * Location description in text format (e.g., address) + * @maxLength 255 + * @nullable + */ + location_text?: string | null; + /** @nullable */ + deleted_by?: number | null; + detector: string; +} diff --git a/frontend/src/api/model/detectorLogbookRequest.ts b/frontend/src/api/model/detectorLogbookRequest.ts new file mode 100644 index 0000000..43969be --- /dev/null +++ b/frontend/src/api/model/detectorLogbookRequest.ts @@ -0,0 +1,65 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { EntryTypeEnum } from './entryTypeEnum'; +import type { SourceEnum } from './sourceEnum'; + +export interface DetectorLogbookRequest { + metadata?: unknown; + is_deleted?: boolean; + /** @nullable */ + deleted_at?: string | null; + /** + * Detailed description of activity made on the detector. + * @minLength 1 + */ + text: string; + /** Private logbook will be visible for maintainers of detector and for dosportal admins. */ + public?: boolean; + /** Category of the logbook entry. + +* `reset` - Reset +* `sync` - Sync +* `maintenance` - Maintenance +* `note` - Note +* `location_update` - Location update +* `calibration` - Calibration +* `other` - Other */ + entry_type?: EntryTypeEnum; + /** Origin of the logbook entry. + +* `web` - Web +* `api` - API +* `qr` - QR +* `auto` - Automatic +* `other` - Other */ + source?: SourceEnum; + /** + * GPS latitude of the location + * @nullable + */ + latitude?: number | null; + /** + * GPS longitude of the location + * @nullable + */ + longitude?: number | null; + /** + * Altitude of the location in meters + * @nullable + */ + altitude?: number | null; + /** + * Location description in text format (e.g., address) + * @maxLength 255 + * @nullable + */ + location_text?: string | null; + /** @nullable */ + deleted_by?: number | null; + detector: string; +} diff --git a/frontend/src/api/model/detectorManufacturer.ts b/frontend/src/api/model/detectorManufacturer.ts new file mode 100644 index 0000000..d0a5b28 --- /dev/null +++ b/frontend/src/api/model/detectorManufacturer.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface DetectorManufacturer { + readonly id: string; + /** @maxLength 80 */ + name: string; + /** @maxLength 200 */ + url: string; +} diff --git a/frontend/src/api/model/detectorManufacturerRequest.ts b/frontend/src/api/model/detectorManufacturerRequest.ts new file mode 100644 index 0000000..46cad74 --- /dev/null +++ b/frontend/src/api/model/detectorManufacturerRequest.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface DetectorManufacturerRequest { + /** + * @minLength 1 + * @maxLength 80 + */ + name: string; + /** + * @minLength 1 + * @maxLength 200 + */ + url: string; +} diff --git a/frontend/src/api/model/detectorManufacturersListParams.ts b/frontend/src/api/model/detectorManufacturersListParams.ts new file mode 100644 index 0000000..f09e960 --- /dev/null +++ b/frontend/src/api/model/detectorManufacturersListParams.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export type DetectorManufacturersListParams = { +/** + * A page number within the paginated result set. + */ +page?: number; +}; diff --git a/frontend/src/api/model/detectorType.ts b/frontend/src/api/model/detectorType.ts new file mode 100644 index 0000000..4e9b6a5 --- /dev/null +++ b/frontend/src/api/model/detectorType.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface DetectorType { + readonly id: string; + /** @maxLength 80 */ + name: string; + manufacturer: string; + /** + * @maxLength 200 + * @nullable + */ + url?: string | null; + /** Detector description */ + description?: string; + readonly image: string; +} diff --git a/frontend/src/api/model/detectorTypeRequest.ts b/frontend/src/api/model/detectorTypeRequest.ts new file mode 100644 index 0000000..5dbf7e9 --- /dev/null +++ b/frontend/src/api/model/detectorTypeRequest.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface DetectorTypeRequest { + /** + * @minLength 1 + * @maxLength 80 + */ + name: string; + manufacturer: string; + /** + * @maxLength 200 + * @nullable + */ + url?: string | null; + /** Detector description */ + description?: string; +} diff --git a/frontend/src/api/model/detectorTypesListParams.ts b/frontend/src/api/model/detectorTypesListParams.ts new file mode 100644 index 0000000..b6188d8 --- /dev/null +++ b/frontend/src/api/model/detectorTypesListParams.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export type DetectorTypesListParams = { +/** + * A page number within the paginated result set. + */ +page?: number; +}; diff --git a/frontend/src/api/model/detectorWriteRequestRequest.ts b/frontend/src/api/model/detectorWriteRequestRequest.ts new file mode 100644 index 0000000..70790c2 --- /dev/null +++ b/frontend/src/api/model/detectorWriteRequestRequest.ts @@ -0,0 +1,42 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +/** + * Schema serializer for multipart write requests. + */ +export interface DetectorWriteRequestRequest { + owner_id: string; + type_id: string; + /** @nullable */ + image?: Blob | null; + is_deleted?: boolean; + /** @nullable */ + deleted_at?: string | null; + /** + * @minLength 1 + * @maxLength 80 + */ + sn: string; + /** + * @minLength 1 + * @maxLength 150 + */ + name: string; + /** + * Date when detector was manufactured + * @nullable + */ + manufactured_date?: string | null; + /** Detector metadata encoded as JSON string for multipart/form-data requests. */ + data?: string; + /** @nullable */ + deleted_by?: number | null; + /** Detector calibration */ + calib?: string[]; + access?: string[]; +} diff --git a/frontend/src/api/model/detectorsListParams.ts b/frontend/src/api/model/detectorsListParams.ts new file mode 100644 index 0000000..c40bbbd --- /dev/null +++ b/frontend/src/api/model/detectorsListParams.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export type DetectorsListParams = { +/** + * Filter by organization ID + */ +owner?: string; +/** + * A page number within the paginated result set. + */ +page?: number; +}; diff --git a/frontend/src/api/model/detectorsQrRetrieveParams.ts b/frontend/src/api/model/detectorsQrRetrieveParams.ts new file mode 100644 index 0000000..e46feed --- /dev/null +++ b/frontend/src/api/model/detectorsQrRetrieveParams.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export type DetectorsQrRetrieveParams = { +/** + * Include detector label (name and serial number) - true/false + */ +label?: string; +}; diff --git a/frontend/src/api/model/entryTypeEnum.ts b/frontend/src/api/model/entryTypeEnum.ts new file mode 100644 index 0000000..962a1fc --- /dev/null +++ b/frontend/src/api/model/entryTypeEnum.ts @@ -0,0 +1,30 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +/** + * * `reset` - Reset +* `sync` - Sync +* `maintenance` - Maintenance +* `note` - Note +* `location_update` - Location update +* `calibration` - Calibration +* `other` - Other + */ +export type EntryTypeEnum = typeof EntryTypeEnum[keyof typeof EntryTypeEnum]; + + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const EntryTypeEnum = { + reset: 'reset', + sync: 'sync', + maintenance: 'maintenance', + note: 'note', + location_update: 'location_update', + calibration: 'calibration', + other: 'other', +} as const; diff --git a/frontend/src/api/model/file.ts b/frontend/src/api/model/file.ts new file mode 100644 index 0000000..61747e2 --- /dev/null +++ b/frontend/src/api/model/file.ts @@ -0,0 +1,31 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { FileTypeEnum } from './fileTypeEnum'; +import type { SourceTypeEnum } from './sourceTypeEnum'; + +export interface File { + readonly id: string; + is_deleted?: boolean; + /** @nullable */ + deleted_at?: string | null; + /** @maxLength 200 */ + filename: string; + file: string; + file_type?: FileTypeEnum; + source_type?: SourceTypeEnum; + metadata?: unknown; + /** @nullable */ + readonly size: number | null; + readonly created_at: string; + /** @nullable */ + deleted_by?: number | null; + /** @nullable */ + author?: number | null; + /** @nullable */ + owner?: string | null; +} diff --git a/frontend/src/api/model/fileRequest.ts b/frontend/src/api/model/fileRequest.ts new file mode 100644 index 0000000..f4995f7 --- /dev/null +++ b/frontend/src/api/model/fileRequest.ts @@ -0,0 +1,30 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { FileTypeEnum } from './fileTypeEnum'; +import type { SourceTypeEnum } from './sourceTypeEnum'; + +export interface FileRequest { + is_deleted?: boolean; + /** @nullable */ + deleted_at?: string | null; + /** + * @minLength 1 + * @maxLength 200 + */ + filename: string; + file: Blob; + file_type?: FileTypeEnum; + source_type?: SourceTypeEnum; + metadata?: unknown; + /** @nullable */ + deleted_by?: number | null; + /** @nullable */ + author?: number | null; + /** @nullable */ + owner?: string | null; +} diff --git a/frontend/src/api/model/fileTypeEnum.ts b/frontend/src/api/model/fileTypeEnum.ts new file mode 100644 index 0000000..25bd39f --- /dev/null +++ b/frontend/src/api/model/fileTypeEnum.ts @@ -0,0 +1,28 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +/** + * * `log` - Log file +* `trajectory` - Trajectory +* `document` - Document +* `image` - Image +* `other` - Other +* `parquet` - Parquet + */ +export type FileTypeEnum = typeof FileTypeEnum[keyof typeof FileTypeEnum]; + + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const FileTypeEnum = { + log: 'log', + trajectory: 'trajectory', + document: 'document', + image: 'image', + other: 'other', + parquet: 'parquet', +} as const; diff --git a/frontend/src/api/model/fileUploadRequest.ts b/frontend/src/api/model/fileUploadRequest.ts new file mode 100644 index 0000000..2641cb1 --- /dev/null +++ b/frontend/src/api/model/fileUploadRequest.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { FileTypeEnum } from './fileTypeEnum'; + +export interface FileUploadRequest { + /** + * @minLength 1 + * @maxLength 200 + */ + filename: string; + file: Blob; + file_type?: FileTypeEnum; + metadata?: unknown; + /** @nullable */ + owner?: string | null; +} diff --git a/frontend/src/api/model/filesListParams.ts b/frontend/src/api/model/filesListParams.ts new file mode 100644 index 0000000..1c8178c --- /dev/null +++ b/frontend/src/api/model/filesListParams.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export type FilesListParams = { +/** + * Filter by file type + */ +file_type?: string; +/** + * Filter by organization ID + */ +owner?: string; +/** + * A page number within the paginated result set. + */ +page?: number; +}; diff --git a/frontend/src/api/model/flight.ts b/frontend/src/api/model/flight.ts new file mode 100644 index 0000000..a9b9933 --- /dev/null +++ b/frontend/src/api/model/flight.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { Airport } from './airport'; + +export interface Flight { + readonly id: string; + flight_number: string; + /** @nullable */ + departure_time?: string | null; + readonly takeoff: Airport; + readonly land: Airport; +} diff --git a/frontend/src/api/model/flightRequest.ts b/frontend/src/api/model/flightRequest.ts new file mode 100644 index 0000000..78cff9b --- /dev/null +++ b/frontend/src/api/model/flightRequest.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface FlightRequest { + /** @minLength 1 */ + flight_number: string; + /** @nullable */ + departure_time?: string | null; +} diff --git a/frontend/src/api/model/flightsListParams.ts b/frontend/src/api/model/flightsListParams.ts new file mode 100644 index 0000000..f934aad --- /dev/null +++ b/frontend/src/api/model/flightsListParams.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export type FlightsListParams = { +/** + * A page number within the paginated result set. + */ +page?: number; +}; diff --git a/frontend/src/api/model/index.ts b/frontend/src/api/model/index.ts new file mode 100644 index 0000000..f7302b1 --- /dev/null +++ b/frontend/src/api/model/index.ts @@ -0,0 +1,87 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export * from './airport'; +export * from './airportRequest'; +export * from './airportsListParams'; +export * from './artifactTypeEnum'; +export * from './dataPolicyEnum'; +export * from './detector'; +export * from './detectorLogbook'; +export * from './detectorLogbookRequest'; +export * from './detectorManufacturer'; +export * from './detectorManufacturerRequest'; +export * from './detectorManufacturersListParams'; +export * from './detectorType'; +export * from './detectorTypeRequest'; +export * from './detectorTypesListParams'; +export * from './detectorWriteRequestRequest'; +export * from './detectorsListParams'; +export * from './detectorsQrRetrieveParams'; +export * from './entryTypeEnum'; +export * from './file'; +export * from './fileRequest'; +export * from './fileTypeEnum'; +export * from './fileUploadRequest'; +export * from './filesListParams'; +export * from './flight'; +export * from './flightRequest'; +export * from './flightsListParams'; +export * from './logbooksListParams'; +export * from './loginRequestRequest'; +export * from './loginResponse'; +export * from './measurementCreate'; +export * from './measurementCreateRequest'; +export * from './measurementSegment'; +export * from './measurementSegmentRequest'; +export * from './measurementSegmentsListParams'; +export * from './measurementTypeEnum'; +export * from './measurements'; +export * from './measurementsListParams'; +export * from './measurementsRequest'; +export * from './organizationDetail'; +export * from './organizationDetailRequest'; +export * from './organizationSummary'; +export * from './organizationSummaryRequest'; +export * from './organizationUser'; +export * from './organizationsListParams'; +export * from './paginatedAirportList'; +export * from './paginatedDetectorList'; +export * from './paginatedDetectorLogbookList'; +export * from './paginatedDetectorManufacturerList'; +export * from './paginatedDetectorTypeList'; +export * from './paginatedFileList'; +export * from './paginatedFlightList'; +export * from './paginatedMeasurementSegmentList'; +export * from './paginatedMeasurementsList'; +export * from './paginatedOrganizationDetailList'; +export * from './paginatedSpectralRecordArtifactList'; +export * from './paginatedSpectralRecordList'; +export * from './patchedDetectorLogbookRequest'; +export * from './patchedDetectorManufacturerRequest'; +export * from './patchedDetectorTypeRequest'; +export * from './patchedDetectorWriteRequestRequest'; +export * from './patchedMeasurementSegmentRequest'; +export * from './patchedOrganizationDetailRequest'; +export * from './patchedSpectralRecordUpdateRequest'; +export * from './processingStatusEnum'; +export * from './signupRequestRequest'; +export * from './signupResponse'; +export * from './sourceEnum'; +export * from './sourceTypeEnum'; +export * from './spectralRecord'; +export * from './spectralRecordArtifact'; +export * from './spectralRecordArtifactsListParams'; +export * from './spectralRecordCreate'; +export * from './spectralRecordCreateRequest'; +export * from './spectralRecordUpdate'; +export * from './spectralRecordsListParams'; +export * from './userProfile'; +export * from './userProfileRequest'; +export * from './userSummary'; +export * from './userSummaryRequest'; \ No newline at end of file diff --git a/frontend/src/api/model/logbooksListParams.ts b/frontend/src/api/model/logbooksListParams.ts new file mode 100644 index 0000000..e70a3db --- /dev/null +++ b/frontend/src/api/model/logbooksListParams.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export type LogbooksListParams = { +date_from?: string; +date_to?: string; +detector?: string; +entry_type?: string; +/** + * A page number within the paginated result set. + */ +page?: number; +}; diff --git a/frontend/src/api/model/loginRequestRequest.ts b/frontend/src/api/model/loginRequestRequest.ts new file mode 100644 index 0000000..1b4bdfb --- /dev/null +++ b/frontend/src/api/model/loginRequestRequest.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface LoginRequestRequest { + /** + * Username + * @minLength 1 + */ + username: string; + /** + * Password + * @minLength 1 + */ + password: string; +} diff --git a/frontend/src/api/model/loginResponse.ts b/frontend/src/api/model/loginResponse.ts new file mode 100644 index 0000000..99f5596 --- /dev/null +++ b/frontend/src/api/model/loginResponse.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface LoginResponse { + detail: string; + username: string; + token: string; +} diff --git a/frontend/src/api/model/measurementCreate.ts b/frontend/src/api/model/measurementCreate.ts new file mode 100644 index 0000000..cb735f4 --- /dev/null +++ b/frontend/src/api/model/measurementCreate.ts @@ -0,0 +1,35 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { MeasurementTypeEnum } from './measurementTypeEnum'; + +export interface MeasurementCreate { + /** @maxLength 150 */ + name: string; + /** Type of measurement + +* `D` - Debug measurement +* `S` - Static measurement +* `M` - Mobile measurement (ground) +* `C` - Civil airborne measurement +* `A` - Special airborne measurement */ + measurement_type?: MeasurementTypeEnum; + description?: string; + public?: boolean; + /** @nullable */ + time_start?: string | null; + /** @nullable */ + time_end?: string | null; + /** @nullable */ + base_location_lat?: number | null; + /** @nullable */ + base_location_lon?: number | null; + /** @nullable */ + base_location_alt?: number | null; + /** @nullable */ + owner_id?: string | null; +} diff --git a/frontend/src/api/model/measurementCreateRequest.ts b/frontend/src/api/model/measurementCreateRequest.ts new file mode 100644 index 0000000..1efada1 --- /dev/null +++ b/frontend/src/api/model/measurementCreateRequest.ts @@ -0,0 +1,38 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { MeasurementTypeEnum } from './measurementTypeEnum'; + +export interface MeasurementCreateRequest { + /** + * @minLength 1 + * @maxLength 150 + */ + name: string; + /** Type of measurement + +* `D` - Debug measurement +* `S` - Static measurement +* `M` - Mobile measurement (ground) +* `C` - Civil airborne measurement +* `A` - Special airborne measurement */ + measurement_type?: MeasurementTypeEnum; + description?: string; + public?: boolean; + /** @nullable */ + time_start?: string | null; + /** @nullable */ + time_end?: string | null; + /** @nullable */ + base_location_lat?: number | null; + /** @nullable */ + base_location_lon?: number | null; + /** @nullable */ + base_location_alt?: number | null; + /** @nullable */ + owner_id?: string | null; +} diff --git a/frontend/src/api/model/measurementSegment.ts b/frontend/src/api/model/measurementSegment.ts new file mode 100644 index 0000000..6127eb5 --- /dev/null +++ b/frontend/src/api/model/measurementSegment.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface MeasurementSegment { + readonly id: string; + measurement: string; + spectral_record: string; + /** @nullable */ + time_from?: string | null; + /** @nullable */ + time_to?: string | null; + /** + * @minimum -2147483648 + * @maximum 2147483647 + */ + position?: number; +} diff --git a/frontend/src/api/model/measurementSegmentRequest.ts b/frontend/src/api/model/measurementSegmentRequest.ts new file mode 100644 index 0000000..d4449c7 --- /dev/null +++ b/frontend/src/api/model/measurementSegmentRequest.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface MeasurementSegmentRequest { + measurement: string; + spectral_record: string; + /** @nullable */ + time_from?: string | null; + /** @nullable */ + time_to?: string | null; + /** + * @minimum -2147483648 + * @maximum 2147483647 + */ + position?: number; +} diff --git a/frontend/src/api/model/measurementSegmentsListParams.ts b/frontend/src/api/model/measurementSegmentsListParams.ts new file mode 100644 index 0000000..b44c74b --- /dev/null +++ b/frontend/src/api/model/measurementSegmentsListParams.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export type MeasurementSegmentsListParams = { +/** + * Filter segments by measurement ID. + */ +measurement?: string; +/** + * A page number within the paginated result set. + */ +page?: number; +}; diff --git a/frontend/src/api/model/measurementTypeEnum.ts b/frontend/src/api/model/measurementTypeEnum.ts new file mode 100644 index 0000000..953b50c --- /dev/null +++ b/frontend/src/api/model/measurementTypeEnum.ts @@ -0,0 +1,26 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +/** + * * `D` - Debug measurement +* `S` - Static measurement +* `M` - Mobile measurement (ground) +* `C` - Civil airborne measurement +* `A` - Special airborne measurement + */ +export type MeasurementTypeEnum = typeof MeasurementTypeEnum[keyof typeof MeasurementTypeEnum]; + + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const MeasurementTypeEnum = { + D: 'D', + S: 'S', + M: 'M', + C: 'C', + A: 'A', +} as const; diff --git a/frontend/src/api/model/measurements.ts b/frontend/src/api/model/measurements.ts new file mode 100644 index 0000000..1f4f8ef --- /dev/null +++ b/frontend/src/api/model/measurements.ts @@ -0,0 +1,58 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { File } from './file'; +import type { OrganizationSummary } from './organizationSummary'; +import type { UserSummary } from './userSummary'; +import type { Flight } from './flight'; +import type { ProcessingStatusEnum } from './processingStatusEnum'; +import type { MeasurementTypeEnum } from './measurementTypeEnum'; + +export interface Measurements { + readonly id: string; + readonly files: readonly File[]; + readonly owner: OrganizationSummary; + readonly author: UserSummary; + readonly flight: Flight; + is_deleted?: boolean; + /** @nullable */ + deleted_at?: string | null; + /** Status of async background processing + +* `pending` - Pending processing +* `processing` - Processing in progress +* `completed` - Processing completed +* `failed` - Processing failed */ + processing_status?: ProcessingStatusEnum; + /** @nullable */ + time_start?: string | null; + /** @nullable */ + time_end?: string | null; + readonly time_created: string; + /** @maxLength 150 */ + name: string; + description?: string; + public?: boolean; + /** Type of measurement + +* `D` - Debug measurement +* `S` - Static measurement +* `M` - Mobile measurement (ground) +* `C` - Civil airborne measurement +* `A` - Special airborne measurement */ + measurement_type?: MeasurementTypeEnum; + /** @nullable */ + base_location_lat?: number | null; + /** @nullable */ + base_location_lon?: number | null; + /** @nullable */ + base_location_alt?: number | null; + /** @nullable */ + deleted_by?: number | null; + /** Measurement campaigns this measurement belongs to. */ + campaigns?: string[]; +} diff --git a/frontend/src/api/model/measurementsListParams.ts b/frontend/src/api/model/measurementsListParams.ts new file mode 100644 index 0000000..57b0e33 --- /dev/null +++ b/frontend/src/api/model/measurementsListParams.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export type MeasurementsListParams = { +/** + * A page number within the paginated result set. + */ +page?: number; +}; diff --git a/frontend/src/api/model/measurementsRequest.ts b/frontend/src/api/model/measurementsRequest.ts new file mode 100644 index 0000000..6cde5dd --- /dev/null +++ b/frontend/src/api/model/measurementsRequest.ts @@ -0,0 +1,51 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { ProcessingStatusEnum } from './processingStatusEnum'; +import type { MeasurementTypeEnum } from './measurementTypeEnum'; + +export interface MeasurementsRequest { + is_deleted?: boolean; + /** @nullable */ + deleted_at?: string | null; + /** Status of async background processing + +* `pending` - Pending processing +* `processing` - Processing in progress +* `completed` - Processing completed +* `failed` - Processing failed */ + processing_status?: ProcessingStatusEnum; + /** @nullable */ + time_start?: string | null; + /** @nullable */ + time_end?: string | null; + /** + * @minLength 1 + * @maxLength 150 + */ + name: string; + description?: string; + public?: boolean; + /** Type of measurement + +* `D` - Debug measurement +* `S` - Static measurement +* `M` - Mobile measurement (ground) +* `C` - Civil airborne measurement +* `A` - Special airborne measurement */ + measurement_type?: MeasurementTypeEnum; + /** @nullable */ + base_location_lat?: number | null; + /** @nullable */ + base_location_lon?: number | null; + /** @nullable */ + base_location_alt?: number | null; + /** @nullable */ + deleted_by?: number | null; + /** Measurement campaigns this measurement belongs to. */ + campaigns?: string[]; +} diff --git a/frontend/src/api/model/organizationDetail.ts b/frontend/src/api/model/organizationDetail.ts new file mode 100644 index 0000000..4c17179 --- /dev/null +++ b/frontend/src/api/model/organizationDetail.ts @@ -0,0 +1,31 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { DataPolicyEnum } from './dataPolicyEnum'; + +export interface OrganizationDetail { + readonly id: string; + /** @maxLength 200 */ + name: string; + /** @pattern ^[-a-zA-Z0-9_]+$ */ + readonly slug: string; + data_policy?: DataPolicyEnum; + /** + * @maxLength 200 + * @nullable + */ + website?: string | null; + /** + * @maxLength 200 + * @nullable + */ + contact_email?: string | null; + /** @nullable */ + description?: string | null; + readonly created_at: string; + readonly members: string; +} diff --git a/frontend/src/api/model/organizationDetailRequest.ts b/frontend/src/api/model/organizationDetailRequest.ts new file mode 100644 index 0000000..1e159b8 --- /dev/null +++ b/frontend/src/api/model/organizationDetailRequest.ts @@ -0,0 +1,29 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { DataPolicyEnum } from './dataPolicyEnum'; + +export interface OrganizationDetailRequest { + /** + * @minLength 1 + * @maxLength 200 + */ + name: string; + data_policy?: DataPolicyEnum; + /** + * @maxLength 200 + * @nullable + */ + website?: string | null; + /** + * @maxLength 200 + * @nullable + */ + contact_email?: string | null; + /** @nullable */ + description?: string | null; +} diff --git a/frontend/src/api/model/organizationSummary.ts b/frontend/src/api/model/organizationSummary.ts new file mode 100644 index 0000000..63bea46 --- /dev/null +++ b/frontend/src/api/model/organizationSummary.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface OrganizationSummary { + readonly id: string; + /** @maxLength 200 */ + name: string; + /** + * @maxLength 255 + * @pattern ^[-a-zA-Z0-9_]+$ + */ + slug?: string; +} diff --git a/frontend/src/api/model/organizationSummaryRequest.ts b/frontend/src/api/model/organizationSummaryRequest.ts new file mode 100644 index 0000000..e3ba37d --- /dev/null +++ b/frontend/src/api/model/organizationSummaryRequest.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface OrganizationSummaryRequest { + /** + * @minLength 1 + * @maxLength 200 + */ + name: string; + /** + * @maxLength 255 + * @pattern ^[-a-zA-Z0-9_]+$ + */ + slug?: string; +} diff --git a/frontend/src/api/model/organizationUser.ts b/frontend/src/api/model/organizationUser.ts new file mode 100644 index 0000000..dda1ab7 --- /dev/null +++ b/frontend/src/api/model/organizationUser.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface OrganizationUser { + id: string; + name: string; + user_type: string; + data_policy: string; +} diff --git a/frontend/src/api/model/organizationsListParams.ts b/frontend/src/api/model/organizationsListParams.ts new file mode 100644 index 0000000..57827f8 --- /dev/null +++ b/frontend/src/api/model/organizationsListParams.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export type OrganizationsListParams = { +/** + * A page number within the paginated result set. + */ +page?: number; +}; diff --git a/frontend/src/api/model/paginatedAirportList.ts b/frontend/src/api/model/paginatedAirportList.ts new file mode 100644 index 0000000..d8bd0be --- /dev/null +++ b/frontend/src/api/model/paginatedAirportList.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { Airport } from './airport'; + +export interface PaginatedAirportList { + count: number; + /** @nullable */ + next?: string | null; + /** @nullable */ + previous?: string | null; + results: Airport[]; +} diff --git a/frontend/src/api/model/paginatedDetectorList.ts b/frontend/src/api/model/paginatedDetectorList.ts new file mode 100644 index 0000000..883b6ed --- /dev/null +++ b/frontend/src/api/model/paginatedDetectorList.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { Detector } from './detector'; + +export interface PaginatedDetectorList { + count: number; + /** @nullable */ + next?: string | null; + /** @nullable */ + previous?: string | null; + results: Detector[]; +} diff --git a/frontend/src/api/model/paginatedDetectorLogbookList.ts b/frontend/src/api/model/paginatedDetectorLogbookList.ts new file mode 100644 index 0000000..e57b85f --- /dev/null +++ b/frontend/src/api/model/paginatedDetectorLogbookList.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { DetectorLogbook } from './detectorLogbook'; + +export interface PaginatedDetectorLogbookList { + count: number; + /** @nullable */ + next?: string | null; + /** @nullable */ + previous?: string | null; + results: DetectorLogbook[]; +} diff --git a/frontend/src/api/model/paginatedDetectorManufacturerList.ts b/frontend/src/api/model/paginatedDetectorManufacturerList.ts new file mode 100644 index 0000000..4eee872 --- /dev/null +++ b/frontend/src/api/model/paginatedDetectorManufacturerList.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { DetectorManufacturer } from './detectorManufacturer'; + +export interface PaginatedDetectorManufacturerList { + count: number; + /** @nullable */ + next?: string | null; + /** @nullable */ + previous?: string | null; + results: DetectorManufacturer[]; +} diff --git a/frontend/src/api/model/paginatedDetectorTypeList.ts b/frontend/src/api/model/paginatedDetectorTypeList.ts new file mode 100644 index 0000000..2052917 --- /dev/null +++ b/frontend/src/api/model/paginatedDetectorTypeList.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { DetectorType } from './detectorType'; + +export interface PaginatedDetectorTypeList { + count: number; + /** @nullable */ + next?: string | null; + /** @nullable */ + previous?: string | null; + results: DetectorType[]; +} diff --git a/frontend/src/api/model/paginatedFileList.ts b/frontend/src/api/model/paginatedFileList.ts new file mode 100644 index 0000000..b0d9a0e --- /dev/null +++ b/frontend/src/api/model/paginatedFileList.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { File } from './file'; + +export interface PaginatedFileList { + count: number; + /** @nullable */ + next?: string | null; + /** @nullable */ + previous?: string | null; + results: File[]; +} diff --git a/frontend/src/api/model/paginatedFlightList.ts b/frontend/src/api/model/paginatedFlightList.ts new file mode 100644 index 0000000..8a53d97 --- /dev/null +++ b/frontend/src/api/model/paginatedFlightList.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { Flight } from './flight'; + +export interface PaginatedFlightList { + count: number; + /** @nullable */ + next?: string | null; + /** @nullable */ + previous?: string | null; + results: Flight[]; +} diff --git a/frontend/src/api/model/paginatedMeasurementSegmentList.ts b/frontend/src/api/model/paginatedMeasurementSegmentList.ts new file mode 100644 index 0000000..d3f25e2 --- /dev/null +++ b/frontend/src/api/model/paginatedMeasurementSegmentList.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { MeasurementSegment } from './measurementSegment'; + +export interface PaginatedMeasurementSegmentList { + count: number; + /** @nullable */ + next?: string | null; + /** @nullable */ + previous?: string | null; + results: MeasurementSegment[]; +} diff --git a/frontend/src/api/model/paginatedMeasurementsList.ts b/frontend/src/api/model/paginatedMeasurementsList.ts new file mode 100644 index 0000000..4dbd313 --- /dev/null +++ b/frontend/src/api/model/paginatedMeasurementsList.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { Measurements } from './measurements'; + +export interface PaginatedMeasurementsList { + count: number; + /** @nullable */ + next?: string | null; + /** @nullable */ + previous?: string | null; + results: Measurements[]; +} diff --git a/frontend/src/api/model/paginatedOrganizationDetailList.ts b/frontend/src/api/model/paginatedOrganizationDetailList.ts new file mode 100644 index 0000000..4f9280f --- /dev/null +++ b/frontend/src/api/model/paginatedOrganizationDetailList.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { OrganizationDetail } from './organizationDetail'; + +export interface PaginatedOrganizationDetailList { + count: number; + /** @nullable */ + next?: string | null; + /** @nullable */ + previous?: string | null; + results: OrganizationDetail[]; +} diff --git a/frontend/src/api/model/paginatedSpectralRecordArtifactList.ts b/frontend/src/api/model/paginatedSpectralRecordArtifactList.ts new file mode 100644 index 0000000..cbcbc97 --- /dev/null +++ b/frontend/src/api/model/paginatedSpectralRecordArtifactList.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { SpectralRecordArtifact } from './spectralRecordArtifact'; + +export interface PaginatedSpectralRecordArtifactList { + count: number; + /** @nullable */ + next?: string | null; + /** @nullable */ + previous?: string | null; + results: SpectralRecordArtifact[]; +} diff --git a/frontend/src/api/model/paginatedSpectralRecordList.ts b/frontend/src/api/model/paginatedSpectralRecordList.ts new file mode 100644 index 0000000..7a21024 --- /dev/null +++ b/frontend/src/api/model/paginatedSpectralRecordList.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { SpectralRecord } from './spectralRecord'; + +export interface PaginatedSpectralRecordList { + count: number; + /** @nullable */ + next?: string | null; + /** @nullable */ + previous?: string | null; + results: SpectralRecord[]; +} diff --git a/frontend/src/api/model/patchedDetectorLogbookRequest.ts b/frontend/src/api/model/patchedDetectorLogbookRequest.ts new file mode 100644 index 0000000..6bd74b7 --- /dev/null +++ b/frontend/src/api/model/patchedDetectorLogbookRequest.ts @@ -0,0 +1,65 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { EntryTypeEnum } from './entryTypeEnum'; +import type { SourceEnum } from './sourceEnum'; + +export interface PatchedDetectorLogbookRequest { + metadata?: unknown; + is_deleted?: boolean; + /** @nullable */ + deleted_at?: string | null; + /** + * Detailed description of activity made on the detector. + * @minLength 1 + */ + text?: string; + /** Private logbook will be visible for maintainers of detector and for dosportal admins. */ + public?: boolean; + /** Category of the logbook entry. + +* `reset` - Reset +* `sync` - Sync +* `maintenance` - Maintenance +* `note` - Note +* `location_update` - Location update +* `calibration` - Calibration +* `other` - Other */ + entry_type?: EntryTypeEnum; + /** Origin of the logbook entry. + +* `web` - Web +* `api` - API +* `qr` - QR +* `auto` - Automatic +* `other` - Other */ + source?: SourceEnum; + /** + * GPS latitude of the location + * @nullable + */ + latitude?: number | null; + /** + * GPS longitude of the location + * @nullable + */ + longitude?: number | null; + /** + * Altitude of the location in meters + * @nullable + */ + altitude?: number | null; + /** + * Location description in text format (e.g., address) + * @maxLength 255 + * @nullable + */ + location_text?: string | null; + /** @nullable */ + deleted_by?: number | null; + detector?: string; +} diff --git a/frontend/src/api/model/patchedDetectorManufacturerRequest.ts b/frontend/src/api/model/patchedDetectorManufacturerRequest.ts new file mode 100644 index 0000000..8e95d5a --- /dev/null +++ b/frontend/src/api/model/patchedDetectorManufacturerRequest.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface PatchedDetectorManufacturerRequest { + /** + * @minLength 1 + * @maxLength 80 + */ + name?: string; + /** + * @minLength 1 + * @maxLength 200 + */ + url?: string; +} diff --git a/frontend/src/api/model/patchedDetectorTypeRequest.ts b/frontend/src/api/model/patchedDetectorTypeRequest.ts new file mode 100644 index 0000000..3433ba9 --- /dev/null +++ b/frontend/src/api/model/patchedDetectorTypeRequest.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface PatchedDetectorTypeRequest { + /** + * @minLength 1 + * @maxLength 80 + */ + name?: string; + manufacturer?: string; + /** + * @maxLength 200 + * @nullable + */ + url?: string | null; + /** Detector description */ + description?: string; +} diff --git a/frontend/src/api/model/patchedDetectorWriteRequestRequest.ts b/frontend/src/api/model/patchedDetectorWriteRequestRequest.ts new file mode 100644 index 0000000..7131e6b --- /dev/null +++ b/frontend/src/api/model/patchedDetectorWriteRequestRequest.ts @@ -0,0 +1,42 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +/** + * Schema serializer for multipart write requests. + */ +export interface PatchedDetectorWriteRequestRequest { + owner_id?: string; + type_id?: string; + /** @nullable */ + image?: Blob | null; + is_deleted?: boolean; + /** @nullable */ + deleted_at?: string | null; + /** + * @minLength 1 + * @maxLength 80 + */ + sn?: string; + /** + * @minLength 1 + * @maxLength 150 + */ + name?: string; + /** + * Date when detector was manufactured + * @nullable + */ + manufactured_date?: string | null; + /** Detector metadata encoded as JSON string for multipart/form-data requests. */ + data?: string; + /** @nullable */ + deleted_by?: number | null; + /** Detector calibration */ + calib?: string[]; + access?: string[]; +} diff --git a/frontend/src/api/model/patchedMeasurementSegmentRequest.ts b/frontend/src/api/model/patchedMeasurementSegmentRequest.ts new file mode 100644 index 0000000..7ad21a3 --- /dev/null +++ b/frontend/src/api/model/patchedMeasurementSegmentRequest.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface PatchedMeasurementSegmentRequest { + measurement?: string; + spectral_record?: string; + /** @nullable */ + time_from?: string | null; + /** @nullable */ + time_to?: string | null; + /** + * @minimum -2147483648 + * @maximum 2147483647 + */ + position?: number; +} diff --git a/frontend/src/api/model/patchedOrganizationDetailRequest.ts b/frontend/src/api/model/patchedOrganizationDetailRequest.ts new file mode 100644 index 0000000..2a3c744 --- /dev/null +++ b/frontend/src/api/model/patchedOrganizationDetailRequest.ts @@ -0,0 +1,29 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { DataPolicyEnum } from './dataPolicyEnum'; + +export interface PatchedOrganizationDetailRequest { + /** + * @minLength 1 + * @maxLength 200 + */ + name?: string; + data_policy?: DataPolicyEnum; + /** + * @maxLength 200 + * @nullable + */ + website?: string | null; + /** + * @maxLength 200 + * @nullable + */ + contact_email?: string | null; + /** @nullable */ + description?: string | null; +} diff --git a/frontend/src/api/model/patchedSpectralRecordUpdateRequest.ts b/frontend/src/api/model/patchedSpectralRecordUpdateRequest.ts new file mode 100644 index 0000000..35c9ed8 --- /dev/null +++ b/frontend/src/api/model/patchedSpectralRecordUpdateRequest.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface PatchedSpectralRecordUpdateRequest { + /** + * Name of this record. Short and simple description of record. + * @minLength 1 + * @maxLength 80 + * @nullable + */ + name?: string | null; + /** Description of the record */ + description?: string; + /** record metadata, used for advanced data processing and maintaining */ + metadata?: unknown; +} diff --git a/frontend/src/api/model/processingStatusEnum.ts b/frontend/src/api/model/processingStatusEnum.ts new file mode 100644 index 0000000..0e265e1 --- /dev/null +++ b/frontend/src/api/model/processingStatusEnum.ts @@ -0,0 +1,24 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +/** + * * `pending` - Pending processing +* `processing` - Processing in progress +* `completed` - Processing completed +* `failed` - Processing failed + */ +export type ProcessingStatusEnum = typeof ProcessingStatusEnum[keyof typeof ProcessingStatusEnum]; + + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const ProcessingStatusEnum = { + pending: 'pending', + processing: 'processing', + completed: 'completed', + failed: 'failed', +} as const; diff --git a/frontend/src/api/model/signupRequestRequest.ts b/frontend/src/api/model/signupRequestRequest.ts new file mode 100644 index 0000000..8f42a4e --- /dev/null +++ b/frontend/src/api/model/signupRequestRequest.ts @@ -0,0 +1,40 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface SignupRequestRequest { + /** + * Desired username + * @minLength 1 + */ + username: string; + /** + * First name + * @minLength 1 + */ + first_name: string; + /** + * Last name + * @minLength 1 + */ + last_name: string; + /** + * Email address + * @minLength 1 + */ + email: string; + /** + * Password (min 8 characters) + * @minLength 1 + */ + password: string; + /** + * Password confirmation + * @minLength 1 + */ + password_confirm: string; +} diff --git a/frontend/src/api/model/signupResponse.ts b/frontend/src/api/model/signupResponse.ts new file mode 100644 index 0000000..78625f3 --- /dev/null +++ b/frontend/src/api/model/signupResponse.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface SignupResponse { + detail: string; + username: string; +} diff --git a/frontend/src/api/model/sourceEnum.ts b/frontend/src/api/model/sourceEnum.ts new file mode 100644 index 0000000..20faed9 --- /dev/null +++ b/frontend/src/api/model/sourceEnum.ts @@ -0,0 +1,26 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +/** + * * `web` - Web +* `api` - API +* `qr` - QR +* `auto` - Automatic +* `other` - Other + */ +export type SourceEnum = typeof SourceEnum[keyof typeof SourceEnum]; + + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const SourceEnum = { + web: 'web', + api: 'api', + qr: 'qr', + auto: 'auto', + other: 'other', +} as const; diff --git a/frontend/src/api/model/sourceTypeEnum.ts b/frontend/src/api/model/sourceTypeEnum.ts new file mode 100644 index 0000000..64aaba4 --- /dev/null +++ b/frontend/src/api/model/sourceTypeEnum.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +/** + * * `uploaded` - Uploaded by user +* `generated` - Generated by system + */ +export type SourceTypeEnum = typeof SourceTypeEnum[keyof typeof SourceTypeEnum]; + + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const SourceTypeEnum = { + uploaded: 'uploaded', + generated: 'generated', +} as const; diff --git a/frontend/src/api/model/spectralRecord.ts b/frontend/src/api/model/spectralRecord.ts new file mode 100644 index 0000000..3c76136 --- /dev/null +++ b/frontend/src/api/model/spectralRecord.ts @@ -0,0 +1,72 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { SpectralRecordArtifact } from './spectralRecordArtifact'; +import type { File } from './file'; +import type { OrganizationSummary } from './organizationSummary'; +import type { UserSummary } from './userSummary'; +import type { ProcessingStatusEnum } from './processingStatusEnum'; + +/** + * Serializer for spectral records. + */ +export interface SpectralRecord { + readonly id: string; + readonly artifacts: readonly SpectralRecordArtifact[]; + readonly artifacts_count: string; + readonly raw_file: File; + readonly owner: OrganizationSummary; + readonly author: UserSummary; + is_deleted?: boolean; + /** @nullable */ + deleted_at?: string | null; + /** Status of async background processing + +* `pending` - Pending processing +* `processing` - Processing in progress +* `completed` - Processing completed +* `failed` - Processing failed */ + processing_status?: ProcessingStatusEnum; + /** + * Name of this record. Short and simple description of record. + * @maxLength 80 + * @nullable + */ + name?: string | null; + /** Description of the record */ + description?: string; + /** Tick this box if the record is dependent on absolute time. When you need align record to real time. */ + time_tracked?: boolean; + /** + * System time of record start + * @nullable + */ + time_internal_start?: number | null; + /** + * When 'time is tracked', you can set start time of the record beginning. + * @nullable + */ + time_start?: string | null; + /** @nullable */ + time_of_interest_start?: number | null; + /** @nullable */ + time_of_interest_end?: number | null; + readonly created: string; + /** + * Duration of record + * @nullable + */ + record_duration?: string | null; + /** record metadata, used for advanced data processing and maintaining */ + metadata?: unknown; + /** @nullable */ + deleted_by?: number | null; + /** @nullable */ + detector?: string | null; + /** @nullable */ + calib?: string | null; +} diff --git a/frontend/src/api/model/spectralRecordArtifact.ts b/frontend/src/api/model/spectralRecordArtifact.ts new file mode 100644 index 0000000..897f0fd --- /dev/null +++ b/frontend/src/api/model/spectralRecordArtifact.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import type { ArtifactTypeEnum } from './artifactTypeEnum'; +import type { File } from './file'; + +/** + * Serializer for spectral record artifacts. + */ +export interface SpectralRecordArtifact { + readonly id: string; + /** Type of artifact (e.g. histogram, processed spectral logs, ...) + +* `spectral` - Processed log file into spectral file (Parquet) */ + artifact_type: ArtifactTypeEnum; + readonly artifact: File; + /** Reference to SpectralRecord to which this artifact belongs */ + spectral_record: string; + /** Time when the artifact was created */ + readonly created_at: string; +} diff --git a/frontend/src/api/model/spectralRecordArtifactsListParams.ts b/frontend/src/api/model/spectralRecordArtifactsListParams.ts new file mode 100644 index 0000000..6085b23 --- /dev/null +++ b/frontend/src/api/model/spectralRecordArtifactsListParams.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export type SpectralRecordArtifactsListParams = { +artifact_type?: string; +/** + * A page number within the paginated result set. + */ +page?: number; +/** + * Filter by spectral record ID + */ +spectral_record?: string; +}; diff --git a/frontend/src/api/model/spectralRecordCreate.ts b/frontend/src/api/model/spectralRecordCreate.ts new file mode 100644 index 0000000..a00f1d4 --- /dev/null +++ b/frontend/src/api/model/spectralRecordCreate.ts @@ -0,0 +1,31 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +/** + * Serializer for creating spectral records. + */ +export interface SpectralRecordCreate { + /** + * Name of this record. Short and simple description of record. + * @maxLength 80 + * @nullable + */ + name?: string | null; + raw_file: string; + /** @nullable */ + detector?: string | null; + /** Description of the record */ + description?: string; + /** + * Organization that owns this record + * @nullable + */ + owner?: string | null; + /** record metadata, used for advanced data processing and maintaining */ + metadata?: unknown; +} diff --git a/frontend/src/api/model/spectralRecordCreateRequest.ts b/frontend/src/api/model/spectralRecordCreateRequest.ts new file mode 100644 index 0000000..1c545e2 --- /dev/null +++ b/frontend/src/api/model/spectralRecordCreateRequest.ts @@ -0,0 +1,32 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +/** + * Serializer for creating spectral records. + */ +export interface SpectralRecordCreateRequest { + /** + * Name of this record. Short and simple description of record. + * @minLength 1 + * @maxLength 80 + * @nullable + */ + name?: string | null; + raw_file: string; + /** @nullable */ + detector?: string | null; + /** Description of the record */ + description?: string; + /** + * Organization that owns this record + * @nullable + */ + owner?: string | null; + /** record metadata, used for advanced data processing and maintaining */ + metadata?: unknown; +} diff --git a/frontend/src/api/model/spectralRecordUpdate.ts b/frontend/src/api/model/spectralRecordUpdate.ts new file mode 100644 index 0000000..854a4cd --- /dev/null +++ b/frontend/src/api/model/spectralRecordUpdate.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface SpectralRecordUpdate { + /** + * Name of this record. Short and simple description of record. + * @maxLength 80 + * @nullable + */ + name?: string | null; + /** Description of the record */ + description?: string; + /** record metadata, used for advanced data processing and maintaining */ + metadata?: unknown; +} diff --git a/frontend/src/api/model/spectralRecordsListParams.ts b/frontend/src/api/model/spectralRecordsListParams.ts new file mode 100644 index 0000000..cd05181 --- /dev/null +++ b/frontend/src/api/model/spectralRecordsListParams.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export type SpectralRecordsListParams = { +/** + * A page number within the paginated result set. + */ +page?: number; +/** + * Filter by processing status (pending/processing/completed/failed) + */ +processing_status?: string; +}; diff --git a/frontend/src/api/model/userProfile.ts b/frontend/src/api/model/userProfile.ts new file mode 100644 index 0000000..b505724 --- /dev/null +++ b/frontend/src/api/model/userProfile.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface UserProfile { + readonly id: number; + /** + * Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only. + * @maxLength 150 + * @pattern ^[\w.@+-]+$ + */ + username: string; + /** @maxLength 254 */ + email?: string; + /** @maxLength 150 */ + first_name?: string; + /** @maxLength 150 */ + last_name?: string; +} diff --git a/frontend/src/api/model/userProfileRequest.ts b/frontend/src/api/model/userProfileRequest.ts new file mode 100644 index 0000000..412761f --- /dev/null +++ b/frontend/src/api/model/userProfileRequest.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface UserProfileRequest { + /** + * Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only. + * @minLength 1 + * @maxLength 150 + * @pattern ^[\w.@+-]+$ + */ + username: string; + /** @maxLength 254 */ + email?: string; + /** @maxLength 150 */ + first_name?: string; + /** @maxLength 150 */ + last_name?: string; +} diff --git a/frontend/src/api/model/userSummary.ts b/frontend/src/api/model/userSummary.ts new file mode 100644 index 0000000..bfbc120 --- /dev/null +++ b/frontend/src/api/model/userSummary.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface UserSummary { + readonly id: number; + /** + * Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only. + * @maxLength 150 + * @pattern ^[\w.@+-]+$ + */ + username: string; + /** @maxLength 150 */ + first_name?: string; + /** @maxLength 150 */ + last_name?: string; +} diff --git a/frontend/src/api/model/userSummaryRequest.ts b/frontend/src/api/model/userSummaryRequest.ts new file mode 100644 index 0000000..47c80bb --- /dev/null +++ b/frontend/src/api/model/userSummaryRequest.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ + +export interface UserSummaryRequest { + /** + * Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only. + * @minLength 1 + * @maxLength 150 + * @pattern ^[\w.@+-]+$ + */ + username: string; + /** @maxLength 150 */ + first_name?: string; + /** @maxLength 150 */ + last_name?: string; +} diff --git a/frontend/src/api/organizations/organizations.ts b/frontend/src/api/organizations/organizations.ts new file mode 100644 index 0000000..5ea37e4 --- /dev/null +++ b/frontend/src/api/organizations/organizations.ts @@ -0,0 +1,1067 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import { + useMutation, + useQuery +} from '@tanstack/react-query'; +import type { + DataTag, + DefinedInitialDataOptions, + DefinedUseQueryResult, + MutationFunction, + QueryClient, + QueryFunction, + QueryKey, + UndefinedInitialDataOptions, + UseMutationOptions, + UseMutationResult, + UseQueryOptions, + UseQueryResult +} from '@tanstack/react-query'; + +import * as axios from 'axios'; +import type { + AxiosError, + AxiosRequestConfig, + AxiosResponse +} from 'axios'; + +import type { + OrganizationDetail, + OrganizationDetailRequest, + OrganizationsListParams, + PaginatedOrganizationDetailList, + PatchedOrganizationDetailRequest +} from '.././model'; + + + + + +/** + * Get invite details by token (public, no authentication required). + */ +export const invitesRetrieve = ( + token: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/invites/${token}/`,options + ); + } + + + + +export const getInvitesRetrieveQueryKey = (token?: string,) => { + return [ + `/api/invites/${token}/` + ] as const; + } + + +export const getInvitesRetrieveQueryOptions = >, TError = AxiosError>(token: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getInvitesRetrieveQueryKey(token); + + + + const queryFn: QueryFunction>> = ({ signal }) => invitesRetrieve(token, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(token), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type InvitesRetrieveQueryResult = NonNullable>> +export type InvitesRetrieveQueryError = AxiosError + + +export function useInvitesRetrieve>, TError = AxiosError>( + token: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useInvitesRetrieve>, TError = AxiosError>( + token: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useInvitesRetrieve>, TError = AxiosError>( + token: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useInvitesRetrieve>, TError = AxiosError>( + token: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getInvitesRetrieveQueryOptions(token,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Accept an invite and join the organization. Requires authentication. + */ +export const invitesAcceptCreate = ( + token: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.post( + `/api/invites/${token}/accept/`,undefined,options + ); + } + + + +export const getInvitesAcceptCreateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{token: string}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{token: string}, TContext> => { + +const mutationKey = ['invitesAcceptCreate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {token: string}> = (props) => { + const {token} = props ?? {}; + + return invitesAcceptCreate(token,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type InvitesAcceptCreateMutationResult = NonNullable>> + + export type InvitesAcceptCreateMutationError = AxiosError + + export const useInvitesAcceptCreate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{token: string}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {token: string}, + TContext + > => { + + const mutationOptions = getInvitesAcceptCreateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * List all organizations (any authenticated user). + */ +export const organizationsList = ( + params?: OrganizationsListParams, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/organizations/`,{ + ...options, + params: {...params, ...options?.params},} + ); + } + + + + +export const getOrganizationsListQueryKey = (params?: OrganizationsListParams,) => { + return [ + `/api/organizations/`, ...(params ? [params]: []) + ] as const; + } + + +export const getOrganizationsListQueryOptions = >, TError = AxiosError>(params?: OrganizationsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getOrganizationsListQueryKey(params); + + + + const queryFn: QueryFunction>> = ({ signal }) => organizationsList(params, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type OrganizationsListQueryResult = NonNullable>> +export type OrganizationsListQueryError = AxiosError + + +export function useOrganizationsList>, TError = AxiosError>( + params: undefined | OrganizationsListParams, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useOrganizationsList>, TError = AxiosError>( + params?: OrganizationsListParams, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useOrganizationsList>, TError = AxiosError>( + params?: OrganizationsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useOrganizationsList>, TError = AxiosError>( + params?: OrganizationsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getOrganizationsListQueryOptions(params,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Create a new organization. The creator automatically becomes owner. + */ +export const organizationsCreate = ( + organizationDetailRequest: OrganizationDetailRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.post( + `/api/organizations/`, + organizationDetailRequest,options + ); + } + + + +export const getOrganizationsCreateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: OrganizationDetailRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{data: OrganizationDetailRequest}, TContext> => { + +const mutationKey = ['organizationsCreate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {data: OrganizationDetailRequest}> = (props) => { + const {data} = props ?? {}; + + return organizationsCreate(data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type OrganizationsCreateMutationResult = NonNullable>> + export type OrganizationsCreateMutationBody = OrganizationDetailRequest + export type OrganizationsCreateMutationError = AxiosError + + export const useOrganizationsCreate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: OrganizationDetailRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {data: OrganizationDetailRequest}, + TContext + > => { + + const mutationOptions = getOrganizationsCreateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Get organization detail by ID. + */ +export const organizationsRetrieve = ( + orgId: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/organizations/${orgId}/`,options + ); + } + + + + +export const getOrganizationsRetrieveQueryKey = (orgId?: string,) => { + return [ + `/api/organizations/${orgId}/` + ] as const; + } + + +export const getOrganizationsRetrieveQueryOptions = >, TError = AxiosError>(orgId: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getOrganizationsRetrieveQueryKey(orgId); + + + + const queryFn: QueryFunction>> = ({ signal }) => organizationsRetrieve(orgId, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(orgId), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type OrganizationsRetrieveQueryResult = NonNullable>> +export type OrganizationsRetrieveQueryError = AxiosError + + +export function useOrganizationsRetrieve>, TError = AxiosError>( + orgId: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useOrganizationsRetrieve>, TError = AxiosError>( + orgId: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useOrganizationsRetrieve>, TError = AxiosError>( + orgId: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useOrganizationsRetrieve>, TError = AxiosError>( + orgId: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getOrganizationsRetrieveQueryOptions(orgId,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Update organization (owner/admin only). + */ +export const organizationsUpdate = ( + orgId: string, + organizationDetailRequest: OrganizationDetailRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.put( + `/api/organizations/${orgId}/`, + organizationDetailRequest,options + ); + } + + + +export const getOrganizationsUpdateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{orgId: string;data: OrganizationDetailRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{orgId: string;data: OrganizationDetailRequest}, TContext> => { + +const mutationKey = ['organizationsUpdate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {orgId: string;data: OrganizationDetailRequest}> = (props) => { + const {orgId,data} = props ?? {}; + + return organizationsUpdate(orgId,data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type OrganizationsUpdateMutationResult = NonNullable>> + export type OrganizationsUpdateMutationBody = OrganizationDetailRequest + export type OrganizationsUpdateMutationError = AxiosError + + export const useOrganizationsUpdate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{orgId: string;data: OrganizationDetailRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {orgId: string;data: OrganizationDetailRequest}, + TContext + > => { + + const mutationOptions = getOrganizationsUpdateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Partially update organization (owner/admin only). + */ +export const organizationsPartialUpdate = ( + orgId: string, + patchedOrganizationDetailRequest: PatchedOrganizationDetailRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.patch( + `/api/organizations/${orgId}/`, + patchedOrganizationDetailRequest,options + ); + } + + + +export const getOrganizationsPartialUpdateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{orgId: string;data: PatchedOrganizationDetailRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{orgId: string;data: PatchedOrganizationDetailRequest}, TContext> => { + +const mutationKey = ['organizationsPartialUpdate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {orgId: string;data: PatchedOrganizationDetailRequest}> = (props) => { + const {orgId,data} = props ?? {}; + + return organizationsPartialUpdate(orgId,data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type OrganizationsPartialUpdateMutationResult = NonNullable>> + export type OrganizationsPartialUpdateMutationBody = PatchedOrganizationDetailRequest + export type OrganizationsPartialUpdateMutationError = AxiosError + + export const useOrganizationsPartialUpdate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{orgId: string;data: PatchedOrganizationDetailRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {orgId: string;data: PatchedOrganizationDetailRequest}, + TContext + > => { + + const mutationOptions = getOrganizationsPartialUpdateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Soft-delete an organization (owner/admin only). + */ +export const organizationsDestroy = ( + orgId: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.delete( + `/api/organizations/${orgId}/`,options + ); + } + + + +export const getOrganizationsDestroyMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{orgId: string}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{orgId: string}, TContext> => { + +const mutationKey = ['organizationsDestroy']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {orgId: string}> = (props) => { + const {orgId} = props ?? {}; + + return organizationsDestroy(orgId,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type OrganizationsDestroyMutationResult = NonNullable>> + + export type OrganizationsDestroyMutationError = AxiosError + + export const useOrganizationsDestroy = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{orgId: string}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {orgId: string}, + TContext + > => { + + const mutationOptions = getOrganizationsDestroyMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * GET: List organization invites (admin/owner only). POST: Create a new invite (admin/owner only). + */ +export const organizationsInvitesRetrieve = ( + orgId: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/organizations/${orgId}/invites/`,options + ); + } + + + + +export const getOrganizationsInvitesRetrieveQueryKey = (orgId?: string,) => { + return [ + `/api/organizations/${orgId}/invites/` + ] as const; + } + + +export const getOrganizationsInvitesRetrieveQueryOptions = >, TError = AxiosError>(orgId: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getOrganizationsInvitesRetrieveQueryKey(orgId); + + + + const queryFn: QueryFunction>> = ({ signal }) => organizationsInvitesRetrieve(orgId, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(orgId), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type OrganizationsInvitesRetrieveQueryResult = NonNullable>> +export type OrganizationsInvitesRetrieveQueryError = AxiosError + + +export function useOrganizationsInvitesRetrieve>, TError = AxiosError>( + orgId: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useOrganizationsInvitesRetrieve>, TError = AxiosError>( + orgId: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useOrganizationsInvitesRetrieve>, TError = AxiosError>( + orgId: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useOrganizationsInvitesRetrieve>, TError = AxiosError>( + orgId: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getOrganizationsInvitesRetrieveQueryOptions(orgId,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * GET: List organization invites (admin/owner only). POST: Create a new invite (admin/owner only). + */ +export const organizationsInvitesCreate = ( + orgId: string, + organizationDetailRequest: OrganizationDetailRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.post( + `/api/organizations/${orgId}/invites/`, + organizationDetailRequest,options + ); + } + + + +export const getOrganizationsInvitesCreateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{orgId: string;data: OrganizationDetailRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{orgId: string;data: OrganizationDetailRequest}, TContext> => { + +const mutationKey = ['organizationsInvitesCreate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {orgId: string;data: OrganizationDetailRequest}> = (props) => { + const {orgId,data} = props ?? {}; + + return organizationsInvitesCreate(orgId,data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type OrganizationsInvitesCreateMutationResult = NonNullable>> + export type OrganizationsInvitesCreateMutationBody = OrganizationDetailRequest + export type OrganizationsInvitesCreateMutationError = AxiosError + + export const useOrganizationsInvitesCreate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{orgId: string;data: OrganizationDetailRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {orgId: string;data: OrganizationDetailRequest}, + TContext + > => { + + const mutationOptions = getOrganizationsInvitesCreateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Revoke an active invite by its UUID (admin/owner only). + */ +export const organizationsInvitesDestroy = ( + orgId: string, + inviteId: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.delete( + `/api/organizations/${orgId}/invites/${inviteId}/`,options + ); + } + + + +export const getOrganizationsInvitesDestroyMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{orgId: string;inviteId: string}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{orgId: string;inviteId: string}, TContext> => { + +const mutationKey = ['organizationsInvitesDestroy']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {orgId: string;inviteId: string}> = (props) => { + const {orgId,inviteId} = props ?? {}; + + return organizationsInvitesDestroy(orgId,inviteId,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type OrganizationsInvitesDestroyMutationResult = NonNullable>> + + export type OrganizationsInvitesDestroyMutationError = AxiosError + + export const useOrganizationsInvitesDestroy = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{orgId: string;inviteId: string}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {orgId: string;inviteId: string}, + TContext + > => { + + const mutationOptions = getOrganizationsInvitesDestroyMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * GET: List all members. POST: Add a member (admin/owner only). + */ +export const organizationsMembersRetrieve = ( + orgId: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/organizations/${orgId}/members/`,options + ); + } + + + + +export const getOrganizationsMembersRetrieveQueryKey = (orgId?: string,) => { + return [ + `/api/organizations/${orgId}/members/` + ] as const; + } + + +export const getOrganizationsMembersRetrieveQueryOptions = >, TError = AxiosError>(orgId: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getOrganizationsMembersRetrieveQueryKey(orgId); + + + + const queryFn: QueryFunction>> = ({ signal }) => organizationsMembersRetrieve(orgId, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(orgId), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type OrganizationsMembersRetrieveQueryResult = NonNullable>> +export type OrganizationsMembersRetrieveQueryError = AxiosError + + +export function useOrganizationsMembersRetrieve>, TError = AxiosError>( + orgId: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useOrganizationsMembersRetrieve>, TError = AxiosError>( + orgId: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useOrganizationsMembersRetrieve>, TError = AxiosError>( + orgId: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useOrganizationsMembersRetrieve>, TError = AxiosError>( + orgId: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getOrganizationsMembersRetrieveQueryOptions(orgId,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * GET: List all members. POST: Add a member (admin/owner only). + */ +export const organizationsMembersCreate = ( + orgId: string, + organizationDetailRequest: OrganizationDetailRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.post( + `/api/organizations/${orgId}/members/`, + organizationDetailRequest,options + ); + } + + + +export const getOrganizationsMembersCreateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{orgId: string;data: OrganizationDetailRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{orgId: string;data: OrganizationDetailRequest}, TContext> => { + +const mutationKey = ['organizationsMembersCreate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {orgId: string;data: OrganizationDetailRequest}> = (props) => { + const {orgId,data} = props ?? {}; + + return organizationsMembersCreate(orgId,data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type OrganizationsMembersCreateMutationResult = NonNullable>> + export type OrganizationsMembersCreateMutationBody = OrganizationDetailRequest + export type OrganizationsMembersCreateMutationError = AxiosError + + export const useOrganizationsMembersCreate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{orgId: string;data: OrganizationDetailRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {orgId: string;data: OrganizationDetailRequest}, + TContext + > => { + + const mutationOptions = getOrganizationsMembersCreateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * PUT: Update a member's role (admin/owner only). DELETE: Remove a member. + */ +export const organizationsMembersUpdate = ( + orgId: string, + username: string, + organizationDetailRequest: OrganizationDetailRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.put( + `/api/organizations/${orgId}/members/${username}/`, + organizationDetailRequest,options + ); + } + + + +export const getOrganizationsMembersUpdateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{orgId: string;username: string;data: OrganizationDetailRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{orgId: string;username: string;data: OrganizationDetailRequest}, TContext> => { + +const mutationKey = ['organizationsMembersUpdate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {orgId: string;username: string;data: OrganizationDetailRequest}> = (props) => { + const {orgId,username,data} = props ?? {}; + + return organizationsMembersUpdate(orgId,username,data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type OrganizationsMembersUpdateMutationResult = NonNullable>> + export type OrganizationsMembersUpdateMutationBody = OrganizationDetailRequest + export type OrganizationsMembersUpdateMutationError = AxiosError + + export const useOrganizationsMembersUpdate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{orgId: string;username: string;data: OrganizationDetailRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {orgId: string;username: string;data: OrganizationDetailRequest}, + TContext + > => { + + const mutationOptions = getOrganizationsMembersUpdateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * PUT: Update a member's role (admin/owner only). DELETE: Remove a member. + */ +export const organizationsMembersDestroy = ( + orgId: string, + username: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.delete( + `/api/organizations/${orgId}/members/${username}/`,options + ); + } + + + +export const getOrganizationsMembersDestroyMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{orgId: string;username: string}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{orgId: string;username: string}, TContext> => { + +const mutationKey = ['organizationsMembersDestroy']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {orgId: string;username: string}> = (props) => { + const {orgId,username} = props ?? {}; + + return organizationsMembersDestroy(orgId,username,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type OrganizationsMembersDestroyMutationResult = NonNullable>> + + export type OrganizationsMembersDestroyMutationError = AxiosError + + export const useOrganizationsMembersDestroy = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{orgId: string;username: string}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {orgId: string;username: string}, + TContext + > => { + + const mutationOptions = getOrganizationsMembersDestroyMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + \ No newline at end of file diff --git a/frontend/src/api/spectral-records/spectral-records.ts b/frontend/src/api/spectral-records/spectral-records.ts new file mode 100644 index 0000000..4264749 --- /dev/null +++ b/frontend/src/api/spectral-records/spectral-records.ts @@ -0,0 +1,750 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import { + useMutation, + useQuery +} from '@tanstack/react-query'; +import type { + DataTag, + DefinedInitialDataOptions, + DefinedUseQueryResult, + MutationFunction, + QueryClient, + QueryFunction, + QueryKey, + UndefinedInitialDataOptions, + UseMutationOptions, + UseMutationResult, + UseQueryOptions, + UseQueryResult +} from '@tanstack/react-query'; + +import * as axios from 'axios'; +import type { + AxiosError, + AxiosRequestConfig, + AxiosResponse +} from 'axios'; + +import type { + PaginatedSpectralRecordArtifactList, + PaginatedSpectralRecordList, + PatchedSpectralRecordUpdateRequest, + SpectralRecord, + SpectralRecordArtifact, + SpectralRecordArtifactsListParams, + SpectralRecordCreate, + SpectralRecordCreateRequest, + SpectralRecordUpdate, + SpectralRecordsListParams +} from '.././model'; + + + + + +/** + * List spectral record artifacts accessible to the current user. + */ +export const spectralRecordArtifactsList = ( + params?: SpectralRecordArtifactsListParams, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/spectral-record-artifacts/`,{ + ...options, + params: {...params, ...options?.params},} + ); + } + + + + +export const getSpectralRecordArtifactsListQueryKey = (params?: SpectralRecordArtifactsListParams,) => { + return [ + `/api/spectral-record-artifacts/`, ...(params ? [params]: []) + ] as const; + } + + +export const getSpectralRecordArtifactsListQueryOptions = >, TError = AxiosError>(params?: SpectralRecordArtifactsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getSpectralRecordArtifactsListQueryKey(params); + + + + const queryFn: QueryFunction>> = ({ signal }) => spectralRecordArtifactsList(params, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type SpectralRecordArtifactsListQueryResult = NonNullable>> +export type SpectralRecordArtifactsListQueryError = AxiosError + + +export function useSpectralRecordArtifactsList>, TError = AxiosError>( + params: undefined | SpectralRecordArtifactsListParams, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useSpectralRecordArtifactsList>, TError = AxiosError>( + params?: SpectralRecordArtifactsListParams, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useSpectralRecordArtifactsList>, TError = AxiosError>( + params?: SpectralRecordArtifactsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useSpectralRecordArtifactsList>, TError = AxiosError>( + params?: SpectralRecordArtifactsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getSpectralRecordArtifactsListQueryOptions(params,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Get spectral record artifact detail. + */ +export const spectralRecordArtifactsRetrieve = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/spectral-record-artifacts/${id}/`,options + ); + } + + + + +export const getSpectralRecordArtifactsRetrieveQueryKey = (id?: string,) => { + return [ + `/api/spectral-record-artifacts/${id}/` + ] as const; + } + + +export const getSpectralRecordArtifactsRetrieveQueryOptions = >, TError = AxiosError>(id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getSpectralRecordArtifactsRetrieveQueryKey(id); + + + + const queryFn: QueryFunction>> = ({ signal }) => spectralRecordArtifactsRetrieve(id, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(id), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type SpectralRecordArtifactsRetrieveQueryResult = NonNullable>> +export type SpectralRecordArtifactsRetrieveQueryError = AxiosError + + +export function useSpectralRecordArtifactsRetrieve>, TError = AxiosError>( + id: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useSpectralRecordArtifactsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useSpectralRecordArtifactsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useSpectralRecordArtifactsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getSpectralRecordArtifactsRetrieveQueryOptions(id,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * List spectral records accessible to the current user. + */ +export const spectralRecordsList = ( + params?: SpectralRecordsListParams, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/spectral-records/`,{ + ...options, + params: {...params, ...options?.params},} + ); + } + + + + +export const getSpectralRecordsListQueryKey = (params?: SpectralRecordsListParams,) => { + return [ + `/api/spectral-records/`, ...(params ? [params]: []) + ] as const; + } + + +export const getSpectralRecordsListQueryOptions = >, TError = AxiosError>(params?: SpectralRecordsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getSpectralRecordsListQueryKey(params); + + + + const queryFn: QueryFunction>> = ({ signal }) => spectralRecordsList(params, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type SpectralRecordsListQueryResult = NonNullable>> +export type SpectralRecordsListQueryError = AxiosError + + +export function useSpectralRecordsList>, TError = AxiosError>( + params: undefined | SpectralRecordsListParams, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useSpectralRecordsList>, TError = AxiosError>( + params?: SpectralRecordsListParams, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useSpectralRecordsList>, TError = AxiosError>( + params?: SpectralRecordsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useSpectralRecordsList>, TError = AxiosError>( + params?: SpectralRecordsListParams, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getSpectralRecordsListQueryOptions(params,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Create a spectral record. Supply owner (org UUID) — user must be admin/owner of the organization. + */ +export const spectralRecordsCreate = ( + spectralRecordCreateRequest: SpectralRecordCreateRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.post( + `/api/spectral-records/`, + spectralRecordCreateRequest,options + ); + } + + + +export const getSpectralRecordsCreateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: SpectralRecordCreateRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{data: SpectralRecordCreateRequest}, TContext> => { + +const mutationKey = ['spectralRecordsCreate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {data: SpectralRecordCreateRequest}> = (props) => { + const {data} = props ?? {}; + + return spectralRecordsCreate(data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type SpectralRecordsCreateMutationResult = NonNullable>> + export type SpectralRecordsCreateMutationBody = SpectralRecordCreateRequest + export type SpectralRecordsCreateMutationError = AxiosError + + export const useSpectralRecordsCreate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{data: SpectralRecordCreateRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {data: SpectralRecordCreateRequest}, + TContext + > => { + + const mutationOptions = getSpectralRecordsCreateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Get spectral record detail. + */ +export const spectralRecordsRetrieve = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/spectral-records/${id}/`,options + ); + } + + + + +export const getSpectralRecordsRetrieveQueryKey = (id?: string,) => { + return [ + `/api/spectral-records/${id}/` + ] as const; + } + + +export const getSpectralRecordsRetrieveQueryOptions = >, TError = AxiosError>(id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getSpectralRecordsRetrieveQueryKey(id); + + + + const queryFn: QueryFunction>> = ({ signal }) => spectralRecordsRetrieve(id, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(id), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type SpectralRecordsRetrieveQueryResult = NonNullable>> +export type SpectralRecordsRetrieveQueryError = AxiosError + + +export function useSpectralRecordsRetrieve>, TError = AxiosError>( + id: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useSpectralRecordsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useSpectralRecordsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useSpectralRecordsRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getSpectralRecordsRetrieveQueryOptions(id,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Update editable fields of a spectral record. + */ +export const spectralRecordsPartialUpdate = ( + id: string, + patchedSpectralRecordUpdateRequest: PatchedSpectralRecordUpdateRequest, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.patch( + `/api/spectral-records/${id}/`, + patchedSpectralRecordUpdateRequest,options + ); + } + + + +export const getSpectralRecordsPartialUpdateMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: PatchedSpectralRecordUpdateRequest}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string;data: PatchedSpectralRecordUpdateRequest}, TContext> => { + +const mutationKey = ['spectralRecordsPartialUpdate']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string;data: PatchedSpectralRecordUpdateRequest}> = (props) => { + const {id,data} = props ?? {}; + + return spectralRecordsPartialUpdate(id,data,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type SpectralRecordsPartialUpdateMutationResult = NonNullable>> + export type SpectralRecordsPartialUpdateMutationBody = PatchedSpectralRecordUpdateRequest + export type SpectralRecordsPartialUpdateMutationError = AxiosError + + export const useSpectralRecordsPartialUpdate = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string;data: PatchedSpectralRecordUpdateRequest}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string;data: PatchedSpectralRecordUpdateRequest}, + TContext + > => { + + const mutationOptions = getSpectralRecordsPartialUpdateMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Soft-delete a spectral record (org admin/owner only). + */ +export const spectralRecordsDestroy = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.delete( + `/api/spectral-records/${id}/`,options + ); + } + + + +export const getSpectralRecordsDestroyMutationOptions = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string}, TContext>, axios?: AxiosRequestConfig} +): UseMutationOptions>, TError,{id: string}, TContext> => { + +const mutationKey = ['spectralRecordsDestroy']; +const {mutation: mutationOptions, axios: axiosOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, axios: undefined}; + + + + + const mutationFn: MutationFunction>, {id: string}> = (props) => { + const {id} = props ?? {}; + + return spectralRecordsDestroy(id,axiosOptions) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type SpectralRecordsDestroyMutationResult = NonNullable>> + + export type SpectralRecordsDestroyMutationError = AxiosError + + export const useSpectralRecordsDestroy = , + TContext = unknown>(options?: { mutation?:UseMutationOptions>, TError,{id: string}, TContext>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {id: string}, + TContext + > => { + + const mutationOptions = getSpectralRecordsDestroyMutationOptions(options); + + return useMutation(mutationOptions, queryClient); + } + /** + * Get counts-per-second evolution over time from Parquet artifact. + */ +export const spectralRecordsEvolutionRetrieve = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/spectral-records/${id}/evolution/`,options + ); + } + + + + +export const getSpectralRecordsEvolutionRetrieveQueryKey = (id?: string,) => { + return [ + `/api/spectral-records/${id}/evolution/` + ] as const; + } + + +export const getSpectralRecordsEvolutionRetrieveQueryOptions = >, TError = AxiosError>(id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getSpectralRecordsEvolutionRetrieveQueryKey(id); + + + + const queryFn: QueryFunction>> = ({ signal }) => spectralRecordsEvolutionRetrieve(id, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(id), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type SpectralRecordsEvolutionRetrieveQueryResult = NonNullable>> +export type SpectralRecordsEvolutionRetrieveQueryError = AxiosError + + +export function useSpectralRecordsEvolutionRetrieve>, TError = AxiosError>( + id: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useSpectralRecordsEvolutionRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useSpectralRecordsEvolutionRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useSpectralRecordsEvolutionRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getSpectralRecordsEvolutionRetrieveQueryOptions(id,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + +/** + * Get energy/channel spectrum (sum over all exposures) from Parquet artifact. + */ +export const spectralRecordsSpectrumRetrieve = ( + id: string, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/spectral-records/${id}/spectrum/`,options + ); + } + + + + +export const getSpectralRecordsSpectrumRetrieveQueryKey = (id?: string,) => { + return [ + `/api/spectral-records/${id}/spectrum/` + ] as const; + } + + +export const getSpectralRecordsSpectrumRetrieveQueryOptions = >, TError = AxiosError>(id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getSpectralRecordsSpectrumRetrieveQueryKey(id); + + + + const queryFn: QueryFunction>> = ({ signal }) => spectralRecordsSpectrumRetrieve(id, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(id), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type SpectralRecordsSpectrumRetrieveQueryResult = NonNullable>> +export type SpectralRecordsSpectrumRetrieveQueryError = AxiosError + + +export function useSpectralRecordsSpectrumRetrieve>, TError = AxiosError>( + id: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useSpectralRecordsSpectrumRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useSpectralRecordsSpectrumRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useSpectralRecordsSpectrumRetrieve>, TError = AxiosError>( + id: string, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getSpectralRecordsSpectrumRetrieveQueryOptions(id,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + diff --git a/frontend/src/api/system/system.ts b/frontend/src/api/system/system.ts new file mode 100644 index 0000000..adfd178 --- /dev/null +++ b/frontend/src/api/system/system.ts @@ -0,0 +1,120 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import { + useQuery +} from '@tanstack/react-query'; +import type { + DataTag, + DefinedInitialDataOptions, + DefinedUseQueryResult, + QueryClient, + QueryFunction, + QueryKey, + UndefinedInitialDataOptions, + UseQueryOptions, + UseQueryResult +} from '@tanstack/react-query'; + +import * as axios from 'axios'; +import type { + AxiosError, + AxiosRequestConfig, + AxiosResponse +} from 'axios'; + + + + + +/** + * Get API version and git information + */ +export const versionRetrieve = ( + options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/version/`,options + ); + } + + + + +export const getVersionRetrieveQueryKey = () => { + return [ + `/api/version/` + ] as const; + } + + +export const getVersionRetrieveQueryOptions = >, TError = AxiosError>( options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getVersionRetrieveQueryKey(); + + + + const queryFn: QueryFunction>> = ({ signal }) => versionRetrieve({ signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type VersionRetrieveQueryResult = NonNullable>> +export type VersionRetrieveQueryError = AxiosError + + +export function useVersionRetrieve>, TError = AxiosError>( + options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useVersionRetrieve>, TError = AxiosError>( + options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useVersionRetrieve>, TError = AxiosError>( + options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useVersionRetrieve>, TError = AxiosError>( + options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getVersionRetrieveQueryOptions(options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + diff --git a/frontend/src/api/users/users.ts b/frontend/src/api/users/users.ts new file mode 100644 index 0000000..da60686 --- /dev/null +++ b/frontend/src/api/users/users.ts @@ -0,0 +1,124 @@ +/** + * Generated by orval v7.21.0 🍺 + * Do not edit manually. + * DOSPORTAL API + * API Documentation for DOSPORTAL + * OpenAPI spec version: 1.0.0 + */ +import { + useQuery +} from '@tanstack/react-query'; +import type { + DataTag, + DefinedInitialDataOptions, + DefinedUseQueryResult, + QueryClient, + QueryFunction, + QueryKey, + UndefinedInitialDataOptions, + UseQueryOptions, + UseQueryResult +} from '@tanstack/react-query'; + +import * as axios from 'axios'; +import type { + AxiosError, + AxiosRequestConfig, + AxiosResponse +} from 'axios'; + +import type { + UserSummary +} from '.././model'; + + + + + +/** + * Get public user information by ID + */ +export const userRetrieve = ( + userId: number, options?: AxiosRequestConfig + ): Promise> => { + + + return axios.default.get( + `/api/user/${userId}/`,options + ); + } + + + + +export const getUserRetrieveQueryKey = (userId?: number,) => { + return [ + `/api/user/${userId}/` + ] as const; + } + + +export const getUserRetrieveQueryOptions = >, TError = AxiosError>(userId: number, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} +) => { + +const {query: queryOptions, axios: axiosOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getUserRetrieveQueryKey(userId); + + + + const queryFn: QueryFunction>> = ({ signal }) => userRetrieve(userId, { signal, ...axiosOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(userId), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type UserRetrieveQueryResult = NonNullable>> +export type UserRetrieveQueryError = AxiosError + + +export function useUserRetrieve>, TError = AxiosError>( + userId: number, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useUserRetrieve>, TError = AxiosError>( + userId: number, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useUserRetrieve>, TError = AxiosError>( + userId: number, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } + +export function useUserRetrieve>, TError = AxiosError>( + userId: number, options?: { query?:Partial>, TError, TData>>, axios?: AxiosRequestConfig} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getUserRetrieveQueryOptions(userId,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + query.queryKey = queryOptions.queryKey ; + + return query; +} + + + + diff --git a/frontend/src/app/App.tsx b/frontend/src/app/App.tsx new file mode 100644 index 0000000..cfe52ff --- /dev/null +++ b/frontend/src/app/App.tsx @@ -0,0 +1,24 @@ +import { RouterProvider } from 'react-router-dom' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import '../App.css' +import { AuthProvider } from '@/features/auth/context/AuthProvider' +import { router } from './router' +import { Toaster } from '@/components/ui/sonner' +import { ThemeProvider } from '@/components/theme-provider' + +const queryClient = new QueryClient() + +function App() { + return ( + + + + + + + + + ) +} + +export default App diff --git a/frontend/src/app/RouterLayout.tsx b/frontend/src/app/RouterLayout.tsx new file mode 100644 index 0000000..3edc390 --- /dev/null +++ b/frontend/src/app/RouterLayout.tsx @@ -0,0 +1,9 @@ +import { Outlet } from 'react-router-dom' +import { Layout } from '@/shared/components/Layout/Layout' +import { useAuthContext } from '@/features/auth/hooks/useAuthContext' + +export function RouterLayout() { + const { isLoading } = useAuthContext() + if (isLoading) return null + return +} diff --git a/frontend/src/app/router.tsx b/frontend/src/app/router.tsx new file mode 100644 index 0000000..d9acd74 --- /dev/null +++ b/frontend/src/app/router.tsx @@ -0,0 +1,61 @@ +import { createBrowserRouter, Navigate } from 'react-router-dom' +import { RouterLayout } from './RouterLayout' +import { ProtectedRoute } from '@/features/auth/ProtectedRoute' +import { GuestRoute } from '@/features/auth/GuestRoute' +import { HomePage } from '@/pages/HomePage' +import { LoginPage } from '@/features/auth/pages/LoginPage' +import { SignupPage } from '@/features/auth/pages/SignupPage' +import { SignupSuccessPage } from '@/features/auth/pages/SignupSuccessPage' +import { InviteAcceptPage } from '@/features/organization/pages/InviteAcceptPage' +import { LogbooksPage } from '@/features/devices/pages/LogbooksPage' +import { DevicePage } from '@/features/devices/pages/DevicePage' +import { LogbookEntryPage } from '@/features/devices/pages/LogbookEntryPage' +import { ProfilePage } from '@/features/organization/pages/ProfilePage' +import { CreateOrganizationPage } from '@/features/organization/pages/CreateOrganizationPage' +import { OrganizationDetailPage } from '@/features/organization/pages/OrganizationDetailPage' +import { DetectorCreatePage } from '@/features/devices/pages/DetectorCreatePage' +import { LogsUploadPage } from '@/features/logs/pages/LogsUploadPage' +import { MeasurementsPage } from '@/features/measurements/pages/MeasurementsPage' +import { MeasurementDetailPage } from '@/features/measurements/pages/MeasurementDetailPage' +import { LogsPage } from '@/features/logs/pages/LogsPage' +import { SpectralRecordStatusPage } from '@/features/logs/pages/SpectralRecordStatusPage' +import { SpectralRecordDetailPage } from '@/features/logs/pages/SpectralRecordDetailPage' +import { AirportDetailPage } from '@/features/flights/pages/AirportDetailPage' +import { UserDetailPage } from '@/features/organization/pages/UserDetailPage' +import { MeasurementCreatePage } from '@/features/measurements/pages/MeasurementCreatePage' +import { MeasurementEditorPage } from '@/features/measurements/pages/MeasurementEditorPage' +import { MeasurementStatusPage } from '@/features/measurements/pages/MeasurementStatusPage' + + +export const router = createBrowserRouter([ + { + element: , + children: [ + { path: '/login', element: }, + { path: '/signup', element: }, + { path: '/signup/success', element: }, + { path: '/', element: }, + { path: '/devices', element: }, + { path: '/device/:id', element: }, + { path: '/device/:id/create', element: }, + { path: '/device/:id/edit/:entryId', element: }, + { path: '/device/create', element: }, + { path: '/profile', element: }, + { path: '/user/:id', element: }, + { path: '/organization/create', element: }, + { path: '/organization/:id', element: }, + { path: '/invite/:token', element: }, + { path: '/logs/upload', element: }, + { path: '/measurements', element: }, + { path: '/measurement/create', element: }, + { path: '/measurement/edit/:id', element: }, + { path: '/measurement/status/:id', element: }, + { path: '/measurement/:id', element: }, + { path: '/logs', element: }, + { path: '/spectral-record-status/:id', element: }, + { path: '/spectral-record/:id', element: }, + { path: '/airport/:id', element: }, + { path: '*', element: }, + ], + }, +]) diff --git a/frontend/src/components/AddOrganizationMemberPopup.tsx b/frontend/src/components/AddOrganizationMemberPopup.tsx deleted file mode 100644 index 634069e..0000000 --- a/frontend/src/components/AddOrganizationMemberPopup.tsx +++ /dev/null @@ -1,232 +0,0 @@ -import { useState, useEffect } from 'react'; -import { theme } from '../theme'; - -export const AddOrganizationMemberPopup = ({ - open, - onClose, - orgId, - apiBase, - getAuthHeader, - onMemberAdded, -}: { - open: boolean; - onClose: () => void; - orgId: string; - apiBase: string; - getAuthHeader: () => { Authorization?: string }; - onMemberAdded?: (username: string) => void; -}) => { - const [username, setUsername] = useState(''); - const [userType, setUserType] = useState('ME'); - const [inviteLink, setInviteLink] = useState(null); - const [mode, setMode] = useState<'form' | 'invite'>('form'); - const [copied, setCopied] = useState(false); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(false); - const [orgName, setOrgName] = useState(''); - - useEffect(() => { - if (!open) return; - setOrgName(''); - fetch(`${apiBase}/organizations/${orgId}/`, { - headers: { ...getAuthHeader() }, - }) - .then(async (res) => { - if (!res.ok) throw new Error('Failed to fetch organization'); - return res.json(); - }) - .then((data) => setOrgName(data.name || '')) - .catch(() => setOrgName('')); - }, [open, orgId, apiBase, getAuthHeader]); - - const handleAdd = async () => { - if (!username.trim()) return; - setLoading(true); - setError(null); - try { - const res = await fetch(`${apiBase}/organizations/${orgId}/member/`, { - method: 'POST', - headers: { 'Content-Type': 'application/json', ...getAuthHeader() }, - body: JSON.stringify({ username: username.trim(), user_type: userType }), - }); - const data = await res.json(); - if (!res.ok) throw new Error(data.detail || 'Failed to add member'); - if (onMemberAdded) onMemberAdded(username.trim()); - setUsername(''); - setUserType('ME'); - onClose(); - } catch (e: any) { - setError(e.message); - } finally { - setLoading(false); - } - }; - - const handleInvite = async () => { - setLoading(true); - setError(null); - try { - const res = await fetch(`${apiBase}/organizations/${orgId}/invites/`, { - method: 'POST', - headers: { 'Content-Type': 'application/json', ...getAuthHeader() }, - body: JSON.stringify({ user_type: userType }), - }); - const data = await res.json(); - if (!res.ok) throw new Error(data.detail || 'Failed to generate invite link'); - setInviteLink(window.location.origin + data.invite_url); - setMode('invite'); - } catch (e: any) { - setError(e.message); - } finally { - setLoading(false); - } - }; - - if (!open) return null; - - return ( -
-
- -

Add Member

- {mode === 'form' && ( - <> - setUsername(e.target.value)} - style={{ - width: '100%', - marginBottom: theme.spacing.md, - padding: theme.spacing.sm, - background: theme.colors.bg, - color: theme.colors.textDark, - border: `${theme.borders.width} solid ${theme.colors.mutedLighter}`, - borderRadius: theme.borders.radius.sm, - fontSize: theme.typography.fontSize.base, - boxSizing: 'border-box', - }} - disabled={loading} - /> - - {error &&
{error}
} -
- - -
- - )} - {mode === 'invite' && ( - <> -
- -
- Organization: {orgName || orgId}
- Role: {userType === 'ME' ? 'Member' : userType === 'AD' ? 'Admin' : userType}

- This invite link is valid for 24 hours and can be used once. Send it to your new member. -
-
-
- -
- - {copied && Copied!} -
-
- - )} -
-
- ); -}; diff --git a/frontend/src/components/CreateEntryButton.tsx b/frontend/src/components/CreateEntryButton.tsx deleted file mode 100644 index 89e7ed4..0000000 --- a/frontend/src/components/CreateEntryButton.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react' -import { Link } from 'react-router-dom' -import { theme } from '../theme' - -interface CreateEntryButtonProps { - onClick?: () => void - to?: string // optional: for react-router link - children?: React.ReactNode - style?: React.CSSProperties - className?: string -} - -export const CreateEntryButton: React.FC = ({ - onClick, - to, - children = '+ Create Entry', - style = {}, - className = '', -}) => { - const baseStyle: React.CSSProperties = { - display: 'inline-block', - background: theme.colors.success, - color: 'white', - border: 'none', - borderRadius: theme.borders.radius.sm, - padding: `${theme.spacing.sm} ${theme.spacing.md}`, - fontWeight: theme.typography.fontWeight.medium, - fontSize: theme.typography.fontSize.base, - cursor: 'pointer', - textDecoration: 'none', - transition: theme.transitions.fast, - textAlign: 'center', - ...style, - } - if (to) { - return ( - - {children} - - ) - } - return ( - - ) -} diff --git a/frontend/src/components/EmptyState.tsx b/frontend/src/components/EmptyState.tsx deleted file mode 100644 index 7a0a1c6..0000000 --- a/frontend/src/components/EmptyState.tsx +++ /dev/null @@ -1,7 +0,0 @@ -interface EmptyStateProps { - message: string -} - -export const EmptyState = ({ message }: EmptyStateProps) => { - return

{message}

-} diff --git a/frontend/src/components/LabeledInput.tsx b/frontend/src/components/LabeledInput.tsx deleted file mode 100644 index a679ac1..0000000 --- a/frontend/src/components/LabeledInput.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import React from "react"; -import { theme } from "../theme"; - -interface LabeledInputProps { - id: string; - label: string; - value: string; - onChange: (e: React.ChangeEvent) => void; - placeholder?: string; - required?: boolean; - type?: string; - disabled?: boolean; - style?: React.CSSProperties; -} - -export const LabeledInput: React.FC = ({ - id, - label, - value, - onChange, - placeholder, - required = false, - type = "text", - disabled = false, - style = {}, -}) => ( -
- - -
-); diff --git a/frontend/src/components/Navbar.tsx b/frontend/src/components/Navbar.tsx deleted file mode 100644 index 294b5e7..0000000 --- a/frontend/src/components/Navbar.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { Link } from 'react-router-dom' - -export const Navbar = ({ - isAuthed, - onLogout, -}: { - isAuthed: boolean - onLogout: () => Promise -}) => { - return ( - - ) -} diff --git a/frontend/src/components/Section.tsx b/frontend/src/components/Section.tsx deleted file mode 100644 index dc9195e..0000000 --- a/frontend/src/components/Section.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import type { ReactNode } from 'react' - -interface SectionProps { - title?: string | ReactNode - children: ReactNode - style?: React.CSSProperties -} - -export const Section = ({ title, children, style }: SectionProps) => { - return ( -
- {title && ( -
- {typeof title === 'string' ?

{title}

: title} -
- )} -
- {children} -
-
- ) -} diff --git a/frontend/src/components/SpectralCharts.tsx b/frontend/src/components/SpectralCharts.tsx deleted file mode 100644 index 2d7f2b6..0000000 --- a/frontend/src/components/SpectralCharts.tsx +++ /dev/null @@ -1,222 +0,0 @@ -import { useState, useEffect, useRef } from 'react' -import ReactECharts from 'echarts-for-react' -import type { EChartsOption } from 'echarts' -import { theme } from '../theme' - -type EvolutionData = { - evolution_values: [number, number][] - total_time: number -} - -type SpectrumData = { - spectrum_values: [number, number][] - total_time: number - calib: boolean -} - -export const SpectralCharts = ({ - apiBase, - recordId, - getAuthHeader, -}: { - apiBase: string - recordId: string - getAuthHeader: () => { Authorization?: string } -}) => { - const [evolutionData, setEvolutionData] = useState(null) - const [spectrumData, setSpectrumData] = useState(null) - const [loading, setLoading] = useState(true) - const [error, setError] = useState(null) - const chartRef = useRef(null) - - useEffect(() => { - const headers = { - 'Content-Type': 'application/json', - ...getAuthHeader(), - } - - const fetchEvolution = fetch(`${apiBase}/spectral-record/${recordId}/evolution/`, { - method: 'GET', - headers, - }).then(res => { - if (!res.ok) throw new Error(`Evolution HTTP ${res.status}`) - return res.json() as Promise - }) - - const fetchSpectrum = fetch(`${apiBase}/spectral-record/${recordId}/spectrum/`, { - method: 'GET', - headers, - }).then(res => { - if (!res.ok) throw new Error(`Spectrum HTTP ${res.status}`) - return res.json() as Promise - }) - - Promise.all([fetchEvolution, fetchSpectrum]) - .then(([evo, spec]) => { - setEvolutionData(evo) - setSpectrumData(spec) - }) - .catch(e => { - setError(e instanceof Error ? e.message : 'Failed to load chart data') - }) - .finally(() => setLoading(false)) - }, [apiBase, recordId, getAuthHeader]) - - if (loading) { - return ( -
- Loading chart data... -
- ) - } - - if (error) { - return ( -
- Failed to load charts: {error} -
- ) - } - - if (!evolutionData || !spectrumData) return null - - const xAxisSpectrum = spectrumData.calib - ? { name: 'Energy [keV]', axisLabel: { formatter: '{value} keV' } } - : { name: 'Channel [#]', axisLabel: { formatter: '{value} ch' } } - - const option: EChartsOption = { - title: [ - { left: 'center', text: 'Counts evolution', top: '0%' }, - { left: 'center', text: 'Energy spectrum', top: '48%' }, - ], - tooltip: { - trigger: 'axis', - axisPointer: { type: 'cross' }, - }, - toolbox: { - right: 10, - feature: { - dataZoom: {}, - restore: {}, - saveAsImage: {}, - }, - }, - grid: [ - { left: '5%', right: '5%', height: '40%', bottom: '62%' }, - { left: '5%', right: '5%', height: '40%', bottom: '8%' }, - ], - dataZoom: [ - { type: 'inside', xAxisIndex: 0 }, - { type: 'inside', xAxisIndex: 1 }, - { - type: 'slider', - filterMode: 'empty', - realtime: true, - height: '5%', - bottom: '54%', - xAxisIndex: 0, - }, - { - type: 'slider', - filterMode: 'empty', - realtime: false, - height: '5%', - bottom: 0, - xAxisIndex: 1, - }, - ], - xAxis: [ - { - name: 'time', - type: 'value', - axisLabel: { formatter: '{value} s' }, - min: 'dataMin', - max: 'dataMax', - }, - { - gridIndex: 1, - type: 'value', - ...xAxisSpectrum, - min: 'dataMin', - max: 'dataMax', - }, - ], - yAxis: [ - { - axisLabel: { - formatter: (value: number) => value.toFixed(8).replace(/\.?0+$/, ''), - }, - min: 'dataMin', - max: 'dataMax', - name: 'Counts per second', - }, - { - axisLabel: { - formatter: (value: number) => value.toFixed(8).replace(/\.?0+$/, ''), - }, - gridIndex: 1, - min: 'dataMin', - max: 'dataMax', - name: 'Counts per second', - }, - ], - series: [ - { - id: 'evolution', - data: evolutionData.evolution_values, - type: 'scatter', - name: 'Counts per second', - xAxisIndex: 0, - yAxisIndex: 0, - symbol: 'rect', - symbolSize: 5, - itemStyle: { color: '#198754' }, - }, - { - id: 'spectrum-trend', - data: spectrumData.spectrum_values, - type: 'line', - xAxisIndex: 1, - yAxisIndex: 1, - symbol: 'none', - lineStyle: { color: '#0d6efd', opacity: 0.25, width: 2 }, - smooth: true, - z: 1, - emphasis: { disabled: true }, - tooltip: { show: false }, - }, - { - id: 'spectrum', - data: spectrumData.spectrum_values, - type: 'scatter', - name: 'Energetic spectrum', - xAxisIndex: 1, - yAxisIndex: 1, - symbolSize: 5, - itemStyle: { color: '#0d6dfdc8' }, - }, - ], - } - - return ( -
- -
- ) -} diff --git a/frontend/src/components/theme-provider.tsx b/frontend/src/components/theme-provider.tsx new file mode 100644 index 0000000..4a68078 --- /dev/null +++ b/frontend/src/components/theme-provider.tsx @@ -0,0 +1,6 @@ +import { ThemeProvider as NextThemesProvider } from 'next-themes' +import type { ThemeProviderProps } from 'next-themes' + +export function ThemeProvider({ children, ...props }: ThemeProviderProps) { + return {children} +} diff --git a/frontend/src/components/ui/button.tsx b/frontend/src/components/ui/button.tsx new file mode 100644 index 0000000..c88ffd6 --- /dev/null +++ b/frontend/src/components/ui/button.tsx @@ -0,0 +1,67 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" +import { Slot } from "radix-ui" + +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80", + outline: + "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground", + ghost: + "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50", + destructive: + "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: + "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2", + xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3", + sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5", + lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3", + icon: "size-8", + "icon-xs": + "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3", + "icon-sm": + "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg", + "icon-lg": "size-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +function Button({ + className, + variant = "default", + size = "default", + asChild = false, + ...props +}: React.ComponentProps<"button"> & + VariantProps & { + asChild?: boolean + }) { + const Comp = asChild ? Slot.Root : "button" + + return ( + + ) +} + +export { Button, buttonVariants } diff --git a/frontend/src/components/ui/navigation-menu.tsx b/frontend/src/components/ui/navigation-menu.tsx new file mode 100644 index 0000000..9ad9735 --- /dev/null +++ b/frontend/src/components/ui/navigation-menu.tsx @@ -0,0 +1,164 @@ +import * as React from "react" +import { cva } from "class-variance-authority" +import { NavigationMenu as NavigationMenuPrimitive } from "radix-ui" + +import { cn } from "@/lib/utils" +import { ChevronDownIcon } from "lucide-react" + +function NavigationMenu({ + className, + children, + viewport = true, + ...props +}: React.ComponentProps & { + viewport?: boolean +}) { + return ( + + {children} + {viewport && } + + ) +} + +function NavigationMenuList({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function NavigationMenuItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +const navigationMenuTriggerStyle = cva( + "group/navigation-menu-trigger inline-flex h-9 w-max items-center justify-center rounded-lg bg-background px-2.5 py-1.5 text-sm font-medium transition-all outline-none hover:bg-muted focus:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-popup-open:bg-muted/50 data-popup-open:hover:bg-muted data-open:bg-muted/50 data-open:hover:bg-muted data-open:focus:bg-muted" +) + +function NavigationMenuTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + {children}{" "} + + ) +} + +function NavigationMenuContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function NavigationMenuViewport({ + className, + ...props +}: React.ComponentProps) { + return ( +
+ +
+ ) +} + +function NavigationMenuLink({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function NavigationMenuIndicator({ + className, + ...props +}: React.ComponentProps) { + return ( + +
+ + ) +} + +export { + NavigationMenu, + NavigationMenuList, + NavigationMenuItem, + NavigationMenuContent, + NavigationMenuTrigger, + NavigationMenuLink, + NavigationMenuIndicator, + NavigationMenuViewport, + navigationMenuTriggerStyle, +} diff --git a/frontend/src/components/ui/sheet.tsx b/frontend/src/components/ui/sheet.tsx new file mode 100644 index 0000000..0536c7f --- /dev/null +++ b/frontend/src/components/ui/sheet.tsx @@ -0,0 +1,145 @@ +import * as React from "react" +import { Dialog as SheetPrimitive } from "radix-ui" + +import { cn } from "@/lib/utils" +import { Button } from "@/components/ui/button" +import { XIcon } from "lucide-react" + +function Sheet({ ...props }: React.ComponentProps) { + return +} + +function SheetTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function SheetClose({ + ...props +}: React.ComponentProps) { + return +} + +function SheetPortal({ + ...props +}: React.ComponentProps) { + return +} + +function SheetOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SheetContent({ + className, + children, + side = "right", + showCloseButton = true, + ...props +}: React.ComponentProps & { + side?: "top" | "right" | "bottom" | "left" + showCloseButton?: boolean +}) { + return ( + + + + {children} + {showCloseButton && ( + + + + )} + + + ) +} + +function SheetHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function SheetFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function SheetTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SheetDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + Sheet, + SheetTrigger, + SheetClose, + SheetContent, + SheetHeader, + SheetFooter, + SheetTitle, + SheetDescription, +} diff --git a/frontend/src/components/ui/sonner.tsx b/frontend/src/components/ui/sonner.tsx new file mode 100644 index 0000000..9772eb2 --- /dev/null +++ b/frontend/src/components/ui/sonner.tsx @@ -0,0 +1,47 @@ +import { useTheme } from "next-themes" +import { Toaster as Sonner, type ToasterProps } from "sonner" +import { CircleCheckIcon, InfoIcon, TriangleAlertIcon, OctagonXIcon, Loader2Icon } from "lucide-react" + +const Toaster = ({ ...props }: ToasterProps) => { + const { theme = "system" } = useTheme() + + return ( + + ), + info: ( + + ), + warning: ( + + ), + error: ( + + ), + loading: ( + + ), + }} + style={ + { + "--normal-bg": "var(--popover)", + "--normal-text": "var(--popover-foreground)", + "--normal-border": "var(--border)", + "--border-radius": "var(--radius)", + } as React.CSSProperties + } + toastOptions={{ + classNames: { + toast: "cn-toast", + }, + }} + {...props} + /> + ) +} + +export { Toaster } diff --git a/frontend/src/config.ts b/frontend/src/config.ts new file mode 100644 index 0000000..b0bfd25 --- /dev/null +++ b/frontend/src/config.ts @@ -0,0 +1,2 @@ +export const API_BASE = import.meta.env.VITE_API_URL || '/api' +export const ORIGIN_BASE = API_BASE.replace(/\/?api\/?$/, '') diff --git a/frontend/src/features/auth/GuestRoute.tsx b/frontend/src/features/auth/GuestRoute.tsx new file mode 100644 index 0000000..3e02a6f --- /dev/null +++ b/frontend/src/features/auth/GuestRoute.tsx @@ -0,0 +1,13 @@ +import { type ReactNode } from 'react' +import { Navigate } from 'react-router-dom' +import { useAuthContext } from './hooks/useAuthContext' + +export const GuestRoute = ({ children }: { children: ReactNode }) => { + const { isAuthed } = useAuthContext() + + if (isAuthed) { + return + } + + return <>{children} +} diff --git a/frontend/src/features/auth/ProtectedRoute.tsx b/frontend/src/features/auth/ProtectedRoute.tsx new file mode 100644 index 0000000..2d8439c --- /dev/null +++ b/frontend/src/features/auth/ProtectedRoute.tsx @@ -0,0 +1,18 @@ +import { type ReactNode } from 'react' +import { Navigate, useLocation } from 'react-router-dom' +import { useAuthContext } from './hooks/useAuthContext' + +export const ProtectedRoute = ({ children }: { children: ReactNode }) => { + const { isAuthed, isLoading } = useAuthContext() + const location = useLocation() + + if (isLoading) { + return null + } + + if (!isAuthed) { + return + } + + return <>{children} +} diff --git a/frontend/src/features/auth/context/AuthContext.ts b/frontend/src/features/auth/context/AuthContext.ts new file mode 100644 index 0000000..3acfd22 --- /dev/null +++ b/frontend/src/features/auth/context/AuthContext.ts @@ -0,0 +1,20 @@ +import { createContext } from 'react' + +export interface AuthContextValue { + isAuthed: boolean + isLoading: boolean + token: string | null + login: (username: string, password: string) => Promise + signup: ( + username: string, + firstName: string, + lastName: string, + password: string, + password_confirm: string, + email: string, + ) => Promise + logout: () => Promise + getAuthHeader: () => { Authorization?: string } +} + +export const AuthContext = createContext(null) diff --git a/frontend/src/features/auth/context/AuthProvider.tsx b/frontend/src/features/auth/context/AuthProvider.tsx new file mode 100644 index 0000000..78ebc4a --- /dev/null +++ b/frontend/src/features/auth/context/AuthProvider.tsx @@ -0,0 +1,92 @@ +import { useState, useEffect, useCallback, type ReactNode } from 'react' +import axios from 'axios' +import { loginCreate, logoutCreate, signupCreate } from '@/api/authentication/authentication' +import { AuthContext } from './AuthContext' + +export const AuthProvider = ({ children }: { children: ReactNode }) => { + const [isAuthed, setIsAuthed] = useState(false) + const [isLoading, setIsLoading] = useState(true) + const [token, setToken] = useState(null) + + const applyToken = useCallback((t: string | null) => { + if (t) { + axios.defaults.headers.common['Authorization'] = `Token ${t}` + } else { + delete axios.defaults.headers.common['Authorization'] + } + }, []) + + useEffect(() => { + const storedToken = localStorage.getItem('authToken') + if (storedToken) { + setToken(storedToken) + applyToken(storedToken) + setIsAuthed(true) + } + setIsLoading(false) + }, [applyToken]) + + const login = async (username: string, password: string) => { + try { + const res = await loginCreate({ username, password }) + const newToken = res.data.token + localStorage.setItem('authToken', newToken) + setToken(newToken) + applyToken(newToken) + setIsAuthed(true) + } catch (err) { + if (axios.isAxiosError(err)) { + throw new Error(err.response?.data?.detail || 'Login failed') + } + throw new Error('Login failed') + } + } + + const signup = async ( + username: string, + firstName: string, + lastName: string, + password: string, + password_confirm: string, + email: string, + ) => { + try { + await signupCreate({ + username, + first_name: firstName, + last_name: lastName, + email, + password, + password_confirm, + }) + } catch (err) { + if (axios.isAxiosError(err)) { + throw new Error(err.response?.data?.detail || 'Signup failed') + } + throw new Error('Signup failed') + } + } + + const logout = async () => { + try { + await logoutCreate() + } catch (e) { + console.error('Logout error:', e) + } finally { + localStorage.removeItem('authToken') + setToken(null) + applyToken(null) + setIsAuthed(false) + } + } + + const getAuthHeader = useCallback((): { Authorization?: string } => { + return token ? { Authorization: `Token ${token}` } : {} + }, [token]) + + return ( + + {children} + + ) +} diff --git a/frontend/src/features/auth/hooks/useAuth.ts b/frontend/src/features/auth/hooks/useAuth.ts new file mode 100644 index 0000000..b9bbd2f --- /dev/null +++ b/frontend/src/features/auth/hooks/useAuth.ts @@ -0,0 +1,2 @@ + +export { useAuthContext as useAuth } from './useAuthContext' diff --git a/frontend/src/features/auth/hooks/useAuthContext.ts b/frontend/src/features/auth/hooks/useAuthContext.ts new file mode 100644 index 0000000..697f0b5 --- /dev/null +++ b/frontend/src/features/auth/hooks/useAuthContext.ts @@ -0,0 +1,12 @@ +import { useContext } from 'react' +import { AuthContext } from '../context/AuthContext' + +type AuthContextValue = NonNullable> + +export const useAuthContext = (): AuthContextValue => { + const ctx = useContext(AuthContext) + if (!ctx) { + throw new Error('useAuthContext must be used inside AuthProvider') + } + return ctx +} diff --git a/frontend/src/pages/LoginPage.tsx b/frontend/src/features/auth/pages/LoginPage.tsx similarity index 83% rename from frontend/src/pages/LoginPage.tsx rename to frontend/src/features/auth/pages/LoginPage.tsx index 6af5402..feed378 100644 --- a/frontend/src/pages/LoginPage.tsx +++ b/frontend/src/features/auth/pages/LoginPage.tsx @@ -1,12 +1,10 @@ import { useState } from 'react' -import loginBg from '../assets/img/login_background.jpg' +import loginBg from '../../../assets/img/login_background.jpg' +import { useAuthContext } from '@/features/auth/hooks/useAuthContext' +import { Button } from '@/shared/components/Button/Button' -export const LoginPage = ({ - onLogin, -}: { - originBase: string - onLogin: (username: string, password: string) => Promise -}) => { +export const LoginPage = () => { + const { login } = useAuthContext() const [username, setUsername] = useState('') const [password, setPassword] = useState('') const [status, setStatus] = useState<'idle' | 'loading' | 'error' | 'success'>('idle') @@ -17,11 +15,11 @@ export const LoginPage = ({ setStatus('loading') setError(null) try { - await onLogin(username, password) + await login(username, password) setStatus('success') - } catch (err: any) { + } catch (err) { setStatus('error') - setError(err.message) + setError(err instanceof Error ? err.message : 'Login failed') } } @@ -84,9 +82,10 @@ export const LoginPage = ({ />
- + + diff --git a/frontend/src/pages/SignupPage.tsx b/frontend/src/features/auth/pages/SignupPage.tsx similarity index 89% rename from frontend/src/pages/SignupPage.tsx rename to frontend/src/features/auth/pages/SignupPage.tsx index baeea85..02a1eba 100644 --- a/frontend/src/pages/SignupPage.tsx +++ b/frontend/src/features/auth/pages/SignupPage.tsx @@ -1,21 +1,12 @@ import { useState } from 'react' import { useNavigate } from 'react-router-dom' -import loginBg from '../assets/img/login_background.jpg' -import { theme } from '../theme' +import loginBg from '../../../assets/img/login_background.jpg' +import { theme } from '@/theme' +import { useAuthContext } from '@/features/auth/hooks/useAuthContext' +import { Button } from '@/shared/components/Button/Button' -export const SignupPage = ({ - onSignup, -}: { - originBase: string - onSignup: ( - username: string, - firstName: string, - lastName: string, - password: string, - passwordConfirm: string, - email: string, - ) => Promise -}) => { +export const SignupPage = () => { + const { signup } = useAuthContext() const navigate = useNavigate() const [username, setUsername] = useState('') const [firstName, setFirstName] = useState('') @@ -31,12 +22,12 @@ export const SignupPage = ({ setStatus('loading') setError(null) try { - await onSignup(username, firstName, lastName, password, passwordConfirm, email) + await signup(username, firstName, lastName, password, passwordConfirm, email) setStatus('success') navigate('/signup/success') - } catch (err: any) { + } catch (err) { setStatus('error') - setError(err.message) + setError(err instanceof Error ? err.message : 'Signup failed') } } @@ -155,10 +146,9 @@ export const SignupPage = ({ />
- - +
diff --git a/frontend/src/pages/SignupSuccessPage.tsx b/frontend/src/features/auth/pages/SignupSuccessPage.tsx similarity index 94% rename from frontend/src/pages/SignupSuccessPage.tsx rename to frontend/src/features/auth/pages/SignupSuccessPage.tsx index b7c20ce..344c010 100644 --- a/frontend/src/pages/SignupSuccessPage.tsx +++ b/frontend/src/features/auth/pages/SignupSuccessPage.tsx @@ -1,5 +1,5 @@ -import loginBg from '../assets/img/login_background.jpg' -import { theme } from '../theme' +import loginBg from '../../../assets/img/login_background.jpg' +import { theme } from '@/theme' export const SignupSuccessPage = () => { return ( diff --git a/frontend/src/components/DetectorCard.tsx b/frontend/src/features/devices/components/DetectorCard.tsx similarity index 91% rename from frontend/src/components/DetectorCard.tsx rename to frontend/src/features/devices/components/DetectorCard.tsx index 364cdc0..4597e8f 100644 --- a/frontend/src/components/DetectorCard.tsx +++ b/frontend/src/features/devices/components/DetectorCard.tsx @@ -1,17 +1,12 @@ import { useNavigate } from 'react-router-dom' -import { theme } from '../theme' +import { theme } from '@/theme' interface DetectorCardProps { detector: { id: string name: string sn: string - type: { - name: string - manufacturer: { - name: string - } - } + type?: { name: string } } } @@ -20,7 +15,7 @@ export const DetectorCard = ({ detector }: DetectorCardProps) => { return (
navigate(`/logbook/${detector.id}`)} + onClick={() => navigate(`/device/${detector.id}`)} style={{ padding: theme.spacing['2xl'], background: theme.colors.card, diff --git a/frontend/src/components/DetectorTypeInfo.tsx b/frontend/src/features/devices/components/DetectorTypeInfo.tsx similarity index 97% rename from frontend/src/components/DetectorTypeInfo.tsx rename to frontend/src/features/devices/components/DetectorTypeInfo.tsx index 0bc0a92..18a0ad0 100644 --- a/frontend/src/components/DetectorTypeInfo.tsx +++ b/frontend/src/features/devices/components/DetectorTypeInfo.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { theme } from "../theme"; +import { theme } from "@/theme"; export interface DetectorTypeInfoProps { type: { diff --git a/frontend/src/features/devices/pages/DetectorCreatePage.tsx b/frontend/src/features/devices/pages/DetectorCreatePage.tsx new file mode 100644 index 0000000..115d55f --- /dev/null +++ b/frontend/src/features/devices/pages/DetectorCreatePage.tsx @@ -0,0 +1,192 @@ +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import axios from "axios"; +import { AppSelect } from '@/shared/components/common/AppSelect'; +import type { SelectOption } from '@/shared/components/common/AppSelect'; +import { PageLayout } from "@/shared/components/Layout/PageLayout"; +import { theme } from "@/theme"; +import { LabeledInput } from "@/shared/components/common/LabeledInput"; +import logbookBg from "@/assets/img/SPACEDOS01.jpg"; +import { DetectorTypeInfo } from "@/features/devices/components/DetectorTypeInfo"; +import { Button } from "@/shared/components/Button/Button"; +import { Section } from "@/shared/components/Layout/Section"; +import { + useDetectorTypesList, + useDetectorTypesRetrieve, + useDetectorsCreate, +} from "@/api/detectors/detectors"; +import { useUserOrganizationsOwnedList } from "@/api/authentication/authentication"; +import type { DetectorWriteRequestRequest as DetectorRequest } from "@/api/model"; + +const labelStyle: React.CSSProperties = { + display: "block", + marginBottom: theme.spacing.sm, + fontWeight: theme.typography.fontWeight.medium, + color: theme.colors.textDark, +}; + +export const DetectorCreatePage = () => { + const navigate = useNavigate(); + const [sn, setSn] = useState(""); + const [name, setName] = useState(""); + const [type, setType] = useState(null); + const [owner, setOwner] = useState(null); + const [selectedAccess, setSelectedAccess] = useState([]); + const [error, setError] = useState(null); + const [imageFile, setImageFile] = useState(null); + const [imagePreview, setImagePreview] = useState(null); + + const handleImageChange = (e: React.ChangeEvent) => { + const file = e.target.files?.[0] ?? null; + setImageFile(file); + if (file) { + const reader = new FileReader(); + reader.onload = (ev) => setImagePreview(ev.target?.result as string); + reader.readAsDataURL(file); + } else { + setImagePreview(null); + } + }; + + const detectorTypesQuery = useDetectorTypesList(); + const typeOptions: SelectOption[] = (detectorTypesQuery.data?.data?.results ?? []).map((t) => ({ + value: t.id, + label: t.name, + })); + + const typeInfoQuery = useDetectorTypesRetrieve(type?.value ?? "", { query: { enabled: !!type } }); + const typeInfo = typeInfoQuery.data?.data ?? null; + + const ownedOrgsQuery = useUserOrganizationsOwnedList(); + const ownedOrgs = (ownedOrgsQuery.data?.data ?? []) as { id: string; name: string }[]; + const ownerOptions: SelectOption[] = ownedOrgs.map((o) => ({ value: o.id, label: o.name })); + + const createMutation = useDetectorsCreate(); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setError(null); + try { + await createMutation.mutateAsync({ + data: { + sn, + name, + type_id: type!.value, + owner_id: owner!.value, + access: selectedAccess.map((o) => o.value), + ...(imageFile ? { image: imageFile } : {}), + } as DetectorRequest, + }); + navigate("/logbooks"); + } catch (err) { + const detail = axios.isAxiosError(err) + ? (err.response?.data as Record | undefined)?.detail ?? err.message + : err instanceof Error ? err.message : "Failed to create detector"; + setError(detail); + } + }; + + return ( + +
+
+
+ setSn(e.target.value)} + placeholder="e.g., 123456" + required + /> + + setName(e.target.value)} + placeholder="Detector name" + required + /> + +
+ + setType(opt)} + placeholder="Select type..." + isLoading={detectorTypesQuery.isLoading} + /> +
+ + {type && typeInfo && ( + + )} + +
+ + setOwner(opt)} + placeholder="Select owner..." + isLoading={ownedOrgsQuery.isLoading} + /> +
+ +
+ + + {imagePreview && ( + Preview + )} +
+ +
+ + + inputId="access" + isMulti + options={ownerOptions} + value={selectedAccess} + onChange={(opts) => setSelectedAccess(opts as SelectOption[])} + placeholder="Select organizations..." + isLoading={ownedOrgsQuery.isLoading} + /> +
+ +
+ + +
+
+
+
+
+ ); +}; diff --git a/frontend/src/features/devices/pages/DevicePage.tsx b/frontend/src/features/devices/pages/DevicePage.tsx new file mode 100644 index 0000000..509c8bc --- /dev/null +++ b/frontend/src/features/devices/pages/DevicePage.tsx @@ -0,0 +1,290 @@ +import { useState } from 'react' +import { useParams, useNavigate } from 'react-router-dom' +import { Button } from '@/shared/components/Button/Button' +import ReactMarkdown from 'react-markdown' +import { PageLayout } from '@/shared/components/Layout/PageLayout' +import { Section } from '@/shared/components/Layout/Section' +import { theme } from '@/theme' +import logbookBg from '@/assets/img/SPACEDOS01.jpg' +import { + useDetectorsRetrieve, + useLogbooksList, + detectorsQrRetrieve, +} from '@/api/detectors/detectors' +import type { DetectorLogbook } from '@/api/model' +import axios from 'axios' + +export const DevicePage = () => { + const { id } = useParams<{ id: string }>() + const navigate = useNavigate() + const [qrError, setQrError] = useState(null) + + const detectorQuery = useDetectorsRetrieve(id ?? '', { query: { enabled: !!id } }) + const logbookQuery = useLogbooksList({ detector: id }, { query: { enabled: !!id } }) + + const detector = detectorQuery.data?.data + const logbook: DetectorLogbook[] = logbookQuery.data?.data?.results ?? [] + + const loading = detectorQuery.isLoading || logbookQuery.isLoading + + const queryError = detectorQuery.error + ? `Failed to load detector: ${(detectorQuery.error as Error).message}` + : logbookQuery.error + ? `Failed to load logbook: ${(logbookQuery.error as Error).message}` + : null + + const error = queryError ?? qrError + + const handleQrDownload = async () => { + if (!detector) return + setQrError(null) + try { + const res = await detectorsQrRetrieve( + detector.id, + { label: 'true' }, + { responseType: 'blob' }, + ) + const blob = res.data as unknown as Blob + const url = window.URL.createObjectURL(blob) + const link = document.createElement('a') + link.href = url + link.download = `detector_${detector.sn}_qr.png` + document.body.appendChild(link) + link.click() + link.remove() + window.URL.revokeObjectURL(url) + } catch (e) { + const msg = axios.isAxiosError(e) + ? e.message + : e instanceof Error + ? e.message + : 'Unknown error' + setQrError(`Failed to download QR code: ${msg}`) + } + } + + return ( + +
+ QR + + ) : undefined + } + > + {loading &&

Loading logbook...

} + + {detector && ( +
+

+ Detector Information +

+
+
+ + Serial Number: + +
{detector.sn}
+
+
+ + Type: + +
+ {detector.type?.url ? ( + + {detector.type.name} + + ) : ( + detector.type?.name + )} +
+
+ {detector.owner && ( +
+ + Owner: + +
{detector.owner.name}
+
+ )} + {detector.manufactured_date && ( +
+ + Manufactured: + +
+ {new Date(detector.manufactured_date).toLocaleDateString()} +
+
+ )} +
+ {detector.image && ( +
+ + Photo: + + {detector.name} +
+ )} +
+ )} + +
+

+ Logbook Entries +

+ {logbook.length === 0 && !loading ? ( +

No logbook entries yet.

+ ) : ( +
    + {logbook.map((item) => ( +
  • +
    + {item.entry_type} + + {item.location_text && ( + + {item.location_text} + + )} + {item.author?.username && ( + + by @{item.author.username} + + )} + +
    +
    + {item.text} +
    + {item.modified && ( +
    + Last modified: {new Date(item.modified).toLocaleString()} + {item.modified_by?.username && ( + by @{item.modified_by.username} + )} +
    + )} + {item.latitude && item.longitude ? ( + + View on map + + ) : null} +
  • + ))} +
+ )} +
+ + +
+
+ ) +} \ No newline at end of file diff --git a/frontend/src/pages/LogbookEntryPage.tsx b/frontend/src/features/devices/pages/LogbookEntryPage.tsx similarity index 70% rename from frontend/src/pages/LogbookEntryPage.tsx rename to frontend/src/features/devices/pages/LogbookEntryPage.tsx index 858e865..0b677d0 100644 --- a/frontend/src/pages/LogbookEntryPage.tsx +++ b/frontend/src/features/devices/pages/LogbookEntryPage.tsx @@ -1,41 +1,25 @@ -import { useState, useEffect } from 'react' +import { useState, useEffect, useRef } from 'react' import { useParams, useNavigate, Link } from 'react-router-dom' -import { PageLayout } from '../components/PageLayout' -import { LocationSearchMap } from '../components/LocationSearchMap' -import { theme } from '../theme' -import logbookBg from '../assets/img/SPACEDOS01.jpg' - -interface Detector { - id: string - name: string - sn: string - type: { - name: string - } -} - -export const LogbookEntryPage = ({ - apiBase, - isAuthed, - getAuthHeader, -}: { - apiBase: string - isAuthed: boolean - getAuthHeader: () => { Authorization?: string } -}) => { +import { PageLayout } from '@/shared/components/Layout/PageLayout' +import { LocationSearchMap } from '@/shared/components/common/LocationSearchMap' +import { theme } from '@/theme' +import logbookBg from '@/assets/img/SPACEDOS01.jpg' +import { useDetectorsRetrieve, useLogbooksRetrieve, useLogbooksCreate, useLogbooksUpdate } from '@/api/detectors/detectors' +import type { EntryTypeEnum, SourceEnum } from '@/api/model' +import { Button } from '@/shared/components/Button/Button' + +export const LogbookEntryPage = () => { const { id, entryId } = useParams<{ id: string; entryId?: string }>() const navigate = useNavigate() - const [detector, setDetector] = useState(null) - const [loading, setLoading] = useState(false) - const [error, setError] = useState(null) - const [submitting, setSubmitting] = useState(false) const isEditMode = !!entryId + const formInitialized = useRef(false) + const [submitting, setSubmitting] = useState(false) + const [submitError, setSubmitError] = useState(null) // Form fields const [text, setText] = useState('') const [entryType, setEntryType] = useState('note') const [isPublic, setIsPublic] = useState(true) - const [source] = useState('web') const [latitude, setLatitude] = useState('') const [longitude, setLongitude] = useState('') const [altitude, setAltitude] = useState('') @@ -51,112 +35,64 @@ export const LogbookEntryPage = ({ { value: 'other', label: 'Other' }, ] - useEffect(() => { - if (!id || !isAuthed) return + const detectorQuery = useDetectorsRetrieve(id!, { query: { enabled: !!id } }) + const detector = detectorQuery.data?.data - const fetchData = async () => { - setLoading(true) - setError(null) - try { - // Fetch detector details - const detectorRes = await fetch(`${apiBase}/detector/`, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - ...getAuthHeader(), - }, - }) - if (!detectorRes.ok) throw new Error(`HTTP ${detectorRes.status}`) - const detectors = await detectorRes.json() - const foundDetector = detectors.find((d: Detector) => d.id === id) - - if (!foundDetector) { - throw new Error('Detector not found') - } - setDetector(foundDetector) + const entryQuery = useLogbooksRetrieve(entryId!, { query: { enabled: isEditMode && !!entryId } }) + const entry = entryQuery.data?.data - // If in edit mode, fetch the logbook entry - if (isEditMode && entryId) { - const logbookRes = await fetch(`${apiBase}/logbook/?detector=${id}`, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - ...getAuthHeader(), - }, - }) - if (!logbookRes.ok) throw new Error(`HTTP ${logbookRes.status}`) - const logbookData = await logbookRes.json() - const entry = logbookData.find((e: any) => e.id === entryId) - - if (entry) { - setText(entry.text || '') - setEntryType(entry.entry_type || 'note') - setIsPublic(entry.public ?? true) - setLatitude(entry.latitude?.toString() || '') - setLongitude(entry.longitude?.toString() || '') - setAltitude(entry.altitude?.toString() || '') - setLocationText(entry.location_text || '') - } else { - throw new Error('Logbook entry not found') - } - } - } catch (e: any) { - setError(`Failed to load data: ${e.message}`) - } finally { - setLoading(false) - } + useEffect(() => { + if (entry && !formInitialized.current) { + formInitialized.current = true + setText(entry.text || '') + setEntryType(entry.entry_type || 'note') + setIsPublic(entry.public ?? true) + setLatitude(entry.latitude?.toString() || '') + setLongitude(entry.longitude?.toString() || '') + setAltitude(entry.altitude?.toString() || '') + setLocationText(entry.location_text || '') } + }, [entry]) - fetchData() - }, [id, entryId, isEditMode, apiBase, isAuthed]) + const createMutation = useLogbooksCreate() + const updateMutation = useLogbooksUpdate() + + const loading = detectorQuery.isLoading || (isEditMode && entryQuery.isLoading) + const error = detectorQuery.error + ? `Failed to load detector: ${(detectorQuery.error as Error)?.message ?? 'Unknown error'}` + : (isEditMode && entryQuery.error) + ? `Failed to load logbook entry: ${(entryQuery.error as Error)?.message ?? 'Unknown error'}` + : submitError const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() if (!id) return setSubmitting(true) - setError(null) + setSubmitError(null) try { - const payload: any = { + const payload = { detector: id, text, - entry_type: entryType, + entry_type: entryType as EntryTypeEnum, public: isPublic, - source, + source: 'web' as SourceEnum, + ...(latitude && { latitude: parseFloat(latitude) }), + ...(longitude && { longitude: parseFloat(longitude) }), + ...(altitude && { altitude: parseFloat(altitude) }), + ...(locationText && { location_text: locationText }), } - // Add optional location fields if provided - if (latitude) payload.latitude = parseFloat(latitude) - if (longitude) payload.longitude = parseFloat(longitude) - if (altitude) payload.altitude = parseFloat(altitude) - if (locationText) payload.location_text = locationText - - - const url = isEditMode - ? `${apiBase}/logbook/${entryId}/` - : `${apiBase}/logbook/add/` - - const method = isEditMode ? 'PUT' : 'POST' - - const res = await fetch(url, { - method, - headers: { - 'Content-Type': 'application/json', - ...getAuthHeader() - }, - body: JSON.stringify(payload), - }) - - if (!res.ok) { - const errorData = await res.json().catch(() => ({})) - throw new Error(errorData.detail || `HTTP ${res.status}`) + if (isEditMode && entryId) { + await updateMutation.mutateAsync({ id: entryId, data: payload }) + } else { + await createMutation.mutateAsync({ data: payload }) } - // Navigate back to the detector logbook page - navigate(`/logbook/${id}`) - } catch (e: any) { - setError(`Failed to ${isEditMode ? 'update' : 'create'} entry: ${e.message}`) + navigate(`/device/${id}`) + } catch (e: unknown) { + setSubmitError(`Failed to ${isEditMode ? 'update' : 'create'} entry: ${e instanceof Error ? e.message : 'Unknown error'}`) } finally { setSubmitting(false) } @@ -173,33 +109,21 @@ export const LogbookEntryPage = ({ } }, (error) => { - setError(`Failed to get location: ${error.message}`) + setSubmitError(`Failed to get location: ${error.message}`) } ) } else { - setError('Geolocation is not supported by your browser') + setSubmitError('Geolocation is not supported by your browser') } } - if (!isAuthed) { - return ( - -
theme.colors.danger, padding: theme.spacing['3xl'] -
- Login required to create logbook entry. -
-
-
- ) - } - return (
← Back to Logbook @@ -258,6 +182,7 @@ export const LogbookEntryPage = ({ > Description * +