From f67690bc56e5c1043207af437bdcd48779d6134c Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Tue, 28 Apr 2026 16:47:51 +0200 Subject: [PATCH 001/102] Bump version to 2025.5.0.dev0 --- src/pretix/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pretix/__init__.py b/src/pretix/__init__.py index a6fca5e3e..6018ee944 100644 --- a/src/pretix/__init__.py +++ b/src/pretix/__init__.py @@ -19,4 +19,4 @@ # You should have received a copy of the GNU Affero General Public License along with this program. If not, see # . # -__version__ = "2026.4.0" +__version__ = "2025.5.0.dev0" -- 2.54.0 From bda27d72e7443143a5e01dafcde4872ee7c919e1 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Tue, 28 Apr 2026 16:48:33 +0200 Subject: [PATCH 002/102] Bump version to 2026.5.0.dev0 --- src/pretix/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pretix/__init__.py b/src/pretix/__init__.py index 6018ee944..63266c3ac 100644 --- a/src/pretix/__init__.py +++ b/src/pretix/__init__.py @@ -19,4 +19,4 @@ # You should have received a copy of the GNU Affero General Public License along with this program. If not, see # . # -__version__ = "2025.5.0.dev0" +__version__ = "2026.5.0.dev0" -- 2.54.0 From 589f51454e7bbf2b46f6a35a068a10fe524dda27 Mon Sep 17 00:00:00 2001 From: Phin Wolkwitz Date: Wed, 29 Apr 2026 11:59:06 +0200 Subject: [PATCH 003/102] Add locations to program times (Z#23221129) Add location for program time slots and extend .ical and PDF placeholder --- doc/api/resources/item_program_times.rst | 19 +++-- src/pretix/api/serializers/item.py | 4 +- .../0299_itemprogramtime_location.py | 19 +++++ src/pretix/base/models/items.py | 7 ++ src/pretix/base/pdf.py | 24 +++--- src/pretix/control/forms/item.py | 7 +- .../item/include_program_times.html | 2 + src/pretix/presale/ical.py | 2 +- src/tests/api/test_items.py | 78 ++++++++++++++++++- src/tests/base/test_event_clone.py | 7 +- src/tests/control/test_items.py | 4 +- 11 files changed, 151 insertions(+), 22 deletions(-) create mode 100644 src/pretix/base/migrations/0299_itemprogramtime_location.py diff --git a/doc/api/resources/item_program_times.rst b/doc/api/resources/item_program_times.rst index db8a6d336..19a188518 100644 --- a/doc/api/resources/item_program_times.rst +++ b/doc/api/resources/item_program_times.rst @@ -16,6 +16,7 @@ Field Type Description id integer Internal ID of the program time start datetime The start date time for this program time slot. end datetime The end date time for this program time slot. +location multi-lingual string The program time slot's location (or ``null``) ===================================== ========================== ======================================================= .. versionchanged:: TODO @@ -54,17 +55,20 @@ Endpoints { "id": 2, "start": "2025-08-14T22:00:00Z", - "end": "2025-08-15T00:00:00Z" + "end": "2025-08-15T00:00:00Z", + "location": null }, { "id": 3, "start": "2025-08-12T22:00:00Z", - "end": "2025-08-13T22:00:00Z" + "end": "2025-08-13T22:00:00Z", + "location": null }, { "id": 14, "start": "2025-08-15T22:00:00Z", - "end": "2025-08-17T22:00:00Z" + "end": "2025-08-17T22:00:00Z", + "location": null } ] } @@ -99,7 +103,8 @@ Endpoints { "id": 1, "start": "2025-08-15T22:00:00Z", - "end": "2025-10-27T23:00:00Z" + "end": "2025-10-27T23:00:00Z", + "location": null } :param organizer: The ``slug`` field of the organizer to fetch @@ -125,7 +130,8 @@ Endpoints { "start": "2025-08-15T10:00:00Z", - "end": "2025-08-15T22:00:00Z" + "end": "2025-08-15T22:00:00Z", + "location": null } **Example response**: @@ -139,7 +145,8 @@ Endpoints { "id": 17, "start": "2025-08-15T10:00:00Z", - "end": "2025-08-15T22:00:00Z" + "end": "2025-08-15T22:00:00Z", + "location": null } :param organizer: The ``slug`` field of the organizer of the event/item to create a program time for diff --git a/src/pretix/api/serializers/item.py b/src/pretix/api/serializers/item.py index a2c6258f5..35750c02d 100644 --- a/src/pretix/api/serializers/item.py +++ b/src/pretix/api/serializers/item.py @@ -191,7 +191,7 @@ class InlineItemAddOnSerializer(serializers.ModelSerializer): class InlineItemProgramTimeSerializer(serializers.ModelSerializer): class Meta: model = ItemProgramTime - fields = ('start', 'end') + fields = ('start', 'end', 'location') class ItemBundleSerializer(serializers.ModelSerializer): @@ -222,7 +222,7 @@ class ItemBundleSerializer(serializers.ModelSerializer): class ItemProgramTimeSerializer(serializers.ModelSerializer): class Meta: model = ItemProgramTime - fields = ('id', 'start', 'end') + fields = ('id', 'start', 'end', 'location') def validate(self, data): data = super().validate(data) diff --git a/src/pretix/base/migrations/0299_itemprogramtime_location.py b/src/pretix/base/migrations/0299_itemprogramtime_location.py new file mode 100644 index 000000000..390b33d72 --- /dev/null +++ b/src/pretix/base/migrations/0299_itemprogramtime_location.py @@ -0,0 +1,19 @@ +# Generated by Django 4.2.27 on 2026-01-21 12:06 + +import i18nfield.fields +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("pretixbase", "0298_pluggable_permissions"), + ] + + operations = [ + migrations.AddField( + model_name="itemprogramtime", + name="location", + field=i18nfield.fields.I18nTextField(max_length=200, null=True), + ) + ] diff --git a/src/pretix/base/models/items.py b/src/pretix/base/models/items.py index 339ad4501..feb7dec8a 100644 --- a/src/pretix/base/models/items.py +++ b/src/pretix/base/models/items.py @@ -2306,10 +2306,17 @@ class ItemProgramTime(models.Model): :type start: datetime :param end: The date and time this program time ends :type end: datetime + :param location: venue + :type location: str """ item = models.ForeignKey('Item', related_name='program_times', on_delete=models.CASCADE) start = models.DateTimeField(verbose_name=_("Start")) end = models.DateTimeField(verbose_name=_("End")) + location = I18nTextField( + null=True, blank=True, + max_length=200, + verbose_name=_("Location"), + ) def clean(self): if hasattr(self, 'item') and self.item and self.item.event.has_subevents: diff --git a/src/pretix/base/pdf.py b/src/pretix/base/pdf.py index 8a91c8228..a8cb2fc2c 100644 --- a/src/pretix/base/pdf.py +++ b/src/pretix/base/pdf.py @@ -498,9 +498,9 @@ DEFAULT_VARIABLES = OrderedDict(( ) if op.valid_until else "" }), ("program_times", { - "label": _("Program times: date and time"), + "label": _("Program times"), "editor_sample": _( - "2017-05-31 10:00 – 12:00\n2017-05-31 14:00 – 16:00\n2017-05-31 14:00 – 2017-06-01 14:00"), + "2017-05-31 10:00 – 12:00, Room 1\n2017-05-31 14:00 – 16:00, Room 2\n2017-05-31 14:00 – 2017-06-01 14:00, Building A"), "evaluate": lambda op, order, ev: get_program_times(op, ev) }), ("medium_identifier", { @@ -748,13 +748,19 @@ def get_seat(op: OrderPosition): def get_program_times(op: OrderPosition, ev: Event): - return '\n'.join([ - datetimerange( - pt.start.astimezone(ev.timezone), - pt.end.astimezone(ev.timezone), - as_html=False - ) for pt in op.item.program_times.all() - ]) + ptstr = [] + for pt in op.item.program_times.all(): + ptstr.append([ + datetimerange( + pt.start.astimezone(ev.timezone), + pt.end.astimezone(ev.timezone), + as_html=False + ), + (', ' + ', '.join( + l.strip() for l in str(pt.location).splitlines() if l.strip()) + ) if str(pt.location).strip() else '' + ]) + return '\n'.join(''.join(l) for l in ptstr) def generate_compressed_addon_list(op, order, event, only_checked_in=False): diff --git a/src/pretix/control/forms/item.py b/src/pretix/control/forms/item.py index 6d5b8f179..6829907cd 100644 --- a/src/pretix/control/forms/item.py +++ b/src/pretix/control/forms/item.py @@ -574,7 +574,7 @@ class ItemCreateForm(I18nModelForm): instance.bundles.create(bundled_item=b.bundled_item, bundled_variation=b.bundled_variation, count=b.count, designated_price=b.designated_price) for pt in self.cleaned_data['copy_from'].program_times.all(): - instance.program_times.create(start=pt.start, end=pt.end) + instance.program_times.create(start=pt.start, end=pt.end, location=pt.location) item_copy_data.send(sender=self.event, source=self.cleaned_data['copy_from'], target=instance) @@ -1354,6 +1354,10 @@ class ItemProgramTimeForm(I18nModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['end'].widget.attrs['data-date-after'] = '#id_{prefix}-start_0'.format(prefix=self.prefix) + self.fields['location'].widget.attrs['rows'] = '3' + self.fields['location'].widget.attrs['placeholder'] = _( + 'Sample Conference Center, Heidelberg, Germany' + ) class Meta: model = ItemProgramTime @@ -1361,6 +1365,7 @@ class ItemProgramTimeForm(I18nModelForm): fields = [ 'start', 'end', + 'location' ] field_classes = { 'start': forms.SplitDateTimeField, diff --git a/src/pretix/control/templates/pretixcontrol/item/include_program_times.html b/src/pretix/control/templates/pretixcontrol/item/include_program_times.html index e223a0eec..9939cbf4f 100644 --- a/src/pretix/control/templates/pretixcontrol/item/include_program_times.html +++ b/src/pretix/control/templates/pretixcontrol/item/include_program_times.html @@ -34,6 +34,7 @@ {% bootstrap_form_errors form %} {% bootstrap_field form.start layout="control" %} {% bootstrap_field form.end layout="control" %} + {% bootstrap_field form.location layout="control" %} {% endfor %} @@ -59,6 +60,7 @@
{% bootstrap_field formset.empty_form.start layout="control" %} {% bootstrap_field formset.empty_form.end layout="control" %} + {% bootstrap_field formset.empty_form.location layout="control" %}
{% endescapescript %} diff --git a/src/pretix/presale/ical.py b/src/pretix/presale/ical.py index 14a1ec9ea..ba0571f24 100644 --- a/src/pretix/presale/ical.py +++ b/src/pretix/presale/ical.py @@ -153,7 +153,7 @@ def get_private_icals(event, positions): # Actual ical organizer field is not useful since it will cause "your invitation was accepted" emails to the organizer descr.append(_('Organizer: {organizer}').format(organizer=event.organizer.name)) description = '\n'.join(descr) - location = None + location = ", ".join(l.strip() for l in str(pt.location).splitlines() if l.strip()) dtstart = pt.start.astimezone(tz) dtend = pt.end.astimezone(tz) uid = 'pretix-{}-{}-{}-{}@{}'.format( diff --git a/src/tests/api/test_items.py b/src/tests/api/test_items.py index 25ea7cea8..b2aef4737 100644 --- a/src/tests/api/test_items.py +++ b/src/tests/api/test_items.py @@ -530,6 +530,7 @@ def test_item_detail_program_times(token_client, organizer, event, team, item, c res["program_times"] = [{ "start": "2017-12-27T00:00:00Z", "end": "2017-12-28T00:00:00Z", + "location": None }] resp = token_client.get('/api/v1/organizers/{}/events/{}/items/{}/'.format(organizer.slug, event.slug, item.pk)) @@ -1972,32 +1973,54 @@ def program_time2(item, category): end=datetime(2017, 12, 30, 0, 0, 0, tzinfo=timezone.utc)) +@pytest.fixture +def program_time3(item, category): + return item.program_times.create(start=datetime(2017, 12, 30, 0, 0, 0, tzinfo=timezone.utc), + end=datetime(2017, 12, 31, 0, 0, 0, tzinfo=timezone.utc), + location='Testlocation') + + TEST_PROGRAM_TIMES_RES = { 0: { "start": "2017-12-27T00:00:00Z", "end": "2017-12-28T00:00:00Z", + "location": None, }, 1: { "start": "2017-12-29T00:00:00Z", "end": "2017-12-30T00:00:00Z", + "location": None, + }, + 2: { + "start": "2017-12-30T00:00:00Z", + "end": "2017-12-31T00:00:00Z", + "location": {"en": "Testlocation"}, } } @pytest.mark.django_db -def test_program_times_list(token_client, organizer, event, item, program_time, program_time2): +def test_program_times_list(token_client, organizer, event, item, program_time, program_time2, program_time3): res = dict(TEST_PROGRAM_TIMES_RES) res[0]["id"] = program_time.pk res[1]["id"] = program_time2.pk + res[2]["id"] = program_time3.pk resp = token_client.get('/api/v1/organizers/{}/events/{}/items/{}/program_times/'.format(organizer.slug, event.slug, item.pk)) assert resp.status_code == 200 assert res[0]['start'] == resp.data['results'][0]['start'] assert res[0]['end'] == resp.data['results'][0]['end'] assert res[0]['id'] == resp.data['results'][0]['id'] + assert res[0] == resp.data['results'][0] assert res[1]['start'] == resp.data['results'][1]['start'] assert res[1]['end'] == resp.data['results'][1]['end'] assert res[1]['id'] == resp.data['results'][1]['id'] + assert res[1] == resp.data['results'][1] + assert res[2]['start'] == resp.data['results'][2]['start'] + assert res[2]['end'] == resp.data['results'][2]['end'] + assert res[2]['location'] == resp.data['results'][2]['location'] + assert res[2]['id'] == resp.data['results'][2]['id'] + assert res[2] == resp.data['results'][2] @pytest.mark.django_db @@ -2039,6 +2062,59 @@ def test_program_times_create(token_client, organizer, event, item): assert resp.content.decode() == '{"non_field_errors":["The program end must not be before the program start."]}' +@pytest.mark.django_db +def test_program_times_create_location(token_client, organizer, event, item): + resp = token_client.post( + '/api/v1/organizers/{}/events/{}/items/{}/program_times/'.format(organizer.slug, event.slug, item.pk), + { + "start": "2017-12-27T00:00:00Z", + "end": "2017-12-28T00:00:00Z", + "location": { + "en": "Testlocation", + "de": "Testort" + } + }, + format='json' + ) + assert resp.status_code == 201 + with scopes_disabled(): + program_time = ItemProgramTime.objects.get(pk=resp.data['id']) + assert "Testlocation" == program_time.location.localize("en") + assert "Testort" == program_time.location.localize("de") + + +@pytest.mark.django_db +def test_program_times_create_without_location(token_client, organizer, event, item): + resp = token_client.post( + '/api/v1/organizers/{}/events/{}/items/{}/program_times/'.format(organizer.slug, event.slug, item.pk), + { + "start": "2017-12-27T00:00:00Z", + "end": "2017-12-28T00:00:00Z" + }, + format='json' + ) + assert resp.status_code == 201 + assert resp.data['location'] is None + with scopes_disabled(): + program_time = ItemProgramTime.objects.get(pk=resp.data['id']) + assert str(program_time.location) == "" + + resp = token_client.post( + '/api/v1/organizers/{}/events/{}/items/{}/program_times/'.format(organizer.slug, event.slug, item.pk), + { + "start": "2017-12-27T00:00:00Z", + "end": "2017-12-28T00:00:00Z", + "location": None + }, + format='json' + ) + assert resp.status_code == 201 + assert resp.data['location'] is None + with scopes_disabled(): + program_time = ItemProgramTime.objects.get(pk=resp.data['id']) + assert str(program_time.location) == "" + + @pytest.mark.django_db def test_program_times_update(token_client, organizer, event, item, program_time): resp = token_client.patch( diff --git a/src/tests/base/test_event_clone.py b/src/tests/base/test_event_clone.py index 784bd079a..a003bf54e 100644 --- a/src/tests/base/test_event_clone.py +++ b/src/tests/base/test_event_clone.py @@ -82,7 +82,11 @@ def test_full_clone_same_organizer(): assert item1.meta_data ItemProgramTime.objects.create(item=item1, start=datetime.datetime(2017, 12, 27, 0, 0, 0, tzinfo=datetime.timezone.utc), - end=datetime.datetime(2017, 12, 28, 0, 0, 0, tzinfo=datetime.timezone.utc)) + end=datetime.datetime(2017, 12, 28, 0, 0, 0, tzinfo=datetime.timezone.utc), + location={ + "en": "Testlocation", + "de": "Testort" + }) assert item1.program_times item2 = event.items.create(category=category, tax_rule=tax_rule, name="T-shirt", default_price=15, hidden_if_item_available=item1) @@ -169,6 +173,7 @@ def test_full_clone_same_organizer(): assert copied_item1.meta_data == item1.meta_data assert copied_item1.program_times.first().start == item1.program_times.first().start assert copied_item1.program_times.first().end == item1.program_times.first().end + assert copied_item1.program_times.first().location == item1.program_times.first().location assert copied_item2.variations.get().meta_data == item2v.meta_data assert copied_item1.hidden_if_available == copied_q2 assert copied_item1.grant_membership_type == membership_type diff --git a/src/tests/control/test_items.py b/src/tests/control/test_items.py index d7d37eaaa..4d274e8ca 100644 --- a/src/tests/control/test_items.py +++ b/src/tests/control/test_items.py @@ -692,7 +692,8 @@ class ItemsTest(ItemFormTest): self.item2.program_times.create(start=datetime.datetime(2017, 12, 27, 0, 0, 0, tzinfo=datetime.timezone.utc), end=datetime.datetime(2017, 12, 28, 0, 0, 0, - tzinfo=datetime.timezone.utc)) + tzinfo=datetime.timezone.utc), + location={"en": "Testlocation", "de": "Testort"}) doc = self.get_doc('/control/event/%s/%s/items/add?copy_from=%d' % (self.orga1.slug, self.event1.slug, self.item2.pk)) data = extract_form_fields(doc.select("form")[0]) @@ -723,6 +724,7 @@ class ItemsTest(ItemFormTest): assert set([str(v.value) for v in i_new.variations.all()]) == set([str(v.value) for v in i_old.variations.all()]) assert i_old.program_times.first().start == i_new.program_times.first().start assert i_old.program_times.first().end == i_new.program_times.first().end + assert i_old.program_times.first().location == i_new.program_times.first().location def test_add_to_existing_quota(self): with scopes_disabled(): -- 2.54.0 From 24d26a945553c26a794401eb4c33be83f265cee2 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Wed, 29 Apr 2026 15:31:54 +0200 Subject: [PATCH 004/102] Badges: Add export layout for 4x3" on letter (Z#23232464) (#6128) * Badges: Add export layout for 4x3" on letter (Z#23232464) * Consistent naming --- src/pretix/plugins/badges/exporters.py | 10 +++++++++- src/pretix/plugins/badges/templates.py | 7 ++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/pretix/plugins/badges/exporters.py b/src/pretix/plugins/badges/exporters.py index 9bb4f85a4..0fbbb777a 100644 --- a/src/pretix/plugins/badges/exporters.py +++ b/src/pretix/plugins/badges/exporters.py @@ -57,7 +57,7 @@ from django.utils.translation import gettext as _, gettext_lazy, pgettext_lazy from pypdf import PageObject, PdfReader, PdfWriter, Transformation from pypdf.generic import RectangleObject from reportlab.lib import pagesizes -from reportlab.lib.units import mm +from reportlab.lib.units import inch, mm from reportlab.pdfgen import canvas from pretix.base.exporter import BaseExporter @@ -133,6 +133,14 @@ OPTIONS = OrderedDict([ 'offsets': [66.1 * mm, 29.6 * mm], 'pagesize': pagesizes.A4, }), + ('avery_4inx3in', { + 'name': 'Avery 4" x 3" (74459)', + 'cols': 2, + 'rows': 3, + 'margins': [1 * inch, .25 * inch, 1 * inch, .25 * inch], + 'offsets': [4 * inch, 3 * inch], + 'pagesize': pagesizes.LETTER, + }), ('avery_80x50', { 'name': 'Avery Zweckform 80 x 50 mm (L4785)', 'cols': 2, diff --git a/src/pretix/plugins/badges/templates.py b/src/pretix/plugins/badges/templates.py index ab458293d..b5e59e4c7 100644 --- a/src/pretix/plugins/badges/templates.py +++ b/src/pretix/plugins/badges/templates.py @@ -22,7 +22,7 @@ from django.utils.text import format_lazy from django.utils.translation import gettext_lazy as _ from reportlab.lib import pagesizes -from reportlab.lib.units import mm +from reportlab.lib.units import inch, mm def _simple_template(w, h): @@ -261,4 +261,9 @@ TEMPLATES = { "pagesize": (88.9 * mm, 33.87 * mm), "layout": _simple_template(88.9 * mm, 33.87 * mm), }, + "4inx3in": { + "label": format_lazy(_("{width} x {height} inch label"), width=4, height=3), + "pagesize": (4 * inch, 3 * inch), + "layout": _simple_template(4 * inch, 3 * inch), + }, } -- 2.54.0 From f4fcca19a407f41e7698ee3b6e452363c55bcedb Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Wed, 29 Apr 2026 19:57:08 +0200 Subject: [PATCH 005/102] Orders API: Fix race condition in voucher redemption (Z#23230391) (#6067) The old code relied on the `Voucher.redeemed` value obtained *before* the lock was taken, not afterwards. The change in services/orders.py is functionally pointless, but it makes the pattern of "fill availability only after lock" clearer and might avoid introducing similar bugs in the future. --- src/pretix/api/serializers/order.py | 13 ++++++++----- src/pretix/base/services/orders.py | 5 +++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/pretix/api/serializers/order.py b/src/pretix/api/serializers/order.py index f402e7fc9..9fa6b5ce9 100644 --- a/src/pretix/api/serializers/order.py +++ b/src/pretix/api/serializers/order.py @@ -1416,6 +1416,7 @@ class OrderCreateSerializer(I18nAwareModelSerializer): qa = QuotaAvailability() qa.queue(*[q for q, d in quota_diff_for_locking.items() if d > 0]) qa.compute() + v_avail = {} # These are not technically correct as diff use due to the time offset applied above, so let's prevent accidental # use further down @@ -1445,11 +1446,13 @@ class OrderCreateSerializer(I18nAwareModelSerializer): voucher_usage[v] += 1 if voucher_usage[v] > 0: - redeemed_in_carts = CartPosition.objects.filter( - Q(voucher=pos_data['voucher']) & Q(event=self.context['event']) & Q(expires__gte=now_dt) - ).exclude(pk__in=[cp.pk for cp in delete_cps]) - v_avail = v.max_usages - v.redeemed - redeemed_in_carts.count() - if v_avail < voucher_usage[v]: + if v not in v_avail: + v.refresh_from_db(fields=['redeemed']) + redeemed_in_carts = CartPosition.objects.filter( + Q(voucher=v) & Q(event=self.context['event']) & Q(expires__gte=now_dt) + ).exclude(pk__in=[cp.pk for cp in delete_cps]) + v_avail[v] = v.max_usages - v.redeemed - redeemed_in_carts.count() + if v_avail[v] < voucher_usage[v]: errs[i]['voucher'] = [ 'The voucher has already been used the maximum number of times.' ] diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index ba3e199b9..8fe2d3f1a 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -727,8 +727,6 @@ def _check_positions(event: Event, now_dt: datetime, time_machine_now_dt: dateti _check_date(event, time_machine_now_dt) products_seen = Counter() - q_avail = Counter() - v_avail = Counter() v_usages = Counter() v_budget = {} deleted_positions = set() @@ -793,6 +791,9 @@ def _check_positions(event: Event, now_dt: datetime, time_machine_now_dt: dateti shared_lock_objects=[event] ) + q_avail = Counter() + v_avail = Counter() + # Check maximum order size limit = min(int(event.settings.max_items_per_order), settings.PRETIX_MAX_ORDER_SIZE) if sum(1 for cp in sorted_positions if not cp.addon_to) > limit: -- 2.54.0 From fe2132435c04dae1e849dfc1bd237ff951399bbf Mon Sep 17 00:00:00 2001 From: luelista Date: Mon, 4 May 2026 11:13:38 +0200 Subject: [PATCH 006/102] Fix permissions of /pretix in docker container (#6133) --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 6ad99226a..4a62f561d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,6 +31,7 @@ RUN apt-get update && \ mkdir /etc/pretix && \ mkdir /data && \ useradd -ms /bin/bash -d /pretix -u 15371 pretixuser && \ + chmod 0755 /pretix \ echo 'pretixuser ALL=(ALL) NOPASSWD:SETENV: /usr/bin/supervisord' >> /etc/sudoers && \ mkdir /static && \ mkdir /etc/supervisord -- 2.54.0 From 993acce05add8b74b8997c7f781c0a544e1a4710 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Mon, 4 May 2026 11:22:47 +0200 Subject: [PATCH 007/102] Settings: Fix typo in class path to mail backend (#6144) --- src/pretix/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pretix/settings.py b/src/pretix/settings.py index aa8697796..8971b520d 100644 --- a/src/pretix/settings.py +++ b/src/pretix/settings.py @@ -265,7 +265,7 @@ EMAIL_USE_TLS = config.getboolean('mail', 'tls', fallback=False) EMAIL_USE_SSL = config.getboolean('mail', 'ssl', fallback=False) EMAIL_SUBJECT_PREFIX = '[pretix] ' EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' -EMAIL_CUSTOM_SMTP_BACKEND = 'pretixbase.email.CheckPrivateNetworkSmtpBackend' +EMAIL_CUSTOM_SMTP_BACKEND = 'pretix.base.email.CheckPrivateNetworkSmtpBackend' EMAIL_TIMEOUT = 60 ADMINS = [('Admin', n) for n in config.get('mail', 'admins', fallback='').split(",") if n] -- 2.54.0 From 0acaed41be6eac09b946ce73fd80212f62b26f48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 4 May 2026 11:23:44 +0200 Subject: [PATCH 008/102] Fix Dockerfile syntax for chmod command (#6145) --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 4a62f561d..84309f514 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,7 +31,7 @@ RUN apt-get update && \ mkdir /etc/pretix && \ mkdir /data && \ useradd -ms /bin/bash -d /pretix -u 15371 pretixuser && \ - chmod 0755 /pretix \ + chmod 0755 /pretix && \ echo 'pretixuser ALL=(ALL) NOPASSWD:SETENV: /usr/bin/supervisord' >> /etc/sudoers && \ mkdir /static && \ mkdir /etc/supervisord -- 2.54.0 From 27183a26eee470d0c1dccd4c0ca8552882e30c42 Mon Sep 17 00:00:00 2001 From: luelista Date: Mon, 4 May 2026 11:34:05 +0200 Subject: [PATCH 009/102] Respect per-event plugin availability in OrganizerPluginEvents view (#5983) * Allow plugins to declare their availability per event * Fix message type * small optimization of PluginsField serializer --- src/pretix/api/serializers/fields.py | 4 +- src/pretix/base/plugins.py | 53 +++++++++++++++------------ src/pretix/control/views/organizer.py | 36 ++++++++---------- 3 files changed, 47 insertions(+), 46 deletions(-) diff --git a/src/pretix/api/serializers/fields.py b/src/pretix/api/serializers/fields.py index d3cc5f1b8..d877028ab 100644 --- a/src/pretix/api/serializers/fields.py +++ b/src/pretix/api/serializers/fields.py @@ -115,10 +115,10 @@ class PluginsField(serializers.Field): def to_representation(self, obj): from pretix.base.plugins import get_all_plugins - + active_plugins = set(obj.get_plugins()) return sorted([ p.module for p in get_all_plugins() - if not p.name.startswith('.') and getattr(p, 'visible', True) and p.module in obj.get_plugins() + if not p.name.startswith('.') and getattr(p, 'visible', True) and p.module in active_plugins ]) def to_internal_value(self, data): diff --git a/src/pretix/base/plugins.py b/src/pretix/base/plugins.py index 35647a1ba..a1e1eec71 100644 --- a/src/pretix/base/plugins.py +++ b/src/pretix/base/plugins.py @@ -49,14 +49,39 @@ class PluginType(Enum): EXPORT = 4 +def plugin_is_available(meta, event=None, organizer=None): + if not hasattr(meta.app, 'is_available'): + return True + + level = getattr(meta, "level", PLUGIN_LEVEL_EVENT) + if level == PLUGIN_LEVEL_EVENT: + if event: + return meta.app.is_available(event) + elif organizer: + if not hasattr(organizer, '_plugin_availability_fallback_event'): + with scope(organizer=organizer): + setattr(organizer, '_plugin_availability_fallback_event', organizer.events.first()) + return ( + organizer._plugin_availability_fallback_event + and meta.app.is_available(organizer._plugin_availability_fallback_event) + ) + elif level == PLUGIN_LEVEL_ORGANIZER: + if organizer: + return meta.app.is_available(organizer) + elif event: + return meta.app.is_available(event.organizer) + elif level == PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID and (event or organizer): + return meta.app.is_available(event or organizer) + + return True + + def get_all_plugins(*, event=None, organizer=None) -> List[type]: """ Returns the PretixPluginMeta classes of all plugins found in the installed Django apps. """ assert not event or not organizer plugins = [] - event_fallback = None - event_fallback_used = False for app in apps.get_app_configs(): if hasattr(app, 'PretixPluginMeta'): meta = app.PretixPluginMeta @@ -65,28 +90,8 @@ def get_all_plugins(*, event=None, organizer=None) -> List[type]: if app.name in settings.PRETIX_PLUGINS_EXCLUDE: continue - level = getattr(meta, "level", PLUGIN_LEVEL_EVENT) - if level == PLUGIN_LEVEL_EVENT: - if event and hasattr(app, 'is_available'): - if not app.is_available(event): - continue - elif organizer and hasattr(app, 'is_available'): - if not event_fallback_used: - with scope(organizer=organizer): - event_fallback = organizer.events.first() - event_fallback_used = True - if not event_fallback or not app.is_available(event_fallback): - continue - elif level == PLUGIN_LEVEL_ORGANIZER: - if organizer and hasattr(app, 'is_available'): - if not app.is_available(organizer): - continue - elif event and hasattr(app, 'is_available'): - if not app.is_available(event.organizer): - continue - elif level == PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID and (event or organizer) and hasattr(app, 'is_available'): - if not app.is_available(event or organizer): - continue + if not plugin_is_available(meta, event, organizer): + continue plugins.append(meta) return sorted( diff --git a/src/pretix/control/views/organizer.py b/src/pretix/control/views/organizer.py index 03404813f..e4854b24c 100644 --- a/src/pretix/control/views/organizer.py +++ b/src/pretix/control/views/organizer.py @@ -102,7 +102,7 @@ from pretix.base.models.organizer import ( from pretix.base.payment import PaymentException from pretix.base.plugins import ( PLUGIN_LEVEL_EVENT, PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID, - PLUGIN_LEVEL_ORGANIZER, + PLUGIN_LEVEL_ORGANIZER, plugin_is_available, ) from pretix.base.services.export import ( init_organizer_exporters, multiexport, scheduled_organizer_export, @@ -597,6 +597,13 @@ class OrganizerCreate(CreateView): }) +def available_plugins(organizer): + from pretix.base.plugins import get_all_plugins + + return (p for p in get_all_plugins(organizer=organizer) if not p.name.startswith('.') + and getattr(p, 'visible', True)) + + class OrganizerPlugins(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, TemplateView, SingleObjectMixin): model = Organizer context_object_name = 'organizer' @@ -606,12 +613,6 @@ class OrganizerPlugins(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi def get_object(self, queryset=None) -> Organizer: return self.request.organizer - def available_plugins(self, organizer): - from pretix.base.plugins import get_all_plugins - - return (p for p in get_all_plugins(organizer=organizer) if not p.name.startswith('.') - and getattr(p, 'visible', True)) - def prepare_links(self, pluginmeta, key): links = getattr(pluginmeta, key, []) try: @@ -637,7 +638,7 @@ class OrganizerPlugins(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi from pretix.base.plugins import CATEGORY_LABELS, CATEGORY_ORDER context = super().get_context_data(*args, **kwargs) - plugins = list(self.available_plugins(self.object)) + plugins = list(available_plugins(self.object)) active_counter = Counter() events_total = 0 @@ -685,7 +686,7 @@ class OrganizerPlugins(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi self.object = self.get_object() plugins_available = { - p.module: p for p in self.available_plugins(self.object) + p.module: p for p in available_plugins(self.object) } choose_events_next = False with transaction.atomic(): @@ -786,12 +787,6 @@ class OrganizerPluginEvents(OrganizerDetailViewMixin, OrganizerPermissionRequire } return kwargs - def available_plugins(self, organizer): - from pretix.base.plugins import get_all_plugins - - return (p for p in get_all_plugins(organizer=organizer) if not p.name.startswith('.') - and getattr(p, 'visible', True)) - def get_context_data(self, **kwargs): return super().get_context_data( plugin=self.plugin, @@ -799,12 +794,10 @@ class OrganizerPluginEvents(OrganizerDetailViewMixin, OrganizerPermissionRequire ) def dispatch(self, request, *args, **kwargs): - plugins_available = { - p.module: p for p in self.available_plugins(self.request.organizer) - } - if kwargs["plugin"] not in plugins_available: + try: + self.plugin = next(p for p in available_plugins(self.request.organizer) if p.module == kwargs["plugin"]) + except StopIteration: raise Http404(_("Unknown plugin.")) - self.plugin = plugins_available[kwargs["plugin"]] level = getattr(self.plugin, "level", PLUGIN_LEVEL_EVENT) if level == PLUGIN_LEVEL_ORGANIZER: raise Http404(_("This plugin can only be enabled for the entire organizer account.")) @@ -835,6 +828,9 @@ class OrganizerPluginEvents(OrganizerDetailViewMixin, OrganizerPermissionRequire logentries_to_save = [] for e in self.request.organizer.events.filter(pk__in=events_to_enable): + if not plugin_is_available(self.plugin, organizer=self.request.organizer, event=e): + messages.warning(self.request, _("This plugin cannot be activated for event {}.").format(e.name)) + continue logentries_to_save.append( e.log_action('pretix.event.plugins.enabled', user=self.request.user, data={'plugin': self.plugin.module}, save=False) ) -- 2.54.0 From 0aee73a9bd28127283e16f5404d86f021e9c4ba9 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Mon, 4 May 2026 12:44:22 +0200 Subject: [PATCH 010/102] Quotas: Add bulk-edit, bulk-delete and filter form (#6080) * Quotas: Add bulk-edit, bulk-delete and filter form * Fix GroupConcat * Apply suggestions from code review Co-authored-by: Richard Schreiber * Review notes * Fix handling of required fields --------- Co-authored-by: Richard Schreiber --- src/pretix/control/forms/filter.py | 127 ++++++++++ src/pretix/control/forms/item.py | 55 +++++ .../pretixcontrol/items/quota_bulk_edit.html | 49 ++++ .../items/quota_delete_bulk.html | 34 +++ .../templates/pretixcontrol/items/quotas.html | 227 ++++++++++++------ src/pretix/control/urls.py | 2 + src/pretix/control/views/item.py | 227 +++++++++++++++--- src/pretix/helpers/database.py | 7 +- 8 files changed, 622 insertions(+), 106 deletions(-) create mode 100644 src/pretix/control/templates/pretixcontrol/items/quota_bulk_edit.html create mode 100644 src/pretix/control/templates/pretixcontrol/items/quota_delete_bulk.html diff --git a/src/pretix/control/forms/filter.py b/src/pretix/control/forms/filter.py index 806c5e2ea..fda7545a0 100644 --- a/src/pretix/control/forms/filter.py +++ b/src/pretix/control/forms/filter.py @@ -1528,6 +1528,133 @@ class SubEventFilterForm(FilterForm): return self.event.organizer.meta_properties.filter(filter_allowed=True) +class QuotaFilterForm(FilterForm): + orders = { + '-date': ('-subevent__date_from', 'name', 'pk'), + 'date': ('subevent__date_from', '-name', '-pk'), + 'size': ('size', 'name', 'pk'), + '-size': ('-size', '-name', '-pk'), + 'name': ('name', 'pk'), + '-name': ('-name', '-pk'), + } + subevent = forms.ModelChoiceField( + label=pgettext_lazy('subevent', 'Date'), + queryset=SubEvent.objects.none(), + required=False, + empty_label=pgettext_lazy('subevent', 'All dates') + ) + date_from = forms.DateField( + label=_('Date from'), + required=False, + widget=DatePickerWidget({ + 'placeholder': _('Date from'), + }), + ) + date_until = forms.DateField( + label=_('Date until'), + required=False, + widget=DatePickerWidget({ + 'placeholder': _('Date until'), + }), + ) + time_from = forms.TimeField( + label=_('Start time from'), + required=False, + widget=TimePickerWidget({}), + ) + time_until = forms.TimeField( + label=_('Start time until'), + required=False, + widget=TimePickerWidget({}), + ) + weekday = forms.MultipleChoiceField( + label=_('Weekday'), + choices=( + ('2', _('Monday')), + ('3', _('Tuesday')), + ('4', _('Wednesday')), + ('5', _('Thursday')), + ('6', _('Friday')), + ('7', _('Saturday')), + ('1', _('Sunday')), + ), + widget=forms.CheckboxSelectMultiple, + required=False + ) + query = forms.CharField( + label=_('Quota name'), + widget=forms.TextInput(), + required=False + ) + + def __init__(self, *args, **kwargs): + self.event = kwargs.pop('event') + super().__init__(*args, **kwargs) + if self.event.has_subevents: + self.fields['date_from'].widget = DatePickerWidget() + self.fields['date_until'].widget = DatePickerWidget() + self.fields['subevent'].queryset = self.event.subevents.all() + self.fields['subevent'].widget = Select2( + attrs={ + 'data-model-select2': 'event', + 'data-select2-url': reverse('control:event.subevents.select2', kwargs={ + 'event': self.event.slug, + 'organizer': self.event.organizer.slug, + }), + 'data-placeholder': pgettext_lazy('subevent', 'All dates') + } + ) + self.fields['subevent'].widget.choices = self.fields['subevent'].choices + else: + del self.fields['subevent'] + del self.fields['date_from'] + del self.fields['date_until'] + del self.fields['time_from'] + del self.fields['time_until'] + del self.fields['weekday'] + + def filter_qs(self, qs): + fdata = self.cleaned_data + + if fdata.get('weekday'): + qs = qs.annotate(wday=ExtractWeekDay('subevent__date_from')).filter(wday__in=fdata.get('weekday')) + + if fdata.get('subevent'): + qs = qs.filter(subevent=fdata["subevent"]) + + if fdata.get('query'): + query = fdata.get('query') + qs = qs.filter(name__icontains=query) + + if fdata.get('date_until'): + date_end = make_aware(datetime.combine( + fdata.get('date_until') + timedelta(days=1), + time(hour=0, minute=0, second=0, microsecond=0) + ), get_current_timezone()) + qs = qs.filter( + Q(subevent__date_to__isnull=True, subevent__date_from__lt=date_end) | + Q(subevent__date_to__isnull=False, subevent__date_to__lt=date_end) + ) + if fdata.get('date_from'): + date_start = make_aware(datetime.combine( + fdata.get('date_from'), + time(hour=0, minute=0, second=0, microsecond=0) + ), get_current_timezone()) + qs = qs.filter(subevent__date_from__gte=date_start) + + if fdata.get('time_until'): + qs = qs.filter(subevent__date_from__time__lte=fdata.get('time_until')) + if fdata.get('time_from'): + qs = qs.filter(subevent__date_from__time__gte=fdata.get('time_from')) + + if fdata.get('ordering'): + qs = qs.order_by(*get_deterministic_ordering(Quota, self.get_order_by())) + else: + qs = qs.order_by('-subevent__date_from', 'name', 'pk') + + return qs + + class OrganizerFilterForm(FilterForm): orders = { 'slug': 'slug', diff --git a/src/pretix/control/forms/item.py b/src/pretix/control/forms/item.py index 6829907cd..6fd90da24 100644 --- a/src/pretix/control/forms/item.py +++ b/src/pretix/control/forms/item.py @@ -43,6 +43,7 @@ from django.core.exceptions import ValidationError from django.db.models import Max, Q from django.forms import ChoiceField, RadioSelect from django.forms.formsets import DELETION_FIELD_NAME +from django.forms.utils import ErrorDict from django.urls import reverse from django.utils.functional import cached_property from django.utils.html import escape, format_html @@ -375,6 +376,60 @@ class QuotaForm(I18nModelForm): return inst +class QuotaBulkEditForm(QuotaForm): + + def __init__(self, *args, **kwargs): + self.mixed_values = kwargs.pop('mixed_values') + self.queryset = kwargs.pop('queryset') + super().__init__(**kwargs) + self.fields.pop("subevent", None) # Would add extra complexity and it's hard to imagine a use case for that + self.fields["name"].required = False + self.fields["itemvars"].required = False + + def clean(self): + d = super().clean() + if self.prefix + "name" in self.data.getlist('_bulk') and not d.get("name"): + raise ValidationError({"name": _("This field is required.")}) + if self.prefix + "itemvars" in self.data.getlist('_bulk') and not d.get("itemvars"): + raise ValidationError({"itemvars": _("This field is required.")}) + return d + + def save(self, commit=True): + objs = list(self.queryset) + fields = set() + + for k in self.fields: + cb_val = self.prefix + k + if cb_val not in self.data.getlist('_bulk'): + continue + + fields.add(k) + if k == 'itemvars': + selected_items = set(list(self.event.items.filter(id__in=[ + i.split('-')[0] for i in self.cleaned_data['itemvars'] + ]))) + selected_variations = list(ItemVariation.objects.filter(item__event=self.event, id__in=[ + i.split('-')[1] for i in self.cleaned_data['itemvars'] if '-' in i + ])) + for obj in objs: + obj.items.set(selected_items) + obj.variations.set(selected_variations) + else: + for obj in objs: + setattr(obj, k, self.cleaned_data[k]) + + fields = [f for f in fields if f != 'itemvars'] + if fields: + Quota.objects.bulk_update(objs, fields, 200) + + def full_clean(self): + if len(self.data) == 0: + # form wasn't submitted + self._errors = ErrorDict() + return + super().full_clean() + + class ItemCreateForm(I18nModelForm): NONE = 'none' EXISTING = 'existing' diff --git a/src/pretix/control/templates/pretixcontrol/items/quota_bulk_edit.html b/src/pretix/control/templates/pretixcontrol/items/quota_bulk_edit.html new file mode 100644 index 000000000..080f312cd --- /dev/null +++ b/src/pretix/control/templates/pretixcontrol/items/quota_bulk_edit.html @@ -0,0 +1,49 @@ +{% extends "pretixcontrol/event/base.html" %} +{% load i18n %} +{% load bootstrap3 %} +{% block content %} +

+ {% trans "Change multiple quotas" %} + + {% blocktrans trimmed with number=quotas.count %} + {{ number }} selected + {% endblocktrans %} + +

+
+ {% csrf_token %} + {% bootstrap_form_errors form %} + +
+ {% trans "General information" %} + {% bootstrap_field form.name layout="bulkedit" %} + {% bootstrap_field form.size layout="bulkedit" %} +
+
+ {% trans "Items" %} +

+ {% blocktrans trimmed %} + Please select the products or product variations this quota should be applied to. If you apply two + quotas to the same product, it will only be available if both quotas have capacity + left. + {% endblocktrans %} +

+ {% bootstrap_field form.itemvars layout="bulkedit" %} +
+
+ {% trans "Advanced options" %} + {% bootstrap_field form.close_when_sold_out layout="bulkedit" %} + {% bootstrap_field form.release_after_exit layout="bulkedit" %} + {% bootstrap_field form.ignore_for_event_availability layout="bulkedit" %} +
+
+ +
+
+{% endblock %} diff --git a/src/pretix/control/templates/pretixcontrol/items/quota_delete_bulk.html b/src/pretix/control/templates/pretixcontrol/items/quota_delete_bulk.html new file mode 100644 index 000000000..2420d8bf1 --- /dev/null +++ b/src/pretix/control/templates/pretixcontrol/items/quota_delete_bulk.html @@ -0,0 +1,34 @@ +{% extends "pretixcontrol/event/base.html" %} +{% load i18n %} +{% load bootstrap3 %} +{% block title %}{% trans "Delete quotas" %}{% endblock %} +{% block content %} +

{% trans "Delete quotas" %}

+
+ {% csrf_token %} + {% if allowed %} +

{% blocktrans trimmed count num=allowed|length %} + Are you sure you want to delete the following quota? + {% plural %} + Are you sure you want to delete the following {{ num }} quotas? + {% endblocktrans %}

+
    + {% for q in allowed %} +
  • + {{ q }} {% if q.subevent %}({{ q.subevent }}){% endif %} + +
  • + {% endfor %} +
+ {% endif %} +
+ + {% trans "Cancel" %} + + +
+
+{% endblock %} diff --git a/src/pretix/control/templates/pretixcontrol/items/quotas.html b/src/pretix/control/templates/pretixcontrol/items/quotas.html index 5e2729bfc..0da36c9be 100644 --- a/src/pretix/control/templates/pretixcontrol/items/quotas.html +++ b/src/pretix/control/templates/pretixcontrol/items/quotas.html @@ -1,6 +1,7 @@ {% extends "pretixcontrol/items/base.html" %} {% load i18n %} {% load urlreplace %} +{% load bootstrap3 %} {% block title %}{% trans "Quotas" %}{% endblock %} {% block inside %}

{% trans "Quotas" %}

@@ -13,21 +14,12 @@ number of a specific ticket type at the same time. {% endblocktrans %}

- {% if request.event.has_subevents %} -
- {% include "pretixcontrol/event/fragment_subevent_choice_simple.html" %} -
- {% endif %} - {% if quotas|length == 0 %} + {% if quotas|length == 0 and not filter_form.filtered %}

- {% if request.GET.subevent %} - {% trans "Your search did not match any quotas." %} - {% else %} - {% blocktrans trimmed %} - You haven't created any quotas yet. - {% endblocktrans %} - {% endif %} + {% blocktrans trimmed %} + You haven't created any quotas yet. + {% endblocktrans %}

{% if 'event.items:write' in request.eventpermset %} @@ -36,79 +28,160 @@ {% endif %}
{% else %} + +
+
+

+ {% trans "Filter" %} +

+
+
+
+
+ {% bootstrap_field filter_form.query %} +
+ {% if filter_form.subevent %} +
+ {% bootstrap_field filter_form.subevent %} +
+
+ {% bootstrap_field filter_form.date_from %} +
+
+ {% bootstrap_field filter_form.date_until %} +
+
+ {% bootstrap_field filter_form.time_from %} +
+
+ {% bootstrap_field filter_form.time_until %} +
+
+ {% bootstrap_field filter_form.weekday %} +
+ {% endif %} +
+ +
+ +
+
+
{% if 'event.items:write' in request.eventpermset %}

{% trans "Create a new quota" %}

{% endif %} -
- - - - - - {% if request.event.has_subevents %} - - {% endif %} - - - - - - - {% for q in quotas %} + + {% csrf_token %} + {% for field in filter_form %} + {{ field.as_hidden }} + {% endfor %} +
+
{% trans "Quota name" %} - - - {% trans "Products" %}{% trans "Date" context "subevent" %} - - - {% trans "Total capacity" %} - - - {% trans "Capacity left" %}
+ - - - {% if request.event.has_subevents %} - + {% if "event.items:write" in request.eventpermset %} + {% endif %} - - - + + + {% if request.event.has_subevents %} + + {% endif %} + + + - {% endfor %} - -
- {{ q.name }} - {% if q.ignore_for_event_availability %} - - {% endif %} - -
    - {% for item in q.cached_items %} - {% if not item.has_variations %} -
  • {{ item }}
  • - {% endif %} - {% endfor %} - {% for v in q.variations.all %} -
  • - {{ v.item }} – {{ v }}
  • - {% endfor %} -
-
- {{ q.subevent.name }} – {{ q.subevent.get_date_range_display_with_times }} - + + {% if q.size == None %}Unlimited{% else %}{{ q.size }}{% endif %}{% include "pretixcontrol/items/fragment_quota_availability.html" with availability=q.cached_avail closed=q.closed %} - {% if 'event.items:write' in request.eventpermset %} - - - - - - {% endif %} - {% trans "Quota name" %} + + + {% trans "Products" %}{% trans "Date" context "subevent" %} + + + {% trans "Total capacity" %} + + + {% trans "Capacity left" %}
-
+ {% if "event.items:write" in request.eventpermset and page_obj.paginator.num_pages > 1 %} + + + + + + + + + {% endif %} + + + {% for q in quotas %} + + {% if "event.items:write" in request.eventpermset %} + + + + {% endif %} + + {{ q.name }} + {% if q.ignore_for_event_availability %} + + {% endif %} + + +
    + {% for item in q.cached_items %} + {% if not item.has_variations %} +
  • {{ item }}
  • + {% endif %} + {% endfor %} + {% for v in q.variations.all %} +
  • + {{ v.item }} – {{ v }}
  • + {% endfor %} +
+ + {% if request.event.has_subevents %} + + {{ q.subevent.name }} – {{ q.subevent.get_date_range_display_with_times }} + + {% endif %} + {% if q.size == None %}Unlimited{% else %}{{ q.size }}{% endif %} + {% include "pretixcontrol/items/fragment_quota_availability.html" with availability=q.cached_avail closed=q.closed %} + + {% if 'event.items:write' in request.eventpermset %} + + + + + + {% endif %} + + + {% endfor %} + + + + {% if "event.items:write" in request.eventpermset %} +
+ + +
+ {% endif %} + {% endif %} {% include "pretixcontrol/pagination.html" %} {% endblock %} diff --git a/src/pretix/control/urls.py b/src/pretix/control/urls.py index 35c659fd3..1d9576126 100644 --- a/src/pretix/control/urls.py +++ b/src/pretix/control/urls.py @@ -349,6 +349,8 @@ urlpatterns = [ name='event.items.questions.edit'), re_path(r'^questions/add$', item.QuestionCreate.as_view(), name='event.items.questions.add'), re_path(r'^quotas/$', item.QuotaList.as_view(), name='event.items.quotas'), + re_path(r'^quotas/bulk_action$', item.QuotaBulkAction.as_view(), name='event.items.quotas.bulkaction'), + re_path(r'^quotas/bulk_edit$', item.QuotaBulkUpdateView.as_view(), name='event.items.quotas.bulkedit'), re_path(r'^quotas/(?P\d+)/$', item.QuotaView.as_view(), name='event.items.quotas.show'), re_path(r'^quotas/select$', typeahead.quotas_select2, name='event.items.quotas.select2'), re_path(r'^quotas/(?P\d+)/change$', item.QuotaUpdate.as_view(), name='event.items.quotas.edit'), diff --git a/src/pretix/control/views/item.py b/src/pretix/control/views/item.py index f55f678c0..624999f4f 100644 --- a/src/pretix/control/views/item.py +++ b/src/pretix/control/views/item.py @@ -41,21 +41,22 @@ from json.decoder import JSONDecodeError from django.contrib import messages from django.core.exceptions import PermissionDenied from django.core.files import File -from django.db import transaction +from django.db import models, transaction from django.db.models import ( - Count, Exists, F, OuterRef, Prefetch, ProtectedError, Q, + Count, Exists, F, OuterRef, Prefetch, ProtectedError, Q, Subquery, Value, ) +from django.db.models.functions import Cast, Concat from django.forms.models import inlineformset_factory from django.http import ( Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect, ) -from django.shortcuts import redirect +from django.shortcuts import redirect, render from django.urls import resolve, reverse from django.utils.functional import cached_property from django.utils.timezone import now from django.utils.translation import gettext, gettext_lazy as _ from django.views.decorators.http import require_http_methods -from django.views.generic import ListView +from django.views.generic import FormView, ListView, View from django.views.generic.detail import DetailView, SingleObjectMixin from django_countries.fields import Country @@ -65,7 +66,7 @@ from pretix.api.serializers.item import ( ) from pretix.base.forms import I18nFormSet from pretix.base.models import ( - CartPosition, Item, ItemCategory, ItemProgramTime, ItemVariation, + CartPosition, Item, ItemCategory, ItemProgramTime, ItemVariation, LogEntry, OrderPosition, Question, QuestionAnswer, QuestionOption, Quota, SeatCategoryMapping, Voucher, ) @@ -74,12 +75,15 @@ from pretix.base.models.items import ItemAddOn, ItemBundle, ItemMetaValue from pretix.base.services.quotas import QuotaAvailability from pretix.base.services.tickets import invalidate_cache from pretix.base.signals import quota_availability -from pretix.control.forms.filter import QuestionAnswerFilterForm +from pretix.control.forms.filter import ( + QuestionAnswerFilterForm, QuotaFilterForm, +) from pretix.control.forms.item import ( CategoryForm, ItemAddOnForm, ItemAddOnsFormSet, ItemBundleForm, ItemBundleFormSet, ItemCreateForm, ItemMetaValueForm, ItemProgramTimeForm, ItemProgramTimeFormSet, ItemUpdateForm, ItemVariationForm, - ItemVariationsFormSet, QuestionForm, QuestionOptionForm, QuotaForm, + ItemVariationsFormSet, QuestionForm, QuestionOptionForm, QuotaBulkEditForm, + QuotaForm, ) from pretix.control.permissions import ( EventPermissionRequiredMixin, event_permission_required, @@ -87,6 +91,7 @@ from pretix.control.permissions import ( from pretix.control.signals import item_forms, item_formsets from pretix.helpers.models import modelcopy +from ...helpers import GroupConcat from ...helpers.compat import CompatDeleteView from . import ChartContainingView, CreateView, PaginationMixin, UpdateView @@ -831,13 +836,38 @@ class QuestionCreate(EventPermissionRequiredMixin, QuestionMixin, CreateView): return ret -class QuotaList(PaginationMixin, ListView): +class QuotaQueryMixin: + + @cached_property + def request_data(self): + if self.request.method == "POST": + return self.request.POST + return self.request.GET + + def get_queryset(self): + qs = self.request.event.quotas + if self.filter_form.is_valid(): + qs = self.filter_form.filter_qs(qs) + + if 'quota' in self.request_data and '__ALL' not in self.request_data: + qs = qs.filter( + id__in=self.request_data.getlist('quota') + ) + + return qs + + @cached_property + def filter_form(self): + return QuotaFilterForm(data=self.request_data, prefix='filter', event=self.request.event) + + +class QuotaList(PaginationMixin, QuotaQueryMixin, ListView): model = Quota context_object_name = 'quotas' template_name = 'pretixcontrol/items/quotas.html' def get_queryset(self): - qs = self.request.event.quotas.prefetch_related( + return super().get_queryset().prefetch_related( Prefetch( "items", queryset=Item.objects.annotate( @@ -852,28 +882,10 @@ class QuotaList(PaginationMixin, ListView): queryset=self.request.event.subevents.all() ) ) - if self.request.GET.get("subevent", "") != "": - s = self.request.GET.get("subevent", "") - qs = qs.filter(subevent_id=s) - - valid_orders = { - '-date': ('-subevent__date_from', 'name', 'pk'), - 'date': ('subevent__date_from', '-name', '-pk'), - 'size': ('size', 'name', 'pk'), - '-size': ('-size', '-name', '-pk'), - 'name': ('name', 'pk'), - '-name': ('-name', '-pk'), - } - - if self.request.GET.get("ordering", "-date") in valid_orders: - qs = qs.order_by(*valid_orders[self.request.GET.get("ordering", "-date")]) - else: - qs = qs.order_by('name', 'subevent__date_from', 'pk') - - return qs def get_context_data(self, **kwargs): ctx = super().get_context_data() + ctx['filter_form'] = self.filter_form qa = QuotaAvailability() qa.queue(*ctx['quotas']) @@ -884,6 +896,165 @@ class QuotaList(PaginationMixin, ListView): return ctx +class QuotaBulkAction(QuotaQueryMixin, EventPermissionRequiredMixin, View): + permission = 'event.items:write' + + @transaction.atomic + def post(self, request, *args, **kwargs): + if request.POST.get('action') == 'delete': + return render(request, 'pretixcontrol/items/quota_delete_bulk.html', { + 'allowed': self.get_queryset().select_related("subevent"), + }) + elif request.POST.get('action') == 'delete_confirm': + log_entries = [] + to_delete = [] + for obj in self.get_queryset(): + log_entries.append(obj.log_action('pretix.event.quota.deleted', user=self.request.user, save=False)) + to_delete.append(obj.pk) + + if to_delete: + LogEntry.bulk_create_and_postprocess(log_entries) + Quota.objects.filter(pk__in=to_delete).delete() + messages.success(request, _('The selected quotas have been deleted or disabled.')) + return redirect(self.get_success_url()) + + def get_success_url(self) -> str: + return reverse('control:event.items.quotas', kwargs={ + 'organizer': self.request.event.organizer.slug, + 'event': self.request.event.slug, + }) + + +class QuotaBulkUpdateView(QuotaQueryMixin, EventPermissionRequiredMixin, FormView): + template_name = 'pretixcontrol/items/quota_bulk_edit.html' + permission = 'event.items:write' + context_object_name = 'quota' + form_class = QuotaBulkEditForm + + def get_queryset(self): + return super().get_queryset().prefetch_related(None).order_by() + + def get(self, request, *args, **kwargs): + return HttpResponse(status=405) + + @cached_property + def is_submitted(self): + # Usually, django considers a form "bound" / "submitted" on every POST request. However, this view is always + # called with POST method, even if just to pass the selection of objects to work on, so we want to modify + # that behaviour + return '_bulk' in self.request.POST + + def get_form_kwargs(self): + initial = {} + mixed_values = set() + qs = self.get_queryset().annotate( + items_list=Subquery( + Quota.items.through.objects.filter( + quota_id=OuterRef('pk'), + item__variations__isnull=True, + ).order_by().values('quota_id').annotate( + g=GroupConcat('item_id', separator=',', ordered=True) + ).values('g') + ), + vars_list=Subquery( + Quota.variations.through.objects.filter( + quota_id=OuterRef('pk') + ).order_by().values('quota_id').annotate( + g=GroupConcat( + Concat( + Cast(F('itemvariation__item_id'), output_field=models.TextField()), + Value('-', output_field=models.TextField()), + Cast(F('itemvariation_id'), output_field=models.TextField()), + ), + separator=',', + ordered=True + ) + ).values('g') + ), + ) + + fields = { + 'name': 'name', + 'size': 'size', + 'subevent': 'subevent', + 'close_when_sold_out': 'close_when_sold_out', + 'release_after_exit': 'release_after_exit', + 'ignore_for_event_availability': 'ignore_for_event_availability', + } + for k, f in fields.items(): + existing_values = list(qs.order_by(f).values(f).annotate(c=Count('*'))) + if len(existing_values) == 1: + initial[k] = existing_values[0][f] + elif len(existing_values) > 1: + mixed_values.add(k) + initial[k] = None + + item_values = list(qs.order_by("items_list").values("items_list").annotate(c=Count('*'))) + var_values = list(qs.order_by("vars_list").values("vars_list").annotate(c=Count('*'))) + if len(item_values) > 1 or len(var_values) > 1: + mixed_values.add("itemvars") + else: + initial["itemvars"] = [iv for iv in (item_values[0]["items_list"] or "").split(",") + (var_values[0]["vars_list"] or "").split(",") if iv] + + kwargs = super().get_form_kwargs() + kwargs['event'] = self.request.event + kwargs['prefix'] = 'bulkedit' + kwargs['initial'] = initial + kwargs['queryset'] = self.get_queryset() + kwargs['mixed_values'] = mixed_values + if not self.is_submitted: + kwargs['data'] = None + kwargs['files'] = None + return kwargs + + def get_success_url(self): + return reverse('control:event.items.quotas', kwargs={ + 'organizer': self.request.event.organizer.slug, + 'event': self.request.event.slug, + }) + + @transaction.atomic() + def form_valid(self, form): + log_entries = [] + + # Main form + form.save() + data = { + k: v + for k, v in form.cleaned_data.items() + if k in form.changed_data + } + data['_raw_bulk_data'] = self.request.POST.dict() + for obj in self.get_queryset(): + log_entries.append( + obj.log_action('pretix.event.quota.changed', data=data, user=self.request.user, save=False) + ) + + LogEntry.bulk_create_and_postprocess(log_entries) + + messages.success(self.request, _('Your changes have been saved.')) + return super().form_valid(form) + + def get_context_data(self, **kwargs): + ctx = super().get_context_data(**kwargs) + ctx['quotas'] = self.get_queryset() + ctx['bulk_selected'] = self.request.POST.getlist("_bulk") + return ctx + + def post(self, request, *args, **kwargs): + form = self.get_form() + is_valid = ( + self.is_submitted and + form.is_valid() + ) + if is_valid: + return self.form_valid(form) + else: + if self.is_submitted: + messages.error(self.request, _('We could not save your changes. See below for details.')) + return self.form_invalid(form) + + class QuotaCreate(EventPermissionRequiredMixin, CreateView): model = Quota form_class = QuotaForm diff --git a/src/pretix/helpers/database.py b/src/pretix/helpers/database.py index 1289f4f1a..d9d8ffb16 100644 --- a/src/pretix/helpers/database.py +++ b/src/pretix/helpers/database.py @@ -117,12 +117,17 @@ class GroupConcat(Aggregate): template = "%(function)s(%(distinct)s%(field)s::text, '%(separator)s' ORDER BY %(field)s::text ASC)" else: template = "%(function)s(%(distinct)s%(field)s::text, '%(separator)s')" - return super().as_sql( + + template, params = super().as_sql( compiler, connection, function='string_agg', template=template, **extra_context, ) + if self.ordered: + # ordered statement requires field parameters twice + params = params + params + return template, params class ReplicaRouter: -- 2.54.0 From ac08359a0e474683b4fc97c8a204e9a1a9612a30 Mon Sep 17 00:00:00 2001 From: Richard Schreiber Date: Mon, 4 May 2026 16:19:02 +0200 Subject: [PATCH 011/102] Widget: Raise BadRequest when GET-offset is not an int (#6143) --- src/pretix/presale/views/widget.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pretix/presale/views/widget.py b/src/pretix/presale/views/widget.py index d2e54ed90..0e8ff11c0 100644 --- a/src/pretix/presale/views/widget.py +++ b/src/pretix/presale/views/widget.py @@ -34,6 +34,7 @@ from compressor.filters.jsmin import rJSMinFilter from django.conf import settings from django.contrib.staticfiles import finders from django.core.cache import cache +from django.core.exceptions import BadRequest from django.core.files.base import ContentFile, File from django.core.files.storage import default_storage from django.db.models import Q @@ -676,7 +677,10 @@ class WidgetAPIProductList(EventListMixin, View): for d in data['days']: d['events'] = self._serialize_events(d['events'] or []) else: - offset = int(self.request.GET.get("offset", 0)) + try: + offset = int(self.request.GET.get("offset", 0)) + except ValueError: + raise BadRequest('GET parameter "offset" must be an integer.') limit = 50 if hasattr(self.request, 'event'): evs = filter_qs_by_attr( -- 2.54.0 From 6010d7f9e5159fdd7126de1ac0f013a908f2360e Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Tue, 5 May 2026 14:56:02 +0200 Subject: [PATCH 012/102] Order details: Link to subevent details (Z#23227664) (#6148) --- src/pretix/control/templates/pretixcontrol/order/index.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pretix/control/templates/pretixcontrol/order/index.html b/src/pretix/control/templates/pretixcontrol/order/index.html index 1d3fa472d..bece30e11 100644 --- a/src/pretix/control/templates/pretixcontrol/order/index.html +++ b/src/pretix/control/templates/pretixcontrol/order/index.html @@ -471,7 +471,9 @@ {% endif %} {% if line.subevent %}
- {{ line.subevent.name }} · {{ line.subevent.get_date_range_display_with_times }} + + {{ line.subevent.name }} + · {{ line.subevent.get_date_range_display_with_times }} {% endif %} {% if line.used_membership %}
-- 2.54.0 From ca7c982abd63dff3a4d4fe7801ef70fc13891e0b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 17:13:40 +0200 Subject: [PATCH 013/102] Bump @babel/preset-env from 7.29.0 to 7.29.3 in /src/pretix/static/npm_dir (#6136) Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.29.0 to 7.29.3. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.29.3/packages/babel-preset-env) --- updated-dependencies: - dependency-name: "@babel/preset-env" dependency-version: 7.29.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/pretix/static/npm_dir/package-lock.json | 56 +++++++++++++++------ src/pretix/static/npm_dir/package.json | 2 +- 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/pretix/static/npm_dir/package-lock.json b/src/pretix/static/npm_dir/package-lock.json index 9f6323490..02a638e4f 100644 --- a/src/pretix/static/npm_dir/package-lock.json +++ b/src/pretix/static/npm_dir/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.0", "dependencies": { "@babel/core": "^7.28.5", - "@babel/preset-env": "^7.29.0", + "@babel/preset-env": "^7.29.3", "@rollup/plugin-babel": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.3", "rollup": "^2.79.1", @@ -32,9 +32,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", + "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", "engines": { "node": ">=6.9.0" } @@ -439,6 +439,21 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.3.tgz", + "integrity": "sha512-SRS46DFR4HqzUzCVgi90/xMoL+zeBDBvWdKYXSEzh79kXswNFEglUpMKxR04//dPqwYXWUBJ3mpUd933ru9Kmg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", @@ -1301,17 +1316,18 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.0.tgz", - "integrity": "sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.3.tgz", + "integrity": "sha512-ySZypNLAIH1ClygLDQzVMoGQRViATnkHkYYV6TcNDz+8+jwZCdsguGvsb3EY5d9wyWyhmF1iSuFM0Yh5XPnqSA==", "dependencies": { - "@babel/compat-data": "^7.29.0", + "@babel/compat-data": "^7.29.3", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.3", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", @@ -3751,9 +3767,9 @@ } }, "@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==" + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", + "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==" }, "@babel/core": { "version": "7.28.5", @@ -4033,6 +4049,15 @@ "@babel/helper-plugin-utils": "^7.27.1" } }, + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.3.tgz", + "integrity": "sha512-SRS46DFR4HqzUzCVgi90/xMoL+zeBDBvWdKYXSEzh79kXswNFEglUpMKxR04//dPqwYXWUBJ3mpUd933ru9Kmg==", + "requires": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + } + }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", @@ -4532,17 +4557,18 @@ } }, "@babel/preset-env": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.0.tgz", - "integrity": "sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.3.tgz", + "integrity": "sha512-ySZypNLAIH1ClygLDQzVMoGQRViATnkHkYYV6TcNDz+8+jwZCdsguGvsb3EY5d9wyWyhmF1iSuFM0Yh5XPnqSA==", "requires": { - "@babel/compat-data": "^7.29.0", + "@babel/compat-data": "^7.29.3", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.3", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", diff --git a/src/pretix/static/npm_dir/package.json b/src/pretix/static/npm_dir/package.json index 755c5028d..2f543e53d 100644 --- a/src/pretix/static/npm_dir/package.json +++ b/src/pretix/static/npm_dir/package.json @@ -5,7 +5,7 @@ "scripts": {}, "dependencies": { "@babel/core": "^7.28.5", - "@babel/preset-env": "^7.29.0", + "@babel/preset-env": "^7.29.3", "@rollup/plugin-babel": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.3", "vue": "^2.7.16", -- 2.54.0 From bd6abbc2808c4db8c18c0b221ec1b0ac54ac6629 Mon Sep 17 00:00:00 2001 From: Daniel Musketa Date: Tue, 5 May 2026 17:14:22 +0200 Subject: [PATCH 014/102] Docs: Update link to Django style guide (#6140) --- doc/development/contribution/style.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/development/contribution/style.rst b/doc/development/contribution/style.rst index 0f69a2697..d6065a019 100644 --- a/doc/development/contribution/style.rst +++ b/doc/development/contribution/style.rst @@ -86,7 +86,7 @@ individual commits, we use "Rebase and merge" instead. Merge commits should be a .. _PEP 8: https://legacy.python.org/dev/peps/pep-0008/ .. _flake8: https://pypi.python.org/pypi/flake8 .. _Django Coding Style: https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/coding-style/ -.. _translation: https://docs.djangoproject.com/en/1.11/topics/i18n/translation/ -.. _class-based views: https://docs.djangoproject.com/en/1.11/topics/class-based-views/ +.. _translation: https://docs.djangoproject.com/en/6.0/topics/i18n/translation/ +.. _class-based views: https://docs.djangoproject.com/en/6.0/topics/class-based-views/ .. _pytest-style: https://docs.pytest.org/en/latest/assert.html .. _fixtures: https://docs.pytest.org/en/latest/fixture.html -- 2.54.0 From 994e4b410a97bda8568ce484a800cd70cf1abc75 Mon Sep 17 00:00:00 2001 From: Daniel Musketa Date: Tue, 5 May 2026 17:15:14 +0200 Subject: [PATCH 015/102] Fix gettext singular forms in cart error_messages (#6147) --- src/pretix/base/services/cart.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pretix/base/services/cart.py b/src/pretix/base/services/cart.py index 59abf6c87..99604e637 100644 --- a/src/pretix/base/services/cart.py +++ b/src/pretix/base/services/cart.py @@ -162,12 +162,12 @@ error_messages = { 'price_too_high': gettext_lazy('The entered price is to high.'), 'voucher_invalid': gettext_lazy('This voucher code is not known in our database.'), 'voucher_min_usages': ngettext_lazy( - 'The voucher code "%(voucher)s" can only be used if you select at least %(number)s matching products.', + 'The voucher code "%(voucher)s" can only be used if you select at least %(number)s matching product.', 'The voucher code "%(voucher)s" can only be used if you select at least %(number)s matching products.', 'number' ), 'voucher_min_usages_removed': ngettext_lazy( - 'The voucher code "%(voucher)s" can only be used if you select at least %(number)s matching products. ' + 'The voucher code "%(voucher)s" can only be used if you select at least %(number)s matching product. ' 'We have therefore removed some positions from your cart that can no longer be purchased like this.', 'The voucher code "%(voucher)s" can only be used if you select at least %(number)s matching products. ' 'We have therefore removed some positions from your cart that can no longer be purchased like this.', -- 2.54.0 From e87b030427f6f74cf63fee38157a1b0fd3227855 Mon Sep 17 00:00:00 2001 From: Daniel Musketa Date: Tue, 5 May 2026 17:15:34 +0200 Subject: [PATCH 016/102] Stripe: Add missing word in help text (#6146) --- src/pretix/plugins/stripe/payment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pretix/plugins/stripe/payment.py b/src/pretix/plugins/stripe/payment.py index 5211d0943..9bf307362 100644 --- a/src/pretix/plugins/stripe/payment.py +++ b/src/pretix/plugins/stripe/payment.py @@ -386,7 +386,7 @@ class StripeSettingsHolder(BasePaymentProvider): disabled=self.event.currency != 'EUR', help_text=( _('Some payment methods might need to be enabled in the settings of your Stripe account ' - 'before work properly.') + + 'before they work properly.') + '
%s
' % _( 'SEPA Direct Debit payments via Stripe are not processed ' 'instantly but might take up to 14 days to be confirmed in some cases. ' -- 2.54.0 From 70d59a960c7c2c949b3a292d6d88d1a038e97217 Mon Sep 17 00:00:00 2001 From: CVZ-es Date: Thu, 30 Apr 2026 11:08:07 +0200 Subject: [PATCH 017/102] Translations: Update French Currently translated at 100.0% (6295 of 6295 strings) Translation: pretix/pretix Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/fr/ powered by weblate --- src/pretix/locale/fr/LC_MESSAGES/django.po | 43 ++++++++++------------ 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/src/pretix/locale/fr/LC_MESSAGES/django.po b/src/pretix/locale/fr/LC_MESSAGES/django.po index 8db959e12..b8e0a9990 100644 --- a/src/pretix/locale/fr/LC_MESSAGES/django.po +++ b/src/pretix/locale/fr/LC_MESSAGES/django.po @@ -4,16 +4,16 @@ msgstr "" "Project-Id-Version: 1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-28 09:03+0000\n" -"PO-Revision-Date: 2026-03-31 17:00+0000\n" +"PO-Revision-Date: 2026-04-30 18:00+0000\n" "Last-Translator: CVZ-es \n" -"Language-Team: French \n" +"Language-Team: French \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 5.16.2\n" +"X-Generator: Weblate 5.17\n" #: pretix/_base_settings.py:87 msgid "English" @@ -8279,10 +8279,8 @@ msgstr "" "2x Add-on 2" #: pretix/base/pdf.py:383 -#, fuzzy -#| msgid "List of Add-Ons" msgid "List of Checked-In Add-Ons" -msgstr "Liste des Addons" +msgstr "Liste des modules complémentaires enregistrés" #: pretix/base/pdf.py:390 pretix/control/forms/filter.py:1537 #: pretix/control/forms/filter.py:1539 @@ -9296,10 +9294,8 @@ msgid "Czech National Bank" msgstr "Banque nationale tchèque" #: pretix/base/services/currencies.py:41 -#, fuzzy -#| msgid "Czech National Bank" msgid "National Bank of Poland" -msgstr "Banque nationale tchèque" +msgstr "Banque nationale de Pologne" #: pretix/base/services/export.py:95 pretix/base/services/export.py:155 msgid "" @@ -10396,16 +10392,12 @@ msgstr "" "que le montant de la facture n’est pas en CZK." #: pretix/base/settings.py:577 pretix/base/settings.py:586 -#, fuzzy -#| msgid "" -#| "Based on Czech National Bank daily rates, whenever the invoice amount is " -#| "not in CZK." msgid "" "Based on National Bank of Poland daily rates, whenever the invoice amount is " "not in PLN." msgstr "" -"Sur la base des taux journaliers de la Banque nationale tchèque, chaque fois " -"que le montant de la facture n’est pas en CZK." +"Sur la base des taux quotidiens de la Banque nationale de Pologne, lorsque " +"le montant de la facture n'est pas libellé en PLN." #: pretix/base/settings.py:597 msgid "Require invoice address" @@ -16569,10 +16561,8 @@ msgstr "" "Autoriser à surbooker les quotas lors de l’exécution de cette opération" #: pretix/control/forms/orders.py:335 -#, fuzzy -#| msgid "Number of orders" msgid "Number of products to add" -msgstr "Nombre de commandes" +msgstr "Nombre d'articles à ajouter" #: pretix/control/forms/orders.py:344 msgid "Add-on to" @@ -16604,10 +16594,10 @@ msgstr "" "produit" #: pretix/control/forms/orders.py:441 -#, fuzzy -#| msgid "You can not select the same seat multiple times." msgid "You can not choose a seat when adding multiple products at once." -msgstr "Vous ne pouvez pas sélectionner le même siège plusieurs fois." +msgstr "" +"Vous ne pouvez pas choisir de siège lorsque vous ajoutez plusieurs produits " +"à la fois." #: pretix/control/forms/orders.py:478 pretix/control/forms/orders.py:482 #: pretix/control/forms/orders.py:510 pretix/control/forms/orders.py:552 @@ -17230,7 +17220,7 @@ msgstr "Jour de fin de semaine" #: pretix/control/forms/subevents.py:106 msgctxt "subevent" msgid "Skip dates that overlap with any existing date" -msgstr "" +msgstr "Ignorer les dates qui coïncident avec une date existante" #: pretix/control/forms/subevents.py:109 msgctxt "subevent" @@ -17240,6 +17230,11 @@ msgid "" "This respects even inactive dates and works best if all dates have both a " "start and end time." msgstr "" +"Cette option peut s'avérer utile si toutes vos dates se déroulent au même " +"endroit et qu'aucune date ne doit être créée en double et entrer en conflit " +"avec des événements spéciaux existants. Elle prend en compte même les dates " +"inactives et fonctionne mieux si toutes les dates comportent à la fois une " +"heure de début et une heure de fin." #: pretix/control/forms/subevents.py:128 msgid "Keep the current values" @@ -30512,6 +30507,8 @@ msgstr "Veuillez ne pas créer plus de 100.000 dates à la fois." #: pretix/control/views/subevents.py:966 msgid "All dates would be skipped because they conflict with existing dates." msgstr "" +"Toutes ces dates seraient ignorées car elles entrent en conflit avec des " +"dates déjà existantes." #: pretix/control/views/subevents.py:1102 #, python-brace-format -- 2.54.0 From b0d1c93fd9bfa17eba28e55f41fdff0c02e8bade Mon Sep 17 00:00:00 2001 From: CVZ-es Date: Thu, 30 Apr 2026 11:09:57 +0200 Subject: [PATCH 018/102] Translations: Update Spanish Currently translated at 100.0% (6295 of 6295 strings) Translation: pretix/pretix Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/es/ powered by weblate --- src/pretix/locale/es/LC_MESSAGES/django.po | 37 ++++++++++------------ 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/pretix/locale/es/LC_MESSAGES/django.po b/src/pretix/locale/es/LC_MESSAGES/django.po index 7ac4d4868..ac0b38e4a 100644 --- a/src/pretix/locale/es/LC_MESSAGES/django.po +++ b/src/pretix/locale/es/LC_MESSAGES/django.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-28 09:03+0000\n" -"PO-Revision-Date: 2026-04-17 03:00+0000\n" -"Last-Translator: Tim \n" +"PO-Revision-Date: 2026-04-30 18:00+0000\n" +"Last-Translator: CVZ-es \n" "Language-Team: Spanish \n" "Language: es\n" @@ -8231,10 +8231,8 @@ msgstr "" "2x complemento 2" #: pretix/base/pdf.py:383 -#, fuzzy -#| msgid "List of Add-Ons" msgid "List of Checked-In Add-Ons" -msgstr "Lista de add-ons" +msgstr "Lista de complementos registrados" #: pretix/base/pdf.py:390 pretix/control/forms/filter.py:1537 #: pretix/control/forms/filter.py:1539 @@ -9237,10 +9235,8 @@ msgid "Czech National Bank" msgstr "Banco Nacional Checo" #: pretix/base/services/currencies.py:41 -#, fuzzy -#| msgid "Czech National Bank" msgid "National Bank of Poland" -msgstr "Banco Nacional Checo" +msgstr "Banco Nacional de Polonia" #: pretix/base/services/export.py:95 pretix/base/services/export.py:155 msgid "" @@ -10336,16 +10332,12 @@ msgstr "" "importe de la factura no esté en CZK." #: pretix/base/settings.py:577 pretix/base/settings.py:586 -#, fuzzy -#| msgid "" -#| "Based on Czech National Bank daily rates, whenever the invoice amount is " -#| "not in CZK." msgid "" "Based on National Bank of Poland daily rates, whenever the invoice amount is " "not in PLN." msgstr "" -"Basado en las tarifas diarias del Banco Nacional Checo, siempre que el " -"importe de la factura no esté en CZK." +"Según los tipos de cambio diarios del Banco Nacional de Polonia, siempre que " +"el importe de la factura no esté en PLN." #: pretix/base/settings.py:597 msgid "Require invoice address" @@ -16430,10 +16422,8 @@ msgid "Allow to overbook quotas when performing this operation" msgstr "Permitir sobrevender cupos cuando se realice esta operación" #: pretix/control/forms/orders.py:335 -#, fuzzy -#| msgid "Number of orders" msgid "Number of products to add" -msgstr "Número de pedidos" +msgstr "Número de productos que se van a añadir" #: pretix/control/forms/orders.py:344 msgid "Add-on to" @@ -16465,10 +16455,8 @@ msgstr "" "defecto del producto" #: pretix/control/forms/orders.py:441 -#, fuzzy -#| msgid "You can not select the same seat multiple times." msgid "You can not choose a seat when adding multiple products at once." -msgstr "No se puede seleccionar la misma butaca varias veces." +msgstr "No es posible elegir un asiento al añadir varios productos a la vez." #: pretix/control/forms/orders.py:478 pretix/control/forms/orders.py:482 #: pretix/control/forms/orders.py:510 pretix/control/forms/orders.py:552 @@ -17076,7 +17064,7 @@ msgstr "Día de fin de semana" #: pretix/control/forms/subevents.py:106 msgctxt "subevent" msgid "Skip dates that overlap with any existing date" -msgstr "" +msgstr "Omite las fechas que coincidan con alguna fecha ya existente" #: pretix/control/forms/subevents.py:109 msgctxt "subevent" @@ -17086,6 +17074,11 @@ msgid "" "This respects even inactive dates and works best if all dates have both a " "start and end time." msgstr "" +"Esto puede resultar útil si todas tus citas tienen lugar en el mismo lugar y " +"no se deben crear citas repetidas que entren en conflicto con eventos " +"especiales ya existentes. Esta función tiene en cuenta incluso las citas " +"inactivas y funciona mejor si todas las citas tienen una hora de inicio y " +"una hora de finalización." #: pretix/control/forms/subevents.py:128 msgid "Keep the current values" @@ -30280,6 +30273,8 @@ msgstr "No cree más de 100.000 fechas a la vez." #: pretix/control/views/subevents.py:966 msgid "All dates would be skipped because they conflict with existing dates." msgstr "" +"Se omitirían todas las fechas, ya que entran en conflicto con las ya " +"existentes." #: pretix/control/views/subevents.py:1102 #, python-brace-format -- 2.54.0 From 301c47b76115aae97b8f25fd6a53f45f61dadbb6 Mon Sep 17 00:00:00 2001 From: Paul Berschick Date: Thu, 30 Apr 2026 16:11:25 +0200 Subject: [PATCH 019/102] Translations: Update Spanish Currently translated at 100.0% (6295 of 6295 strings) Translation: pretix/pretix Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/es/ powered by weblate --- src/pretix/locale/es/LC_MESSAGES/django.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pretix/locale/es/LC_MESSAGES/django.po b/src/pretix/locale/es/LC_MESSAGES/django.po index ac0b38e4a..7f7e46921 100644 --- a/src/pretix/locale/es/LC_MESSAGES/django.po +++ b/src/pretix/locale/es/LC_MESSAGES/django.po @@ -9,7 +9,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-28 09:03+0000\n" "PO-Revision-Date: 2026-04-30 18:00+0000\n" -"Last-Translator: CVZ-es \n" +"Last-Translator: Paul Berschick \n" "Language-Team: Spanish \n" "Language: es\n" @@ -34922,7 +34922,7 @@ msgstr "tiene errores" #: pretix/presale/templates/pretixpresale/event/fragment_voucher_form.html:14 msgctxt "form" msgid "required" -msgstr "requerido" +msgstr "obligatorio" #: pretix/presale/ical.py:87 pretix/presale/ical.py:146 #: pretix/presale/ical.py:182 -- 2.54.0 From 33ccd4342f9fc56e4cb35f45d7d4b6c5239b9cb0 Mon Sep 17 00:00:00 2001 From: Paul Berschick Date: Thu, 30 Apr 2026 16:28:06 +0200 Subject: [PATCH 020/102] Translations: Update Catalan Currently translated at 29.7% (1875 of 6295 strings) Translation: pretix/pretix Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/ca/ powered by weblate --- src/pretix/locale/ca/LC_MESSAGES/django.po | 31 +++++++++------------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/pretix/locale/ca/LC_MESSAGES/django.po b/src/pretix/locale/ca/LC_MESSAGES/django.po index e1c735879..b109c718b 100644 --- a/src/pretix/locale/ca/LC_MESSAGES/django.po +++ b/src/pretix/locale/ca/LC_MESSAGES/django.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-28 09:03+0000\n" -"PO-Revision-Date: 2025-09-29 07:39+0000\n" -"Last-Translator: Raphael Michel \n" +"PO-Revision-Date: 2026-04-30 18:00+0000\n" +"Last-Translator: Paul Berschick \n" "Language-Team: Catalan \n" "Language: ca\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.13.3\n" +"X-Generator: Weblate 5.17\n" #: pretix/_base_settings.py:87 msgid "English" @@ -14132,13 +14132,13 @@ msgid "Contact:" msgstr "Adreça de contacte" #: pretix/base/templates/pretixbase/email/order_details.html:54 -#, fuzzy, python-format -#| msgid "" -#| "You are receiving this email because you placed an order for {event}." +#, python-format msgid "" "You are receiving this email because you placed an order for " "%(event)s." -msgstr "Heu rebut aquest correu perquè heu fet una comanda per {event}." +msgstr "" +"Has rebut aquest correu perquè has fet una inscripció a %(event)s." #: pretix/base/templates/pretixbase/email/order_details.html:93 #: pretix/control/templates/pretixcontrol/organizers/customer.html:23 @@ -24790,7 +24790,7 @@ msgstr "Data d'inici de l'esdeveniment" #: pretix/control/templates/pretixcontrol/order/index.html:465 #: pretix/presale/templates/pretixpresale/event/fragment_cart.html:55 msgid "Voucher code used:" -msgstr "" +msgstr "Codi de descompte utilitzat:" #: pretix/control/templates/pretixcontrol/order/index.html:467 #, fuzzy, python-format @@ -35206,11 +35206,9 @@ msgstr "" #: pretix/presale/forms/renderers.py:66 #: pretix/presale/templates/pretixpresale/event/fragment_voucher_form.html:14 -#, fuzzy -#| msgid "expired" msgctxt "form" msgid "required" -msgstr "expirat" +msgstr "obligatori" #: pretix/presale/ical.py:87 pretix/presale/ical.py:146 #: pretix/presale/ical.py:182 @@ -35399,10 +35397,8 @@ msgid "We're now trying to book these add-ons for you!" msgstr "" #: pretix/presale/templates/pretixpresale/event/checkout_addons.html:28 -#, fuzzy -#| msgid "Meta information" msgid "Additional options for" -msgstr "Informació meta" +msgstr "Opcions addicionals per a" #: pretix/presale/templates/pretixpresale/event/checkout_addons.html:60 #, fuzzy @@ -35754,12 +35750,11 @@ msgstr[0] "Heu de triar només una opció d'aquesta categoria." msgstr[1] "Heu de triar %(min_count)s d'aquesta categoria." #: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:26 -#, fuzzy, python-format -#| msgid "You can choose up to %(max_count)s options from this category." +#, python-format msgid "You can choose one option from this category." msgid_plural "You can choose up to %(max_count)s options from this category." -msgstr[0] "Podeu triar fins a %(max_count)s opcions d'aquesta categoria." -msgstr[1] "Podeu triar fins a %(max_count)s opcions d'aquesta categoria." +msgstr[0] "Pots triar una opció d'aquesta categoria." +msgstr[1] "Pots escollir fins a %(max_count)s opcions d’aquesta categoria." #: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:34 #, python-format -- 2.54.0 From 9183034c15fe4f927a97750f6a136116838209b6 Mon Sep 17 00:00:00 2001 From: Paul Berschick Date: Fri, 1 May 2026 14:01:38 +0200 Subject: [PATCH 021/102] Translations: Update Spanish Currently translated at 100.0% (6295 of 6295 strings) Translation: pretix/pretix Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/es/ powered by weblate --- src/pretix/locale/es/LC_MESSAGES/django.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pretix/locale/es/LC_MESSAGES/django.po b/src/pretix/locale/es/LC_MESSAGES/django.po index 7f7e46921..4938dfa7e 100644 --- a/src/pretix/locale/es/LC_MESSAGES/django.po +++ b/src/pretix/locale/es/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-28 09:03+0000\n" -"PO-Revision-Date: 2026-04-30 18:00+0000\n" +"PO-Revision-Date: 2026-05-01 21:00+0000\n" "Last-Translator: Paul Berschick \n" "Language-Team: Spanish \n" @@ -24357,7 +24357,7 @@ msgstr "Escaneo de entrada: %(date)s" #: pretix/control/templates/pretixcontrol/order/index.html:465 #: pretix/presale/templates/pretixpresale/event/fragment_cart.html:55 msgid "Voucher code used:" -msgstr "Código de vale de compra utilizado:" +msgstr "Código de descuento utilizado:" #: pretix/control/templates/pretixcontrol/order/index.html:467 #, python-format -- 2.54.0 From 4bc8caae73cb886ea1074ca4cfebe92ecf932e2f Mon Sep 17 00:00:00 2001 From: Daniel Musketa Date: Sat, 2 May 2026 18:55:28 +0200 Subject: [PATCH 022/102] Translations: Update German Currently translated at 100.0% (6295 of 6295 strings) Translation: pretix/pretix Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/ powered by weblate --- src/pretix/locale/de/LC_MESSAGES/django.po | 71 +++++++++++----------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/src/pretix/locale/de/LC_MESSAGES/django.po b/src/pretix/locale/de/LC_MESSAGES/django.po index 727738b98..b49ab88d5 100644 --- a/src/pretix/locale/de/LC_MESSAGES/django.po +++ b/src/pretix/locale/de/LC_MESSAGES/django.po @@ -5,8 +5,8 @@ msgstr "" "Project-Id-Version: 1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-28 09:03+0000\n" -"PO-Revision-Date: 2026-04-28 09:22+0000\n" -"Last-Translator: Raphael Michel \n" +"PO-Revision-Date: 2026-05-02 23:00+0000\n" +"Last-Translator: Daniel Musketa \n" "Language-Team: German \n" "Language: de\n" @@ -4971,7 +4971,7 @@ msgstr "" "Sollte kurz sein und darf nur Kleinbuchstaben, Zahlen, Bindestriche und " "Punkte enthalten. Muss unter Ihren Veranstaltungen einmalig sein. Wir " "empfehlen eine Abkürzung oder ein Datum mit unter 10 Zeichen, das man sich " -"gut merken kann. Sie können jedoch auch einen zufälligen Wert verwendet. " +"gut merken kann. Sie können jedoch auch einen zufälligen Wert verwenden. " "Dies wird z.B. in Links, Bestellnummern, Rechnungsnummern und " "Verwendungszwecken für Banküberweisungen benutzt." @@ -7515,7 +7515,7 @@ msgid "" "You are already on this waiting list! We will notify you as soon as we have " "a ticket available for you." msgstr "" -"Sie sind bereits auf der Warteliste! Wir benachrichtigen Sie sobald wir ein " +"Sie sind bereits auf der Warteliste! Wir benachrichtigen Sie, sobald wir ein " "verfügbares Ticket für Sie haben." #: pretix/base/notifications.py:192 pretix/control/navigation.py:205 @@ -8671,8 +8671,8 @@ msgid "" "offline scanning – please refer to documentation or support for details)" msgstr "" "pretix Signaturverfahren 1 (für sehr große Veranstaltungen, ändert die " -"Funktionsweise des Offline-Modus, bitte informiere dich in der Dokumentation " -"oder beim Support)" +"Funktionsweise des Offline-Modus, bitte informieren Sie sich in der " +"Dokumentation oder beim Support)" #: pretix/base/services/cancelevent.py:265 #: pretix/base/services/cancelevent.py:351 @@ -9579,8 +9579,8 @@ msgid "" "changes are still accurate and try again." msgstr "" "Diese Bestellung wurde zeitgleich von einem anderen Benutzer bearbeitet. " -"Bitte prüfe, ob deine Änderungen immer noch zutreffend sind und probiere es " -"erneut." +"Bitte prüfen Sie, ob Ihre Änderungen immer noch zutreffend sind und " +"probieren Sie es erneut." #: pretix/base/services/orders.py:150 msgid "Your cart is empty." @@ -11363,7 +11363,7 @@ msgid "" "If your event series has more than 50 dates in the future, only the month or " "week calendar can be used." msgstr "" -"Wenn deine Veranstaltungsreihe mehr als 50 zukünftige Termine hat, kann nur " +"Wenn Ihre Veranstaltungsreihe mehr als 50 zukünftige Termine hat, kann nur " "der Monats- oder Wochenkalender verwendet werden." #: pretix/base/settings.py:1892 @@ -11636,8 +11636,9 @@ msgid "" "set this to e.g. 10, they will only be able to choose values in increments " "of 10." msgstr "" -"Standardmäßig können Kunden auf einen beliebigen Betrag verzichten. Wenn du " -"diesen Wert z.B. auf 10 setzt, sind nur noch Werte im Abstand von 10 erlaubt." +"Standardmäßig können Kunden auf einen beliebigen Betrag verzichten. Wenn Sie " +"diesen Wert z.B. auf 10 setzen, sind nur noch Werte im Abstand von 10 " +"erlaubt." #: pretix/base/settings.py:2193 msgid "" @@ -17304,7 +17305,7 @@ msgstr "" #: pretix/control/forms/vouchers.py:448 msgid "You need to specify as many seats as voucher codes." -msgstr "Sie müssen genau so viele Sitze angeben, wie du Gutscheine erzeugst." +msgstr "Sie müssen genau so viele Sitze angeben, wie Sie Gutscheine erzeugen." #: pretix/control/forms/waitinglist.py:39 msgid "Select a valid choice." @@ -20819,7 +20820,7 @@ msgid "" "event and only retain the financial information such as the number and type " "of tickets sold." msgstr "" -"Sie können personenbezogene Daten wie Namen und E-Mail-Adressen aus deiner " +"Sie können personenbezogene Daten wie Namen und E-Mail-Adressen aus Ihrer " "Veranstaltung entfernen und nur finanzielle Infos wie die Anzahl und Art der " "verkauften Tickets aufbewahren." @@ -23019,7 +23020,7 @@ msgstr "" "Wenn Sie eine Gültigkeit in Tagen, Monaten oder Jahren angeben, endet die " "Gültigkeit immer am Ende eines vollen Tages (Mitternacht), plus der " "ausgewählten Anzahl an Minuten und Stunden. Der Starttermin wird in die " -"Berechnung eingeschlossen, d.h. wenn Sie \"1 Tag\" auswählen ist das Ticket " +"Berechnung eingeschlossen, d.h. wenn Sie \"1 Tag\" auswählen, ist das Ticket " "gültig bis zum Ende des Tages, an dem die Gültigkeit beginnt." #: pretix/control/templates/pretixcontrol/item/index.html:254 @@ -23452,7 +23453,7 @@ msgid "" "statistical data on customers who previously selected this option, and when " "such customers edit their answers, they need to select a different option." msgstr "" -"Wenn du eine Antwortoption löschst, kannst du anschließend keine " +"Wenn Sie eine Antwortoption löschen, können Sie anschließend keine " "statistischen Daten mehr zur Verwendung dieser Option abrufen und wenn " "Kunden, die diese Option gewählt haben, ihre Daten bearbeiten möchten, muss " "eine andere Option gewählt werden." @@ -25961,8 +25962,8 @@ msgid "" "Instead of an URL, you can also configure a text that will be shown within " "pretix. This will be ignored if a URL is configured." msgstr "" -"Statt einer URL kannst du auch einen Text eingeben, der von pretix angezeigt " -"wird. Dies wird ignoriert, wenn eine URL konfiguriert wurde." +"Statt einer URL können Sie auch einen Text eingeben, der von pretix " +"angezeigt wird. Dies wird ignoriert, wenn eine URL konfiguriert wurde." #: pretix/control/templates/pretixcontrol/organizers/edit.html:229 msgid "Barcode media" @@ -26128,7 +26129,7 @@ msgid "" "This feature allows you to configure acceptance of gift cards across " "multiple organizer accounts." msgstr "" -"Diese Funktion erlaubt dir, die Akzeptanz von Wertgutscheinen über mehrere " +"Diese Funktion erlaubt Ihnen, die Akzeptanz von Wertgutscheinen über mehrere " "Veranstalterkonten hinweg zu konfigurieren." #: pretix/control/templates/pretixcontrol/organizers/giftcard_acceptance_list.html:18 @@ -26168,7 +26169,7 @@ msgstr "Ablehnen" #: pretix/control/templates/pretixcontrol/organizers/giftcard_acceptance_list.html:84 msgid "Other organizers accepting gift cards from you" -msgstr "Andere Veranstalter, die deine Wertgutscheine akzeptieren" +msgstr "Andere Veranstalter, die Ihre Wertgutscheine akzeptieren" #: pretix/control/templates/pretixcontrol/organizers/giftcard_acceptance_list.html:87 msgid "" @@ -27156,9 +27157,9 @@ msgid "" "use pretixPRINT version %(print_version)s (or newer) or pretixSCAN Desktop " "version %(scan_version)s (or newer)." msgstr "" -"Dieses Layout verwendet neue Funktionen. Wenn du mit einem Gerät druckst, " -"stelle sicher, dass pretixPRINT-Version %(print_version)s (oder neuer) oder " -"pretixSCAN Desktop Version %(scan_version)s (oder neuer) im Einsatz ist." +"Dieses Layout verwendet neue Funktionen. Wenn Sie mit einem Gerät drucken, " +"stellen Sie sicher, dass pretixPRINT-Version %(print_version)s (oder neuer) " +"oder pretixSCAN Desktop Version %(scan_version)s (oder neuer) im Einsatz ist." #: pretix/control/templates/pretixcontrol/pdf/placeholders.html:16 msgid "Available placeholders" @@ -27234,8 +27235,8 @@ msgid "" "might be required to keep some of this data on file. You can therefore " "download the following file and store it in a safe place:" msgstr "" -"Sie sind dabei, Daten unwiderruflich vom Server zu löschen, auch wenn du " -"manche dieser Daten ggf. aus gesetzlichen Gründen noch aufheben musst. Wir " +"Sie sind dabei, Daten unwiderruflich vom Server zu löschen, auch wenn Sie " +"manche dieser Daten ggf. aus gesetzlichen Gründen noch aufheben müssen. Wir " "empfehlen daher, die folgende Datei herunterzuladen und sie sicher " "aufzubewahren:" @@ -27284,7 +27285,7 @@ msgid "" "while to complete. We will inform you via email once it has been completed." msgstr "" "Abhängig von der Datenmenge in der Veranstaltung kann der folgende Schritt " -"eine Weile dauern. Wir informieren dich per E-Mail, sobald er abgeschlossen " +"eine Weile dauern. Wir informieren Sie per E-Mail, sobald er abgeschlossen " "ist." #: pretix/control/templates/pretixcontrol/shredder/index.html:11 @@ -32188,8 +32189,8 @@ msgid "" msgstr "" "Während die meisten Zahlungsmethoden keinen grundlosen Widerruf vorsehen, " "können SEPA-Lastschriften per Mausklick zurückgerufen werden. Aus diesem " -"Grund - und abhängig von der Art Ihrer Veranstaltung - kann es notwendig " -"sein SEPA-Lastschriften nicht anzubieten und damit das Risiko von " +"Grund – und abhängig von der Art Ihrer Veranstaltung – kann es notwendig " +"sein, SEPA-Lastschriften nicht anzubieten und damit das Risiko von " "kostspieligen Rücklastschriften zu vermeiden." #: pretix/plugins/paypal2/payment.py:182 @@ -33624,8 +33625,8 @@ msgid "" "Some payment methods might need to be enabled in the settings of your Stripe " "account before they work properly." msgstr "" -"Manche Zahlungsmethoden müssen in den Einstellungen deines Stripe-Kontos " -"aktiviert werden bevor sie funktionieren." +"Manche Zahlungsmethoden müssen in den Einstellungen Ihres Stripe-Kontos " +"aktiviert werden, bevor sie funktionieren." #: pretix/plugins/stripe/payment.py:369 pretix/plugins/stripe/payment.py:1597 msgid "Alipay" @@ -33644,8 +33645,8 @@ msgid "" "Some payment methods might need to be enabled in the settings of your Stripe " "account before work properly." msgstr "" -"Manche Zahlungsmethoden müssen in den Einstellungen deines Stripe-Kontos " -"aktiviert werden bevor sie funktionieren." +"Manche Zahlungsmethoden müssen in den Einstellungen Ihres Stripe-Kontos " +"aktiviert werden, bevor sie funktionieren." #: pretix/plugins/stripe/payment.py:391 msgid "" @@ -35338,7 +35339,7 @@ msgstr "Diese Zahlungsmethode unterstützt den Testmodus nicht." #: pretix/presale/templates/pretixpresale/event/checkout_payment.html:113 msgid "If you continue, actual money might be transferred." -msgstr "Wenn du fortfährst, wird möglicherweise echtes Geld transferiert." +msgstr "Wenn Sie fortfahren, wird möglicherweise echtes Geld transferiert." #: pretix/presale/templates/pretixpresale/event/checkout_payment.html:124 msgid "There are no payment providers enabled." @@ -35790,7 +35791,7 @@ msgid "" msgstr "" "Da Sie eine Firmenadresse eingegeben haben, wurde Ihr Preis aus dem Preis " "ohne Umsatzsteuer neu berechnet. Durch geänderte Rundung hat sich der " -"Endpreis deiner Buchung minimal verändert." +"Endpreis Ihrer Buchung minimal verändert." #: pretix/presale/templates/pretixpresale/event/fragment_cart.html:516 #, python-format @@ -37754,8 +37755,8 @@ msgstr "" #: pretix/presale/views/order.py:1198 msgid "Please click the link we sent you via email to download your tickets." msgstr "" -"Bitte klicke den Link, den wir dir per E-Mail geschickt haben, um deine " -"Tickets herunterzuladen." +"Bitte klicken Sie den Link, den wir Ihnen per E-Mail geschickt haben, um " +"Ihre Tickets herunterzuladen." #: pretix/presale/views/order.py:1689 #, python-brace-format -- 2.54.0 From b4f3d5c4358530004714e81d67b3803c272dcfd2 Mon Sep 17 00:00:00 2001 From: Daniel Musketa Date: Sat, 2 May 2026 18:33:55 +0200 Subject: [PATCH 023/102] Translations: Update German (informal) (de_Informal) Currently translated at 100.0% (6295 of 6295 strings) Translation: pretix/pretix Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/ powered by weblate --- .../locale/de_Informal/LC_MESSAGES/django.po | 88 +++++++++---------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/src/pretix/locale/de_Informal/LC_MESSAGES/django.po b/src/pretix/locale/de_Informal/LC_MESSAGES/django.po index 6d95e4689..e8ed036a8 100644 --- a/src/pretix/locale/de_Informal/LC_MESSAGES/django.po +++ b/src/pretix/locale/de_Informal/LC_MESSAGES/django.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: 1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-28 09:03+0000\n" -"PO-Revision-Date: 2026-04-28 09:22+0000\n" -"Last-Translator: Raphael Michel \n" +"PO-Revision-Date: 2026-05-02 23:00+0000\n" +"Last-Translator: Daniel Musketa \n" "Language-Team: German (informal) \n" "Language: de_Informal\n" @@ -829,7 +829,7 @@ msgid "" "Field \"{field_name}\" requires {required_input}, but only got " "{available_inputs}. Please check your {provider_name} settings." msgstr "" -"Feld \"{field_name}\" erfordert {required_input}, aber hat nur " +"Feld \"{field_name}\" erfordert {required_input}, aber nur " "{available_inputs} sind verfügbar. Bitte prüfe die Einstellungen für " "{provider_name}." @@ -1529,8 +1529,8 @@ msgid "" "Only include invoices issued in this time frame. Note that the invoice date " "does not always correspond to the order or payment date." msgstr "" -"Nur Rechnungen, die in diesem Zeitraum wurden. Achtung: Das Rechnungsdatum " -"korrespondiert nicht zwingend zum Bestell- oder Zahlungsdatum." +"Nur Rechnungen, die in diesem Zeitraum ausgestellt wurden. Achtung: Das " +"Rechnungsdatum korrespondiert nicht zwingend zum Bestell- oder Zahlungsdatum." #: pretix/base/exporters/events.py:47 msgid "Event data" @@ -3540,7 +3540,7 @@ msgstr "Das eingegebene aktuelle Passwort war nicht korrekt." #: pretix/base/forms/user.py:95 msgid "Please choose a password different to your current one." -msgstr "Bitte wählen ein anderes Passwort als das derzeitige." +msgstr "Bitte wähle ein anderes Passwort als das derzeitige." #: pretix/base/forms/user.py:105 pretix/presale/forms/customer.py:399 #: pretix/presale/forms/customer.py:475 @@ -3579,7 +3579,7 @@ msgid "" "up. Please note: to use literal \"{\" or \"}\", you need to double them as " "\"{{\" and \"}}\"." msgstr "" -"Es ist ein Fehler in deine Platzhalter-Syntax. Bitte prüfe, dass die " +"Es ist ein Fehler in deiner Platzhalter-Syntax. Bitte prüfe, dass die " "öffnenden \"{\" und schließenden \"}\" geschweiften Klammern zusammenpassen. " "Um die geschweiften Klammern \"{\" und \"}\" im erzeugten Text zu verwenden, " "müssen sie doppelt gesetzt werden als \"{{\" und \"}}\"." @@ -4217,7 +4217,7 @@ msgstr "Automatisch generieren" #: pretix/base/modelimport_orders.py:496 msgid "You cannot assign a position secret that already exists." -msgstr "Sie können keinen Ticketcode verwenden, der bereits existiert." +msgstr "Du kannst keinen Ticketcode verwenden, der bereits existiert." #: pretix/base/modelimport_orders.py:528 msgid "Please enter a valid language code." @@ -4971,7 +4971,7 @@ msgstr "" "Sollte kurz sein und darf nur Kleinbuchstaben, Zahlen, Bindestriche und " "Punkte enthalten. Muss unter deinen Veranstaltungen einmalig sein. Wir " "empfehlen eine Abkürzung oder ein Datum mit unter 10 Zeichen, das man sich " -"gut merken kann. Du kannst jedoch auch einen zufälligen Wert verwendet. Dies " +"gut merken kann. Du kannst jedoch auch einen zufälligen Wert verwenden. Dies " "wird z.B. in Links, Bestellnummern, Rechnungsnummern und Verwendungszwecken " "für Banküberweisungen benutzt." @@ -6186,7 +6186,7 @@ msgstr "Minimaler Wert" #: pretix/base/models/items.py:1747 pretix/base/models/items.py:1750 #: pretix/base/models/items.py:1754 msgid "Currently not supported in our apps and during check-in" -msgstr "Derzeit nicht von unseren Apps und während dem Check-In unterstützt" +msgstr "Derzeit nicht von unseren Apps und beim Check-In unterstützt" #: pretix/base/models/items.py:1737 pretix/base/models/items.py:1743 #: pretix/base/models/items.py:1749 @@ -6231,7 +6231,7 @@ msgstr "Ungültige Nummerneingabe." #: pretix/base/models/items.py:1870 pretix/base/models/items.py:1894 msgid "Please choose a later date." -msgstr "Bitte wählen Sie ein späteres Datum." +msgstr "Bitte wähle ein späteres Datum." #: pretix/base/models/items.py:1872 pretix/base/models/items.py:1896 msgid "Please choose an earlier date." @@ -6880,7 +6880,7 @@ msgid "" msgstr "" "Wenn du dies anschaltest, müssen alle Mitglieder entweder Zwei-Faktor-" "Authentifizierung einrichten oder das Team verlassen. Die Einstellung kann " -"ein paar Minuten benötigen um für alle Benutzer aktiv zu werden." +"ein paar Minuten benötigen, um für alle Benutzer aktiv zu werden." #: pretix/base/models/organizer.py:384 msgid "All event permissions" @@ -9015,7 +9015,7 @@ msgstr "" msgid "One of the products you selected can only be bought part of a bundle." msgstr "" "Eins der ausgewählten Produkte wird nicht einzeln verkauft, sondern nur als " -"Teil fester Produktpaketen." +"Teil fester Produktpakete." #: pretix/base/services/cart.py:218 msgid "Please select a valid seat." @@ -9912,7 +9912,7 @@ msgid "" "country is currently not available. We will therefore need to charge you the " "same tax rate as if you did not enter a VAT ID." msgstr "" -"Die USt-ID-Nr. konnte nicht geprüft werden, da der Prüfdienst Ihres Landes " +"Die USt-ID-Nr. konnte nicht geprüft werden, da der Prüfdienst deines Landes " "im Moment nicht verfügbar ist. Wir müssen daher den selben Steuersatz " "berechnen, wie wenn keine USt-ID-Nr. eingegeben worden wäre." @@ -11535,8 +11535,8 @@ msgid "" "cancellation fee from the user." msgstr "" "Betrifft nur ausstehende Zahlungen, für kostenlose Bestellungen wird nie " -"eine Stornogebühr erhoben. Bitte beachten Sie, dass Sie für das Eintreiben " -"der Stornogebühr selbst verantwortlich sind." +"eine Stornogebühr erhoben. Bitte beachte dass du für das Eintreiben der " +"Stornogebühr selbst verantwortlich bist." #: pretix/base/settings.py:2073 msgid "Charge payment, shipping and service fees" @@ -19340,8 +19340,8 @@ msgstr "" msgid "" "Please leave a short comment on what you did in the following admin sessions:" msgstr "" -"Bitte hinterlassen Sie einen kurzen Kommentar, was Sie in diesen Admin-" -"Sitzungen gemacht haben:" +"Bitte hinterlass einen kurzen Kommentar, was du in diesen Admin-Sitzungen " +"gemacht hast:" #: pretix/control/templates/pretixcontrol/base.html:376 msgid "Read more" @@ -19427,8 +19427,7 @@ msgstr "im Entwicklermodus" #: pretix/presale/templates/pretixpresale/postmessage.html:27 #: pretix/presale/templates/pretixpresale/waiting.html:42 msgid "If this takes longer than a few minutes, please contact us." -msgstr "" -"Wenn dies länger als einige Minuten dauert, kontaktieren Sie uns bitte." +msgstr "Wenn dies länger als einige Minuten dauert, kontaktier uns bitte." #: pretix/control/templates/pretixcontrol/boxoffice/payment.html:4 #: pretix/control/templates/pretixcontrol/organizers/devices.html:75 @@ -22988,7 +22987,7 @@ msgstr "" "Wenn du eine Gültigkeit in Tagen, Monaten oder Jahren angibst, endet die " "Gültigkeit immer am Ende eines vollen Tages (Mitternacht), plus der " "ausgewählten Anzahl an Minuten und Stunden. Der Starttermin wird in die " -"Berechnung eingeschlossen, d.h. wenn Sie \"1 Tag\" auswählen ist das Ticket " +"Berechnung eingeschlossen, d.h. wenn du \"1 Tag\" auswählst, ist das Ticket " "gültig bis zum Ende des Tages, an dem die Gültigkeit beginnt." #: pretix/control/templates/pretixcontrol/item/index.html:254 @@ -23662,8 +23661,8 @@ msgid "" "Are you sure you want to generate a new client secret for the application " "%(application)s?" msgstr "" -"Möchten Sie wirklich einen neuen Schlüssel für die App " -"%(application)s generieren?" +"Möchtest du wirklich einen neuen Schlüssel für die App %(application)" +"s generieren?" #: pretix/control/templates/pretixcontrol/oauth/app_rollkeys.html:15 msgid "Roll secret" @@ -23720,7 +23719,7 @@ msgstr "Bestellung freigeben" #: pretix/control/templates/pretixcontrol/order/approve.html:10 msgid "Do you really want to approve this order?" -msgstr "Möchten Sie diese Bestellung wirklich freigeben?" +msgstr "Möchtest du diese Bestellung wirklich freigeben?" #: pretix/control/templates/pretixcontrol/order/approve.html:20 #: pretix/control/templates/pretixcontrol/order/cancel.html:46 @@ -25689,8 +25688,8 @@ msgid "" "Download an app that is compatible with pretix. For example, our check-in " "app pretixSCAN is available on all major platforms." msgstr "" -"Laden Sie eine App herunter, die mit pretix kompatibel ist, wie z.B. unsere " -"Check-in-App pretixSCAN." +"Lad eine App herunter, die mit pretix kompatibel ist, wie z.B. unsere Check-" +"in-App pretixSCAN." #: pretix/control/templates/pretixcontrol/organizers/device_connect.html:14 msgid "Download pretixSCAN" @@ -25917,7 +25916,7 @@ msgid "" "target=\"_blank\">our documentation." msgstr "" "In einigen Regionen, einschließlich der Europäischen Union, bist du " -"verpflichtet, Informationen über die Barrierefreiheit Ihres Ticketshops zu " +"verpflichtet, Informationen über die Barrierefreiheit deines Ticketshops zu " "veröffentlichen. Du findest eine Vorlage in unserer Dokumentation." @@ -26023,7 +26022,7 @@ msgstr "Station löschen:" #: pretix/control/templates/pretixcontrol/organizers/gate_delete.html:8 msgid "Are you sure you want to delete the gate?" -msgstr "Möchten Sie die Station wirklich löschen?" +msgstr "Möchtest du die Station wirklich löschen?" #: pretix/control/templates/pretixcontrol/organizers/gate_edit.html:6 msgid "Gate:" @@ -26389,7 +26388,7 @@ msgid "" "The plugin \"%(name)s\" is enabled for your organizer account, but also " "needs to be enabled for the specific events you want to use it with." msgstr "" -"Die Erweiterung \"%(name)s\" ist für Ihr Veranstalterkonto aktiv, muss " +"Die Erweiterung \"%(name)s\" ist für dein Veranstalterkonto aktiv, muss " "jedoch auch für die einzelnen Veranstaltungen aktiviert werden, für die sie " "benutzt werden soll." @@ -26936,7 +26935,7 @@ msgid "" msgstr "" "Dieser Editor wurde mit aktuellen Versionen von Google Chrome, Mozilla " "Firefox und Opera getestet. Andere Browser, besonders Internet Explorer oder " -"Microsoft Edge, haben möglicherweise Probleme Ihr Hintergrund-PDF korrekt " +"Microsoft Edge, haben möglicherweise Probleme, dein Hintergrund-PDF korrekt " "darzustellen oder die richtigen Schriftarten zu laden." #: pretix/control/templates/pretixcontrol/pdf/index.html:207 @@ -27121,9 +27120,9 @@ msgid "" "use pretixPRINT version %(print_version)s (or newer) or pretixSCAN Desktop " "version %(scan_version)s (or newer)." msgstr "" -"Dieses Layout verwendet neue Funktionen. Wenn Sie mit einem Gerät drucken, " -"stellen Sie sicher, dass pretixPRINT-Version %(print_version)s (oder neuer) " -"oder pretixSCAN Desktop Version %(scan_version)s (oder neuer) im Einsatz ist." +"Dieses Layout verwendet neue Funktionen. Wenn du mit einem Gerät druckst, " +"stell sicher, dass pretixPRINT-Version %(print_version)s (oder neuer) oder " +"pretixSCAN Desktop Version %(scan_version)s (oder neuer) im Einsatz ist." #: pretix/control/templates/pretixcontrol/pdf/placeholders.html:16 msgid "Available placeholders" @@ -27397,7 +27396,7 @@ msgid "" msgstr "" "Du kannst entweder eine oder mehrere Check-in-Listen für jeden Termin deiner " "Veranstaltungsreihe einzeln anlegen oder nur eine Check-in-Liste für alle " -"Ihre Termine verwenden und den Einlass über Check-in-Regeln limitieren. " +"deine Termine verwenden und den Einlass über Check-in-Regeln limitieren. " "Welcher Ansatz besser geeignet ist, hängt von mehreren Faktoren ab, wie z.B. " "der Menge an Terminen in deiner Veranstaltungsreihe. Für Reihen mit weniger " "als einem Termin pro Tag sind einzelne Check-in-Listen in der Regel " @@ -29233,7 +29232,7 @@ msgid "" "participants won't be able to buy the bundle unless you remove this item " "from it." msgstr "" -"Sie haben dieses Produkt deaktiviert, obwohl es Teil eines Paketes ist. " +"Du hast dieses Produkt deaktiviert, obwohl es Teil eines Paketes ist. " "Solange dies so ist, kann auch das Paket nicht mehr gekauft werden." #: pretix/control/views/item.py:1622 @@ -30396,7 +30395,7 @@ msgid "" "and requested a reset of the credentials." msgstr "" "Ein Zwei-Faktor-Notfall-Token wurde von einem Systemadministrator generiert. " -"Dies passiert üblicherweise, wenn du den Zugriff auf Ihren zweiten Faktor " +"Dies passiert üblicherweise, wenn du den Zugriff auf deinen zweiten Faktor " "verloren und ein Zurücksetzen der Zugangsdaten angefordert hast." #: pretix/control/views/users.py:169 @@ -32143,8 +32142,8 @@ msgid "" msgstr "" "Während die meisten Zahlungsmethoden keinen grundlosen Widerruf vorsehen, " "können SEPA-Lastschriften per Mausklick zurückgerufen werden. Aus diesem " -"Grund - und abhängig von der Art Ihrer Veranstaltung - kann es notwendig " -"sein SEPA-Lastschriften nicht anzubieten und damit das Risiko von " +"Grund – und abhängig von der Art deiner Veranstaltung – kann es notwendig " +"sein, SEPA-Lastschriften nicht anzubieten und damit das Risiko von " "kostspieligen Rücklastschriften zu vermeiden." #: pretix/plugins/paypal2/payment.py:182 @@ -32474,7 +32473,7 @@ msgid "" "Your PayPal account is now connected to pretix. You can change the settings " "in detail below." msgstr "" -"Ihr PayPal-Konto ist nun mit pretix verbunden. Auf dieser Seite können Sie " +"Dein PayPal-Konto ist nun mit pretix verbunden. Auf dieser Seite kannst du " "die Einstellungen im Detail anpassen." #: pretix/plugins/pretixdroid/apps.py:30 pretix/plugins/pretixdroid/apps.py:33 @@ -33051,7 +33050,8 @@ msgstr "Neue Regel erstellen" #: pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_update.html:10 msgid "Scheduled emails are not sent as long as your ticket shop is offline." msgstr "" -"Geplante E-Mails werden nicht verschickt, solange Ihr Ticketshop offline ist." +"Geplante E-Mails werden nicht verschickt, solange dein Ticketshop offline " +"ist." #: pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_create.html:49 #: pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_update.html:63 @@ -33383,7 +33383,7 @@ msgid "" "methods such as iDEAL, Alipay,and many more." msgstr "" "Akzeptiere Zahlungen über Stripe, einen weltweit beliebten " -"Zahlungsdienstleister. PayPal unterstützt Zahlungen per Kreditkarte sowie " +"Zahlungsdienstleister. Stripe unterstützt Zahlungen per Kreditkarte sowie " "viele lokale Zahlungsarten wie z.B. iDEAL, Alipay, und viele mehr." #: pretix/plugins/stripe/forms.py:40 @@ -33968,8 +33968,8 @@ msgid "" "Pay by bank allows you to authorize a secure Open Banking payment from your " "banking app. Currently available only with a UK bank account." msgstr "" -"Zahlung per Onlinebanking erlaubt die sichere Zahlung über Ihre Banking-App. " -"Derzeit nur für britische Bankkonten verfügbar." +"Zahlung per Onlinebanking erlaubt die sichere Zahlung über deine Banking-" +"App. Derzeit nur für britische Bankkonten verfügbar." #: pretix/plugins/stripe/payment.py:1886 msgid "PayPal via Stripe" @@ -34356,7 +34356,7 @@ msgid "" "Your Stripe account is now connected to pretix. You can change the settings " "in detail below." msgstr "" -"Ihr Stripe-Konto ist nun mit pretix verbunden. Auf dieser Seite können Sie " +"Dein Stripe-Konto ist nun mit pretix verbunden. Auf dieser Seite kannst du " "die Einstellungen im Detail anpassen." #: pretix/plugins/stripe/views.py:488 -- 2.54.0 From e460bf8bae14fffb69b7c5b13766e2739cda2896 Mon Sep 17 00:00:00 2001 From: Daniel Musketa Date: Sat, 2 May 2026 19:15:50 +0200 Subject: [PATCH 024/102] =?UTF-8?q?Translations:=20Update=20Norwegian=20Bo?= =?UTF-8?q?km=C3=A5l?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 83.3% (5247 of 6295 strings) Translation: pretix/pretix Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/nb_NO/ powered by weblate --- src/pretix/locale/nb_NO/LC_MESSAGES/django.po | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/pretix/locale/nb_NO/LC_MESSAGES/django.po b/src/pretix/locale/nb_NO/LC_MESSAGES/django.po index 8fc2680de..7159b93f5 100644 --- a/src/pretix/locale/nb_NO/LC_MESSAGES/django.po +++ b/src/pretix/locale/nb_NO/LC_MESSAGES/django.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-28 09:03+0000\n" -"PO-Revision-Date: 2024-05-10 15:47+0000\n" -"Last-Translator: Martin Gross \n" +"PO-Revision-Date: 2026-05-02 23:00+0000\n" +"Last-Translator: Daniel Musketa \n" "Language-Team: Norwegian Bokmål \n" "Language: nb_NO\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.4.3\n" +"X-Generator: Weblate 5.17\n" #: pretix/_base_settings.py:87 msgid "English" @@ -37,11 +37,11 @@ msgstr "Arabisk" #: pretix/_base_settings.py:91 msgid "Basque" -msgstr "" +msgstr "Baskisk" #: pretix/_base_settings.py:92 msgid "Catalan" -msgstr "" +msgstr "Katalansk" #: pretix/_base_settings.py:93 msgid "Chinese (simplified)" @@ -57,7 +57,7 @@ msgstr "Tsjekkisk" #: pretix/_base_settings.py:96 msgid "Croatian" -msgstr "" +msgstr "Kroatisk" #: pretix/_base_settings.py:97 msgid "Danish" @@ -89,7 +89,7 @@ msgstr "Gresk" #: pretix/_base_settings.py:104 msgid "Hebrew" -msgstr "" +msgstr "Hebraisk" #: pretix/_base_settings.py:105 msgid "Indonesian" @@ -101,7 +101,7 @@ msgstr "Italiensk" #: pretix/_base_settings.py:107 msgid "Japanese" -msgstr "" +msgstr "Japansk" #: pretix/_base_settings.py:108 msgid "Latvian" @@ -133,11 +133,11 @@ msgstr "Russisk" #: pretix/_base_settings.py:115 msgid "Slovak" -msgstr "" +msgstr "Slovakisk" #: pretix/_base_settings.py:116 msgid "Swedish" -msgstr "" +msgstr "Svensk" #: pretix/_base_settings.py:117 msgid "Spanish" @@ -145,7 +145,7 @@ msgstr "Spansk" #: pretix/_base_settings.py:118 msgid "Spanish (Latin America)" -msgstr "" +msgstr "Spansk (Latin-Amerika)" #: pretix/_base_settings.py:119 msgid "Turkish" -- 2.54.0 From b60c8165c2657c853735f13ab2eda23400aec687 Mon Sep 17 00:00:00 2001 From: Martin Gross Date: Mon, 4 May 2026 09:42:18 +0200 Subject: [PATCH 025/102] Translations: Update German (informal) (de_Informal) Currently translated at 100.0% (6295 of 6295 strings) Translation: pretix/pretix Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/ powered by weblate --- src/pretix/locale/de_Informal/LC_MESSAGES/django.po | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pretix/locale/de_Informal/LC_MESSAGES/django.po b/src/pretix/locale/de_Informal/LC_MESSAGES/django.po index e8ed036a8..736221b5f 100644 --- a/src/pretix/locale/de_Informal/LC_MESSAGES/django.po +++ b/src/pretix/locale/de_Informal/LC_MESSAGES/django.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: 1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-28 09:03+0000\n" -"PO-Revision-Date: 2026-05-02 23:00+0000\n" -"Last-Translator: Daniel Musketa \n" +"PO-Revision-Date: 2026-05-04 07:42+0000\n" +"Last-Translator: Martin Gross \n" "Language-Team: German (informal) \n" "Language: de_Informal\n" @@ -19340,7 +19340,7 @@ msgstr "" msgid "" "Please leave a short comment on what you did in the following admin sessions:" msgstr "" -"Bitte hinterlass einen kurzen Kommentar, was du in diesen Admin-Sitzungen " +"Bitte hinterlasse einen kurzen Kommentar, was du in diesen Admin-Sitzungen " "gemacht hast:" #: pretix/control/templates/pretixcontrol/base.html:376 @@ -19427,7 +19427,7 @@ msgstr "im Entwicklermodus" #: pretix/presale/templates/pretixpresale/postmessage.html:27 #: pretix/presale/templates/pretixpresale/waiting.html:42 msgid "If this takes longer than a few minutes, please contact us." -msgstr "Wenn dies länger als einige Minuten dauert, kontaktier uns bitte." +msgstr "Wenn dies länger als einige Minuten dauert, kontaktiere uns bitte." #: pretix/control/templates/pretixcontrol/boxoffice/payment.html:4 #: pretix/control/templates/pretixcontrol/organizers/devices.html:75 @@ -25688,7 +25688,7 @@ msgid "" "Download an app that is compatible with pretix. For example, our check-in " "app pretixSCAN is available on all major platforms." msgstr "" -"Lad eine App herunter, die mit pretix kompatibel ist, wie z.B. unsere Check-" +"Lade eine App herunter, die mit pretix kompatibel ist, wie z.B. unsere Check-" "in-App pretixSCAN." #: pretix/control/templates/pretixcontrol/organizers/device_connect.html:14 -- 2.54.0 From 6ae8cfe6f058b0e6fe2f7d682daf83fb67d862f4 Mon Sep 17 00:00:00 2001 From: Martin Gross Date: Mon, 4 May 2026 09:41:25 +0200 Subject: [PATCH 026/102] Translations: Update German (informal) (de_Informal) Currently translated at 100.0% (256 of 256 strings) Translation: pretix/pretix (JavaScript parts) Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/de_Informal/ powered by weblate --- src/pretix/locale/de_Informal/LC_MESSAGES/djangojs.po | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/pretix/locale/de_Informal/LC_MESSAGES/djangojs.po b/src/pretix/locale/de_Informal/LC_MESSAGES/djangojs.po index d911fbab9..a082a4eaf 100644 --- a/src/pretix/locale/de_Informal/LC_MESSAGES/djangojs.po +++ b/src/pretix/locale/de_Informal/LC_MESSAGES/djangojs.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-28 09:04+0000\n" -"PO-Revision-Date: 2026-03-17 14:30+0000\n" -"Last-Translator: Raphael Michel \n" +"PO-Revision-Date: 2026-05-04 07:42+0000\n" +"Last-Translator: Martin Gross \n" "Language-Team: German (informal) \n" "Language: de_Informal\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.16.2\n" +"X-Generator: Weblate 5.17\n" #: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56 #: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62 @@ -428,8 +428,7 @@ msgstr "" #: pretix/static/pretixbase/js/asynctask.js:276 msgid "If this takes longer than a few minutes, please contact us." -msgstr "" -"Wenn dies länger als einige Minuten dauert, kontaktieren Sie uns bitte." +msgstr "Wenn dies länger als einige Minuten dauert, kontaktiere uns bitte." #: pretix/static/pretixbase/js/asynctask.js:331 msgid "Close message" -- 2.54.0 From 01bd81a3cdc21eed6ce6baaf3e7cca99a7552236 Mon Sep 17 00:00:00 2001 From: Daniel Musketa Date: Mon, 4 May 2026 12:08:27 +0200 Subject: [PATCH 027/102] Translations: Update German (informal) (de_Informal) Currently translated at 100.0% (6295 of 6295 strings) Translation: pretix/pretix Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/ powered by weblate --- src/pretix/locale/de_Informal/LC_MESSAGES/django.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pretix/locale/de_Informal/LC_MESSAGES/django.po b/src/pretix/locale/de_Informal/LC_MESSAGES/django.po index 736221b5f..6dfc15804 100644 --- a/src/pretix/locale/de_Informal/LC_MESSAGES/django.po +++ b/src/pretix/locale/de_Informal/LC_MESSAGES/django.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: 1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-28 09:03+0000\n" -"PO-Revision-Date: 2026-05-04 07:42+0000\n" -"Last-Translator: Martin Gross \n" +"PO-Revision-Date: 2026-05-04 10:44+0000\n" +"Last-Translator: Daniel Musketa \n" "Language-Team: German (informal) \n" "Language: de_Informal\n" @@ -11535,7 +11535,7 @@ msgid "" "cancellation fee from the user." msgstr "" "Betrifft nur ausstehende Zahlungen, für kostenlose Bestellungen wird nie " -"eine Stornogebühr erhoben. Bitte beachte dass du für das Eintreiben der " +"eine Stornogebühr erhoben. Bitte beachte, dass du für das Eintreiben der " "Stornogebühr selbst verantwortlich bist." #: pretix/base/settings.py:2073 -- 2.54.0 From 6a9815ea5f1f28712860859594470d8115284cec Mon Sep 17 00:00:00 2001 From: Mie Frydensbjerg Date: Mon, 4 May 2026 15:22:54 +0200 Subject: [PATCH 028/102] Translations: Update Danish Currently translated at 58.4% (3677 of 6295 strings) Translation: pretix/pretix Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/ powered by weblate --- src/pretix/locale/da/LC_MESSAGES/django.po | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/pretix/locale/da/LC_MESSAGES/django.po b/src/pretix/locale/da/LC_MESSAGES/django.po index a6e668f9c..7fb2375e1 100644 --- a/src/pretix/locale/da/LC_MESSAGES/django.po +++ b/src/pretix/locale/da/LC_MESSAGES/django.po @@ -4,10 +4,10 @@ msgstr "" "Project-Id-Version: 1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-28 09:03+0000\n" -"PO-Revision-Date: 2026-04-23 17:00+0000\n" -"Last-Translator: Nikolai \n" -"Language-Team: Danish \n" +"PO-Revision-Date: 2026-05-04 14:19+0000\n" +"Last-Translator: Mie Frydensbjerg \n" +"Language-Team: Danish \n" "Language: da\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -36278,9 +36278,8 @@ msgstr "Fortsæt" #: pretix/presale/templates/pretixpresale/fragment_event_list_status.html:14 #: pretix/presale/templates/pretixpresale/fragment_week_calendar.html:58 #: pretix/presale/views/widget.py:441 -#, fuzzy msgid "Few tickets left" -msgstr "PDF-billet" +msgstr "Få billetter tilbage" #: pretix/presale/templates/pretixpresale/fragment_calendar.html:92 #: pretix/presale/templates/pretixpresale/fragment_day_calendar.html:97 -- 2.54.0 From 074d26cff3594d53c72d1edb3fce0ea5ba28bae3 Mon Sep 17 00:00:00 2001 From: Ruud Hendrickx Date: Tue, 5 May 2026 11:10:31 +0200 Subject: [PATCH 029/102] Translations: Update Dutch Currently translated at 100.0% (6295 of 6295 strings) Translation: pretix/pretix Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/nl/ powered by weblate --- src/pretix/locale/nl/LC_MESSAGES/django.po | 42 ++++++++++------------ 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/pretix/locale/nl/LC_MESSAGES/django.po b/src/pretix/locale/nl/LC_MESSAGES/django.po index dfeb94a0e..93c3949e4 100644 --- a/src/pretix/locale/nl/LC_MESSAGES/django.po +++ b/src/pretix/locale/nl/LC_MESSAGES/django.po @@ -7,16 +7,16 @@ msgstr "" "Project-Id-Version: 1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-28 09:03+0000\n" -"PO-Revision-Date: 2026-03-31 17:00+0000\n" +"PO-Revision-Date: 2026-05-05 13:26+0000\n" "Last-Translator: Ruud Hendrickx \n" -"Language-Team: Dutch \n" +"Language-Team: Dutch " +"\n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.16.2\n" +"X-Generator: Weblate 5.17.1\n" #: pretix/_base_settings.py:87 msgid "English" @@ -8209,10 +8209,8 @@ msgstr "" "2x Add-on 2" #: pretix/base/pdf.py:383 -#, fuzzy -#| msgid "List of Add-Ons" msgid "List of Checked-In Add-Ons" -msgstr "Lijst met add-ons" +msgstr "Lijst met ingecheckte add-ons" #: pretix/base/pdf.py:390 pretix/control/forms/filter.py:1537 #: pretix/control/forms/filter.py:1539 @@ -9206,10 +9204,8 @@ msgid "Czech National Bank" msgstr "Tsjechische Nationale Bank" #: pretix/base/services/currencies.py:41 -#, fuzzy -#| msgid "Czech National Bank" msgid "National Bank of Poland" -msgstr "Tsjechische Nationale Bank" +msgstr "Nationale Bank van Polen" #: pretix/base/services/export.py:95 pretix/base/services/export.py:155 msgid "" @@ -10296,16 +10292,12 @@ msgstr "" "wanneer het factuurbedrag niet in CZK is." #: pretix/base/settings.py:577 pretix/base/settings.py:586 -#, fuzzy -#| msgid "" -#| "Based on Czech National Bank daily rates, whenever the invoice amount is " -#| "not in CZK." msgid "" "Based on National Bank of Poland daily rates, whenever the invoice amount is " "not in PLN." msgstr "" -"Gebaseerd op de dagelijkse tarieven van de Tsjechische Nationale Bank, " -"wanneer het factuurbedrag niet in CZK is." +"Op basis van de dagkoersen van de Nationale Bank van Polen, wanneer het " +"factuurbedrag niet in PLN is uitgedrukt." #: pretix/base/settings.py:597 msgid "Require invoice address" @@ -16375,10 +16367,8 @@ msgid "Allow to overbook quotas when performing this operation" msgstr "Quota overboeken bij deze handeling toestaan" #: pretix/control/forms/orders.py:335 -#, fuzzy -#| msgid "Number of orders" msgid "Number of products to add" -msgstr "Aantal bestellingen" +msgstr "Aantal producten dat moet worden toegevoegd" #: pretix/control/forms/orders.py:344 msgid "Add-on to" @@ -16410,10 +16400,9 @@ msgstr "" "standaardprijs van het product" #: pretix/control/forms/orders.py:441 -#, fuzzy -#| msgid "You can not select the same seat multiple times." msgid "You can not choose a seat when adding multiple products at once." -msgstr "U kunt dezelfde stoel niet meerdere keren kiezen." +msgstr "" +"U kunt geen zitplaats kiezen wanneer u meerdere producten tegelijk toevoegt." #: pretix/control/forms/orders.py:478 pretix/control/forms/orders.py:482 #: pretix/control/forms/orders.py:510 pretix/control/forms/orders.py:552 @@ -17027,7 +17016,7 @@ msgstr "Weekenddag" #: pretix/control/forms/subevents.py:106 msgctxt "subevent" msgid "Skip dates that overlap with any existing date" -msgstr "" +msgstr "Sla data over die samenvallen met bestaande data" #: pretix/control/forms/subevents.py:109 msgctxt "subevent" @@ -17037,6 +17026,11 @@ msgid "" "This respects even inactive dates and works best if all dates have both a " "start and end time." msgstr "" +"Dit kan handig zijn als alle afspraken op dezelfde locatie plaatsvinden en " +"je wilt voorkomen dat terugkerende afspraken in conflict komen met bestaande " +"speciale afspraken. Hierbij wordt ook rekening gehouden met inactieve " +"afspraken en het werkt het beste als alle afspraken een begin- en eindtijd " +"hebben." #: pretix/control/forms/subevents.py:128 msgid "Keep the current values" @@ -30168,6 +30162,8 @@ msgstr "U kunt maximaal 100.000 datums tegelijk aanmaken." #: pretix/control/views/subevents.py:966 msgid "All dates would be skipped because they conflict with existing dates." msgstr "" +"Alle afspraken zouden worden overgeslagen omdat ze samenvallen met bestaande " +"afspraken." #: pretix/control/views/subevents.py:1102 #, python-brace-format -- 2.54.0 From 952f12100849f3ff7c1b1b8204d87116fa17e19c Mon Sep 17 00:00:00 2001 From: Ruud Hendrickx Date: Tue, 5 May 2026 11:14:04 +0200 Subject: [PATCH 030/102] Translations: Update Dutch (Belgium) Currently translated at 83.0% (5228 of 6295 strings) Translation: pretix/pretix Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/nl_BE/ powered by weblate --- src/pretix/locale/nl_BE/LC_MESSAGES/django.po | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/pretix/locale/nl_BE/LC_MESSAGES/django.po b/src/pretix/locale/nl_BE/LC_MESSAGES/django.po index 3d2bafc75..84da8597e 100644 --- a/src/pretix/locale/nl_BE/LC_MESSAGES/django.po +++ b/src/pretix/locale/nl_BE/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-28 09:03+0000\n" -"PO-Revision-Date: 2026-04-08 18:00+0000\n" +"PO-Revision-Date: 2026-05-05 13:26+0000\n" "Last-Translator: Ruud Hendrickx \n" "Language-Team: Dutch (Belgium) \n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.16.2\n" +"X-Generator: Weblate 5.17.1\n" #: pretix/_base_settings.py:87 msgid "English" @@ -8204,10 +8204,8 @@ msgstr "" "2x Add-on 2" #: pretix/base/pdf.py:383 -#, fuzzy -#| msgid "List of Add-Ons" msgid "List of Checked-In Add-Ons" -msgstr "Lijst met add-ons" +msgstr "Lijst met ingecheckte add-ons" #: pretix/base/pdf.py:390 pretix/control/forms/filter.py:1537 #: pretix/control/forms/filter.py:1539 @@ -9202,10 +9200,8 @@ msgid "Czech National Bank" msgstr "Tsjechische Nationale Bank" #: pretix/base/services/currencies.py:41 -#, fuzzy -#| msgid "Czech National Bank" msgid "National Bank of Poland" -msgstr "Tsjechische Nationale Bank" +msgstr "Nationale Bank van Polen" #: pretix/base/services/export.py:95 pretix/base/services/export.py:155 msgid "" @@ -10293,16 +10289,12 @@ msgstr "" "wanneer het factuurbedrag niet in CZK is." #: pretix/base/settings.py:577 pretix/base/settings.py:586 -#, fuzzy -#| msgid "" -#| "Based on Czech National Bank daily rates, whenever the invoice amount is " -#| "not in CZK." msgid "" "Based on National Bank of Poland daily rates, whenever the invoice amount is " "not in PLN." msgstr "" -"Gebaseerd op de dagelijkse tarieven van de Tsjechische Nationale Bank, " -"wanneer het factuurbedrag niet in CZK is." +"Op basis van de dagkoersen van de Nationale Bank van Polen, wanneer het " +"factuurbedrag niet in PLN is uitgedrukt." #: pretix/base/settings.py:597 msgid "Require invoice address" @@ -16369,10 +16361,8 @@ msgid "Allow to overbook quotas when performing this operation" msgstr "Quota overboeken bij deze handeling toestaan" #: pretix/control/forms/orders.py:335 -#, fuzzy -#| msgid "Number of orders" msgid "Number of products to add" -msgstr "Aantal bestellingen" +msgstr "Aantal producten dat moet worden toegevoegd" #: pretix/control/forms/orders.py:344 msgid "Add-on to" @@ -16404,10 +16394,9 @@ msgstr "" "standaardprijs van het product" #: pretix/control/forms/orders.py:441 -#, fuzzy -#| msgid "You can not select the same seat multiple times." msgid "You can not choose a seat when adding multiple products at once." -msgstr "U kunt dezelfde stoel niet meerdere keren kiezen." +msgstr "" +"U kunt geen zitplaats kiezen wanneer u meerdere producten tegelijk toevoegt." #: pretix/control/forms/orders.py:478 pretix/control/forms/orders.py:482 #: pretix/control/forms/orders.py:510 pretix/control/forms/orders.py:552 @@ -17020,7 +17009,7 @@ msgstr "Weekenddag" #: pretix/control/forms/subevents.py:106 msgctxt "subevent" msgid "Skip dates that overlap with any existing date" -msgstr "" +msgstr "Sla data over die samenvallen met bestaande data" #: pretix/control/forms/subevents.py:109 msgctxt "subevent" @@ -17030,6 +17019,11 @@ msgid "" "This respects even inactive dates and works best if all dates have both a " "start and end time." msgstr "" +"Dit kan handig zijn als alle afspraken op dezelfde locatie plaatsvinden en " +"je wilt voorkomen dat terugkerende afspraken in conflict komen met bestaande " +"speciale afspraken. Hierbij wordt ook rekening gehouden met inactieve " +"afspraken en het werkt het beste als alle afspraken een begin- en eindtijd " +"hebben." #: pretix/control/forms/subevents.py:128 msgid "Keep the current values" @@ -30145,6 +30139,8 @@ msgstr "U kunt maximaal 100.000 datums tegelijk aanmaken." #: pretix/control/views/subevents.py:966 msgid "All dates would be skipped because they conflict with existing dates." msgstr "" +"Alle afspraken zouden worden overgeslagen omdat ze samenvallen met bestaande " +"afspraken." #: pretix/control/views/subevents.py:1102 #, python-brace-format @@ -31447,10 +31443,16 @@ msgid "" "refunds.\n" " " msgstr "" +"\n" +" Let op: terugbetalingen zullen als uitgevoerd worden " +"gemarkeerd zodra er een exportbestand wordt aangemaakt.\n" +" Zorg ervoor dat u het exportbestand downloadt en de " +"terugbetalingen daadwerkelijk uitvoert.\n" +" " #: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/refund_export.html:50 msgid "Exported files" -msgstr "" +msgstr "Geëxporteerde bestanden" #: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/refund_export.html:55 msgid "Export date" @@ -31462,17 +31464,17 @@ msgstr "Aantal bestellingen" #: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/refund_export.html:80 msgid "not downloaded" -msgstr "" +msgstr "niet gedownload" #: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/refund_export.html:85 #: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/refund_export.html:96 msgid "Download CSV" -msgstr "" +msgstr "CSV downloaden" #: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/refund_export.html:90 #: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/refund_export.html:101 msgid "SEPA XML" -msgstr "" +msgstr "SEPA-XML" #: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/refund_export.html:110 msgid "No exports have been created yet." @@ -31480,7 +31482,7 @@ msgstr "Er zijn nog geen exports aangemaakt." #: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/sepa_export.html:10 msgid "Export SEPA xml" -msgstr "" +msgstr "Exporteer SEPA-XML" #: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/sepa_export.html:13 #, python-format -- 2.54.0 From 14708eef806048d3a16e757ff95477a6ab4902b1 Mon Sep 17 00:00:00 2001 From: sweenu Date: Tue, 5 May 2026 17:58:02 +0200 Subject: [PATCH 031/102] Invoice: fix issuer details rendering when address missing (#6139) --- src/pretix/base/invoicing/pdf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pretix/base/invoicing/pdf.py b/src/pretix/base/invoicing/pdf.py index 21765a629..b47b376bd 100644 --- a/src/pretix/base/invoicing/pdf.py +++ b/src/pretix/base/invoicing/pdf.py @@ -1160,7 +1160,7 @@ class Modern1Renderer(ClassicInvoiceRenderer): return stylesheet def _draw_invoice_from(self, canvas): - if not self.invoice.invoice_from: + if not self.invoice.address_invoice_from: return c = [ self._clean_text(l) -- 2.54.0 From 5bbbf0334dd220db7c5fd509b471e2401eddd0b9 Mon Sep 17 00:00:00 2001 From: pajowu Date: Wed, 6 May 2026 15:56:06 +0200 Subject: [PATCH 032/102] sendmail: Do not copy rules with subevent when closing an event (Z#23233683) (#6156) --- ...0011_remove_cross_event_scheduled_mails.py | 19 +++++++++ src/pretix/plugins/sendmail/signals.py | 2 +- src/tests/plugins/sendmail/test_rules.py | 41 ++++++++++++++++++- 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 src/pretix/plugins/sendmail/migrations/0011_remove_cross_event_scheduled_mails.py diff --git a/src/pretix/plugins/sendmail/migrations/0011_remove_cross_event_scheduled_mails.py b/src/pretix/plugins/sendmail/migrations/0011_remove_cross_event_scheduled_mails.py new file mode 100644 index 000000000..67e252a12 --- /dev/null +++ b/src/pretix/plugins/sendmail/migrations/0011_remove_cross_event_scheduled_mails.py @@ -0,0 +1,19 @@ +from django.db import migrations +from django.db.models import F + + +def remove_cross_event_scheduled_mails(apps, schema_editor): + Rule = apps.get_model("sendmail", "Rule") + ScheduledMail = apps.get_model("sendmail", "ScheduledMail") + ScheduledMail.objects.filter(rule__subevent__isnull=False).exclude(rule__subevent__event=F('rule__event')).delete() + Rule.objects.filter(subevent__isnull=False).exclude(subevent__event=F('event')).delete() + + +class Migration(migrations.Migration): + dependencies = [ + ("sendmail", "0010_auto_20250801_1342"), + ] + + operations = [ + migrations.RunPython(remove_cross_event_scheduled_mails), + ] diff --git a/src/pretix/plugins/sendmail/signals.py b/src/pretix/plugins/sendmail/signals.py index e573ce71d..76626097f 100644 --- a/src/pretix/plugins/sendmail/signals.py +++ b/src/pretix/plugins/sendmail/signals.py @@ -232,7 +232,7 @@ def sendmail_copy_data_receiver(sender, other, item_map, **kwargs): if sender.sendmail_rules.exists(): # idempotency return - for r in other.sendmail_rules.prefetch_related('limit_products'): + for r in other.sendmail_rules.filter(subevent__isnull=True).prefetch_related('limit_products'): limit_products = list(r.limit_products.all()) r = copy.copy(r) r.pk = None diff --git a/src/tests/plugins/sendmail/test_rules.py b/src/tests/plugins/sendmail/test_rules.py index 58f26aaae..7b33f063f 100644 --- a/src/tests/plugins/sendmail/test_rules.py +++ b/src/tests/plugins/sendmail/test_rules.py @@ -25,10 +25,11 @@ from zoneinfo import ZoneInfo import pytest from django.core import mail as djmail +from django.db.models import F from django.utils.timezone import now from django_scopes import scopes_disabled -from pretix.base.models import InvoiceAddress, Order +from pretix.base.models import Event, InvoiceAddress, Order from pretix.base.services.checkin import perform_checkin from pretix.plugins.sendmail.models import Rule, ScheduledMail from pretix.plugins.sendmail.signals import sendmail_run_rules @@ -687,3 +688,41 @@ def test_sendmail_context_localization(event, order, pos): sendmail_run_rules(None) assert "Hallo Herr Mustermann" in djmail.outbox[0].body + + +@pytest.mark.django_db +@scopes_disabled() +def test_event_clone_ignores_rules_with_subevent(event, order, pos): + event.has_subevents = True + event.save() + se1 = event.subevents.create(name="subevent 1", date_from=dt_now) + + event.sendmail_rules.create(date_is_absolute=False, send_offset_days=1, send_offset_time=datetime.time(hour=12), + subject='Mail To Subevent', template='TestBody', subevent=se1) + event.sendmail_rules.create(date_is_absolute=False, send_offset_days=1, send_offset_time=datetime.time(hour=12), + subject='Mail To All', template='TestBody') + + assert event.sendmail_rules.count() == 2 + assert event.scheduledmail_set.count() == 2 + for rule in event.sendmail_rules.all(): + assert rule.scheduledmail_set.count() == 1 + + copied_event = Event.objects.create( + organizer=event.organizer, name='Dummy2', slug='dummy2', + date_from=datetime.datetime(2022, 4, 15, 9, 0, 0, tzinfo=datetime.timezone.utc), + has_subevents=True + ) + copied_event.copy_data_from(event) + copied_event.refresh_from_db() + event.refresh_from_db() + + assert copied_event.sendmail_rules.count() == 1 + assert copied_event.sendmail_rules.first().scheduledmail_set.count() == 0 + assert str(copied_event.sendmail_rules.first().subject) == "Mail To All" + + copied_event.subevents.create(name="subevent 1 in copied", date_from=dt_now) + assert copied_event.sendmail_rules.first().scheduledmail_set.count() == 1 + + # Double-Check: no scheduled mails and rules exist where subevent.event and event do not align + assert ScheduledMail.objects.filter(rule__subevent__isnull=False).exclude(rule__subevent__event=F('rule__event')).count() == 0 + assert Rule.objects.filter(subevent__isnull=False).exclude(subevent__event=F('event')).count() == 0 -- 2.54.0 From 8303ba7808007b549532838c75701c6a5c6921dc Mon Sep 17 00:00:00 2001 From: Daniel Musketa Date: Tue, 5 May 2026 18:10:52 +0200 Subject: [PATCH 033/102] Translations: Update German Currently translated at 100.0% (6295 of 6295 strings) Translation: pretix/pretix Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/ powered by weblate --- src/pretix/locale/de/LC_MESSAGES/django.po | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pretix/locale/de/LC_MESSAGES/django.po b/src/pretix/locale/de/LC_MESSAGES/django.po index b49ab88d5..cf3283cd7 100644 --- a/src/pretix/locale/de/LC_MESSAGES/django.po +++ b/src/pretix/locale/de/LC_MESSAGES/django.po @@ -5,7 +5,7 @@ msgstr "" "Project-Id-Version: 1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-28 09:03+0000\n" -"PO-Revision-Date: 2026-05-02 23:00+0000\n" +"PO-Revision-Date: 2026-05-06 00:00+0000\n" "Last-Translator: Daniel Musketa \n" "Language-Team: German \n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.17\n" +"X-Generator: Weblate 5.17.1\n" "X-Poedit-Bookmarks: -1,-1,904,-1,-1,-1,-1,-1,-1,-1\n" #: pretix/_base_settings.py:87 @@ -3072,7 +3072,7 @@ msgstr "Wertgutscheine" #: pretix/base/exporters/orderlist.py:1367 msgid "Download a spreadsheet of all gift cards including their current value." msgstr "" -"Tabelle (Excel oder CSV) mit allen Wertgutscheinen und deren aktuellen Wert." +"Tabelle (Excel oder CSV) mit allen Wertgutscheinen und deren aktuellem Wert." #: pretix/base/exporters/orderlist.py:1378 msgid "Show value at" @@ -36026,7 +36026,7 @@ msgid "" "the order clicked the link in the email they received to confirm the email " "address is valid." msgstr "" -"Sie können Ihre Tickets hier herunterladen sobald die Person, die die " +"Sie können Ihre Tickets hier herunterladen, sobald die Person, die die " "Bestellung aufgegeben hat, einen Link in der an sie geschickten E-Mail " "geklickt hat." @@ -37012,10 +37012,10 @@ msgid "" "need the ticket any more, please be so kind and remove your ticket from the " "list so we can pass it on to the next person waiting as quickly as possible!" msgstr "" -"Sie wurden von unserer Warteliste ausgewählt um ein Ticket zu erhalten. Wenn " -"Sie das Ticket nicht mehr brauchen, helfen Sie uns indem Sie sich von der " -"Warteliste entfernen, sodass wir das Ticket schnellstmöglich an die nächste " -"wartende Person weitergeben können." +"Sie wurden von unserer Warteliste ausgewählt, um ein Ticket zu erhalten. " +"Wenn Sie das Ticket nicht mehr brauchen, helfen Sie uns, indem Sie sich von " +"der Warteliste entfernen, sodass wir das Ticket schnellstmöglich an die " +"nächste wartende Person weitergeben können." #: pretix/presale/templates/pretixpresale/event/waitinglist_remove.html:16 msgctxt "waitinglist" -- 2.54.0 From 71edfa8e1adb12701c4bf345b5adc5ce906382d9 Mon Sep 17 00:00:00 2001 From: corentin-spec Date: Thu, 7 May 2026 21:51:20 +0200 Subject: [PATCH 034/102] Translations: Update French Currently translated at 100.0% (6295 of 6295 strings) Translation: pretix/pretix Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/fr/ powered by weblate --- src/pretix/locale/fr/LC_MESSAGES/django.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pretix/locale/fr/LC_MESSAGES/django.po b/src/pretix/locale/fr/LC_MESSAGES/django.po index b8e0a9990..6ed52e0f0 100644 --- a/src/pretix/locale/fr/LC_MESSAGES/django.po +++ b/src/pretix/locale/fr/LC_MESSAGES/django.po @@ -4,8 +4,8 @@ msgstr "" "Project-Id-Version: 1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-28 09:03+0000\n" -"PO-Revision-Date: 2026-04-30 18:00+0000\n" -"Last-Translator: CVZ-es \n" +"PO-Revision-Date: 2026-05-08 04:00+0000\n" +"Last-Translator: corentin-spec \n" "Language-Team: French \n" "Language: fr\n" @@ -13,7 +13,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 5.17\n" +"X-Generator: Weblate 5.17.1\n" #: pretix/_base_settings.py:87 msgid "English" @@ -37884,7 +37884,7 @@ msgstr "Votre panier a été mis à jour." #: pretix/presale/views/cart.py:525 pretix/presale/views/cart.py:551 msgid "Your cart is now empty." -msgstr "Votre panier à été vidé." +msgstr "Votre panier a été vidé." #: pretix/presale/views/cart.py:584 msgid "" -- 2.54.0 From 27148324a668359231079cee62f157fc6d72f3ca Mon Sep 17 00:00:00 2001 From: pajowu Date: Mon, 11 May 2026 14:53:47 +0200 Subject: [PATCH 035/102] sendmail: Add missing cleanup migration (#6158) --- ...0012_remove_cross_event_scheduled_mails.py | 25 +++++++++++++++++++ ...0012_remove_cross_event_scheduled_mails.py | 17 +++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/pretix/plugins/sendmail/migrations/0011_remove_cross_event_scheduled_mails_squashed_0012_remove_cross_event_scheduled_mails.py create mode 100644 src/pretix/plugins/sendmail/migrations/0012_remove_cross_event_scheduled_mails.py diff --git a/src/pretix/plugins/sendmail/migrations/0011_remove_cross_event_scheduled_mails_squashed_0012_remove_cross_event_scheduled_mails.py b/src/pretix/plugins/sendmail/migrations/0011_remove_cross_event_scheduled_mails_squashed_0012_remove_cross_event_scheduled_mails.py new file mode 100644 index 000000000..76bcd7673 --- /dev/null +++ b/src/pretix/plugins/sendmail/migrations/0011_remove_cross_event_scheduled_mails_squashed_0012_remove_cross_event_scheduled_mails.py @@ -0,0 +1,25 @@ +# Generated by Django 5.2.13 on 2026-05-06 15:45 + +from django.db import migrations +from django.db.models import F + + +def remove_cross_event_scheduled_mails(apps, schema_editor): + Rule = apps.get_model("sendmail", "Rule") + ScheduledMail = apps.get_model("sendmail", "ScheduledMail") + ScheduledMail.objects.filter(subevent__isnull=False).exclude(subevent__event=F('rule__event')).delete() + Rule.objects.filter(subevent__isnull=False).exclude(subevent__event=F('event')).delete() + +class Migration(migrations.Migration): + + replaces = [('sendmail', '0011_remove_cross_event_scheduled_mails'), ('sendmail', '0012_remove_cross_event_scheduled_mails')] + + dependencies = [ + ('sendmail', '0010_auto_20250801_1342'), + ] + + operations = [ + migrations.RunPython( + code=remove_cross_event_scheduled_mails, + ), + ] diff --git a/src/pretix/plugins/sendmail/migrations/0012_remove_cross_event_scheduled_mails.py b/src/pretix/plugins/sendmail/migrations/0012_remove_cross_event_scheduled_mails.py new file mode 100644 index 000000000..2c0b532ce --- /dev/null +++ b/src/pretix/plugins/sendmail/migrations/0012_remove_cross_event_scheduled_mails.py @@ -0,0 +1,17 @@ +from django.db import migrations +from django.db.models import F + + +def remove_cross_event_scheduled_mails(apps, schema_editor): + ScheduledMail = apps.get_model("sendmail", "ScheduledMail") + ScheduledMail.objects.filter(subevent__isnull=False).exclude(subevent__event=F('rule__event')).delete() + + +class Migration(migrations.Migration): + dependencies = [ + ("sendmail", "0011_remove_cross_event_scheduled_mails"), + ] + + operations = [ + migrations.RunPython(remove_cross_event_scheduled_mails), + ] -- 2.54.0 From 1640ddd49790becd7e2473382155dd084edb122f Mon Sep 17 00:00:00 2001 From: pajowu Date: Mon, 11 May 2026 15:02:57 +0200 Subject: [PATCH 036/102] Widget: handle cart if not same-site (Z#23233393) Sets SameSite for cookie if page is secure, so cookie can be read even if not same-site. Also stores cart-id in vue state, so correct cart is used even if cookies to not work --- .../static/pretixpresale/js/widget/widget.js | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/pretix/static/pretixpresale/js/widget/widget.js b/src/pretix/static/pretixpresale/js/widget/widget.js index b24f1efca..34179e877 100644 --- a/src/pretix/static/pretixpresale/js/widget/widget.js +++ b/src/pretix/static/pretixpresale/js/widget/widget.js @@ -114,8 +114,13 @@ var setCookie = function (cname, cvalue, exdays) { var expires = "expires=Thu, 01 Jan 1970 00:00:00 GMT"; cvalue = ""; } - document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; + var same_site = ""; + if (site_is_secure()) { + same_site = ";SameSite=None;Secure" + } + document.cookie = cname + "=" + cvalue + ";" + expires + same_site + ";path=/"; }; + var getCookie = function (name) { var value = "; " + document.cookie; var parts = value.split("; " + name + "="); @@ -2052,11 +2057,16 @@ var shared_root_methods = { }) }, get_cart_id: function() { - if (this.$root.keep_cart) { - return getCookie(this.$root.cookieName); + if (!this.$root.keep_cart) { + return null } + if (this.$root.cart_id) { + return this.$root.cart_id + } + return getCookie(this.$root.cookieName); }, set_cart_id: function(newValue) { + this.$root.cart_id = newValue setCookie(this.$root.cookieName, newValue, 30); }, }; @@ -2359,6 +2369,7 @@ var create_widget = function (element, html_id=null) { has_seating_plan_waitinglist: false, meta_filter_fields: [], keep_cart: true, + cart_id: null } }, created: function () { @@ -2450,6 +2461,7 @@ var create_button = function (element, html_id=null) { html_id: html_id, button_text: button_text, keep_cart: keep_cart || items.length > 0, + cart_id: null } }, created: function () { @@ -2525,7 +2537,8 @@ window.PretixWidget.open = function (target_url, voucher, subevent, items, widge widget_data: all_widget_data, widget_id: 'pretix-widget-' + widget_id, button_text: "", - keep_cart: true + keep_cart: true, + cart_id: null } }, created: function () { -- 2.54.0 From f04df7a6ee69022f52cf4f96ddadb9ac46025bc0 Mon Sep 17 00:00:00 2001 From: rash Date: Mon, 11 May 2026 15:05:06 +0200 Subject: [PATCH 037/102] Migrate vue2 control components and widget to vue3 and vite (#5989) * setup vite and integrate fully with django - vite starts with `python manage.py runserver` - add templatetags to simply load vite hmr and entry points - add eslint (recheck rules) - enable non-strict ts * better syntax for cors header setting * migrate checkin rules editor to vue3 - move constants to a module - move reading from and writing to non-vue html to django interop module - switch to composition api and script setup sfc with pug - use optional chaining operators a lot to simplify code * migrate webcheckin plugin to vite+vue3 - migrate vue sfcs to script setup and pug - move fetch calls into a api.ts module - move common formatting and i18n strings into module * fix migration error * first draft migrating widget to vue3/vite * first couple widget e2e tests courtesy of claude most of the tests don't work yet * test file is not actually used * drop widget_ prefix from e2e test fixtures * add test for complete widget journey for simple event * switch timezone in e2e tests to Europe/Berlin * make dates in e2e tests relative * migrate widget bugfix #5886 * start testing event series widget * working vite widget setup for prod (untested), local dev (with or without dev server) and pytests, with flags for running the old version or the vite version * simplify e2e test iframe check * less flaky e2e tests * top level await in iife build mode is not supported, so let's do import.meta.glob instead (we just need the build step not to see await, the code doesn't actually ever get loaded because it's DEV only) * fix inconsistencies from automatic migration * Allow gradual rollout of new vite-based widget by adding urls to an allowlist that gets checked against the "Origin" http header of request fetching the widget js * add e2e tests for widget button, testing empty cart, adding specific items, and subevents * remove janky claude testts again * resolve migration TODOs: properly refocus parent on navigations * use `npm run dev:control` for the vite dev server for admin components * upgrade npm dependencies * fix js linter errors * fix python linter errors * build all control vue components * add new js config files to check-manifest ignore * working prod build acutal serving of built assets not tested yet * fix templatetag paths to match what's in the vite mantifest * add missing quotes around 'unsafe-eval' cors value * remove now unused old vue2 tooling * try fixing e2e test ci * fix flake8 error * check if vite build artefacts are in the wheel * add license headers * remove dom manipilation code necessary for `div.pretix-widget-compat` to work. No longer needed for vue3 * remove superfluous `createElement` calls They might have been there because of IE, which is no longer relevant * make widget dev mode parametizable through query params and document the usage and those params * fix rst syntax * remove migration todos file Co-authored-by: luelista * rearrange dockerfile commands for smaller image, thanks @luelista * Update .gitignore, adding .vite Co-authored-by: luelista * add eslint CI * make vue dev work in plugins * fix docker build * rebuild vite setup to support static prod plugins and dynamic hmr plugin development * use toml for vite plugin config instead of standalone json file * Add widget changes from #6047, #6149 * Allow buttons to reuse cart (Z#23226853) * Always keep cart of buttons with items set * widget: handle cart if not same-site (#6149) --------- Co-authored-by: luelista Co-authored-by: Kara Engelhardt --- .dockerignore | 1 + .editorconfig | 5 + .github/workflows/build.yml | 5 +- .github/workflows/style-js.yml | 43 + .github/workflows/tests.yml | 45 +- .gitignore | 2 + .prettierignore | 1 + Dockerfile | 10 +- MANIFEST.in | 5 + doc/development/setup.rst | 50 + eslint.config.mjs | 108 + package-lock.json | 4788 ++++++++++++ package.json | 52 + pyproject.toml | 1 + setup.cfg | 5 + src/Makefile | 12 +- src/pretix/_base_settings.py | 5 +- src/pretix/_build.py | 13 +- src/pretix/_build_settings.py | 2 + .../base/management/commands/runserver.py | 59 + src/pretix/base/middleware.py | 14 +- src/pretix/base/settings.py | 6 +- src/pretix/base/templatetags/vite.py | 243 + src/pretix/control/forms/global_settings.py | 6 + .../control/templates/pretixcontrol/base.html | 2 + .../pretixcontrol/checkin/list_edit.html | 60 +- .../pretixcontrol/checkin/simulator.html | 15 +- src/pretix/helpers/compressor.py | 63 - .../static/pretixplugins/webcheckin/api.ts | 271 + .../webcheckin/components/app.vue | 1165 +-- .../components/checkinlist-item.vue | 47 +- .../components/checkinlist-select.vue | 198 +- .../webcheckin/components/datefield.vue | 116 +- .../webcheckin/components/datetimefield.vue | 118 +- .../components/searchresult-item.vue | 94 +- .../webcheckin/components/timefield.vue | 116 +- .../static/pretixplugins/webcheckin/i18n.ts | 106 + .../static/pretixplugins/webcheckin/main.js | 79 - .../static/pretixplugins/webcheckin/main.ts | 17 + .../pretixplugins/webcheckin/index.html | 32 +- src/pretix/presale/views/widget.py | 72 +- src/pretix/settings.py | 7 + src/pretix/static/npm_dir/package-lock.json | 6430 ----------------- src/pretix/static/npm_dir/package.json | 16 - src/pretix/static/npm_dir/rollup.config.js | 23 - .../pretixcontrol/js/ui/checkinrules.js | 318 - .../pretixcontrol/js/ui/checkinrules/App.vue | 98 + .../js/ui/checkinrules/checkin-rule.vue | 716 +- .../ui/checkinrules/checkin-rules-editor.vue | 46 +- .../checkin-rules-visualization.vue | 519 +- .../js/ui/checkinrules/constants.ts | 193 + .../js/ui/checkinrules/datetimefield.vue | 98 +- .../js/ui/checkinrules/django-interop.ts | 68 + .../pretixcontrol/js/ui/checkinrules/index.ts | 12 + .../js/ui/checkinrules/jsonlogic-boolalg.js | 180 +- .../js/ui/checkinrules/lookup-select2.vue | 211 +- .../js/ui/checkinrules/timefield.vue | 98 +- .../js/ui/checkinrules/viz-node.vue | 457 +- .../static/pretixpresale/widget/TODOS.md | 0 .../static/pretixpresale/widget/index.html | 47 + .../static/pretixpresale/widget/src/api.ts | 93 + .../static/pretixpresale/widget/src/button.ts | 67 + .../widget/src/components/AvailBox.vue | 153 + .../widget/src/components/Button.vue | 54 + .../widget/src/components/Category.vue | 23 + .../widget/src/components/EventCalendar.vue | 118 + .../src/components/EventCalendarCell.vue | 120 + .../src/components/EventCalendarEvent.vue | 45 + .../src/components/EventCalendarRow.vue | 15 + .../widget/src/components/EventForm.vue | 237 + .../widget/src/components/EventList.vue | 69 + .../widget/src/components/EventListEntry.vue | 44 + .../src/components/EventListFilterField.vue | 26 + .../src/components/EventListFilterForm.vue | 40 + .../src/components/EventWeekCalendar.vue | 96 + .../widget/src/components/EventWeekCell.vue | 75 + .../widget/src/components/Item.vue | 218 + .../widget/src/components/Overlay.vue | 231 + .../widget/src/components/PriceBox.vue | 114 + .../widget/src/components/Variation.vue | 97 + .../widget/src/components/Widget.vue | 76 + .../pretixpresale/widget/src/globals.d.ts | 3 + .../static/pretixpresale/widget/src/i18n.ts | 126 + .../pretixpresale/widget/src/lib/store.ts | 80 + .../static/pretixpresale/widget/src/main.ts | 127 + .../pretixpresale/widget/src/sharedStore.ts | 561 ++ .../static/pretixpresale/widget/src/types.ts | 92 + .../static/pretixpresale/widget/src/utils.ts | 100 + .../pretixpresale/widget/src/vite-env.d.ts | 1 + .../static/pretixpresale/widget/src/widget.ts | 63 + .../static/pretixpresale/widget/tsconfig.json | 11 + .../pretixpresale/widget/vite.config.ts | 38 + src/setup.cfg | 6 + src/tests/e2e/conftest.py | 1257 ++++ src/tests/e2e/test_widget_button.py | 94 + src/tests/e2e/test_widget_journey_series.py | 159 + src/tests/e2e/test_widget_journey_single.py | 93 + tsconfig.json | 26 + vite.config.ts | 150 + 99 files changed, 13462 insertions(+), 9125 deletions(-) create mode 100644 .editorconfig create mode 100644 .github/workflows/style-js.yml create mode 100644 .prettierignore create mode 100644 eslint.config.mjs create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/pretix/base/management/commands/runserver.py create mode 100644 src/pretix/base/templatetags/vite.py delete mode 100644 src/pretix/helpers/compressor.py create mode 100644 src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/api.ts create mode 100644 src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/i18n.ts delete mode 100644 src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js create mode 100644 src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.ts delete mode 100644 src/pretix/static/npm_dir/package-lock.json delete mode 100644 src/pretix/static/npm_dir/package.json delete mode 100644 src/pretix/static/npm_dir/rollup.config.js delete mode 100644 src/pretix/static/pretixcontrol/js/ui/checkinrules.js create mode 100644 src/pretix/static/pretixcontrol/js/ui/checkinrules/App.vue create mode 100644 src/pretix/static/pretixcontrol/js/ui/checkinrules/constants.ts create mode 100644 src/pretix/static/pretixcontrol/js/ui/checkinrules/django-interop.ts create mode 100644 src/pretix/static/pretixcontrol/js/ui/checkinrules/index.ts create mode 100644 src/pretix/static/pretixpresale/widget/TODOS.md create mode 100644 src/pretix/static/pretixpresale/widget/index.html create mode 100644 src/pretix/static/pretixpresale/widget/src/api.ts create mode 100644 src/pretix/static/pretixpresale/widget/src/button.ts create mode 100644 src/pretix/static/pretixpresale/widget/src/components/AvailBox.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/Button.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/Category.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/EventCalendar.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/EventCalendarCell.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/EventCalendarEvent.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/EventCalendarRow.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/EventForm.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/EventList.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/EventListEntry.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/EventListFilterField.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/EventListFilterForm.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/EventWeekCalendar.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/EventWeekCell.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/Item.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/Overlay.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/PriceBox.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/Variation.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/components/Widget.vue create mode 100644 src/pretix/static/pretixpresale/widget/src/globals.d.ts create mode 100644 src/pretix/static/pretixpresale/widget/src/i18n.ts create mode 100644 src/pretix/static/pretixpresale/widget/src/lib/store.ts create mode 100644 src/pretix/static/pretixpresale/widget/src/main.ts create mode 100644 src/pretix/static/pretixpresale/widget/src/sharedStore.ts create mode 100644 src/pretix/static/pretixpresale/widget/src/types.ts create mode 100644 src/pretix/static/pretixpresale/widget/src/utils.ts create mode 100644 src/pretix/static/pretixpresale/widget/src/vite-env.d.ts create mode 100644 src/pretix/static/pretixpresale/widget/src/widget.ts create mode 100644 src/pretix/static/pretixpresale/widget/tsconfig.json create mode 100644 src/pretix/static/pretixpresale/widget/vite.config.ts create mode 100644 src/tests/e2e/conftest.py create mode 100644 src/tests/e2e/test_widget_button.py create mode 100644 src/tests/e2e/test_widget_journey_series.py create mode 100644 src/tests/e2e/test_widget_journey_single.py create mode 100644 tsconfig.json create mode 100644 vite.config.ts diff --git a/.dockerignore b/.dockerignore index bdcd52c3a..4b80bc2d1 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,6 @@ doc/ env/ +node_modules/ res/ local/ .git/ diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..be3fd7a2b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,5 @@ +[*.{js,jsx,ts,tsx,vue}] +indent_style = tab +indent_size = 2 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e2ab2c390..381e679df 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,4 +46,7 @@ jobs: - name: Run build run: python -m build - name: Check files - run: unzip -l dist/pretix*whl | grep node_modules || exit 1 + run: | + for pat in 'static.dist/vite/widget/widget.js' 'static.dist/vite/control/assets/checkinrules/main-' 'static.dist/vite/control/assets/webcheckin/main-'; do + unzip -l dist/pretix*whl | grep -q "$pat" || { echo "Missing: $pat"; exit 1; } + done diff --git a/.github/workflows/style-js.yml b/.github/workflows/style-js.yml new file mode 100644 index 000000000..64e35fecc --- /dev/null +++ b/.github/workflows/style-js.yml @@ -0,0 +1,43 @@ +name: JS Code Style + +on: + push: + branches: [ master ] + paths: + - 'src/pretix/static/pretixpresale/widget/**' + - 'src/pretix/static/pretixcontrol/js/ui/checkinrules/**' + - 'src/pretix/plugins/webcheckin/**' + - 'eslint.config.mjs' + - 'package.json' + - 'package-lock.json' + pull_request: + branches: [ master ] + paths: + - 'src/pretix/static/pretixpresale/widget/**' + - 'src/pretix/static/pretixcontrol/js/ui/checkinrules/**' + - 'src/pretix/plugins/webcheckin/**' + - 'eslint.config.mjs' + - 'package.json' + - 'package-lock.json' + +permissions: + contents: read + +env: + FORCE_COLOR: 1 + +jobs: + eslint: + name: eslint + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - name: Set up Node.js 24 + uses: actions/setup-node@v4 + with: + node-version: 24 + cache: npm + - name: Install Dependencies + run: npm ci + - name: Run ESLint + run: npm run lint:eslint diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c1d228e28..1eb04f22b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -72,7 +72,7 @@ jobs: run: make all compress - name: Run tests working-directory: ./src - run: PRETIX_CONFIG_FILE=tests/ci_${{ matrix.database }}.cfg py.test -n 3 -p no:sugar --cov=./ --cov-report=xml tests --maxfail=100 + run: PRETIX_CONFIG_FILE=tests/ci_${{ matrix.database }}.cfg py.test -n 3 -p no:sugar --cov=./ --cov-report=xml tests --ignore=tests/e2e --maxfail=100 - name: Run concurrency tests working-directory: ./src run: PRETIX_CONFIG_FILE=tests/ci_${{ matrix.database }}.cfg py.test tests/concurrency_tests/ --reuse-db @@ -84,3 +84,46 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: false if: matrix.database == 'postgres' && matrix.python-version == '3.13' + e2e: + runs-on: ubuntu-22.04 + name: E2E Tests + services: + postgres: + image: postgres:15 + env: + POSTGRES_PASSWORD: postgres + POSTGRES_DB: pretix + options: >- + --health-cmd "pg_isready -U postgres -d pretix" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.13" + - uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + - name: Install system dependencies + run: sudo apt update && sudo apt install -y gettext + - name: Install Python dependencies + run: pip3 install uv && uv pip install --system -e ".[dev]" psycopg2-binary + - name: Install JS dependencies + working-directory: ./src + run: make npminstall + - name: Compile + working-directory: ./src + run: make all compress + - name: Install Playwright browsers + run: npx playwright install + - name: Run E2E tests + working-directory: ./src + run: PRETIX_CONFIG_FILE=tests/ci_postgres.cfg py.test tests/e2e/ -v --maxfail=10 diff --git a/.gitignore b/.gitignore index 7a1321ee4..d5a3a0e52 100644 --- a/.gitignore +++ b/.gitignore @@ -24,5 +24,7 @@ local/ .project .pydevproject .DS_Store +node_modules/ +.vite/ diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..33662f554 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +/* diff --git a/Dockerfile b/Dockerfile index 84309f514..a59e0bdf7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ FROM python:3.13-trixie -RUN apt-get update && \ +RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \ + apt-get update && \ apt-get install -y --no-install-recommends \ build-essential \ gettext \ @@ -21,8 +22,7 @@ RUN apt-get update && \ libmaxminddb0 \ libmaxminddb-dev \ zlib1g-dev \ - nodejs \ - npm && \ + nodejs && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* && \ dpkg-reconfigure locales && \ @@ -50,6 +50,10 @@ COPY deployment/docker/production_settings.py /pretix/src/production_settings.py COPY pyproject.toml /pretix/pyproject.toml COPY _build /pretix/_build COPY src /pretix/src +COPY package.json /pretix/package.json +COPY package-lock.json /pretix/package-lock.json +COPY tsconfig.json /pretix/tsconfig.json +COPY vite.config.ts /pretix/vite.config.ts RUN pip3 install -U \ pip \ diff --git a/MANIFEST.in b/MANIFEST.in index adf0476f8..c497bff7d 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -48,3 +48,8 @@ recursive-include src Makefile recursive-exclude doc * recursive-exclude deployment * recursive-exclude res * + +include package.json +include package-lock.json +include tsconfig.json +include vite.config.ts diff --git a/doc/development/setup.rst b/doc/development/setup.rst index 9d34aa4d4..f9988d258 100644 --- a/doc/development/setup.rst +++ b/doc/development/setup.rst @@ -110,6 +110,56 @@ process:: However, beware that code changes will not auto-reload within Celery. +Running the local development server will also automatically start a vite dev server for all control vue components. + +Run the widget development server +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To locally develop the presale widget you need to start a separate vite dev server using:: + + npm run dev:widget + +You can control the org, event and much more via query parameters like this:: + + http://localhost:5180/?org=testorg&event=testevent + +The following query parameters are supported: + +.. list-table:: + :header-rows: 1 + :widths: 20 20 60 + + * - Parameter + - Default + - Description + * - ``org`` + - ``testorg`` + - Organization slug + * - ``event`` + - ``testevent`` + - Event slug + * - ``host`` + - ``http://localhost:8000`` + - Backend host URL + * - ``type`` + - ``widget`` + - Element type: ``widget`` or ``button`` + * - ``mode`` + - ``dev`` + - ``dev`` loads the Vite dev source, ``prod`` loads the built ``v2.{lang}.js`` + * - ``lang`` + - ``de`` + - Language code for the prod script + * - ``button-text`` + - ``Buy tickets!`` + - Text content for the button (only used when ``type=button``) + +Any other query parameter is passed through as an attribute on the widget/button element. +For example, ``?skip-ssl-check&list-type=calendar&items=123`` adds those attributes directly. + + + + .. _`checksandtests`: Code checks and unit tests diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..cf85b9cbe --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,108 @@ +import { defineConfig, globalIgnores } from 'eslint/config' +import globals from 'globals' +import js from '@eslint/js' +import ts from 'typescript-eslint' +import stylistic from '@stylistic/eslint-plugin' +import vue from 'eslint-plugin-vue' +import vuePug from 'eslint-plugin-vue-pug' + +const ignores = globalIgnores([ + '**/node_modules', + '**/dist' +]) + +export default defineConfig([ + ignores, + ...ts.config( + js.configs.recommended, + ts.configs.recommended + ), + stylistic.configs.customize({ + indent: 'tab', + braceStyle: '1tbs', + quoteProps: 'as-needed' + }), + ...vue.configs['flat/recommended'], + ...vuePug.configs['flat/recommended'], + { + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + localStorage: false, + $: 'readonly', + $$: 'readonly', + $ref: 'readonly', + $computed: 'readonly', + }, + parserOptions: { + parser: '@typescript-eslint/parser' + } + }, + + rules: { + 'no-debugger': 'off', + curly: 0, + 'no-return-assign': 0, + 'no-console': 'off', + 'vue/require-default-prop': 0, + 'vue/require-v-for-key': 0, + 'vue/valid-v-for': 'warn', + 'vue/no-reserved-keys': 0, + 'vue/no-setup-props-destructure': 0, + 'vue/multi-word-component-names': 0, + 'vue/max-attributes-per-line': 0, + 'vue/attribute-hyphenation': ['warn', 'never'], + 'vue/v-on-event-hyphenation': ['warn', 'never'], + 'import/first': 0, + '@typescript-eslint/ban-ts-comment': 0, + '@typescript-eslint/no-explicit-any': 0, + 'no-use-before-define': 'off', + 'no-var': 'error', + + '@typescript-eslint/no-use-before-define': ['error', { + typedefs: false, + functions: false, + }], + + '@typescript-eslint/no-unused-vars': ['error', { + args: 'all', + argsIgnorePattern: '^_', + caughtErrors: 'all', + caughtErrorsIgnorePattern: '^_', + destructuredArrayIgnorePattern: '^_', + varsIgnorePattern: '^_', + ignoreRestSiblings: true + }], + + '@stylistic/comma-dangle': 0, + '@stylistic/space-before-function-paren': ['error', 'always'], + '@stylistic/max-statements-per-line': ['error', { max: 1, ignoredNodes: ['BreakStatement'] }], + '@stylistic/member-delimiter-style': 0, + '@stylistic/arrow-parens': 0, + '@stylistic/generator-star-spacing': 0, + '@stylistic/yield-star-spacing': ['error', 'after'], + }, + }, + { + files: [ + 'src/pretix/static/pretixcontrol/js/ui/checkinrules/**/*.vue', + 'src/pretix/plugins/webcheckin/**/*.vue', + ], + languageOptions: { + globals: { + moment: 'readonly', + }, + }, + }, + { + files: [ + 'src/pretix/static/pretixpresale/widget/**/*.{ts,vue}', + ], + languageOptions: { + globals: { + LANG: 'readonly', + }, + }, + }, +]) diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..5c162dc16 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4788 @@ +{ + "name": "pretix", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "pretix", + "version": "1.0.0", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "vue": "^3.5.30" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "@stylistic/eslint-plugin": "^5.10.0", + "@types/jquery": "^3.5.33", + "@types/moment": "^2.11.29", + "@types/node": "^25.5.0", + "@vitejs/plugin-vue": "^6.0.5", + "@vue/eslint-config-typescript": "^14.7.0", + "@vue/language-plugin-pug": "^3.2.5", + "eslint": "^10.0.3", + "eslint-plugin-vue": "^10.8.0", + "eslint-plugin-vue-pug": "^1.0.0-alpha.5", + "globals": "^17.4.0", + "pug": "^3.0.3", + "sass-embedded": "^1.98.0", + "smol-toml": "^1.6.1", + "stylus": "^0.64.0", + "typescript-eslint": "^8.57.0", + "vite": "^8.0.0" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz", + "integrity": "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bufbuild/protobuf": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.11.0.tgz", + "integrity": "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==", + "dev": true, + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@emnapi/core": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.0.tgz", + "integrity": "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.0.tgz", + "integrity": "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", + "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.3", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.3.tgz", + "integrity": "sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.3", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-array/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/@eslint/config-array/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "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/@eslint/config-helpers": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.3.tgz", + "integrity": "sha512-lzGN0onllOZCGroKJmRwY6QcEHxbjBw1gwB8SgRSqK8YbbtEXMvKynsXc3553ckIEBxsbMBU7oOZXKIPGZNeZw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.1.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.1.tgz", + "integrity": "sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.3.tgz", + "integrity": "sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.1.tgz", + "integrity": "sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.1.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "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/@napi-rs/wasm-runtime": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", + "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@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" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@oxc-project/runtime": { + "version": "0.115.0", + "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.115.0.tgz", + "integrity": "sha512-Rg8Wlt5dCbXhQnsXPrkOjL1DTSvXLgb2R/KYfnf1/K+R0k6UMLEmbQXPM+kwrWqSmWA2t0B1EtHy2/3zikQpvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.115.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.115.0.tgz", + "integrity": "sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.9.tgz", + "integrity": "sha512-lcJL0bN5hpgJfSIz/8PIf02irmyL43P+j1pTCfbD1DbLkmGRuFIA4DD3B3ZOvGqG0XiVvRznbKtN0COQVaKUTg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.9.tgz", + "integrity": "sha512-J7Zk3kLYFsLtuH6U+F4pS2sYVzac0qkjcO5QxHS7OS7yZu2LRs+IXo+uvJ/mvpyUljDJ3LROZPoQfgBIpCMhdQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.9.tgz", + "integrity": "sha512-iwtmmghy8nhfRGeNAIltcNXzD0QMNaaA5U/NyZc1Ia4bxrzFByNMDoppoC+hl7cDiUq5/1CnFthpT9n+UtfFyg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.9.tgz", + "integrity": "sha512-DLFYI78SCiZr5VvdEplsVC2Vx53lnA4/Ga5C65iyldMVaErr86aiqCoNBLl92PXPfDtUYjUh+xFFor40ueNs4Q==", + "cpu": [ + "x64" + ], + "dev": true, + "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-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.9.tgz", + "integrity": "sha512-CsjTmTwd0Hri6iTw/DRMK7kOZ7FwAkrO4h8YWKoX/kcj833e4coqo2wzIFywtch/8Eb5enQ/lwLM7w6JX1W5RQ==", + "cpu": [ + "arm" + ], + "dev": true, + "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-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-2x9O2JbSPxpxMDhP9Z74mahAStibTlrBMW0520+epJH5sac7/LwZW5Bmg/E6CXuEF53JJFW509uP+lSedaUNxg==", + "cpu": [ + "arm64" + ], + "dev": true, + "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-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.9.tgz", + "integrity": "sha512-JA1QRW31ogheAIRhIg9tjMfsYbglXXYGNPLdPEYrwFxdbkQCAzvpSCSHCDWNl4hTtrol8WeboCSEpjdZK8qrCg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-aOKU9dJheda8Kj8Y3w9gnt9QFOO+qKPAl8SWd7JPHP+Cu0EuDAE5wokQubLzIDQWg2myXq2XhTpOVS07qqvT+w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-OalO94fqj7IWRn3VdXWty75jC5dk4C197AWEuMhIpvVv2lw9fiPhud0+bW2ctCxb3YoBZor71QHbY+9/WToadA==", + "cpu": [ + "s390x" + ], + "dev": true, + "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-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-cVEl1vZtBsBZna3YMjGXNvnYYrOJ7RzuWvZU0ffvJUexWkukMaDuGhUXn0rjnV0ptzGVkvc+vW9Yqy6h8YX4pg==", + "cpu": [ + "x64" + ], + "dev": true, + "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-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.9.tgz", + "integrity": "sha512-UzYnKCIIc4heAKgI4PZ3dfBGUZefGCJ1TPDuLHoCzgrMYPb5Rv6TLFuYtyM4rWyHM7hymNdsg5ik2C+UD9VDbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.9.tgz", + "integrity": "sha512-+6zoiF+RRyf5cdlFQP7nm58mq7+/2PFaY2DNQeD4B87N36JzfF/l9mdBkkmTvSYcYPE8tMh/o3cRlsx1ldLfog==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.9.tgz", + "integrity": "sha512-rgFN6sA/dyebil3YTlL2evvi/M+ivhfnyxec7AccTpRPccno/rPoNlqybEZQBkcbZu8Hy+eqNJCqfBR8P7Pg8g==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.9.tgz", + "integrity": "sha512-lHVNUG/8nlF1IQk1C0Ci574qKYyty2goMiPlRqkC5R+3LkXDkL5Dhx8ytbxq35m+pkHVIvIxviD+TWLdfeuadA==", + "cpu": [ + "arm64" + ], + "dev": true, + "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-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.9.tgz", + "integrity": "sha512-G0oA4+w1iY5AGi5HcDTxWsoxF509hrFIPB2rduV5aDqS9FtDg1CAfa7V34qImbjfhIcA8C+RekocJZA96EarwQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.2", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz", + "integrity": "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@stylistic/eslint-plugin": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.10.0.tgz", + "integrity": "sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/types": "^8.56.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^9.0.0 || ^10.0.0" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jquery": { + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.33.tgz", + "integrity": "sha512-SeyVJXlCZpEki5F0ghuYe+L+PprQta6nRZqhONt9F13dWBtR/ftoaIbdRQ7cis7womE+X2LKhsDdDtkkDhJS6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sizzle": "*" + } + }, + "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/moment": { + "version": "2.11.29", + "resolved": "https://registry.npmjs.org/@types/moment/-/moment-2.11.29.tgz", + "integrity": "sha512-D5WIgbLYQzvgfsDnBhZFSTnt/BjGPOE+Jsh3k1BYYijJAkrn7ceeLvU4jtjKKXXuXN42O3ARlU4D/P9ezbQYFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", + "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/sizzle": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.10.tgz", + "integrity": "sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.0.tgz", + "integrity": "sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.57.0", + "@typescript-eslint/type-utils": "8.57.0", + "@typescript-eslint/utils": "8.57.0", + "@typescript-eslint/visitor-keys": "8.57.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.57.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.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.0.tgz", + "integrity": "sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.57.0", + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/typescript-estree": "8.57.0", + "@typescript-eslint/visitor-keys": "8.57.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.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.0.tgz", + "integrity": "sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.57.0", + "@typescript-eslint/types": "^8.57.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.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.0.tgz", + "integrity": "sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/visitor-keys": "8.57.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.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.0.tgz", + "integrity": "sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA==", + "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.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.0.tgz", + "integrity": "sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/typescript-estree": "8.57.0", + "@typescript-eslint/utils": "8.57.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.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.0.tgz", + "integrity": "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==", + "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.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.0.tgz", + "integrity": "sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.57.0", + "@typescript-eslint/tsconfig-utils": "8.57.0", + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/visitor-keys": "8.57.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "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/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/@typescript-eslint/typescript-estree/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "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/@typescript-eslint/utils": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.0.tgz", + "integrity": "sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.57.0", + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/typescript-estree": "8.57.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.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.0.tgz", + "integrity": "sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.57.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.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.5.tgz", + "integrity": "sha512-bL3AxKuQySfk1iGcBsQnoRVexTPJq0Z/ixFVM8OhVJAP6ZXXXLtM7NFKWhLl30Kg7uTBqIaPXbh+nuQCuBDedg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-rc.2" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.30.tgz", + "integrity": "sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@vue/shared": "3.5.30", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.30.tgz", + "integrity": "sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.30", + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.30.tgz", + "integrity": "sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@vue/compiler-core": "3.5.30", + "@vue/compiler-dom": "3.5.30", + "@vue/compiler-ssr": "3.5.30", + "@vue/shared": "3.5.30", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.8", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.30.tgz", + "integrity": "sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.30", + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/eslint-config-typescript": { + "version": "14.7.0", + "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-14.7.0.tgz", + "integrity": "sha512-iegbMINVc+seZ/QxtzWiOBozctrHiF2WvGedruu2EbLujg9VuU0FQiNcN2z1ycuaoKKpF4m2qzB5HDEMKbxtIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.56.0", + "fast-glob": "^3.3.3", + "typescript-eslint": "^8.56.0", + "vue-eslint-parser": "^10.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^9.10.0 || ^10.0.0", + "eslint-plugin-vue": "^9.28.0 || ^10.0.0", + "typescript": ">=4.8.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/language-plugin-pug": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@vue/language-plugin-pug/-/language-plugin-pug-3.2.5.tgz", + "integrity": "sha512-E98NSmXmlYd5HIrv2f3IbPE1dgKjKABlDCdySqMxrlQ/kh4fAf91mUoxQKsEKhikE62QIylFDts8S84/du5dfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.28", + "muggle-string": "^0.4.1", + "pug-lexer": "^5.0.1", + "pug-parser": "^6.0.0", + "vscode-languageserver-textdocument": "^1.0.11" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.30.tgz", + "integrity": "sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.30.tgz", + "integrity": "sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.30", + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.30.tgz", + "integrity": "sha512-2UIGakjU4WSQ0T4iwDEW0W7vQj6n7AFn7taqZ9Cvm0Q/RA2FFOziLESrDL4GmtI1wV3jXg5nMoJSYO66egDUBw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.30", + "@vue/runtime-core": "3.5.30", + "@vue/shared": "3.5.30", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.30.tgz", + "integrity": "sha512-v+R34icapydRwbZRD0sXwtHqrQJv38JuMB4JxbOxd8NEpGLny7cncMp53W9UH/zo4j8eDHjQ1dEJXwzFQknjtQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.30", + "@vue/shared": "3.5.30" + }, + "peerDependencies": { + "vue": "3.5.30" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.30.tgz", + "integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==", + "license": "MIT" + }, + "node_modules/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/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/assert-never": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.4.0.tgz", + "integrity": "sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-walk": { + "version": "3.0.0-canary-5", + "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", + "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.9.6" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "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/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "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/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/character-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", + "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-regex": "^1.0.3" + } + }, + "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", + "optional": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colorjs.io": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz", + "integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/constantinople": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", + "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "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/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/doctypes": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", + "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.0.3.tgz", + "integrity": "sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.3", + "@eslint/config-helpers": "^0.5.2", + "@eslint/core": "^1.1.1", + "@eslint/plugin-kit": "^0.6.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.1.1", + "esquery": "^1.7.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", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-vue": { + "version": "10.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.8.0.tgz", + "integrity": "sha512-f1J/tcbnrpgC8suPN5AtdJ5MQjuXbSU9pGRSSYAuF3SHoiYCOdEX6O22pLaRyLHXvDcOe+O5ENgc1owQ587agA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.1.1", + "postcss-selector-parser": "^7.1.0", + "semver": "^7.6.3", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "@stylistic/eslint-plugin": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", + "@typescript-eslint/parser": "^7.0.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "vue-eslint-parser": "^10.0.0" + }, + "peerDependenciesMeta": { + "@stylistic/eslint-plugin": { + "optional": true + }, + "@typescript-eslint/parser": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-vue-pug": { + "version": "1.0.0-alpha.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue-pug/-/eslint-plugin-vue-pug-1.0.0-alpha.5.tgz", + "integrity": "sha512-afj+jrA5WA42BIwtrtPdo0KIBx4wQntkuL7fh4siA461Q9Hg9NhVuYWnFneCLA0ICuC9WmEzuSB+/MqVOh2oXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "vue-eslint-parser-template-tokenizer-pug": "^1.0.0" + }, + "peerDependencies": { + "eslint-plugin-vue": ">=10.7.0" + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "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/eslint/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/eslint/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "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/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.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==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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, + "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==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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": "17.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.4.0.tgz", + "integrity": "sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "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==", + "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-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/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/immutable": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", + "dev": true, + "license": "MIT" + }, + "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/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-expression": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", + "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^7.1.1", + "object-assign": "^4.1.1" + } + }, + "node_modules/is-expression/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true, + "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/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/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", + "dev": true, + "license": "MIT" + }, + "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/jstransformer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", + "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-promise": "^2.0.0", + "promise": "^7.0.1" + } + }, + "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/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.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "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/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "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.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "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.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "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.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "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/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/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/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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/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/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "asap": "~2.0.3" + } + }, + "node_modules/pug": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.3.tgz", + "integrity": "sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-code-gen": "^3.0.3", + "pug-filters": "^4.0.0", + "pug-lexer": "^5.0.1", + "pug-linker": "^4.0.0", + "pug-load": "^3.0.0", + "pug-parser": "^6.0.0", + "pug-runtime": "^3.0.1", + "pug-strip-comments": "^2.0.0" + } + }, + "node_modules/pug-attrs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", + "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "js-stringify": "^1.0.2", + "pug-runtime": "^3.0.0" + } + }, + "node_modules/pug-code-gen": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.3.tgz", + "integrity": "sha512-cYQg0JW0w32Ux+XTeZnBEeuWrAY7/HNE6TWnhiHGnnRYlCgyAUPoyh9KzCMa9WhcJlJ1AtQqpEYHc+vbCzA+Aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "doctypes": "^1.1.0", + "js-stringify": "^1.0.2", + "pug-attrs": "^3.0.0", + "pug-error": "^2.1.0", + "pug-runtime": "^3.0.1", + "void-elements": "^3.1.0", + "with": "^7.0.0" + } + }, + "node_modules/pug-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.1.0.tgz", + "integrity": "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pug-filters": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", + "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "jstransformer": "1.0.0", + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0", + "resolve": "^1.15.1" + } + }, + "node_modules/pug-lexer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", + "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-parser": "^2.2.0", + "is-expression": "^4.0.0", + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-linker": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", + "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-load": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", + "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.1", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", + "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0", + "token-stream": "1.0.0" + } + }, + "node_modules/pug-runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", + "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pug-strip-comments": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", + "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-walk": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", + "dev": true, + "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/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/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", + "optional": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.9.tgz", + "integrity": "sha512-9EbgWge7ZH+yqb4d2EnELAntgPTWbfL8ajiTW+SyhJEC4qhBbkCKbqFV4Ge4zmu5ziQuVbWxb/XwLZ+RIO7E8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.115.0", + "@rolldown/pluginutils": "1.0.0-rc.9" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.9", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.9", + "@rolldown/binding-darwin-x64": "1.0.0-rc.9", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.9", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.9", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.9", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.9", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.9", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.9", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.9", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.9", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.9", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.9", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.9", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.9" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.9.tgz", + "integrity": "sha512-w6oiRWgEBl04QkFZgmW+jnU1EC9b57Oihi2ot3HNWIQRqgHp5PnYDia5iZ5FF7rpa4EQdiqMDXjlqKGXBhsoXw==", + "dev": true, + "license": "MIT" + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/sass": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.98.0.tgz", + "integrity": "sha512-+4N/u9dZ4PrgzGgPlKnaaRQx64RO0JBKs9sDhQ2pLgN6JQZ25uPQZKQYaBJU48Kd5BxgXoJ4e09Dq7nMcOUW3A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.1.5", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/sass-embedded": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.98.0.tgz", + "integrity": "sha512-Do7u6iRb6K+lrllcTkB1BXcHwOxcKe3rEfOF/GcCLE2w3WpddakRAosJOHFUR37DpsvimQXEt5abs3NzUjEIqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bufbuild/protobuf": "^2.5.0", + "colorjs.io": "^0.5.0", + "immutable": "^5.1.5", + "rxjs": "^7.4.0", + "supports-color": "^8.1.1", + "sync-child-process": "^1.0.2", + "varint": "^6.0.0" + }, + "bin": { + "sass": "dist/bin/sass.js" + }, + "engines": { + "node": ">=16.0.0" + }, + "optionalDependencies": { + "sass-embedded-all-unknown": "1.98.0", + "sass-embedded-android-arm": "1.98.0", + "sass-embedded-android-arm64": "1.98.0", + "sass-embedded-android-riscv64": "1.98.0", + "sass-embedded-android-x64": "1.98.0", + "sass-embedded-darwin-arm64": "1.98.0", + "sass-embedded-darwin-x64": "1.98.0", + "sass-embedded-linux-arm": "1.98.0", + "sass-embedded-linux-arm64": "1.98.0", + "sass-embedded-linux-musl-arm": "1.98.0", + "sass-embedded-linux-musl-arm64": "1.98.0", + "sass-embedded-linux-musl-riscv64": "1.98.0", + "sass-embedded-linux-musl-x64": "1.98.0", + "sass-embedded-linux-riscv64": "1.98.0", + "sass-embedded-linux-x64": "1.98.0", + "sass-embedded-unknown-all": "1.98.0", + "sass-embedded-win32-arm64": "1.98.0", + "sass-embedded-win32-x64": "1.98.0" + } + }, + "node_modules/sass-embedded-all-unknown": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.98.0.tgz", + "integrity": "sha512-6n4RyK7/1mhdfYvpP3CClS3fGoYqDvRmLClCESS6I7+SAzqjxvGG6u5Fo+cb1nrPNbbilgbM4QKdgcgWHO9NCA==", + "cpu": [ + "!arm", + "!arm64", + "!riscv64", + "!x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "sass": "1.98.0" + } + }, + "node_modules/sass-embedded-android-arm": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.98.0.tgz", + "integrity": "sha512-LjGiMhHgu7VL1n7EJxTCre1x14bUsWd9d3dnkS2rku003IWOI/fxc7OXgaKagoVzok1kv09rzO3vFXJR5ZeONQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-arm64": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.98.0.tgz", + "integrity": "sha512-M9Ra98A6vYJHpwhoC/5EuH1eOshQ9ZyNwC8XifUDSbRl/cGeQceT1NReR9wFj3L7s1pIbmes1vMmaY2np0uAKQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-riscv64": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.98.0.tgz", + "integrity": "sha512-WPe+0NbaJIZE1fq/RfCZANMeIgmy83x4f+SvFOG7LhUthHpZWcOcrPTsCKKmN3xMT3iw+4DXvqTYOCYGRL3hcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-x64": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.98.0.tgz", + "integrity": "sha512-zrD25dT7OHPEgLWuPEByybnIfx4rnCtfge4clBgjZdZ3lF6E7qNLRBtSBmoFflh6Vg0RlEjJo5VlpnTMBM5MQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-darwin-arm64": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.98.0.tgz", + "integrity": "sha512-cgr1z9rBnCdMf8K+JabIaYd9Rag2OJi5mjq08XJfbJGMZV/TA6hFJCLGkr5/+ZOn4/geTM5/3aSfQ8z5EIJAOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-darwin-x64": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.98.0.tgz", + "integrity": "sha512-OLBOCs/NPeiMqTdOrMFbVHBQFj19GS3bSVSxIhcCq16ZyhouUkYJEZjxQgzv9SWA2q6Ki8GCqp4k6jMeUY9dcA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-arm": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.98.0.tgz", + "integrity": "sha512-03baQZCxVyEp8v1NWBRlzGYrmVT/LK7ZrHlF1piscGiGxwfdxoLXVuxsylx3qn/dD/4i/rh7Bzk7reK1br9jvQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-arm64": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.98.0.tgz", + "integrity": "sha512-axOE3t2MTBwCtkUCbrdM++Gj0gC0fdHJPrgzQ+q1WUmY9NoNMGqflBtk5mBZaWUeha2qYO3FawxCB8lctFwCtw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-arm": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.98.0.tgz", + "integrity": "sha512-OBkjTDPYR4hSaueOGIM6FDpl9nt/VZwbSRpbNu9/eEJcxE8G/vynRugW8KRZmCFjPy8j/jkGBvvS+k9iOqKV3g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-arm64": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.98.0.tgz", + "integrity": "sha512-LeqNxQA8y4opjhe68CcFvMzCSrBuJqYVFbwElEj9bagHXQHTp9xVPJRn6VcrC+0VLEDq13HVXMv7RslIuU0zmA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-riscv64": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.98.0.tgz", + "integrity": "sha512-7w6hSuOHKt8FZsmjRb3iGSxEzM87fO9+M8nt5JIQYMhHTj5C+JY/vcske0v715HCVj5e1xyTnbGXf8FcASeAIw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-x64": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.98.0.tgz", + "integrity": "sha512-QikNyDEJOVqPmxyCFkci8ZdCwEssdItfjQFJB+D+Uy5HFqcS5Lv3d3GxWNX/h1dSb23RPyQdQc267ok5SbEyJw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-riscv64": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.98.0.tgz", + "integrity": "sha512-E7fNytc/v4xFBQKzgzBddV/jretA4ULAPO6XmtBiQu4zZBdBozuSxsQLe2+XXeb0X4S2GIl72V7IPABdqke/vA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-x64": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.98.0.tgz", + "integrity": "sha512-VsvP0t/uw00mMNPv3vwyYKUrFbqzxQHnRMO+bHdAMjvLw4NFf6mscpym9Bzf+NXwi1ZNKnB6DtXjmcpcvqFqYg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-unknown-all": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.98.0.tgz", + "integrity": "sha512-C4MMzcAo3oEDQnW7L8SBgB9F2Fq5qHPnaYTZRMOH3Mp/7kM4OooBInXpCiiFjLnjY95hzP4KyctVx0uYR6MYlQ==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "!android", + "!darwin", + "!linux", + "!win32" + ], + "dependencies": { + "sass": "1.98.0" + } + }, + "node_modules/sass-embedded-win32-arm64": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.98.0.tgz", + "integrity": "sha512-nP/10xbAiPbhQkMr3zQfXE4TuOxPzWRQe1Hgbi90jv2R4TbzbqQTuZVOaJf7KOAN4L2Bo6XCTRjK5XkVnwZuwQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-win32-x64": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.98.0.tgz", + "integrity": "sha512-/lbrVsfbcbdZQ5SJCWcV0NVPd6YRs+FtAnfedp4WbCkO/ZO7Zt/58MvI4X2BVpRY/Nt5ZBo1/7v2gYcQ+J4svQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/sax": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz", + "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/smol-toml": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.1.tgz", + "integrity": "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "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/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/stylus": { + "version": "0.64.0", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.64.0.tgz", + "integrity": "sha512-ZIdT8eUv8tegmqy1tTIdJv9We2DumkNZFdCF5mz/Kpq3OcTaxSuCAYZge6HKK2CmNC02G1eJig2RV7XTw5hQrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "~4.3.3", + "debug": "^4.3.2", + "glob": "^10.4.5", + "sax": "~1.4.1", + "source-map": "^0.7.3" + }, + "bin": { + "stylus": "bin/stylus" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://opencollective.com/stylus" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sync-child-process": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz", + "integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sync-message-port": "^1.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/sync-message-port": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.2.0.tgz", + "integrity": "sha512-gAQ9qrUN/UCypHtGFbbe7Rc/f9bzO88IwrG8TDo/aMKAApKyD6E3W4Cm0EfhfBb6Z6SKt59tTCTfD+n1xmAvMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/token-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", + "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==", + "dev": true, + "license": "MIT" + }, + "node_modules/ts-api-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "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/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/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.0.tgz", + "integrity": "sha512-W8GcigEMEeB07xEZol8oJ26rigm3+bfPHxHvwbYUlu1fUDsGuQ7Hiskx5xGW/xM4USc9Ephe3jtv7ZYPQntHeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.57.0", + "@typescript-eslint/parser": "8.57.0", + "@typescript-eslint/typescript-estree": "8.57.0", + "@typescript-eslint/utils": "8.57.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/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/varint": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", + "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.0.tgz", + "integrity": "sha512-fPGaRNj9Zytaf8LEiBhY7Z6ijnFKdzU/+mL8EFBaKr7Vw1/FWcTBAMW0wLPJAGMPX38ZPVCVgLceWiEqeoqL2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/runtime": "0.115.0", + "lightningcss": "^1.32.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.8", + "rolldown": "1.0.0-rc.9", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.0.0-alpha.31", + "esbuild": "^0.27.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.30.tgz", + "integrity": "sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.30", + "@vue/compiler-sfc": "3.5.30", + "@vue/runtime-dom": "3.5.30", + "@vue/server-renderer": "3.5.30", + "@vue/shared": "3.5.30" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-eslint-parser": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.4.0.tgz", + "integrity": "sha512-Vxi9pJdbN3ZnVGLODVtZ7y4Y2kzAAE2Cm0CZ3ZDRvydVYxZ6VrnBhLikBsRS+dpwj4Jv4UCv21PTEwF5rQ9WXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "eslint-scope": "^8.2.0 || ^9.0.0", + "eslint-visitor-keys": "^4.2.0 || ^5.0.0", + "espree": "^10.3.0 || ^11.0.0", + "esquery": "^1.6.0", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/vue-eslint-parser-template-tokenizer-pug": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser-template-tokenizer-pug/-/vue-eslint-parser-template-tokenizer-pug-1.0.0.tgz", + "integrity": "sha512-kBNkXTDvxb0K4KScHOfMdVGngHAQxE1VqCeQmGyhgUOO1VgrDBWW2nb4mhHvAZhX7dIS8f2S48YI1MdjFboNEg==", + "dev": true, + "license": "ISC", + "dependencies": { + "pug-lexer": "^5.0.1" + }, + "peerDependencies": { + "vue-eslint-parser": "^10.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" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/with": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", + "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.9.6", + "@babel/types": "^7.9.6", + "assert-never": "^1.2.1", + "babel-walk": "3.0.0-canary-5" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "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==", + "dev": true, + "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/wrap-ansi-cjs/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..c20749c4e --- /dev/null +++ b/package.json @@ -0,0 +1,52 @@ +{ + "name": "pretix", + "version": "1.0.0", + "description": "", + "homepage": "https://github.com/pretix/pretix#readme", + "bugs": { + "url": "https://github.com/pretix/pretix/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/pretix/pretix.git" + }, + "license": "SEE LICENSE IN LICENSE", + "author": "", + "type": "module", + "main": "index.js", + "directories": { + "doc": "doc" + }, + "scripts": { + "dev:control": "vite", + "dev:widget": "vite src/pretix/static/pretixpresale/widget", + "build": "npm run build:control -s && npm run build:widget -s", + "build:control": "vite build", + "build:widget": "vite build src/pretix/static/pretixpresale/widget", + "lint:eslint": "eslint src/pretix/static/pretixpresale/widget src/pretix/static/pretixcontrol/js/ui/checkinrules src/pretix/plugins/webcheckin", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { + "vue": "^3.5.30" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "@stylistic/eslint-plugin": "^5.10.0", + "@types/jquery": "^3.5.33", + "@types/moment": "^2.11.29", + "@types/node": "^25.5.0", + "@vitejs/plugin-vue": "^6.0.5", + "@vue/eslint-config-typescript": "^14.7.0", + "@vue/language-plugin-pug": "^3.2.5", + "eslint": "^10.0.3", + "eslint-plugin-vue": "^10.8.0", + "eslint-plugin-vue-pug": "^1.0.0-alpha.5", + "globals": "^17.4.0", + "pug": "^3.0.3", + "sass-embedded": "^1.98.0", + "smol-toml": "^1.6.1", + "stylus": "^0.64.0", + "typescript-eslint": "^8.57.0", + "vite": "^8.0.0" + } +} diff --git a/pyproject.toml b/pyproject.toml index 5e61d8719..e37695c00 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -124,6 +124,7 @@ dev = [ "pytest-mock==3.15.*", "pytest-sugar", "pytest-xdist==3.8.*", + "pytest-playwright", "pytest==9.0.*", "responses", ] diff --git a/setup.cfg b/setup.cfg index 25c167e73..e7cdae97c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -37,4 +37,9 @@ ignore = CONTRIBUTING.md Dockerfile SECURITY.md + eslint.config.mjs + package-lock.json + package.json + tsconfig.json + vite.config.js diff --git a/src/Makefile b/src/Makefile index 7834612fa..24ca00328 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,10 +9,10 @@ localegen: ./manage.py makemessages --keep-pot --ignore "pretix/static/npm_dir/*" $(LNGS) ./manage.py makemessages --keep-pot -d djangojs --ignore "pretix/static/npm_dir/*" --ignore "pretix/helpers/*" --ignore "pretix/static/jsi18n/*" --ignore "pretix/static/jsi18n/*" --ignore "pretix/static.dist/*" --ignore "data/*" --ignore "pretix/static/rrule/*" --ignore "build/*" $(LNGS) -staticfiles: jsi18n +staticfiles: npminstall npmbuild jsi18n ./manage.py collectstatic --noinput -compress: npminstall +compress: ./manage.py compress jsi18n: localecompile @@ -25,8 +25,8 @@ coverage: coverage run -m py.test npminstall: - # keep this in sync with pretix/_build.py! - mkdir -p pretix/static.dist/node_prefix/ - cp -r pretix/static/npm_dir/* pretix/static.dist/node_prefix/ - npm ci --prefix=pretix/static.dist/node_prefix + npm ci + +npmbuild: + npm run build diff --git a/src/pretix/_base_settings.py b/src/pretix/_base_settings.py index 2931c7e41..96121867a 100644 --- a/src/pretix/_base_settings.py +++ b/src/pretix/_base_settings.py @@ -37,9 +37,11 @@ INSTALLED_APPS = [ 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', - 'django.contrib.staticfiles', 'django.contrib.humanize', + # pretix needs to go before staticfiles + # so we can override the runserver command 'pretix.base', + 'django.contrib.staticfiles', 'pretix.control', 'pretix.presale', 'pretix.multidomain', @@ -243,7 +245,6 @@ STORAGES = { COMPRESS_PRECOMPILERS = ( ('text/x-scss', 'django_libsass.SassCompiler'), - ('text/vue', 'pretix.helpers.compressor.VueCompiler'), ) COMPRESS_OFFLINE_CONTEXT = { diff --git a/src/pretix/_build.py b/src/pretix/_build.py index de9e2900c..3b6baa7e3 100644 --- a/src/pretix/_build.py +++ b/src/pretix/_build.py @@ -21,13 +21,13 @@ # import os -import shutil import subprocess from setuptools.command.build import build from setuptools.command.build_ext import build_ext here = os.path.abspath(os.path.dirname(__file__)) +project_root = os.path.abspath(os.path.join(here, '..', '..')) npm_installed = False @@ -35,14 +35,14 @@ def npm_install(): global npm_installed if not npm_installed: - # keep this in sync with Makefile! - node_prefix = os.path.join(here, 'static.dist', 'node_prefix') - os.makedirs(node_prefix, exist_ok=True) - shutil.copytree(os.path.join(here, 'static', 'npm_dir'), node_prefix, dirs_exist_ok=True) - subprocess.check_call('npm ci', shell=True, cwd=node_prefix) + subprocess.check_call('npm ci', shell=True, cwd=project_root) npm_installed = True +def npm_build(): + subprocess.check_call('npm run build', shell=True, cwd=project_root) + + class CustomBuild(build): def run(self): if "src" not in os.listdir(".") or "pretix" not in os.listdir("src"): @@ -62,6 +62,7 @@ class CustomBuild(build): settings.COMPRESS_OFFLINE = True npm_install() + npm_build() management.call_command('compilemessages', verbosity=1) management.call_command('compilejsi18n', verbosity=1) management.call_command('collectstatic', verbosity=1, interactive=False) diff --git a/src/pretix/_build_settings.py b/src/pretix/_build_settings.py index 5c04e511d..859a7f912 100644 --- a/src/pretix/_build_settings.py +++ b/src/pretix/_build_settings.py @@ -47,3 +47,5 @@ HAS_MEMCACHED = False HAS_CELERY = False HAS_GEOIP = False SENTRY_ENABLED = False +VITE_DEV_MODE = False +VITE_IGNORE = False diff --git a/src/pretix/base/management/commands/runserver.py b/src/pretix/base/management/commands/runserver.py new file mode 100644 index 000000000..b29f24fa1 --- /dev/null +++ b/src/pretix/base/management/commands/runserver.py @@ -0,0 +1,59 @@ +# +# This file is part of pretix (Community Edition). +# +# Copyright (C) 2014-2020 Raphael Michel and contributors +# Copyright (C) 2020-today pretix GmbH and contributors +# +# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General +# Public License as published by the Free Software Foundation in version 3 of the License. +# +# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are +# applicable granting you additional permissions and placing additional restrictions on your usage of this software. +# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive +# this file, see . +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License along with this program. If not, see +# . +# + +"""This command supersedes the Django-inbuilt runserver command. + +It runs the local frontend server, if node is installed and the setting +is set. +""" +import atexit +import os +import subprocess +from pathlib import Path + +from django.conf import settings +from django.contrib.staticfiles.management.commands.runserver import ( + Command as Parent, +) +from django.utils.autoreload import DJANGO_AUTORELOAD_ENV + + +class Command(Parent): + def handle(self, *args, **options): + # Only start Vite in the non-main process of the autoreloader + if settings.VITE_DEV_MODE and os.environ.get(DJANGO_AUTORELOAD_ENV) != "true": + # Start the vite server in the background + vite_server = subprocess.Popen( + ["npm", "run", "dev:control"], + cwd=Path(__file__).parent.parent.parent.parent.parent + ) + + def cleanup(): + vite_server.terminate() + try: + vite_server.wait(timeout=5) + except subprocess.TimeoutExpired: + vite_server.kill() + + atexit.register(cleanup) + + super().handle(*args, **options) diff --git a/src/pretix/base/middleware.py b/src/pretix/base/middleware.py index c7ab50166..784273da8 100644 --- a/src/pretix/base/middleware.py +++ b/src/pretix/base/middleware.py @@ -281,7 +281,7 @@ class SecurityMiddleware(MiddlewareMixin): h = { 'default-src': ["{static}"], - 'script-src': ['{static}'], + 'script-src': ["{static}"], 'object-src': ["'none'"], 'frame-src': ['{static}'], 'style-src': ["{static}", "{media}"], @@ -295,6 +295,18 @@ class SecurityMiddleware(MiddlewareMixin): # this. However, we'll restrict it to HTTPS. 'form-action': ["{dynamic}", "https:"] + (['http:'] if settings.SITE_URL.startswith('http://') else []), } + + if settings.VITE_DEV_MODE: + h['script-src'] += ["http://localhost:5173", "ws://localhost:5173"] + h['style-src'] += ["'unsafe-inline'"] + h['connect-src'] += ["http://localhost:5173", "ws://localhost:5173"] + + if hasattr(request, 'csp_nonce'): + nonce = f"'nonce-{request.csp_nonce}'" + h['script-src'].append(nonce) + if not settings.VITE_DEV_MODE: + # can't have 'unsafe-inline' and nonce at the same time + h['style-src'].append(nonce) # Only include pay.google.com for wallet detection purposes on the Payment selection page if ( url.url_name == "event.order.pay.change" or diff --git a/src/pretix/base/settings.py b/src/pretix/base/settings.py index 5e2be5713..f3170a0b9 100644 --- a/src/pretix/base/settings.py +++ b/src/pretix/base/settings.py @@ -3714,7 +3714,11 @@ Your {organizer} team""")) # noqa: W291 # To maintain backwards-compatibility, we provide Stripe's ApplePay MerchantID Domain Validation Certificate by default 'default': "7B227073704964223A2239373943394538343346343131343044463144313834343232393232313734313034353044314339464446394437384337313531303944334643463542433731222C2276657273696F6E223A312C22637265617465644F6E223A313536363233343735303036312C227369676E6174757265223A22333038303036303932613836343838366637306430313037303261303830333038303032303130313331306633303064303630393630383634383031363530333034303230313035303033303830303630393261383634383836663730643031303730313030303061303830333038323033653333303832303338386130303330323031303230323038346333303431343935313964353433363330306130363038326138363438636533643034303330323330376133313265333032633036303335353034303330633235343137303730366336353230343137303730366336393633363137343639366636653230343936653734363536373732363137343639366636653230343334313230326432303437333333313236333032343036303335353034306230633164343137303730366336353230343336353732373436393636363936333631373436393666366532303431373537343638366637323639373437393331313333303131303630333535303430613063306134313730373036633635323034393665363332653331306233303039303630333535303430363133303235353533333031653137306433313339333033353331333833303331333333323335333735613137306433323334333033353331333633303331333333323335333735613330356633313235333032333036303335353034303330633163363536333633326437333664373032643632373236663662363537323264373336393637366535663535343333343264353035323466343433313134333031323036303335353034306230633062363934663533323035333739373337343635366437333331313333303131303630333535303430613063306134313730373036633635323034393665363332653331306233303039303630333535303430363133303235353533333035393330313330363037326138363438636533643032303130363038326138363438636533643033303130373033343230303034633231353737656465626436633762323231386636386464373039306131323138646337623062643666326332383364383436303935643934616634613534313162383334323065643831316633343037653833333331663163353463336637656233323230643662616435643465666634393238393839336537633066313361333832303231313330383230323064333030633036303335353164313330313031666630343032333030303330316630363033353531643233303431383330313638303134323366323439633434663933653465663237653663346636323836633366613262626664326534623330343530363038326230363031303530353037303130313034333933303337333033353036303832623036303130353035303733303031383632393638373437343730336132663266366636333733373032653631373037303663363532653633366636643266366636333733373033303334326436313730373036633635363136393633363133333330333233303832303131643036303335353164323030343832303131343330383230313130333038323031306330363039326138363438383666373633363430353031333038316665333038316333303630383262303630313035303530373032303233303831623630633831623335323635366336393631366536333635323036663665323037343638363937333230363336353732373436393636363936333631373436353230363237393230363136653739323037303631373237343739323036313733373337353664363537333230363136333633363537303734363136653633363532303666363632303734363836353230373436383635366532303631373037303663363936333631363236633635323037333734363136653634363137323634323037343635373236643733323036313665363432303633366636653634363937343639366636653733323036663636323037353733363532633230363336353732373436393636363936333631373436353230373036663663363936333739323036313665363432303633363537323734363936363639363336313734363936663665323037303732363136333734363936333635323037333734363137343635366436353665373437333265333033363036303832623036303130353035303730323031313632613638373437343730336132663266373737373737326536313730373036633635326536333666366432663633363537323734363936363639363336313734363536313735373436383666373236393734373932663330333430363033353531643166303432643330326233303239613032376130323538363233363837343734373033613266326636333732366332653631373037303663363532653633366636643266363137303730366336353631363936333631333332653633373236633330316430363033353531643065303431363034313439343537646236666435373438313836383938393736326637653537383530376537396235383234333030653036303335353164306630313031666630343034303330323037383033303066303630393261383634383836663736333634303631643034303230353030333030613036303832613836343863653364303430333032303334393030333034363032323130306265303935373166653731653165373335623535653561666163623463373266656234343566333031383532323263373235313030326236316562643666353530323231303064313862333530613564643664643665623137343630333562313165623263653837636661336536616636636264383338303839306463383263646461613633333038323032656533303832303237356130303330323031303230323038343936643266626633613938646139373330306130363038326138363438636533643034303330323330363733313162333031393036303335353034303330633132343137303730366336353230353236663666373432303433343132303264323034373333333132363330323430363033353530343062306331643431373037303663363532303433363537323734363936363639363336313734363936663665323034313735373436383666373236393734373933313133333031313036303335353034306130633061343137303730366336353230343936653633326533313062333030393036303335353034303631333032353535333330316531373064333133343330333533303336333233333334333633333330356131373064333233393330333533303336333233333334333633333330356133303761333132653330326330363033353530343033306332353431373037303663363532303431373037303663363936333631373436393666366532303439366537343635363737323631373436393666366532303433343132303264323034373333333132363330323430363033353530343062306331643431373037303663363532303433363537323734363936363639363336313734363936663665323034313735373436383666373236393734373933313133333031313036303335353034306130633061343137303730366336353230343936653633326533313062333030393036303335353034303631333032353535333330353933303133303630373261383634386365336430323031303630383261383634386365336430333031303730333432303030346630313731313834313964373634383564353161356532353831303737366538383061326566646537626165346465303864666334623933653133333536643536363562333561653232643039373736306432323465376262613038666437363137636538386362373662623636373062656338653832393834666635343435613338316637333038316634333034363036303832623036303130353035303730313031303433613330333833303336303630383262303630313035303530373330303138363261363837343734373033613266326636663633373337303265363137303730366336353265363336663664326636663633373337303330333432643631373037303663363537323666366637343633363136373333333031643036303335353164306530343136303431343233663234396334346639336534656632376536633466363238366333666132626266643265346233303066303630333535316431333031303166663034303533303033303130316666333031663036303335353164323330343138333031363830313462626230646561313538333338383961613438613939646562656264656261666461636232346162333033373036303335353164316630343330333032653330326361303261613032383836323636383734373437303361326632663633373236633265363137303730366336353265363336663664326636313730373036633635373236663666373436333631363733333265363337323663333030653036303335353164306630313031666630343034303330323031303633303130303630613261383634383836663736333634303630323065303430323035303033303061303630383261383634386365336430343033303230333637303033303634303233303361636637323833353131363939623138366662333563333536636136326266663431376564643930663735346461323865626566313963383135653432623738396638393866373962353939663938643534313064386639646539633266653032333033323264643534343231623061333035373736633564663333383362393036376664313737633263323136643936346663363732363938323132366635346638376137643162393963623962303938393231363130363939306630393932316430303030333138323031386233303832303138373032303130313330383138363330376133313265333032633036303335353034303330633235343137303730366336353230343137303730366336393633363137343639366636653230343936653734363536373732363137343639366636653230343334313230326432303437333333313236333032343036303335353034306230633164343137303730366336353230343336353732373436393636363936333631373436393666366532303431373537343638366637323639373437393331313333303131303630333535303430613063306134313730373036633635323034393665363332653331306233303039303630333535303430363133303235353533303230383463333034313439353139643534333633303064303630393630383634383031363530333034303230313035303061303831393533303138303630393261383634383836663730643031303930333331306230363039326138363438383666373064303130373031333031633036303932613836343838366637306430313039303533313066313730643331333933303338333133393331333733313332333333303561333032613036303932613836343838366637306430313039333433313164333031623330306430363039363038363438303136353033303430323031303530306131306130363038326138363438636533643034303330323330326630363039326138363438383666373064303130393034333132323034323062303731303365313430613462386231376262613230316130336163643036396234653431366232613263383066383661383338313435633239373566633131333030613036303832613836343863653364303430333032303434363330343430323230343639306264636637626461663833636466343934396534633035313039656463663334373665303564373261313264376335666538633033303033343464663032323032363764353863393365626233353031333836363062353730373938613064643731313734316262353864626436613138363633353038353431656565393035303030303030303030303030227D", # NoQA 'type': str, - } + }, + 'widget_vite_origins': { + 'default': '', + 'type': str, + }, } PERSON_NAME_TITLE_GROUPS = OrderedDict([ ('english_common', (_('Most common English titles'), ( diff --git a/src/pretix/base/templatetags/vite.py b/src/pretix/base/templatetags/vite.py new file mode 100644 index 000000000..3c0303c9b --- /dev/null +++ b/src/pretix/base/templatetags/vite.py @@ -0,0 +1,243 @@ +# +# This file is part of pretix (Community Edition). +# +# Copyright (C) 2014-2020 Raphael Michel and contributors +# Copyright (C) 2020-today pretix GmbH and contributors +# +# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General +# Public License as published by the Free Software Foundation in version 3 of the License. +# +# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are +# applicable granting you additional permissions and placing additional restrictions on your usage of this software. +# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive +# this file, see . +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License along with this program. If not, see +# . +# + +import json +import logging +import pathlib +import re +import secrets +from urllib.parse import urljoin +from urllib.request import urlopen + +import importlib_metadata as metadata +from django import template +from django.conf import settings +from django.utils.safestring import mark_safe + +register = template.Library() +LOGGER = logging.getLogger(__name__) +_MANIFEST = {} +# TODO more os.path.join ? +MANIFEST_PATH = settings.STATIC_ROOT + "/vite/control/.vite/manifest.json" +MANIFEST_BASE = "vite/control/" + +# entry_name -> {"manifest_entry": {...}, "url_base": "..."} +_PLUGIN_REGISTRY = {} + + +def _discover_plugin_manifests(): + """Discover plugin vite manifests at startup. + + Scans installed pretix plugins for a .vite/manifest.json inside a static.dist + directory. Only non-editable (wheel) plugins are expected to ship pre-built + assets; editable plugins are served through the Vite dev server. + """ + for ep in metadata.entry_points(group='pretix.plugin'): + dist = ep.dist + if not dist or not dist.files: + continue + + try: + url_info = json.loads(dist.read_text('direct_url.json') or '{}') + if url_info.get('dir_info', {}).get('editable', False): + continue # editable plugins are served via vite dev server + except Exception: + pass + + # Find .vite/manifest.json inside a /static/ directory + try: + manifest_rel = None + for f in dist.files: + if f.name == 'manifest.json' and '/static/' in str(f) and '/.vite/' in str(f): + manifest_rel = f + break + + if not manifest_rel: + continue + + manifest_path = pathlib.Path(str(dist.locate_file(manifest_rel))) + if not manifest_path.exists(): + continue + + plugin_manifest = json.loads(manifest_path.read_text()) + + url_base = re.search(r'/static/(.+?)/\.vite/', str(manifest_rel)).group(1) + '/' + + for _key, entry in plugin_manifest.items(): + if entry.get('isEntry') and 'name' in entry: + _PLUGIN_REGISTRY[entry['name']] = { + 'manifest_entry': entry, + 'url_base': url_base, + } + except Exception: + LOGGER.warning(f"Failed to discover vite manifest for plugin {ep.name}", exc_info=True) + + +# Load core manifest +if not settings.VITE_DEV_MODE and not settings.VITE_IGNORE: + try: + with open(MANIFEST_PATH) as fp: + _MANIFEST = json.load(fp) + except Exception as e: + LOGGER.warning(f"Error reading vite manifest at {MANIFEST_PATH}: {str(e)}") + +# Discover plugin manifests +if not settings.VITE_IGNORE: + _discover_plugin_manifests() + + +def _generate_script_tag(path, attrs, src=None): + all_attrs = " ".join(f'{key}="{value}"' for key, value in attrs.items()) + if src is None: + if settings.VITE_DEV_MODE: + src = urljoin(settings.VITE_DEV_SERVER, path) + else: + src = urljoin(settings.STATIC_URL, path) + return f'' + + +def _generate_css_tags(asset, already_processed=None): + """Recursively builds all CSS tags used in a given asset from the core manifest.""" + tags = [] + manifest_entry = _MANIFEST[asset] + if already_processed is None: + already_processed = [] + + if "css" in manifest_entry: + for css_path in manifest_entry["css"]: + if css_path not in already_processed: + full_path = urljoin(settings.STATIC_URL, MANIFEST_BASE + css_path) + tags.append(f'') + already_processed.append(css_path) + + if "imports" in manifest_entry: + for import_path in manifest_entry["imports"]: + tags += _generate_css_tags(import_path, already_processed) + + return tags + + +def _generate_plugin_css_tags(manifest_entry, url_base): + """Build CSS tags for a plugin manifest entry.""" + tags = [] + if "css" in manifest_entry: + for css_path in manifest_entry["css"]: + full_path = urljoin(settings.STATIC_URL, url_base + css_path) + tags.append(f'') + return tags + + +@register.simple_tag +@mark_safe +def vite_asset(path): + """ + Generates one ' diff --git a/src/pretix/control/forms/global_settings.py b/src/pretix/control/forms/global_settings.py index 518579968..8435f991b 100644 --- a/src/pretix/control/forms/global_settings.py +++ b/src/pretix/control/forms/global_settings.py @@ -104,6 +104,12 @@ class GlobalSettingsForm(SettingsForm): help_text=_("Will be served at {domain}/.well-known/apple-developer-merchantid-domain-association").format( domain=settings.SITE_URL ) + )), + ('widget_vite_origins', forms.CharField( + widget=forms.Textarea(attrs={'rows': '3'}), + required=False, + label=_("Vite widget origins"), + help_text=_("One origin per line (e.g. https://example.com). Requests from these origins will be served the new vite-based widget."), )) ]) responses = register_global_settings.send(self) diff --git a/src/pretix/control/templates/pretixcontrol/base.html b/src/pretix/control/templates/pretixcontrol/base.html index 41fc60f8d..47ff1d45b 100644 --- a/src/pretix/control/templates/pretixcontrol/base.html +++ b/src/pretix/control/templates/pretixcontrol/base.html @@ -2,6 +2,7 @@ {% load static %} {% load i18n %} {% load statici18n %} +{% load vite %} {% load eventsignal %} {% load eventurl %} {% load dialog %} @@ -84,6 +85,7 @@ + {% vite_importmap %} {% block custom_header %}{% endblock %} {% trans "Custom check-in rule" %} -
-
- - - -
-
- -
-
- -
-
- -
-
-

- {% trans "Your rule always filters by product or variation, but the following products or variations are not contained in any of your rule parts so people with these tickets will not get in:" %} -

-
    -
  • {{ "{" }}{h}{{ "}" }}
  • -
-

- {% trans "Please double-check if this was intentional." %} -

-
+
+
{{ form.rules }} @@ -127,11 +91,6 @@ {{ items|json_script:"items" }} - {% if DEBUG %} - - {% else %} - - {% endif %} {% compress js %} @@ -144,15 +103,6 @@ {% endcompress %} - {% compress js %} - - - - - - - - - - {% endcompress %} + {% vite_hmr %} + {% vite_asset "src/pretix/static/pretixcontrol/js/ui/checkinrules/index.ts" %} {% endblock %} diff --git a/src/pretix/control/templates/pretixcontrol/checkin/simulator.html b/src/pretix/control/templates/pretixcontrol/checkin/simulator.html index ff3829969..2ebb94a30 100644 --- a/src/pretix/control/templates/pretixcontrol/checkin/simulator.html +++ b/src/pretix/control/templates/pretixcontrol/checkin/simulator.html @@ -5,6 +5,7 @@ {% load getitem %} {% load static %} {% load compress %} +{% load vite %} {% block title %}{% trans "Check-in simulator" %}{% endblock %} {% block inside %}

@@ -124,11 +125,9 @@ {% endif %} {% if result.rule_graph %}
-
- -
- +
+ {% endif %}

@@ -152,10 +151,6 @@ {% endcompress %} - {% compress js %} - - - - - {% endcompress %} + {% vite_hmr %} + {% vite_asset "src/pretix/static/pretixcontrol/js/ui/checkinrules/index.ts" %} {% endblock %} diff --git a/src/pretix/helpers/compressor.py b/src/pretix/helpers/compressor.py deleted file mode 100644 index 97131548b..000000000 --- a/src/pretix/helpers/compressor.py +++ /dev/null @@ -1,63 +0,0 @@ -# -# This file is part of pretix (Community Edition). -# -# Copyright (C) 2014-2020 Raphael Michel and contributors -# Copyright (C) 2020-today pretix GmbH and contributors -# -# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General -# Public License as published by the Free Software Foundation in version 3 of the License. -# -# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are -# applicable granting you additional permissions and placing additional restrictions on your usage of this software. -# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive -# this file, see . -# -# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied -# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more -# details. -# -# You should have received a copy of the GNU Affero General Public License along with this program. If not, see -# . -# -import os -import re -import shlex - -from compressor.exceptions import FilterError -from compressor.filters import CompilerFilter -from django.conf import settings - - -class VueCompiler(CompilerFilter): - # Based on work (c) Laura Klünder in https://github.com/codingcatgirl/django-vue-rollup - # Released under Apache License 2.0 - - def __init__(self, content, attrs, **kwargs): - config_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'static', 'npm_dir') - node_path = os.path.join(settings.STATIC_ROOT, 'node_prefix', 'node_modules') - self.rollup_bin = os.path.join(node_path, 'rollup', 'dist', 'bin', 'rollup') - rollup_config = os.path.join(config_dir, 'rollup.config.js') - if not os.path.exists(self.rollup_bin) and not settings.DEBUG: - raise FilterError("Rollup not installed or pretix not built properly, please run 'make npminstall' in source root.") - command = ( - ' '.join(( - 'NODE_PATH=' + shlex.quote(node_path), - shlex.quote(self.rollup_bin), - '-c', - shlex.quote(rollup_config)) - ) + - ' --input {infile} -n {export_name} --file {outfile}' - ) - super().__init__(content, command=command, **kwargs) - - def input(self, **kwargs): - if self.filename is None: - raise FilterError('VueCompiler can only compile files, not inline code.') - if not os.path.exists(self.rollup_bin): - raise FilterError("Rollup not installed, please run 'make npminstall' in source root.") - self.options += (('export_name', re.sub( - r'^([a-z])|[^a-z0-9A-Z]+([a-zA-Z0-9])?', - lambda s: s.group(0)[-1].upper(), - os.path.basename(self.filename).split('.')[0] - )),) - return super().input(**kwargs) diff --git a/src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/api.ts b/src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/api.ts new file mode 100644 index 000000000..8e034b500 --- /dev/null +++ b/src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/api.ts @@ -0,0 +1,271 @@ +import type { I18nString, SubEvent } from './i18n' + +const settingsEl = document.getElementById('api-settings') +const { urls } = JSON.parse(settingsEl.textContent || '{}') as { urls: { + lists: string + questions: string +} } + +// interfaces generated from api docs +export interface PaginatedResponse { + count: number + next: string | null + previous: string | null + results: T[] +} + +export interface CheckinList { + id: number + name: string + all_products: boolean + limit_products: number[] + subevent: SubEvent | null + position_count?: number + checkin_count?: number + include_pending: boolean + allow_multiple_entries: boolean + allow_entry_after_exit: boolean + rules: Record + exit_all_at: string | null + addon_match: boolean + ignore_in_statistics?: boolean + consider_tickets_used?: boolean +} + +export interface Checkin { + id: number + list: number + datetime: string + type: 'entry' | 'exit' + gate: number | null + device: number | null + device_id: number | null + auto_checked_in: boolean +} + +export interface Seat { + id: number + name: string + zone_name: string + row_name: string + row_label: string | null + seat_number: string + seat_label: string | null + seat_guid: string +} + +export interface Position { + id: number + order: string + positionid: number + canceled?: boolean + item: { id?: number; name: I18nString; internal_name?: string; admission?: boolean } + variation: { id?: number; value: I18nString } | null + price: string + attendee_name: string + attendee_name_parts: Record + attendee_email: string | null + company?: string | null + street?: string | null + zipcode?: string | null + city?: string | null + country?: string | null + state?: string | null + voucher?: number | null + voucher_budget_use?: string | null + tax_rate: string + tax_value: string + tax_code?: string | null + tax_rule: number | null + secret: string + addon_to: number | null + subevent: SubEvent | null + discount?: number | null + blocked: string[] | null + valid_from: string | null + valid_until: string | null + pseudonymization_id: string + seat: Seat | null + checkins: Checkin[] + downloads?: { output: string; url: string }[] + answers: Answer[] + pdf_data?: Record + plugin_data?: Record + // Additional fields from checkin list positions endpoint + order__status?: string + order__valid_if_pending?: boolean + order__require_approval?: boolean + order__locale?: string + require_attention?: boolean + addons?: Addon[] +} + +export interface Answer { + question: number | AnswerQuestion + answer: string + question_identifier: string + options: number[] + option_identifiers: string[] +} + +export interface AnswerQuestion { + id: number + question: I18nString + help_text?: I18nString + type: string + required: boolean + position: number + items: number[] + identifier: string + ask_during_checkin: boolean + show_during_checkin: boolean + hidden?: boolean + print_on_invoice?: boolean + options: QuestionOption[] + valid_number_min?: string | null + valid_number_max?: string | null + valid_date_min?: string | null + valid_date_max?: string | null + valid_datetime_min?: string | null + valid_datetime_max?: string | null + valid_file_portrait?: boolean + valid_string_length_max?: number | null + dependency_question?: number | null + dependency_values?: string[] +} + +export interface QuestionOption { + id: number + identifier: string + position: number + answer: I18nString +} + +export interface Addon { + item: { name: I18nString; internal_name?: string } + variation: { value: I18nString } | null +} + +export interface CheckinStatusVariation { + id: number + value: string + checkin_count: number + position_count: number +} + +export interface CheckinStatusItem { + id: number + name: string + checkin_count: number + admission: boolean + position_count: number + variations: CheckinStatusVariation[] +} + +export interface CheckinStatus { + checkin_count: number + position_count: number + inside_count: number + event?: { name: string } + items?: CheckinStatusItem[] +} + +export interface RedeemRequest { + questions_supported: boolean + canceled_supported: boolean + ignore_unpaid: boolean + type: 'entry' | 'exit' + answers: Record + datetime?: string | null + force?: boolean + nonce?: string +} + +export interface RedeemResponseList { + id: number + name: string + event: string + subevent: number | null + include_pending: boolean +} + +export interface RedeemResponse { + status: 'ok' | 'error' | 'incomplete' + reason?: 'invalid' | 'unpaid' | 'blocked' | 'invalid_time' | 'canceled' | 'already_redeemed' | 'product' | 'rules' | 'ambiguous' | 'revoked' | 'unapproved' | 'error' + reason_explanation?: string | null + position?: Position + questions?: AnswerQuestion[] + checkin_texts?: string[] + require_attention?: boolean + list?: RedeemResponseList +} + +const CSRF_TOKEN = document.querySelector('input[name=csrfmiddlewaretoken]')?.value ?? '' + +function handleAuthError (response: Response): void { + if ([401, 403].includes(response.status)) { + window.location.href = '/control/login?next=' + encodeURIComponent( + window.location.pathname + window.location.search + window.location.hash + ) + } +} + +export const api = { + // generic fetch wrapper, not sure if this should be exposed + async fetch (url: string, options?: RequestInit): Promise { + const response = await fetch(url, options) + handleAuthError(response) + if (!response.ok && response.status !== 400 && response.status !== 404) { + throw new Error('HTTP status ' + response.status) + } + return response.json() + }, + async fetchCheckinLists (endsAfter?: string): Promise> { + const cutoff = endsAfter ?? moment().subtract(8, 'hours').toISOString() + const url = `${urls.lists}?exclude=checkin_count&exclude=position_count&expand=subevent&ends_after=${cutoff}` + return api.fetch(url) + }, + async fetchCheckinList (listId: string): Promise { + return api.fetch(`${urls.lists}${listId}/?expand=subevent`) + }, + async fetchNextPage (nextUrl: string): Promise> { + return api.fetch(nextUrl) + }, + async fetchStatus (listId: number): Promise { + return api.fetch(`${urls.lists}${listId}/status/`) + }, + async searchPositions (listId: number, query: string): Promise> { + const url = `${urls.lists}${listId}/positions/?ignore_status=true&expand=subevent&expand=item&expand=variation&check_rules=true&search=${encodeURIComponent(query)}` + return api.fetch(url) + }, + async redeemPosition ( + listId: number, + positionId: string, + data: RedeemRequest, + untrusted: boolean = false + ): Promise { + let url = `${urls.lists}${listId}/positions/${encodeURIComponent(positionId)}/redeem/?expand=item&expand=subevent&expand=variation&expand=answers.question&expand=addons` + if (untrusted) url += '&untrusted_input=true' + + const response = await fetch(url, { + method: 'POST', + headers: { + 'X-CSRFToken': CSRF_TOKEN, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }) + + handleAuthError(response) + + if (response.status === 404) { + return { status: 'error', reason: 'invalid' } + } + + if (!response.ok && response.status !== 400) { + throw new Error('HTTP status ' + response.status) + } + + return response.json() + } +} diff --git a/src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/components/app.vue b/src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/components/app.vue index f9e093658..79b15fd75 100644 --- a/src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/components/app.vue +++ b/src/pretix/plugins/webcheckin/static/pretixplugins/webcheckin/components/app.vue @@ -1,588 +1,593 @@ -