Merge branch stable into develop

environments/review-docs-merge-py0v6m/deployments/18364
Georg Krause 2023-09-01 14:09:58 +02:00
rodzic d2f7d45a0d
commit ec8dc8e09f
57 zmienionych plików z 2851 dodań i 1914 usunięć

Wyświetl plik

@ -93,6 +93,7 @@ review_front:
VUE_APP_ROUTER_BASE_URL: /-/$CI_PROJECT_NAME/-/jobs/$CI_JOB_ID/artifacts/front-review/ VUE_APP_ROUTER_BASE_URL: /-/$CI_PROJECT_NAME/-/jobs/$CI_JOB_ID/artifacts/front-review/
VUE_APP_INSTANCE_URL: https://demo.funkwhale.audio VUE_APP_INSTANCE_URL: https://demo.funkwhale.audio
NODE_ENV: review NODE_ENV: review
NODE_OPTIONS: --max-old-space-size=4096
environment: environment:
name: review/front/$CI_COMMIT_REF_NAME name: review/front/$CI_COMMIT_REF_NAME
url: http://$CI_PROJECT_NAMESPACE.pages.funkwhale.audio/-/$CI_PROJECT_NAME/-/jobs/$CI_JOB_ID/artifacts/front-review/index.html url: http://$CI_PROJECT_NAMESPACE.pages.funkwhale.audio/-/$CI_PROJECT_NAME/-/jobs/$CI_JOB_ID/artifacts/front-review/index.html
@ -403,6 +404,7 @@ build_front:
image: $CI_REGISTRY/funkwhale/ci/node-python:18 image: $CI_REGISTRY/funkwhale/ci/node-python:18
variables: variables:
<<: *keep_git_files_permissions <<: *keep_git_files_permissions
NODE_OPTIONS: --max-old-space-size=4096
cache: *front_cache cache: *front_cache
before_script: before_script:
- cd front - cd front

Wyświetl plik

@ -36,14 +36,14 @@ repos:
args: [--directory=api, --check] args: [--directory=api, --check]
- repo: https://github.com/asottile/pyupgrade - repo: https://github.com/asottile/pyupgrade
rev: v3.6.0 rev: v3.9.0
hooks: hooks:
- id: pyupgrade - id: pyupgrade
args: [--py38-plus] args: [--py38-plus]
exclude: ^(api/.*/migrations/.*) exclude: ^(api/.*/migrations/.*)
- repo: https://github.com/psf/black - repo: https://github.com/psf/black
rev: 23.3.0 rev: 23.7.0
hooks: hooks:
- id: black - id: black
@ -58,7 +58,7 @@ repos:
- id: flake8 - id: flake8
- repo: https://github.com/pre-commit/mirrors-prettier - repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.7.1 rev: v3.0.2
hooks: hooks:
- id: prettier - id: prettier
files: \.(md|yml|yaml|json)$ files: \.(md|yml|yaml|json)$

Wyświetl plik

@ -9,10 +9,74 @@ This changelog is viewable on the web at https://docs.funkwhale.audio/changelog.
<!-- towncrier --> <!-- towncrier -->
## 1.3.2 (2023-09-01)
Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Enhancements:
- Enable sourcemaps for production builds
- Use logger composable instead of window.console
Bugfixes:
- Clear shuffled id list on queue clear (#2192)
- Fetch the nodeinfo endpoint from .well-known/nodeinfo when checking instance availability
- Fix instance checking its own availability (#2199)
- Fix multiarch docker builds #2211
- Fix ordering when querystring contains `+` prefix
Resolve multiple updates to ordering fields
- Fix password reset via email
- Make podcast episode pagination reactive (#2205)
- Render HTML in podcast short description (#2206)
- Resolve race condition regarding axios when initializing the frontend
Prevent sending same language setting to backend multiple times
Documentation:
- Fixed incorrect upgrade instructions link in docs.
Contributors to our Issues:
- Ciarán Ainsworth
- Georg Krause
- Kasper Seweryn
- Kay Borowski
- Marcos Peña
- Mathieu Jourdan
- Virgile Robles
- codl
- jooola
- petitminion
- tinglycraniumplacidly
- unkn0wwn52
Contributors to our Merge Requests:
- Ciarán Ainsworth
- Georg Krause
- JuniorJPDJ
- Kasper Seweryn
- Marcos Peña
- Virgile Robles
- codl
- jooola
- petitminion
Committers:
- Ciarán Ainsworth
- codl
- Georg Krause
- jo
- Kasper Seweryn
- petitminion
## 1.3.1 (2023-06-27) ## 1.3.1 (2023-06-27)
Upgrade instructions are available at Upgrade instructions are available at
https://docs.funkwhale.audio/admin/upgrading.html https://docs.funkwhale.audio/administrator/upgrade/index.html
Bugfixes: Bugfixes:
@ -82,7 +146,7 @@ Committers:
## 1.3.0 (2023-06-01) ## 1.3.0 (2023-06-01)
Upgrade instructions are available at Upgrade instructions are available at
https://docs.funkwhale.audio/admin/upgrading.html https://docs.funkwhale.audio/administrator/upgrade/index.html
Update instructions: Update instructions:
@ -496,7 +560,8 @@ Committers:
## 1.2.9 (2022-11-25) ## 1.2.9 (2022-11-25)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Bugfixes: Bugfixes:
@ -535,7 +600,8 @@ Contributors to our Merge Requests:
## 1.2.8 (2022-09-12) ## 1.2.8 (2022-09-12)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Features: Features:
@ -590,7 +656,8 @@ Contributors to our Merge Requests:
## 1.2.7 (2022-07-14) ## 1.2.7 (2022-07-14)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Bugfixes: Bugfixes:
@ -613,7 +680,8 @@ Contributors to our Merge Requests:
## 1.2.6 (2022-07-04) ## 1.2.6 (2022-07-04)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Bugfixes: Bugfixes:
@ -662,7 +730,8 @@ Contributors to our Merge Requests:
## 1.2.5 (2022-05-07) ## 1.2.5 (2022-05-07)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Enhancements: Enhancements:
@ -711,7 +780,8 @@ Contributors to our Merge Requests:
## 1.2.4 (2022-04-23) ## 1.2.4 (2022-04-23)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Enhancements: Enhancements:
@ -752,7 +822,8 @@ Committers:
## 1.2.3 (2022-03-18) ## 1.2.3 (2022-03-18)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Enhancements: Enhancements:
@ -808,7 +879,8 @@ Committers
## 1.2.2 (2022-02-04) ## 1.2.2 (2022-02-04)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Bugfixes: Bugfixes:
@ -862,7 +934,8 @@ Committers
## 1.2.1 (2022-01-06) ## 1.2.1 (2022-01-06)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Bugfixes: Bugfixes:
@ -891,7 +964,8 @@ Committers:
## 1.2.0 (2021-12-27) ## 1.2.0 (2021-12-27)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Due to a bug in our CI Pipeline, you need to download the frontend artifact here: https://dev.funkwhale.audio/funkwhale/funkwhale/-/jobs/81069/artifacts/download Due to a bug in our CI Pipeline, you need to download the frontend artifact here: https://dev.funkwhale.audio/funkwhale/funkwhale/-/jobs/81069/artifacts/download
@ -1086,13 +1160,15 @@ Contributors to our Merge Requests:
## 1.1.4 (2021-08-02) ## 1.1.4 (2021-08-02)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
- Pinned version of asgiref to avoid trouble with latest release. For further information, see #1516 - Pinned version of asgiref to avoid trouble with latest release. For further information, see #1516
## 1.1.3 (2021-08-02) ## 1.1.3 (2021-08-02)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Enhancements: Enhancements:
@ -1108,7 +1184,8 @@ Bugfixes:
## 1.1.2 (2021-05-19) ## 1.1.2 (2021-05-19)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Enhancements: Enhancements:
@ -1123,7 +1200,8 @@ Bugfixes:
## 1.1.1 (2021-04-13) ## 1.1.1 (2021-04-13)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Enhancements: Enhancements:
@ -1140,7 +1218,8 @@ Bugfixes:
## 1.1 (2021-03-10) ## 1.1 (2021-03-10)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Enhancements: Enhancements:
@ -1222,7 +1301,8 @@ Contributors to this release (development, documentation, reviews):
## 1.1-rc2 (2021-03-01) ## 1.1-rc2 (2021-03-01)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Bugfixes: Bugfixes:
@ -1233,7 +1313,8 @@ Bugfixes:
## 1.1-rc1 (2021-02-24) ## 1.1-rc1 (2021-02-24)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Enhancements: Enhancements:
@ -1292,7 +1373,8 @@ Contributors to this release (development, documentation, reviews):
## 1.0.1 (2020-10-31) ## 1.0.1 (2020-10-31)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Enhancements: Enhancements:
@ -1314,7 +1396,8 @@ Contributors to this release (development, documentation, reviews):
## 1.0 (2020-09-09) ## 1.0 (2020-09-09)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
### Dropped python 3.5 support [manual action required, non-docker only] ### Dropped python 3.5 support [manual action required, non-docker only]
@ -1444,7 +1527,8 @@ Contributors to this release (translation, development, documentation, reviews,
## 0.21.2 (2020-07-27) ## 0.21.2 (2020-07-27)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Enhancements: Enhancements:
@ -1472,7 +1556,8 @@ Contributors to this release (development, documentation, reviews):
## 0.21.1 (2020-06-11) ## 0.21.1 (2020-06-11)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Features: Features:
@ -1530,7 +1615,8 @@ This 0.21 release is dedicated to Agate, to thank her, for both having created t
We are truly grateful as well to the dozens of people who contributed to this release with translations, development, documentation, reviews, design, testing, feedback, financial support, third-party projects and integrations… You made it possible! We are truly grateful as well to the dozens of people who contributed to this release with translations, development, documentation, reviews, design, testing, feedback, financial support, third-party projects and integrations… You made it possible!
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html, there are also additional operations you need to execute, listed in the changelog below (search "Manual action"). Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html, there are also additional operations you need to execute, listed in the changelog below (search "Manual action").
### Channels and podcasts ### Channels and podcasts
@ -1835,7 +1921,8 @@ Contributors to this release (translation, development, documentation, reviews,
## 0.20.1 (2019-10-28) ## 0.20.1 (2019-10-28)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
### Denormalized audio permission logic in a separate table to enhance performance ### Denormalized audio permission logic in a separate table to enhance performance
@ -1897,6 +1984,9 @@ Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgradi
### Support for genres via tags ### Support for genres via tags
Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
One of our most requested missing features is now available! One of our most requested missing features is now available!
Starting with Funkwhale 0.20, Starting with Funkwhale 0.20,
@ -2206,7 +2296,8 @@ Contributors to this release (translation, development, documentation, reviews,
## 0.19.1 (2019-06-28) ## 0.19.1 (2019-06-28)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Enhancements: Enhancements:
@ -2250,7 +2341,8 @@ Contributors to this release (committers and reviewers):
## 0.19.0 (2019-05-16) ## 0.19.0 (2019-05-16)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
### Edits on tracks, albums and artists ### Edits on tracks, albums and artists
@ -2454,7 +2546,8 @@ Contributors to this release (committers and translators):
## 0.18.3 (2019-03-21) ## 0.18.3 (2019-03-21)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
### Avoid mixed content when deploying mono-container behind proxy [Manual action required] ### Avoid mixed content when deploying mono-container behind proxy [Manual action required]
@ -2497,7 +2590,8 @@ Documentation:
## 0.18.2 (2019-02-13) ## 0.18.2 (2019-02-13)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
Enhancements: Enhancements:
@ -2514,7 +2608,8 @@ Bugfixes:
## 0.18.1 (2019-01-29) ## 0.18.1 (2019-01-29)
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html
### Fix Gzip compression to avoid BREACH exploit [security] [manual action required] ### Fix Gzip compression to avoid BREACH exploit [security] [manual action required]
@ -2637,7 +2732,8 @@ as you can enjoy it today. Thank you so much Naomi <3
Many thanks to the dozens of people that contributed to this release: translators, developers, Many thanks to the dozens of people that contributed to this release: translators, developers,
bug hunters, admins and backers. You made it possible! bug hunters, admins and backers. You made it possible!
Upgrade instructions are available at https://docs.funkwhale.audio/admin/upgrading.html, ensure you also execute the instructions Upgrade instructions are available at
https://docs.funkwhale.audio/administrator/upgrade/index.html, ensure you also execute the instructions
marked with `[manual action required]` and `[manual action suggested]`. marked with `[manual action required]` and `[manual action suggested]`.
See `Full changelog` below for an exhaustive list of changes! See `Full changelog` below for an exhaustive list of changes!

Wyświetl plik

@ -8,7 +8,7 @@ The Funkwhale software is the core of the community project. While we have a cor
Funkwhale's backend is written in [Python](https://www.python.org/) using [Django](https://www.djangoproject.com) and [Django REST framework](https://www.django-rest-framework.org/). Our web app is written in [Vue.js](https://vuejs.org/) and [Typescript](https://typescriptlang.org). Funkwhale's backend is written in [Python](https://www.python.org/) using [Django](https://www.djangoproject.com) and [Django REST framework](https://www.django-rest-framework.org/). Our web app is written in [Vue.js](https://vuejs.org/) and [Typescript](https://typescriptlang.org).
Whether you're an experienced developer or you're just learning, check out our [developer guide](https://docs.funkwhale.audio/developers/index.html) to get started. Whether you're an experienced developer or you're just learning, check out our [developer guide](https://docs.funkwhale.audio/developer/index.html) to get started.
## Document Funkwhale ## Document Funkwhale

Wyświetl plik

@ -10,7 +10,7 @@ Want to help make Funkwhale even better? We welcome contributions from across th
You can find contribution information in our [documentation hub](https://docs.funkwhale.audio). You can find contribution information in our [documentation hub](https://docs.funkwhale.audio).
- [Developer guides](https://docs.funkwhale.audio/developers/index.html) - [Developer guides](https://docs.funkwhale.audio/developer/index.html)
- [Contributor guides](https://docs.funkwhale.audio/contributing.html) - [Contributor guides](https://docs.funkwhale.audio/contributing.html)
## Get help ## Get help

Wyświetl plik

@ -32,7 +32,7 @@ Each API call returns HTTP headers to pass the following information:
- How many more requests in the scope can be made within the rate-limit timeframe (`X-RateLimit-Remaining`) - How many more requests in the scope can be made within the rate-limit timeframe (`X-RateLimit-Remaining`)
- How much time does the client need to wait to send another request (`Retry-After`) - How much time does the client need to wait to send another request (`Retry-After`)
For more information, check our [rate limit documentation](https://docs.funkwhale.audio/admin/configuration.html#api-configuration) For more information, check our [rate limit documentation](https://docs.funkwhale.audio/developer/api/rate-limit.html)
## Resources ## Resources

Wyświetl plik

@ -1181,7 +1181,8 @@ if BROWSABLE_API_ENABLED:
) )
REST_AUTH_SERIALIZERS = { REST_AUTH_SERIALIZERS = {
"PASSWORD_RESET_SERIALIZER": "funkwhale_api.users.serializers.PasswordResetSerializer" # noqa "PASSWORD_RESET_SERIALIZER": "funkwhale_api.users.serializers.PasswordResetSerializer", # noqa
"PASSWORD_RESET_CONFIRM_SERIALIZER": "funkwhale_api.users.serializers.PasswordResetConfirmSerializer", # noqa
} }
REST_SESSION_LOGIN = False REST_SESSION_LOGIN = False

Wyświetl plik

@ -632,7 +632,7 @@ def fetch_collection(url, max_pages, channel, is_page=False):
def check_all_remote_instance_availability(): def check_all_remote_instance_availability():
domains = models.Domain.objects.all().prefetch_related() domains = models.Domain.objects.all().prefetch_related()
for domain in domains: for domain in domains:
if domain == settings.FUNKWHALE_HOSTNAME: if domain.name == settings.FUNKWHALE_HOSTNAME:
# No need to check the instance itself: Its always reachable # No need to check the instance itself: Its always reachable
domain.reachable = True domain.reachable = True
domain.last_successful_contact = timezone.now() domain.last_successful_contact = timezone.now()
@ -643,8 +643,7 @@ def check_all_remote_instance_availability():
@celery.app.task(name="federation.check_single_remote_instance_availability") @celery.app.task(name="federation.check_single_remote_instance_availability")
def check_single_remote_instance_availability(domain): def check_single_remote_instance_availability(domain):
try: try:
response = requests.get(f"https://{domain.name}/api/v1/instance/nodeinfo/2.0/") nodeinfo = fetch_nodeinfo(domain.name)
nodeinfo = response.json()
except Exception as e: except Exception as e:
logger.info( logger.info(
f"Domain {domain.name} could not be reached because of the following error : {e}. \ f"Domain {domain.name} could not be reached because of the following error : {e}. \

Wyświetl plik

@ -3,15 +3,18 @@ import re
from allauth.account import models as allauth_models from allauth.account import models as allauth_models
from dj_rest_auth.registration.serializers import RegisterSerializer as RS from dj_rest_auth.registration.serializers import RegisterSerializer as RS
from dj_rest_auth.registration.serializers import get_adapter from dj_rest_auth.registration.serializers import get_adapter
from dj_rest_auth.serializers import PasswordResetConfirmSerializer as PRCS
from dj_rest_auth.serializers import PasswordResetSerializer as PRS from dj_rest_auth.serializers import PasswordResetSerializer as PRS
from django.contrib import auth from django.contrib import auth
from django.contrib.auth.forms import PasswordResetForm from django.contrib.auth.forms import PasswordResetForm
from django.core import validators from django.core import validators
from django.utils.deconstruct import deconstructible from django.utils.deconstruct import deconstructible
from django.utils.encoding import force_str
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from drf_spectacular.types import OpenApiTypes from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema_field from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from funkwhale_api.activity import serializers as activity_serializers from funkwhale_api.activity import serializers as activity_serializers
from funkwhale_api.common import models as common_models from funkwhale_api.common import models as common_models
@ -252,6 +255,34 @@ class PasswordResetSerializer(PRS):
return {"extra_email_context": adapters.get_email_context()} return {"extra_email_context": adapters.get_email_context()}
class PasswordResetConfirmSerializer(PRCS):
def validate(self, attrs):
from allauth.account.forms import default_token_generator
from django.utils.http import urlsafe_base64_decode as uid_decoder
UserModel = auth.get_user_model()
# Decode the uidb64 (allauth use base36) to uid to get User object
try:
uid = force_str(uid_decoder(attrs["uid"]))
self.user = UserModel._default_manager.get(pk=uid)
except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
raise ValidationError({"uid": [_("Invalid value")]})
if not default_token_generator.check_token(self.user, attrs["token"]):
raise ValidationError({"token": [_("Invalid value")]})
self.custom_validation(attrs)
# Construct SetPasswordForm instance
self.set_password_form = self.set_password_form_class(
user=self.user,
data=attrs,
)
if not self.set_password_form.is_valid():
raise serializers.ValidationError(self.set_password_form.errors)
return attrs
class UserDeleteSerializer(serializers.Serializer): class UserDeleteSerializer(serializers.Serializer):
password = serializers.CharField() password = serializers.CharField()
confirm = serializers.BooleanField() confirm = serializers.BooleanField()

452
api/poetry.lock wygenerowano
Wyświetl plik

@ -152,24 +152,24 @@ vine = ">=5.0.0"
[[package]] [[package]]
name = "anyio" name = "anyio"
version = "3.7.1" version = "4.0.0"
description = "High level compatibility layer for multiple asynchronous event loop implementations" description = "High level compatibility layer for multiple asynchronous event loop implementations"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8"
files = [ files = [
{file = "anyio-3.7.1-py3-none-any.whl", hash = "sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5"}, {file = "anyio-4.0.0-py3-none-any.whl", hash = "sha256:cfdb2b588b9fc25ede96d8db56ed50848b0b649dca3dd1df0b11f683bb9e0b5f"},
{file = "anyio-3.7.1.tar.gz", hash = "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780"}, {file = "anyio-4.0.0.tar.gz", hash = "sha256:f7ed51751b2c2add651e5747c891b47e26d2a21be5d32d9311dfe9692f3e5d7a"},
] ]
[package.dependencies] [package.dependencies]
exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""}
idna = ">=2.8" idna = ">=2.8"
sniffio = ">=1.1" sniffio = ">=1.1"
[package.extras] [package.extras]
doc = ["Sphinx", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-jquery"] doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)"]
test = ["anyio[trio]", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] test = ["anyio[trio]", "coverage[toml] (>=7)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"]
trio = ["trio (<0.22)"] trio = ["trio (>=0.22)"]
[[package]] [[package]]
name = "appnope" name = "appnope"
@ -234,13 +234,13 @@ wrapt = [
[[package]] [[package]]
name = "async-timeout" name = "async-timeout"
version = "4.0.2" version = "4.0.3"
description = "Timeout context manager for asyncio programs" description = "Timeout context manager for asyncio programs"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.7"
files = [ files = [
{file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"},
{file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
] ]
[[package]] [[package]]
@ -541,13 +541,13 @@ zstd = ["zstandard"]
[[package]] [[package]]
name = "certifi" name = "certifi"
version = "2023.5.7" version = "2023.7.22"
description = "Python package for providing Mozilla's CA Bundle." description = "Python package for providing Mozilla's CA Bundle."
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
{file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"}, {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"},
{file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"}, {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"},
] ]
[[package]] [[package]]
@ -1034,13 +1034,13 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"]
[[package]] [[package]]
name = "dill" name = "dill"
version = "0.3.6" version = "0.3.7"
description = "serialize all of python" description = "serialize all of Python"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "dill-0.3.6-py3-none-any.whl", hash = "sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0"}, {file = "dill-0.3.7-py3-none-any.whl", hash = "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e"},
{file = "dill-0.3.6.tar.gz", hash = "sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373"}, {file = "dill-0.3.7.tar.gz", hash = "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"},
] ]
[package.extras] [package.extras]
@ -1370,13 +1370,13 @@ sidecar = ["drf-spectacular-sidecar"]
[[package]] [[package]]
name = "exceptiongroup" name = "exceptiongroup"
version = "1.1.2" version = "1.1.3"
description = "Backport of PEP 654 (exception groups)" description = "Backport of PEP 654 (exception groups)"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"}, {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"},
{file = "exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"}, {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"},
] ]
[package.extras] [package.extras]
@ -1695,13 +1695,13 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs
[[package]] [[package]]
name = "importlib-resources" name = "importlib-resources"
version = "6.0.0" version = "6.0.1"
description = "Read resources from Python packages" description = "Read resources from Python packages"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "importlib_resources-6.0.0-py3-none-any.whl", hash = "sha256:d952faee11004c045f785bb5636e8f885bed30dc3c940d5d42798a2a4541c185"}, {file = "importlib_resources-6.0.1-py3-none-any.whl", hash = "sha256:134832a506243891221b88b4ae1213327eea96ceb4e407a00d790bb0626f45cf"},
{file = "importlib_resources-6.0.0.tar.gz", hash = "sha256:4cf94875a8368bd89531a756df9a9ebe1f150e0f885030b461237bc7f2d905f2"}, {file = "importlib_resources-6.0.1.tar.gz", hash = "sha256:4359457e42708462b9626a04657c6208ad799ceb41e5c58c57ffa0e6a098a5d4"},
] ]
[package.dependencies] [package.dependencies]
@ -1819,21 +1819,21 @@ requirements-deprecated-finder = ["pip-api", "pipreqs"]
[[package]] [[package]]
name = "jedi" name = "jedi"
version = "0.18.2" version = "0.19.0"
description = "An autocompletion tool for Python that can be used for text editors." description = "An autocompletion tool for Python that can be used for text editors."
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
{file = "jedi-0.18.2-py2.py3-none-any.whl", hash = "sha256:203c1fd9d969ab8f2119ec0a3342e0b49910045abe6af0a3ae83a5764d54639e"}, {file = "jedi-0.19.0-py2.py3-none-any.whl", hash = "sha256:cb8ce23fbccff0025e9386b5cf85e892f94c9b822378f8da49970471335ac64e"},
{file = "jedi-0.18.2.tar.gz", hash = "sha256:bae794c30d07f6d910d32a7048af09b5a39ed740918da923c6b780790ebac612"}, {file = "jedi-0.19.0.tar.gz", hash = "sha256:bcf9894f1753969cbac8022a8c2eaee06bfa3724e4192470aaffe7eb6272b0c4"},
] ]
[package.dependencies] [package.dependencies]
parso = ">=0.8.0,<0.9.0" parso = ">=0.8.3,<0.9.0"
[package.extras] [package.extras]
docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"]
qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"]
testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"]
[[package]] [[package]]
@ -1849,13 +1849,13 @@ files = [
[[package]] [[package]]
name = "jsonschema" name = "jsonschema"
version = "4.18.4" version = "4.19.0"
description = "An implementation of JSON Schema validation for Python" description = "An implementation of JSON Schema validation for Python"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "jsonschema-4.18.4-py3-none-any.whl", hash = "sha256:971be834317c22daaa9132340a51c01b50910724082c2c1a2ac87eeec153a3fe"}, {file = "jsonschema-4.19.0-py3-none-any.whl", hash = "sha256:043dc26a3845ff09d20e4420d6012a9c91c9aa8999fa184e7efcfeccb41e32cb"},
{file = "jsonschema-4.18.4.tar.gz", hash = "sha256:fb3642735399fa958c0d2aad7057901554596c63349f4f6b283c493cf692a25d"}, {file = "jsonschema-4.19.0.tar.gz", hash = "sha256:6e1e7569ac13be8139b2dd2c21a55d350066ee3f80df06c608b398cdc6f30e8f"},
] ]
[package.dependencies] [package.dependencies]
@ -2356,13 +2356,13 @@ testing = ["docopt", "pytest (<6.0.0)"]
[[package]] [[package]]
name = "pathspec" name = "pathspec"
version = "0.11.1" version = "0.11.2"
description = "Utility library for gitignore style pattern matching of file paths." description = "Utility library for gitignore style pattern matching of file paths."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"}, {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"},
{file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"}, {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"},
] ]
[[package]] [[package]]
@ -2488,28 +2488,28 @@ files = [
[[package]] [[package]]
name = "platformdirs" name = "platformdirs"
version = "3.9.1" version = "3.10.0"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "platformdirs-3.9.1-py3-none-any.whl", hash = "sha256:ad8291ae0ae5072f66c16945166cb11c63394c7a3ad1b1bc9828ca3162da8c2f"}, {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"},
{file = "platformdirs-3.9.1.tar.gz", hash = "sha256:1b42b450ad933e981d56e59f1b97495428c9bd60698baab9f3eb3d00d5822421"}, {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"},
] ]
[package.extras] [package.extras]
docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"]
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"]
[[package]] [[package]]
name = "pluggy" name = "pluggy"
version = "1.2.0" version = "1.3.0"
description = "plugin and hook calling mechanisms for python" description = "plugin and hook calling mechanisms for python"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8"
files = [ files = [
{file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"},
{file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"},
] ]
[package.extras] [package.extras]
@ -2645,13 +2645,13 @@ files = [
[[package]] [[package]]
name = "pygments" name = "pygments"
version = "2.15.1" version = "2.16.1"
description = "Pygments is a syntax highlighting package written in Python." description = "Pygments is a syntax highlighting package written in Python."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"}, {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"},
{file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"}, {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"},
] ]
[package.extras] [package.extras]
@ -2997,7 +2997,6 @@ files = [
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
{file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"},
{file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
{file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
{file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
@ -3005,15 +3004,8 @@ files = [
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
{file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"},
{file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
{file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"},
{file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
@ -3030,7 +3022,6 @@ files = [
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
{file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"},
{file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
{file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
{file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
@ -3038,7 +3029,6 @@ files = [
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
{file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"},
{file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
{file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
{file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
@ -3064,13 +3054,13 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"
[[package]] [[package]]
name = "referencing" name = "referencing"
version = "0.30.0" version = "0.30.2"
description = "JSON Referencing + Python" description = "JSON Referencing + Python"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "referencing-0.30.0-py3-none-any.whl", hash = "sha256:c257b08a399b6c2f5a3510a50d28ab5dbc7bbde049bcaf954d43c446f83ab548"}, {file = "referencing-0.30.2-py3-none-any.whl", hash = "sha256:449b6669b6121a9e96a7f9e410b245d471e8d48964c67113ce9afe50c8dd7bdf"},
{file = "referencing-0.30.0.tar.gz", hash = "sha256:47237742e990457f7512c7d27486394a9aadaf876cbfaa4be65b27b4f4d47c6b"}, {file = "referencing-0.30.2.tar.gz", hash = "sha256:794ad8003c65938edcdbc027f1933215e0d0ccc0291e3ce20a4d87432b59efc0"},
] ]
[package.dependencies] [package.dependencies]
@ -3152,119 +3142,119 @@ rsa = ["oauthlib[signedtoken] (>=3.0.0)"]
[[package]] [[package]]
name = "rpds-py" name = "rpds-py"
version = "0.9.2" version = "0.10.0"
description = "Python bindings to Rust's persistent data structures (rpds)" description = "Python bindings to Rust's persistent data structures (rpds)"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "rpds_py-0.9.2-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:ab6919a09c055c9b092798ce18c6c4adf49d24d4d9e43a92b257e3f2548231e7"}, {file = "rpds_py-0.10.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:c1e0e9916301e3b3d970814b1439ca59487f0616d30f36a44cead66ee1748c31"},
{file = "rpds_py-0.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d55777a80f78dd09410bd84ff8c95ee05519f41113b2df90a69622f5540c4f8b"}, {file = "rpds_py-0.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8ce8caa29ebbdcde67e5fd652c811d34bc01f249dbc0d61e5cc4db05ae79a83b"},
{file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a216b26e5af0a8e265d4efd65d3bcec5fba6b26909014effe20cd302fd1138fa"}, {file = "rpds_py-0.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad277f74b1c164f7248afa968700e410651eb858d7c160d109fb451dc45a2f09"},
{file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:29cd8bfb2d716366a035913ced99188a79b623a3512292963d84d3e06e63b496"}, {file = "rpds_py-0.10.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8e1c68303ccf7fceb50fbab79064a2636119fd9aca121f28453709283dbca727"},
{file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44659b1f326214950a8204a248ca6199535e73a694be8d3e0e869f820767f12f"}, {file = "rpds_py-0.10.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:780fcb855be29153901c67fc9c5633d48aebef21b90aa72812fa181d731c6b00"},
{file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:745f5a43fdd7d6d25a53ab1a99979e7f8ea419dfefebcab0a5a1e9095490ee5e"}, {file = "rpds_py-0.10.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bbd7b24d108509a1b9b6679fcc1166a7dd031dbef1f3c2c73788f42e3ebb3beb"},
{file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a987578ac5214f18b99d1f2a3851cba5b09f4a689818a106c23dbad0dfeb760f"}, {file = "rpds_py-0.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0700c2133ba203c4068aaecd6a59bda22e06a5e46255c9da23cbf68c6942215d"},
{file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf4151acb541b6e895354f6ff9ac06995ad9e4175cbc6d30aaed08856558201f"}, {file = "rpds_py-0.10.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:576da63eae7809f375932bfcbca2cf20620a1915bf2fedce4b9cc8491eceefe3"},
{file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:03421628f0dc10a4119d714a17f646e2837126a25ac7a256bdf7c3943400f67f"}, {file = "rpds_py-0.10.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23750a9b8a329844ba1fe267ca456bb3184984da2880ed17ae641c5af8de3fef"},
{file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:13b602dc3e8dff3063734f02dcf05111e887f301fdda74151a93dbbc249930fe"}, {file = "rpds_py-0.10.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d08395595c42bcd82c3608762ce734504c6d025eef1c06f42326a6023a584186"},
{file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fae5cb554b604b3f9e2c608241b5d8d303e410d7dfb6d397c335f983495ce7f6"}, {file = "rpds_py-0.10.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1d7b7b71bcb82d8713c7c2e9c5f061415598af5938666beded20d81fa23e7640"},
{file = "rpds_py-0.9.2-cp310-none-win32.whl", hash = "sha256:47c5f58a8e0c2c920cc7783113df2fc4ff12bf3a411d985012f145e9242a2764"}, {file = "rpds_py-0.10.0-cp310-none-win32.whl", hash = "sha256:97f5811df21703446b42303475b8b855ee07d6ab6cdf8565eff115540624f25d"},
{file = "rpds_py-0.9.2-cp310-none-win_amd64.whl", hash = "sha256:4ea6b73c22d8182dff91155af018b11aac9ff7eca085750455c5990cb1cfae6e"}, {file = "rpds_py-0.10.0-cp310-none-win_amd64.whl", hash = "sha256:cdbed8f21204398f47de39b0a9b180d7e571f02dfb18bf5f1b618e238454b685"},
{file = "rpds_py-0.9.2-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:e564d2238512c5ef5e9d79338ab77f1cbbda6c2d541ad41b2af445fb200385e3"}, {file = "rpds_py-0.10.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:7a3a3d3e4f1e3cd2a67b93a0b6ed0f2499e33f47cc568e3a0023e405abdc0ff1"},
{file = "rpds_py-0.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f411330a6376fb50e5b7a3e66894e4a39e60ca2e17dce258d53768fea06a37bd"}, {file = "rpds_py-0.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fc72ae476732cdb7b2c1acb5af23b478b8a0d4b6fcf19b90dd150291e0d5b26b"},
{file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e7521f5af0233e89939ad626b15278c71b69dc1dfccaa7b97bd4cdf96536bb7"}, {file = "rpds_py-0.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0583f69522732bdd79dca4cd3873e63a29acf4a299769c7541f2ca1e4dd4bc6"},
{file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8d3335c03100a073883857e91db9f2e0ef8a1cf42dc0369cbb9151c149dbbc1b"}, {file = "rpds_py-0.10.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f8b9a7cd381970e64849070aca7c32d53ab7d96c66db6c2ef7aa23c6e803f514"},
{file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d25b1c1096ef0447355f7293fbe9ad740f7c47ae032c2884113f8e87660d8f6e"}, {file = "rpds_py-0.10.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0d292cabd7c8335bdd3237ded442480a249dbcdb4ddfac5218799364a01a0f5c"},
{file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a5d3fbd02efd9cf6a8ffc2f17b53a33542f6b154e88dd7b42ef4a4c0700fdad"}, {file = "rpds_py-0.10.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6903cdca64f1e301af9be424798328c1fe3b4b14aede35f04510989fc72f012"},
{file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5934e2833afeaf36bd1eadb57256239785f5af0220ed8d21c2896ec4d3a765f"}, {file = "rpds_py-0.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bed57543c99249ab3a4586ddc8786529fbc33309e5e8a1351802a06ca2baf4c2"},
{file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:095b460e117685867d45548fbd8598a8d9999227e9061ee7f012d9d264e6048d"}, {file = "rpds_py-0.10.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:15932ec5f224b0e35764dc156514533a4fca52dcfda0dfbe462a1a22b37efd59"},
{file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:91378d9f4151adc223d584489591dbb79f78814c0734a7c3bfa9c9e09978121c"}, {file = "rpds_py-0.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eb2d59bc196e6d3b1827c7db06c1a898bfa0787c0574af398e65ccf2e97c0fbe"},
{file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:24a81c177379300220e907e9b864107614b144f6c2a15ed5c3450e19cf536fae"}, {file = "rpds_py-0.10.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f99d74ddf9d3b6126b509e81865f89bd1283e3fc1b568b68cd7bd9dfa15583d7"},
{file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:de0b6eceb46141984671802d412568d22c6bacc9b230174f9e55fc72ef4f57de"}, {file = "rpds_py-0.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f70bec8a14a692be6dbe7ce8aab303e88df891cbd4a39af091f90b6702e28055"},
{file = "rpds_py-0.9.2-cp311-none-win32.whl", hash = "sha256:700375326ed641f3d9d32060a91513ad668bcb7e2cffb18415c399acb25de2ab"}, {file = "rpds_py-0.10.0-cp311-none-win32.whl", hash = "sha256:5f7487be65b9c2c510819e744e375bd41b929a97e5915c4852a82fbb085df62c"},
{file = "rpds_py-0.9.2-cp311-none-win_amd64.whl", hash = "sha256:0766babfcf941db8607bdaf82569ec38107dbb03c7f0b72604a0b346b6eb3298"}, {file = "rpds_py-0.10.0-cp311-none-win_amd64.whl", hash = "sha256:748e472345c3a82cfb462d0dff998a7bf43e621eed73374cb19f307e97e08a83"},
{file = "rpds_py-0.9.2-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:b1440c291db3f98a914e1afd9d6541e8fc60b4c3aab1a9008d03da4651e67386"}, {file = "rpds_py-0.10.0-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:d4639111e73997567343df6551da9dd90d66aece1b9fc26c786d328439488103"},
{file = "rpds_py-0.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0f2996fbac8e0b77fd67102becb9229986396e051f33dbceada3debaacc7033f"}, {file = "rpds_py-0.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f4760e1b02173f4155203054f77a5dc0b4078de7645c922b208d28e7eb99f3e2"},
{file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f30d205755566a25f2ae0382944fcae2f350500ae4df4e795efa9e850821d82"}, {file = "rpds_py-0.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a6420a36975e0073acaeee44ead260c1f6ea56812cfc6c31ec00c1c48197173"},
{file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:159fba751a1e6b1c69244e23ba6c28f879a8758a3e992ed056d86d74a194a0f3"}, {file = "rpds_py-0.10.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:58fc4d66ee349a23dbf08c7e964120dc9027059566e29cf0ce6205d590ed7eca"},
{file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1f044792e1adcea82468a72310c66a7f08728d72a244730d14880cd1dabe36b"}, {file = "rpds_py-0.10.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:063411228b852fb2ed7485cf91f8e7d30893e69b0acb207ec349db04cccc8225"},
{file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9251eb8aa82e6cf88510530b29eef4fac825a2b709baf5b94a6094894f252387"}, {file = "rpds_py-0.10.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65af12f70355de29e1092f319f85a3467f4005e959ab65129cb697169ce94b86"},
{file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01899794b654e616c8625b194ddd1e5b51ef5b60ed61baa7a2d9c2ad7b2a4238"}, {file = "rpds_py-0.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:298e8b5d8087e0330aac211c85428c8761230ef46a1f2c516d6a2f67fb8803c5"},
{file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0c43f8ae8f6be1d605b0465671124aa8d6a0e40f1fb81dcea28b7e3d87ca1e1"}, {file = "rpds_py-0.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5b9bf77008f2c55dabbd099fd3ac87009471d223a1c7ebea36873d39511b780a"},
{file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:207f57c402d1f8712618f737356e4b6f35253b6d20a324d9a47cb9f38ee43a6b"}, {file = "rpds_py-0.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c7853f27195598e550fe089f78f0732c66ee1d1f0eaae8ad081589a5a2f5d4af"},
{file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b52e7c5ae35b00566d244ffefba0f46bb6bec749a50412acf42b1c3f402e2c90"}, {file = "rpds_py-0.10.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:75dbfd41a61bc1fb0536bf7b1abf272dc115c53d4d77db770cd65d46d4520882"},
{file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:978fa96dbb005d599ec4fd9ed301b1cc45f1a8f7982d4793faf20b404b56677d"}, {file = "rpds_py-0.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b25136212a3d064a8f0b9ebbb6c57094c5229e0de76d15c79b76feff26aeb7b8"},
{file = "rpds_py-0.9.2-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:6aa8326a4a608e1c28da191edd7c924dff445251b94653988efb059b16577a4d"}, {file = "rpds_py-0.10.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:9affee8cb1ec453382c27eb9043378ab32f49cd4bc24a24275f5c39bf186c279"},
{file = "rpds_py-0.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aad51239bee6bff6823bbbdc8ad85136c6125542bbc609e035ab98ca1e32a192"}, {file = "rpds_py-0.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4d55528ef13af4b4e074d067977b1f61408602f53ae4537dccf42ba665c2c7bd"},
{file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bd4dc3602370679c2dfb818d9c97b1137d4dd412230cfecd3c66a1bf388a196"}, {file = "rpds_py-0.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7865df1fb564092bcf46dac61b5def25342faf6352e4bc0e61a286e3fa26a3d"},
{file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd9da77c6ec1f258387957b754f0df60766ac23ed698b61941ba9acccd3284d1"}, {file = "rpds_py-0.10.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3f5cc8c7bc99d2bbcd704cef165ca7d155cd6464c86cbda8339026a42d219397"},
{file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:190ca6f55042ea4649ed19c9093a9be9d63cd8a97880106747d7147f88a49d18"}, {file = "rpds_py-0.10.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cbae50d352e4717ffc22c566afc2d0da744380e87ed44a144508e3fb9114a3f4"},
{file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:876bf9ed62323bc7dcfc261dbc5572c996ef26fe6406b0ff985cbcf460fc8a4c"}, {file = "rpds_py-0.10.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fccbf0cd3411719e4c9426755df90bf3449d9fc5a89f077f4a7f1abd4f70c910"},
{file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa2818759aba55df50592ecbc95ebcdc99917fa7b55cc6796235b04193eb3c55"}, {file = "rpds_py-0.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d10c431073dc6ebceed35ab22948a016cc2b5120963c13a41e38bdde4a7212"},
{file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9ea4d00850ef1e917815e59b078ecb338f6a8efda23369677c54a5825dbebb55"}, {file = "rpds_py-0.10.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1b401e8b9aece651512e62c431181e6e83048a651698a727ea0eb0699e9f9b74"},
{file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:5855c85eb8b8a968a74dc7fb014c9166a05e7e7a8377fb91d78512900aadd13d"}, {file = "rpds_py-0.10.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:7618a082c55cf038eede4a918c1001cc8a4411dfe508dc762659bcd48d8f4c6e"},
{file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:14c408e9d1a80dcb45c05a5149e5961aadb912fff42ca1dd9b68c0044904eb32"}, {file = "rpds_py-0.10.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:b3226b246facae14909b465061ddcfa2dfeadb6a64f407f24300d42d69bcb1a1"},
{file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:65a0583c43d9f22cb2130c7b110e695fff834fd5e832a776a107197e59a1898e"}, {file = "rpds_py-0.10.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a8edd467551c1102dc0f5754ab55cd0703431cd3044edf8c8e7d9208d63fa453"},
{file = "rpds_py-0.9.2-cp38-none-win32.whl", hash = "sha256:71f2f7715935a61fa3e4ae91d91b67e571aeb5cb5d10331ab681256bda2ad920"}, {file = "rpds_py-0.10.0-cp38-none-win32.whl", hash = "sha256:71333c22f7cf5f0480b59a0aef21f652cf9bbaa9679ad261b405b65a57511d1e"},
{file = "rpds_py-0.9.2-cp38-none-win_amd64.whl", hash = "sha256:674c704605092e3ebbbd13687b09c9f78c362a4bc710343efe37a91457123044"}, {file = "rpds_py-0.10.0-cp38-none-win_amd64.whl", hash = "sha256:a8ab1adf04ae2d6d65835995218fd3f3eb644fe20655ca8ee233e2c7270ff53b"},
{file = "rpds_py-0.9.2-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:07e2c54bef6838fa44c48dfbc8234e8e2466d851124b551fc4e07a1cfeb37260"}, {file = "rpds_py-0.10.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:87c93b25d538c433fb053da6228c6290117ba53ff6a537c133b0f2087948a582"},
{file = "rpds_py-0.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f7fdf55283ad38c33e35e2855565361f4bf0abd02470b8ab28d499c663bc5d7c"}, {file = "rpds_py-0.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7996aed3f65667c6dcc8302a69368435a87c2364079a066750a2eac75ea01e"},
{file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:890ba852c16ace6ed9f90e8670f2c1c178d96510a21b06d2fa12d8783a905193"}, {file = "rpds_py-0.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8856aa76839dc234d3469f1e270918ce6bec1d6a601eba928f45d68a15f04fc3"},
{file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:50025635ba8b629a86d9d5474e650da304cb46bbb4d18690532dd79341467846"}, {file = "rpds_py-0.10.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:00215f6a9058fbf84f9d47536902558eb61f180a6b2a0fa35338d06ceb9a2e5a"},
{file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:517cbf6e67ae3623c5127206489d69eb2bdb27239a3c3cc559350ef52a3bbf0b"}, {file = "rpds_py-0.10.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23a059143c1393015c68936370cce11690f7294731904bdae47cc3e16d0b2474"},
{file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0836d71ca19071090d524739420a61580f3f894618d10b666cf3d9a1688355b1"}, {file = "rpds_py-0.10.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e5c26905aa651cc8c0ddc45e0e5dea2a1296f70bdc96af17aee9d0493280a17"},
{file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c439fd54b2b9053717cca3de9583be6584b384d88d045f97d409f0ca867d80f"}, {file = "rpds_py-0.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c651847545422c8131660704c58606d841e228ed576c8f1666d98b3d318f89da"},
{file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f68996a3b3dc9335037f82754f9cdbe3a95db42bde571d8c3be26cc6245f2324"}, {file = "rpds_py-0.10.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:80992eb20755701753e30a6952a96aa58f353d12a65ad3c9d48a8da5ec4690cf"},
{file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7d68dc8acded354c972116f59b5eb2e5864432948e098c19fe6994926d8e15c3"}, {file = "rpds_py-0.10.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ffcf18ad3edf1c170e27e88b10282a2c449aa0358659592462448d71b2000cfc"},
{file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f963c6b1218b96db85fc37a9f0851eaf8b9040aa46dec112611697a7023da535"}, {file = "rpds_py-0.10.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:08e08ccf5b10badb7d0a5c84829b914c6e1e1f3a716fdb2bf294e2bd01562775"},
{file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a46859d7f947061b4010e554ccd1791467d1b1759f2dc2ec9055fa239f1bc26"}, {file = "rpds_py-0.10.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7150b83b3e3ddaac81a8bb6a9b5f93117674a0e7a2b5a5b32ab31fdfea6df27f"},
{file = "rpds_py-0.9.2-cp39-none-win32.whl", hash = "sha256:e07e5dbf8a83c66783a9fe2d4566968ea8c161199680e8ad38d53e075df5f0d0"}, {file = "rpds_py-0.10.0-cp39-none-win32.whl", hash = "sha256:3455ecc46ea443b5f7d9c2f946ce4017745e017b0d0f8b99c92564eff97e97f5"},
{file = "rpds_py-0.9.2-cp39-none-win_amd64.whl", hash = "sha256:682726178138ea45a0766907957b60f3a1bf3acdf212436be9733f28b6c5af3c"}, {file = "rpds_py-0.10.0-cp39-none-win_amd64.whl", hash = "sha256:afe6b5a04b2ab1aa89bad32ca47bf71358e7302a06fdfdad857389dca8fb5f04"},
{file = "rpds_py-0.9.2-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:196cb208825a8b9c8fc360dc0f87993b8b260038615230242bf18ec84447c08d"}, {file = "rpds_py-0.10.0-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:b1cb078f54af0abd835ca76f93a3152565b73be0f056264da45117d0adf5e99c"},
{file = "rpds_py-0.9.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c7671d45530fcb6d5e22fd40c97e1e1e01965fc298cbda523bb640f3d923b387"}, {file = "rpds_py-0.10.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8e7e2b3577e97fa43c2c2b12a16139b2cedbd0770235d5179c0412b4794efd9b"},
{file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83b32f0940adec65099f3b1c215ef7f1d025d13ff947975a055989cb7fd019a4"}, {file = "rpds_py-0.10.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae46a50d235f1631d9ec4670503f7b30405103034830bc13df29fd947207f795"},
{file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f67da97f5b9eac838b6980fc6da268622e91f8960e083a34533ca710bec8611"}, {file = "rpds_py-0.10.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f869e34d2326e417baee430ae998e91412cc8e7fdd83d979277a90a0e79a5b47"},
{file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03975db5f103997904c37e804e5f340c8fdabbb5883f26ee50a255d664eed58c"}, {file = "rpds_py-0.10.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d544a614055b131111bed6edfa1cb0fb082a7265761bcb03321f2dd7b5c6c48"},
{file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:987b06d1cdb28f88a42e4fb8a87f094e43f3c435ed8e486533aea0bf2e53d931"}, {file = "rpds_py-0.10.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ee9c2f6ca9774c2c24bbf7b23086264e6b5fa178201450535ec0859739e6f78d"},
{file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c861a7e4aef15ff91233751619ce3a3d2b9e5877e0fcd76f9ea4f6847183aa16"}, {file = "rpds_py-0.10.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2da4a8c6d465fde36cea7d54bf47b5cf089073452f0e47c8632ecb9dec23c07"},
{file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02938432352359805b6da099c9c95c8a0547fe4b274ce8f1a91677401bb9a45f"}, {file = "rpds_py-0.10.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac00c41dd315d147b129976204839ca9de699d83519ff1272afbe4fb9d362d12"},
{file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ef1f08f2a924837e112cba2953e15aacfccbbfcd773b4b9b4723f8f2ddded08e"}, {file = "rpds_py-0.10.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:0155c33af0676fc38e1107679be882077680ad1abb6303956b97259c3177e85e"},
{file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:35da5cc5cb37c04c4ee03128ad59b8c3941a1e5cd398d78c37f716f32a9b7f67"}, {file = "rpds_py-0.10.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:db6585b600b2e76e98131e0ac0e5195759082b51687ad0c94505970c90718f4a"},
{file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:141acb9d4ccc04e704e5992d35472f78c35af047fa0cfae2923835d153f091be"}, {file = "rpds_py-0.10.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:7b6975d3763d0952c111700c0634968419268e6bbc0b55fe71138987fa66f309"},
{file = "rpds_py-0.9.2-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:79f594919d2c1a0cc17d1988a6adaf9a2f000d2e1048f71f298b056b1018e872"}, {file = "rpds_py-0.10.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:6388e4e95a26717b94a05ced084e19da4d92aca883f392dffcf8e48c8e221a24"},
{file = "rpds_py-0.9.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:a06418fe1155e72e16dddc68bb3780ae44cebb2912fbd8bb6ff9161de56e1798"}, {file = "rpds_py-0.10.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:18f87baa20e02e9277ad8960cd89b63c79c05caf106f4c959a9595c43f2a34a5"},
{file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b2eb034c94b0b96d5eddb290b7b5198460e2d5d0c421751713953a9c4e47d10"}, {file = "rpds_py-0.10.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92f05fc7d832e970047662b3440b190d24ea04f8d3c760e33e7163b67308c878"},
{file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b08605d248b974eb02f40bdcd1a35d3924c83a2a5e8f5d0fa5af852c4d960af"}, {file = "rpds_py-0.10.0-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:291c9ce3929a75b45ce8ddde2aa7694fc8449f2bc8f5bd93adf021efaae2d10b"},
{file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0805911caedfe2736935250be5008b261f10a729a303f676d3d5fea6900c96a"}, {file = "rpds_py-0.10.0-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:861d25ae0985a1dd5297fee35f476b60c6029e2e6e19847d5b4d0a43a390b696"},
{file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab2299e3f92aa5417d5e16bb45bb4586171c1327568f638e8453c9f8d9e0f020"}, {file = "rpds_py-0.10.0-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:668d2b45d62c68c7a370ac3dce108ffda482b0a0f50abd8b4c604a813a59e08f"},
{file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c8d7594e38cf98d8a7df25b440f684b510cf4627fe038c297a87496d10a174f"}, {file = "rpds_py-0.10.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:344b89384c250ba6a4ce1786e04d01500e4dac0f4137ceebcaad12973c0ac0b3"},
{file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8b9ec12ad5f0a4625db34db7e0005be2632c1013b253a4a60e8302ad4d462afd"}, {file = "rpds_py-0.10.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:885e023e73ce09b11b89ab91fc60f35d80878d2c19d6213a32b42ff36543c291"},
{file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1fcdee18fea97238ed17ab6478c66b2095e4ae7177e35fb71fbe561a27adf620"}, {file = "rpds_py-0.10.0-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:841128a22e6ac04070a0f84776d07e9c38c4dcce8e28792a95e45fc621605517"},
{file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:933a7d5cd4b84f959aedeb84f2030f0a01d63ae6cf256629af3081cf3e3426e8"}, {file = "rpds_py-0.10.0-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:899b5e7e2d5a8bc92aa533c2d4e55e5ebba095c485568a5e4bedbc163421259a"},
{file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:686ba516e02db6d6f8c279d1641f7067ebb5dc58b1d0536c4aaebb7bf01cdc5d"}, {file = "rpds_py-0.10.0-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e7947d9a6264c727a556541b1630296bbd5d0a05068d21c38dde8e7a1c703ef0"},
{file = "rpds_py-0.9.2-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:0173c0444bec0a3d7d848eaeca2d8bd32a1b43f3d3fde6617aac3731fa4be05f"}, {file = "rpds_py-0.10.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:4992266817169997854f81df7f6db7bdcda1609972d8ffd6919252f09ec3c0f6"},
{file = "rpds_py-0.9.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d576c3ef8c7b2d560e301eb33891d1944d965a4d7a2eacb6332eee8a71827db6"}, {file = "rpds_py-0.10.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:26d9fd624649a10e4610fab2bc820e215a184d193e47d0be7fe53c1c8f67f370"},
{file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed89861ee8c8c47d6beb742a602f912b1bb64f598b1e2f3d758948721d44d468"}, {file = "rpds_py-0.10.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0028eb0967942d0d2891eae700ae1a27b7fd18604cfcb16a1ef486a790fee99e"},
{file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1054a08e818f8e18910f1bee731583fe8f899b0a0a5044c6e680ceea34f93876"}, {file = "rpds_py-0.10.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9e7e493ded7042712a374471203dd43ae3fff5b81e3de1a0513fa241af9fd41"},
{file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99e7c4bb27ff1aab90dcc3e9d37ee5af0231ed98d99cb6f5250de28889a3d502"}, {file = "rpds_py-0.10.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2d68a8e8a3a816629283faf82358d8c93fe5bd974dd2704152394a3de4cec22a"},
{file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c545d9d14d47be716495076b659db179206e3fd997769bc01e2d550eeb685596"}, {file = "rpds_py-0.10.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d6d5f061f6a2aa55790b9e64a23dfd87b6664ab56e24cd06c78eb43986cb260b"},
{file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9039a11bca3c41be5a58282ed81ae422fa680409022b996032a43badef2a3752"}, {file = "rpds_py-0.10.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c7c4266c1b61eb429e8aeb7d8ed6a3bfe6c890a1788b18dbec090c35c6b93fa"},
{file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fb39aca7a64ad0c9490adfa719dbeeb87d13be137ca189d2564e596f8ba32c07"}, {file = "rpds_py-0.10.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:80772e3bda6787510d9620bc0c7572be404a922f8ccdfd436bf6c3778119464c"},
{file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2d8b3b3a2ce0eaa00c5bbbb60b6713e94e7e0becab7b3db6c5c77f979e8ed1f1"}, {file = "rpds_py-0.10.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:b98e75b21fc2ba5285aef8efaf34131d16af1c38df36bdca2f50634bea2d3060"},
{file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:99b1c16f732b3a9971406fbfe18468592c5a3529585a45a35adbc1389a529a03"}, {file = "rpds_py-0.10.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:d63787f289944cc4bde518ad2b5e70a4f0d6e2ce76324635359c74c113fd188f"},
{file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:c27ee01a6c3223025f4badd533bea5e87c988cb0ba2811b690395dfe16088cfe"}, {file = "rpds_py-0.10.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:872f3dcaa8bf2245944861d7311179d2c0c9b2aaa7d3b464d99a7c2e401f01fa"},
{file = "rpds_py-0.9.2.tar.gz", hash = "sha256:8d70e8f14900f2657c249ea4def963bed86a29b81f81f5b76b5a9215680de945"}, {file = "rpds_py-0.10.0.tar.gz", hash = "sha256:e36d7369363d2707d5f68950a64c4e025991eb0177db01ccb6aa6facae48b69f"},
] ]
[[package]] [[package]]
name = "s3transfer" name = "s3transfer"
version = "0.6.1" version = "0.6.2"
description = "An Amazon S3 Transfer Manager" description = "An Amazon S3 Transfer Manager"
optional = false optional = false
python-versions = ">= 3.7" python-versions = ">= 3.7"
files = [ files = [
{file = "s3transfer-0.6.1-py3-none-any.whl", hash = "sha256:3c0da2d074bf35d6870ef157158641178a4204a6e689e82546083e31e0311346"}, {file = "s3transfer-0.6.2-py3-none-any.whl", hash = "sha256:b014be3a8a2aab98cfe1abc7229cc5a9a0cf05eb9c1f2b86b230fd8df3f78084"},
{file = "s3transfer-0.6.1.tar.gz", hash = "sha256:640bb492711f4c0c0905e1f62b6aaeb771881935ad27884852411f8e9cacbca9"}, {file = "s3transfer-0.6.2.tar.gz", hash = "sha256:cab66d3380cca3e70939ef2255d01cd8aece6a4907a9528740f668c4b0611861"},
] ]
[package.dependencies] [package.dependencies]
@ -3340,18 +3330,18 @@ tests = ["coverage[toml] (>=5.0.2)", "pytest"]
[[package]] [[package]]
name = "setuptools" name = "setuptools"
version = "68.0.0" version = "68.1.2"
description = "Easily download, build, install, upgrade, and uninstall Python packages" description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8"
files = [ files = [
{file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"}, {file = "setuptools-68.1.2-py3-none-any.whl", hash = "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b"},
{file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"}, {file = "setuptools-68.1.2.tar.gz", hash = "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d"},
] ]
[package.extras] [package.extras]
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5,<=7.1.2)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
[[package]] [[package]]
@ -3429,13 +3419,13 @@ files = [
[[package]] [[package]]
name = "tomlkit" name = "tomlkit"
version = "0.11.8" version = "0.12.1"
description = "Style preserving TOML library" description = "Style preserving TOML library"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "tomlkit-0.11.8-py3-none-any.whl", hash = "sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171"}, {file = "tomlkit-0.12.1-py3-none-any.whl", hash = "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"},
{file = "tomlkit-0.11.8.tar.gz", hash = "sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3"}, {file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"},
] ]
[[package]] [[package]]
@ -3455,68 +3445,70 @@ test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"]
[[package]] [[package]]
name = "twisted" name = "twisted"
version = "22.10.0" version = "23.8.0"
description = "An asynchronous networking framework written in Python" description = "An asynchronous networking framework written in Python"
optional = false optional = false
python-versions = ">=3.7.1" python-versions = ">=3.7.1"
files = [ files = [
{file = "Twisted-22.10.0-py3-none-any.whl", hash = "sha256:86c55f712cc5ab6f6d64e02503352464f0400f66d4f079096d744080afcccbd0"}, {file = "twisted-23.8.0-py3-none-any.whl", hash = "sha256:b8bdba145de120ffb36c20e6e071cce984e89fba798611ed0704216fb7f884cd"},
{file = "Twisted-22.10.0.tar.gz", hash = "sha256:32acbd40a94f5f46e7b42c109bfae2b302250945561783a8b7a059048f2d4d31"}, {file = "twisted-23.8.0.tar.gz", hash = "sha256:3c73360add17336a622c0d811c2a2ce29866b6e59b1125fd6509b17252098a24"},
] ]
[package.dependencies] [package.dependencies]
attrs = ">=19.2.0" attrs = ">=21.3.0"
Automat = ">=0.8.0" automat = ">=0.8.0"
constantly = ">=15.1" constantly = ">=15.1"
hyperlink = ">=17.1.1" hyperlink = ">=17.1.1"
idna = {version = ">=2.4", optional = true, markers = "extra == \"tls\""} idna = {version = ">=2.4", optional = true, markers = "extra == \"tls\""}
incremental = ">=21.3.0" incremental = ">=22.10.0"
pyopenssl = {version = ">=21.0.0", optional = true, markers = "extra == \"tls\""} pyopenssl = {version = ">=21.0.0", optional = true, markers = "extra == \"tls\""}
service-identity = {version = ">=18.1.0", optional = true, markers = "extra == \"tls\""} service-identity = {version = ">=18.1.0", optional = true, markers = "extra == \"tls\""}
twisted-iocpsupport = {version = ">=1.0.2,<2", markers = "platform_system == \"Windows\""} twisted-iocpsupport = {version = ">=1.0.2,<2", markers = "platform_system == \"Windows\""}
typing-extensions = ">=3.6.5" typing-extensions = ">=3.10.0"
"zope.interface" = ">=4.4.2" zope-interface = ">=5"
[package.extras] [package.extras]
all-non-platform = ["PyHamcrest (>=1.9.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "contextvars (>=2.4,<3)", "cryptography (>=2.6)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.0,<7.0)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "pyasn1", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "service-identity (>=18.1.0)"] all-non-platform = ["twisted[conch,contextvars,http2,serial,test,tls]", "twisted[conch,contextvars,http2,serial,test,tls]"]
conch = ["appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "cryptography (>=2.6)", "pyasn1"] conch = ["appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)"]
conch-nacl = ["PyNaCl", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "cryptography (>=2.6)", "pyasn1"]
contextvars = ["contextvars (>=2.4,<3)"] contextvars = ["contextvars (>=2.4,<3)"]
dev = ["coverage (>=6b1,<7)", "pydoctor (>=22.9.0,<22.10.0)", "pyflakes (>=2.2,<3.0)", "python-subunit (>=1.4,<2.0)", "readthedocs-sphinx-ext (>=2.1,<3.0)", "sphinx (>=5.0,<6)", "sphinx-rtd-theme (>=1.0,<2.0)", "towncrier (>=22.8,<23.0)", "twistedchecker (>=0.7,<1.0)"] dev = ["coverage (>=6b1,<7)", "pyflakes (>=2.2,<3.0)", "python-subunit (>=1.4,<2.0)", "twisted[dev-release]", "twistedchecker (>=0.7,<1.0)"]
dev-release = ["pydoctor (>=22.9.0,<22.10.0)", "readthedocs-sphinx-ext (>=2.1,<3.0)", "sphinx (>=5.0,<6)", "sphinx-rtd-theme (>=1.0,<2.0)", "towncrier (>=22.8,<23.0)"] dev-release = ["pydoctor (>=23.4.0,<23.5.0)", "pydoctor (>=23.4.0,<23.5.0)", "readthedocs-sphinx-ext (>=2.2,<3.0)", "readthedocs-sphinx-ext (>=2.2,<3.0)", "sphinx (>=5,<7)", "sphinx (>=5,<7)", "sphinx-rtd-theme (>=1.2,<2.0)", "sphinx-rtd-theme (>=1.2,<2.0)", "towncrier (>=22.12,<23.0)", "towncrier (>=22.12,<23.0)", "urllib3 (<2)", "urllib3 (<2)"]
gtk-platform = ["PyHamcrest (>=1.9.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "contextvars (>=2.4,<3)", "cryptography (>=2.6)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.0,<7.0)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "pyasn1", "pygobject", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "service-identity (>=18.1.0)"] gtk-platform = ["pygobject", "pygobject", "twisted[all-non-platform]", "twisted[all-non-platform]"]
http2 = ["h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)"] http2 = ["h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)"]
macos-platform = ["PyHamcrest (>=1.9.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "contextvars (>=2.4,<3)", "cryptography (>=2.6)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.0,<7.0)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "pyasn1", "pyobjc-core", "pyobjc-framework-CFNetwork", "pyobjc-framework-Cocoa", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "service-identity (>=18.1.0)"] macos-platform = ["pyobjc-core", "pyobjc-core", "pyobjc-framework-cfnetwork", "pyobjc-framework-cfnetwork", "pyobjc-framework-cocoa", "pyobjc-framework-cocoa", "twisted[all-non-platform]", "twisted[all-non-platform]"]
mypy = ["PyHamcrest (>=1.9.0)", "PyNaCl", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "contextvars (>=2.4,<3)", "coverage (>=6b1,<7)", "cryptography (>=2.6)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.0,<7.0)", "idna (>=2.4)", "mypy (==0.930)", "mypy-zope (==0.3.4)", "priority (>=1.1.0,<2.0)", "pyasn1", "pydoctor (>=22.9.0,<22.10.0)", "pyflakes (>=2.2,<3.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "python-subunit (>=1.4,<2.0)", "pywin32 (!=226)", "readthedocs-sphinx-ext (>=2.1,<3.0)", "service-identity (>=18.1.0)", "sphinx (>=5.0,<6)", "sphinx-rtd-theme (>=1.0,<2.0)", "towncrier (>=22.8,<23.0)", "twistedchecker (>=0.7,<1.0)", "types-pyOpenSSL", "types-setuptools"] mypy = ["mypy (==0.981)", "mypy-extensions (==0.4.3)", "mypy-zope (==0.3.11)", "twisted[all-non-platform,dev]", "types-pyopenssl", "types-setuptools"]
osx-platform = ["PyHamcrest (>=1.9.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "contextvars (>=2.4,<3)", "cryptography (>=2.6)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.0,<7.0)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "pyasn1", "pyobjc-core", "pyobjc-framework-CFNetwork", "pyobjc-framework-Cocoa", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "service-identity (>=18.1.0)"] osx-platform = ["twisted[macos-platform]", "twisted[macos-platform]"]
serial = ["pyserial (>=3.0)", "pywin32 (!=226)"] serial = ["pyserial (>=3.0)", "pywin32 (!=226)"]
test = ["PyHamcrest (>=1.9.0)", "cython-test-exception-raiser (>=1.0.2,<2)", "hypothesis (>=6.0,<7.0)"] test = ["cython-test-exception-raiser (>=1.0.2,<2)", "hypothesis (>=6.56)", "pyhamcrest (>=2)"]
tls = ["idna (>=2.4)", "pyopenssl (>=21.0.0)", "service-identity (>=18.1.0)"] tls = ["idna (>=2.4)", "pyopenssl (>=21.0.0)", "service-identity (>=18.1.0)"]
windows-platform = ["PyHamcrest (>=1.9.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "contextvars (>=2.4,<3)", "cryptography (>=2.6)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.0,<7.0)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "pyasn1", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)"] windows-platform = ["pywin32 (!=226)", "pywin32 (!=226)", "twisted[all-non-platform]", "twisted[all-non-platform]"]
[[package]] [[package]]
name = "twisted-iocpsupport" name = "twisted-iocpsupport"
version = "1.0.3" version = "1.0.4"
description = "An extension for use in the twisted I/O Completion Ports reactor." description = "An extension for use in the twisted I/O Completion Ports reactor."
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
{file = "twisted-iocpsupport-1.0.3.tar.gz", hash = "sha256:afb00801fdfbaccf0d0173a722626500023d4a19719ac9f129d1347a32e2fc66"}, {file = "twisted-iocpsupport-1.0.4.tar.gz", hash = "sha256:858096c0d15e33f15ac157f455d8f86f2f2cdd223963e58c0f682a3af8362d89"},
{file = "twisted_iocpsupport-1.0.3-cp310-cp310-win32.whl", hash = "sha256:a379ef56a576c8090889f74441bc3822ca31ac82253cc61e8d50631bcb0c26d0"}, {file = "twisted_iocpsupport-1.0.4-cp310-cp310-win32.whl", hash = "sha256:afa2b630797f9ed2f27f3d9f55e3f72b4244911e45a8c82756f44babbf0b243e"},
{file = "twisted_iocpsupport-1.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:1ea2c3fbdb739c95cc8b3355305cd593d2c9ec56d709207aa1a05d4d98671e85"}, {file = "twisted_iocpsupport-1.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:0058c963c8957bcd3deda62122e89953c9de1e867a274facc9b15dde1a9f31e8"},
{file = "twisted_iocpsupport-1.0.3-cp311-cp311-win32.whl", hash = "sha256:7efcdfafb377f32db90f42bd5fc5bb32cd1e3637ee936cdaf3aff4f4786ab3bf"}, {file = "twisted_iocpsupport-1.0.4-cp311-cp311-win32.whl", hash = "sha256:196f7c7ccad4ba4d1783b1c4e1d1b22d93c04275cd780bf7498d16c77319ad6e"},
{file = "twisted_iocpsupport-1.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1dbfac706972bf9ec5ce1ddbc735d2ebba406ad363345df8751ffd5252aa1618"}, {file = "twisted_iocpsupport-1.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:4e5f97bcbabdd79cbaa969b63439b89801ea560f11d42b0a387634275c633623"},
{file = "twisted_iocpsupport-1.0.3-cp36-cp36m-win32.whl", hash = "sha256:1ddfc5fa22ec6f913464b736b3f46e642237f17ac41be47eed6fa9bd52f5d0e0"}, {file = "twisted_iocpsupport-1.0.4-cp312-cp312-win32.whl", hash = "sha256:6081bd7c2f4fcf9b383dcdb3b3385d75a26a7c9d2be25b6950c3d8ea652d2d2d"},
{file = "twisted_iocpsupport-1.0.3-cp36-cp36m-win_amd64.whl", hash = "sha256:1bdccbb22199fc69fd7744d6d2dfd22d073c028c8611d994b41d2d2ad0e0f40d"}, {file = "twisted_iocpsupport-1.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:76f7e67cec1f1d097d1f4ed7de41be3d74546e1a4ede0c7d56e775c4dce5dfb0"},
{file = "twisted_iocpsupport-1.0.3-cp37-cp37m-win32.whl", hash = "sha256:db11c80054b52dbdea44d63d5474a44c9a6531882f0e2960268b15123088641a"}, {file = "twisted_iocpsupport-1.0.4-cp36-cp36m-win32.whl", hash = "sha256:3d306fc4d88a6bcf61ce9d572c738b918578121bfd72891625fab314549024b5"},
{file = "twisted_iocpsupport-1.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:67bec1716eb8f466ef366bbf262e1467ecc9e20940111207663ac24049785bad"}, {file = "twisted_iocpsupport-1.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:391ac4d6002a80e15f35adc4ad6056f4fe1c17ceb0d1f98ba01b0f4f917adfd7"},
{file = "twisted_iocpsupport-1.0.3-cp38-cp38-win32.whl", hash = "sha256:98a6f16ab215f8c1446e9fc60aaed0ab7c746d566aa2f3492a23cea334e6bebb"}, {file = "twisted_iocpsupport-1.0.4-cp37-cp37m-win32.whl", hash = "sha256:0c1b5cf37f0b2d96cc3c9bc86fff16613b9f5d0ca565c96cf1f1fb8cfca4b81c"},
{file = "twisted_iocpsupport-1.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:4f249d0baac836bb431d6fa0178be063a310136bc489465a831e3abd2d7acafd"}, {file = "twisted_iocpsupport-1.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:3c5dc11d72519e55f727320e3cee535feedfaee09c0f0765ed1ca7badff1ab3c"},
{file = "twisted_iocpsupport-1.0.3-cp39-cp39-win32.whl", hash = "sha256:aaca8f30c3b7c80d27a33fe9fe0d0bac42b1b012ddc60f677175c30e1becc1f3"}, {file = "twisted_iocpsupport-1.0.4-cp38-cp38-win32.whl", hash = "sha256:cc86c2ef598c15d824a243c2541c29459881c67fc3c0adb6efe2242f8f0ec3af"},
{file = "twisted_iocpsupport-1.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:dff43136c33665c2d117a73706aef6f7d6433e5c4560332a118fe066b16b8695"}, {file = "twisted_iocpsupport-1.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:c27985e949b9b1a1fb4c20c71d315c10ea0f93fdf3ccdd4a8c158b5926edd8c8"},
{file = "twisted_iocpsupport-1.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:8faceae553cfadc42ad791b1790e7cdecb7751102608c405217f6a26e877e0c5"}, {file = "twisted_iocpsupport-1.0.4-cp39-cp39-win32.whl", hash = "sha256:e311dfcb470696e3c077249615893cada598e62fa7c4e4ca090167bd2b7d331f"},
{file = "twisted_iocpsupport-1.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:6f8c433faaad5d53d30d1da6968d5a3730df415e2efb6864847267a9b51290cd"}, {file = "twisted_iocpsupport-1.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:4574eef1f3bb81501fb02f911298af3c02fe8179c31a33b361dd49180c3e644d"},
{file = "twisted_iocpsupport-1.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3f39c41c0213a81a9ce0961e30d0d7650f371ad80f8d261007d15a2deb6d5be3"}, {file = "twisted_iocpsupport-1.0.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:872747a3b64e2909aee59c803ccd0bceb9b75bf27915520ebd32d69687040fa2"},
{file = "twisted_iocpsupport-1.0.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:c2712b778bacf1db434e3e065adfed3db300754186a29aecac1efae9ef4bcaff"},
{file = "twisted_iocpsupport-1.0.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7c66fa0aa4236b27b3c61cb488662d85dae746a6d1c7b0d91cf7aae118445adf"},
{file = "twisted_iocpsupport-1.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:300437af17396a945a58dcfffd77863303a8b6d9e65c6e81f1d2eed55b50d444"},
] ]
[[package]] [[package]]
@ -3734,33 +3726,33 @@ watchmedo = ["PyYAML (>=3.10)"]
[[package]] [[package]]
name = "watchfiles" name = "watchfiles"
version = "0.19.0" version = "0.20.0"
description = "Simple, modern and high performance file watching and code reload in python." description = "Simple, modern and high performance file watching and code reload in python."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "watchfiles-0.19.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:91633e64712df3051ca454ca7d1b976baf842d7a3640b87622b323c55f3345e7"}, {file = "watchfiles-0.20.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:3796312bd3587e14926013612b23066912cf45a14af71cf2b20db1c12dadf4e9"},
{file = "watchfiles-0.19.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:b6577b8c6c8701ba8642ea9335a129836347894b666dd1ec2226830e263909d3"}, {file = "watchfiles-0.20.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:d0002d81c89a662b595645fb684a371b98ff90a9c7d8f8630c82f0fde8310458"},
{file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:18b28f6ad871b82df9542ff958d0c86bb0d8310bb09eb8e87d97318a3b5273af"}, {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:570848706440373b4cd8017f3e850ae17f76dbdf1e9045fc79023b11e1afe490"},
{file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fac19dc9cbc34052394dbe81e149411a62e71999c0a19e1e09ce537867f95ae0"}, {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a0351d20d03c6f7ad6b2e8a226a5efafb924c7755ee1e34f04c77c3682417fa"},
{file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:09ea3397aecbc81c19ed7f025e051a7387feefdb789cf768ff994c1228182fda"}, {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:007dcc4a401093010b389c044e81172c8a2520dba257c88f8828b3d460c6bb38"},
{file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0376deac92377817e4fb8f347bf559b7d44ff556d9bc6f6208dd3f79f104aaf"}, {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0d82dbc1832da83e441d112069833eedd4cf583d983fb8dd666fbefbea9d99c0"},
{file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c75eff897786ee262c9f17a48886f4e98e6cfd335e011c591c305e5d083c056"}, {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99f4c65fd2fce61a571b2a6fcf747d6868db0bef8a934e8ca235cc8533944d95"},
{file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb5d45c4143c1dd60f98a16187fd123eda7248f84ef22244818c18d531a249d1"}, {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5392dd327a05f538c56edb1c6ebba6af91afc81b40822452342f6da54907bbdf"},
{file = "watchfiles-0.19.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:79c533ff593db861ae23436541f481ec896ee3da4e5db8962429b441bbaae16e"}, {file = "watchfiles-0.20.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:08dc702529bb06a2b23859110c214db245455532da5eaea602921687cfcd23db"},
{file = "watchfiles-0.19.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3d7d267d27aceeeaa3de0dd161a0d64f0a282264d592e335fff7958cc0cbae7c"}, {file = "watchfiles-0.20.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:7d4e66a857621584869cfbad87039e65dadd7119f0d9bb9dbc957e089e32c164"},
{file = "watchfiles-0.19.0-cp37-abi3-win32.whl", hash = "sha256:176a9a7641ec2c97b24455135d58012a5be5c6217fc4d5fef0b2b9f75dbf5154"}, {file = "watchfiles-0.20.0-cp37-abi3-win32.whl", hash = "sha256:a03d1e6feb7966b417f43c3e3783188167fd69c2063e86bad31e62c4ea794cc5"},
{file = "watchfiles-0.19.0-cp37-abi3-win_amd64.whl", hash = "sha256:945be0baa3e2440151eb3718fd8846751e8b51d8de7b884c90b17d271d34cae8"}, {file = "watchfiles-0.20.0-cp37-abi3-win_amd64.whl", hash = "sha256:eccc8942bcdc7d638a01435d915b913255bbd66f018f1af051cd8afddb339ea3"},
{file = "watchfiles-0.19.0-cp37-abi3-win_arm64.whl", hash = "sha256:0089c6dc24d436b373c3c57657bf4f9a453b13767150d17284fc6162b2791911"}, {file = "watchfiles-0.20.0-cp37-abi3-win_arm64.whl", hash = "sha256:b17d4176c49d207865630da5b59a91779468dd3e08692fe943064da260de2c7c"},
{file = "watchfiles-0.19.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cae3dde0b4b2078f31527acff6f486e23abed307ba4d3932466ba7cdd5ecec79"}, {file = "watchfiles-0.20.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d97db179f7566dcf145c5179ddb2ae2a4450e3a634eb864b09ea04e68c252e8e"},
{file = "watchfiles-0.19.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f3920b1285a7d3ce898e303d84791b7bf40d57b7695ad549dc04e6a44c9f120"}, {file = "watchfiles-0.20.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:835df2da7a5df5464c4a23b2d963e1a9d35afa422c83bf4ff4380b3114603644"},
{file = "watchfiles-0.19.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9afd0d69429172c796164fd7fe8e821ade9be983f51c659a38da3faaaaac44dc"}, {file = "watchfiles-0.20.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:608cd94a8767f49521901aff9ae0c92cc8f5a24d528db7d6b0295290f9d41193"},
{file = "watchfiles-0.19.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68dce92b29575dda0f8d30c11742a8e2b9b8ec768ae414b54f7453f27bdf9545"}, {file = "watchfiles-0.20.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89d1de8218874925bce7bb2ae9657efc504411528930d7a83f98b1749864f2ef"},
{file = "watchfiles-0.19.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:5569fc7f967429d4bc87e355cdfdcee6aabe4b620801e2cf5805ea245c06097c"}, {file = "watchfiles-0.20.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:13f995d5152a8ba4ed7c2bbbaeee4e11a5944defc7cacd0ccb4dcbdcfd78029a"},
{file = "watchfiles-0.19.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5471582658ea56fca122c0f0d0116a36807c63fefd6fdc92c71ca9a4491b6b48"}, {file = "watchfiles-0.20.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:9b5c8d3be7b502f8c43a33c63166ada8828dbb0c6d49c8f9ce990a96de2f5a49"},
{file = "watchfiles-0.19.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b538014a87f94d92f98f34d3e6d2635478e6be6423a9ea53e4dd96210065e193"}, {file = "watchfiles-0.20.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e43af4464daa08723c04b43cf978ab86cc55c684c16172622bdac64b34e36af0"},
{file = "watchfiles-0.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20b44221764955b1e703f012c74015306fb7e79a00c15370785f309b1ed9aa8d"}, {file = "watchfiles-0.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87d9e1f75c4f86c93d73b5bd1ebe667558357548f11b4f8af4e0e272f79413ce"},
{file = "watchfiles-0.19.0.tar.gz", hash = "sha256:d9b073073e048081e502b6c6b0b88714c026a1a4c890569238d04aca5f9ca74b"}, {file = "watchfiles-0.20.0.tar.gz", hash = "sha256:728575b6b94c90dd531514677201e8851708e6e4b5fe7028ac506a200b622019"},
] ]
[package.dependencies] [package.dependencies]

Wyświetl plik

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "funkwhale-api" name = "funkwhale-api"
version = "1.3.1" version = "1.3.2"
description = "Funkwhale API" description = "Funkwhale API"
authors = ["Funkwhale Collective"] authors = ["Funkwhale Collective"]

Wyświetl plik

@ -669,7 +669,18 @@ def test_fetch_collection(mocker, r_mock):
def test_check_all_remote_instance_reachable(factories, r_mock): def test_check_all_remote_instance_reachable(factories, r_mock):
domain = factories["federation.Domain"]() domain = factories["federation.Domain"]()
r_mock.get( r_mock.get(
f"https://{domain.name}/api/v1/instance/nodeinfo/2.0/", json={"version": "2"} f"https://{domain.name}/api/v1/instance/nodeinfo/2.0", json={"version": "2"}
)
r_mock.get(
f"https://{domain.name}/.well-known/nodeinfo",
json={
"links": [
{
"rel": "http://nodeinfo.diaspora.software/ns/schema/2.0",
"href": f"https://{domain.name}/api/v1/instance/nodeinfo/2.0",
}
]
},
) )
tasks.check_all_remote_instance_availability() tasks.check_all_remote_instance_availability()
domain = models.Domain.objects.get(name=domain.name) domain = models.Domain.objects.get(name=domain.name)
@ -683,3 +694,10 @@ def test_check_remote_instance_unreachable(factories, r_mock):
tasks.check_all_remote_instance_availability() tasks.check_all_remote_instance_availability()
domain = models.Domain.objects.get(name=domain.name) domain = models.Domain.objects.get(name=domain.name)
assert domain.reachable is False assert domain.reachable is False
def test_check_all_remote_instance_skips_local(settings, factories, r_mock):
domain = factories["federation.Domain"]()
settings.FUNKWHALE_HOSTNAME = domain.name
tasks.check_all_remote_instance_availability()
assert not r_mock.called

1411
docs/poetry.lock wygenerowano

Plik diff jest za duży Load Diff

Wyświetl plik

@ -41,6 +41,7 @@ admin/commands.html, ../administrator/manage-script/index.html
admin/mrf.html, ../administrator/configuration/mrf.html admin/mrf.html, ../administrator/configuration/mrf.html
admin/url.html, ../administrator/configuration/change-url.html admin/url.html, ../administrator/configuration/change-url.html
admin/optimization.html, ../administrator/configuration/optimize.html admin/optimization.html, ../administrator/configuration/optimize.html
admin/upgrading.html, ../administrator/upgrade/index.html
architecture.html, ../developer/architecture.html architecture.html, ../developer/architecture.html
contributing.html, ../developer/index.html contributing.html, ../developer/index.html
api.html, ../developer/api/index.html api.html, ../developer/api/index.html
@ -53,3 +54,6 @@ translators.html, ../contributor/translation.html
federation.html, ../developer/federation/index.html federation.html, ../developer/federation/index.html
upgrading.html, ../administrator/upgrade/index.html upgrading.html, ../administrator/upgrade/index.html
administrator_documentation/upgrade_docs/docker.html, ../../administrator/upgrade/docker.html administrator_documentation/upgrade_docs/docker.html, ../../administrator/upgrade/docker.html
upgrading/0.17.html, ../user/libraries/index.html
admin/external-storages.html, ../../administrator/configuration/object-storage.html
admin/external-storage.html#no-resolver-found, ../../administrator/configuration/object-storage.html#troubleshooting

Wyświetl plik

@ -26,6 +26,9 @@ module.exports = {
// NOTE: Nicer for the eye // NOTE: Nicer for the eye
'operator-linebreak': ['error', 'before'], 'operator-linebreak': ['error', 'before'],
// NOTE: We have a logger instance
'no-console': 'error',
// NOTE: Handled by typescript // NOTE: Handled by typescript
'@typescript-eslint/no-unused-vars': 'off', '@typescript-eslint/no-unused-vars': 'off',
'no-use-before-define': 'off', 'no-use-before-define': 'off',

Wyświetl plik

@ -20,26 +20,25 @@
"@sentry/tracing": "7.47.0", "@sentry/tracing": "7.47.0",
"@sentry/vue": "7.47.0", "@sentry/vue": "7.47.0",
"@vue/runtime-core": "3.3.2", "@vue/runtime-core": "3.3.2",
"@vueuse/core": "9.12.0", "@vueuse/core": "10.3.0",
"@vueuse/integrations": "9.12.0", "@vueuse/integrations": "10.3.0",
"@vueuse/math": "9.12.0", "@vueuse/math": "10.3.0",
"@vueuse/router": "9.12.0", "@vueuse/router": "10.3.0",
"axios": "1.2.3", "axios": "1.2.3",
"axios-auth-refresh": "3.3.6", "axios-auth-refresh": "3.3.6",
"butterchurn": "3.0.0-beta.4", "butterchurn": "3.0.0-beta.4",
"butterchurn-presets": "3.0.0-beta.4", "butterchurn-presets": "3.0.0-beta.4",
"diff": "5.1.0", "diff": "5.1.0",
"dompurify": "2.4.5", "dompurify": "2.4.7",
"focus-trap": "7.2.0", "focus-trap": "7.2.0",
"fomantic-ui-css": "2.9.2", "fomantic-ui-css": "2.9.2",
"howler": "2.2.3", "howler": "2.2.3",
"idb-keyval": "6.2.1", "idb-keyval": "6.2.1",
"js-logger": "1.6.1",
"lodash-es": "4.17.21", "lodash-es": "4.17.21",
"lru-cache": "7.14.1", "lru-cache": "7.14.1",
"moment": "2.29.4", "moment": "2.29.4",
"showdown": "2.1.0", "showdown": "2.1.0",
"standardized-audio-context": "25.3.53", "standardized-audio-context": "25.3.55",
"text-clipper": "2.2.0", "text-clipper": "2.2.0",
"transliteration": "2.3.5", "transliteration": "2.3.5",
"universal-cookie": "4.0.4", "universal-cookie": "4.0.4",
@ -50,7 +49,7 @@
"vue-upload-component": "3.1.8", "vue-upload-component": "3.1.8",
"vue-virtual-scroller": "2.0.0-beta.8", "vue-virtual-scroller": "2.0.0-beta.8",
"vue3-gettext": "2.3.4", "vue3-gettext": "2.3.4",
"vue3-lazyload": "0.3.6", "vue3-lazyload": "0.3.8",
"vuedraggable": "4.1.0", "vuedraggable": "4.1.0",
"vuex": "4.1.0", "vuex": "4.1.0",
"vuex-persistedstate": "4.1.0", "vuex-persistedstate": "4.1.0",
@ -72,6 +71,7 @@
"@typescript-eslint/eslint-plugin": "5.48.2", "@typescript-eslint/eslint-plugin": "5.48.2",
"@vitejs/plugin-vue": "4.2.3", "@vitejs/plugin-vue": "4.2.3",
"@vitest/coverage-c8": "0.25.8", "@vitest/coverage-c8": "0.25.8",
"@vue-macros/volar": "0.13.3",
"@vue/compiler-sfc": "3.3.2", "@vue/compiler-sfc": "3.3.2",
"@vue/eslint-config-standard": "8.0.1", "@vue/eslint-config-standard": "8.0.1",
"@vue/eslint-config-typescript": "11.0.2", "@vue/eslint-config-typescript": "11.0.2",
@ -94,6 +94,7 @@
"sinon": "15.0.2", "sinon": "15.0.2",
"standardized-audio-context-mock": "9.6.18", "standardized-audio-context-mock": "9.6.18",
"typescript": "4.9.5", "typescript": "4.9.5",
"unplugin-vue-macros": "2.4.6",
"utility-types": "3.10.0", "utility-types": "3.10.0",
"vite": "4.3.5", "vite": "4.3.5",
"vite-plugin-pwa": "0.14.4", "vite-plugin-pwa": "0.14.4",

Wyświetl plik

@ -267,7 +267,11 @@ REPLACEMENTS = {
("background", "var(--site-background)"), ("background", "var(--site-background)"),
("color", "var(--text-color)"), ("color", "var(--text-color)"),
], ],
("::-webkit-selection", "::-moz-selection", "::selection"): [ (
"::-webkit-selection",
"::-moz-selection",
"::selection",
): [
("color", "var(--text-selection-color)"), ("color", "var(--text-selection-color)"),
("background-color", "var(--text-selection-background)"), ("background-color", "var(--text-selection-background)"),
], ],
@ -448,7 +452,10 @@ REPLACEMENTS = {
): [ ): [
("color", "var(--input-focus-placeholder-color)"), ("color", "var(--input-focus-placeholder-color)"),
], ],
(".ui.form .field > label", ".ui.form .inline.fields .field > label"): [ (
".ui.form .field > label",
".ui.form .inline.fields .field > label",
): [
("color", "var(--form-label-color)"), ("color", "var(--form-label-color)"),
], ],
}, },
@ -779,7 +786,10 @@ REPLACEMENTS = {
".structured", ".structured",
"tablet stackable", "tablet stackable",
], ],
(".ui.table", ".ui.table > thead > tr > th"): [ (
".ui.table",
".ui.table > thead > tr > th",
): [
("color", "var(--text-color)"), ("color", "var(--text-color)"),
("background", "var(--table-background)"), ("background", "var(--table-background)"),
], ],

Wyświetl plik

@ -4,6 +4,10 @@ import { createEventHook, refDefault, type EventHookOn, useEventListener } from
import { createAudioSource } from '~/composables/audio/audio-api' import { createAudioSource } from '~/composables/audio/audio-api'
import { effectScope, reactive, ref, type Ref } from 'vue' import { effectScope, reactive, ref, type Ref } from 'vue'
import useLogger from '~/composables/useLogger'
const logger = useLogger()
export interface SoundSource { export interface SoundSource {
uuid: string uuid: string
mimetype: string mimetype: string
@ -73,7 +77,7 @@ export class HTMLSound implements Sound {
this.#audio.src = source this.#audio.src = source
this.#audio.preload = 'auto' this.#audio.preload = 'auto'
console.log('CREATED SOUND INSTANCE', this) logger.log('CREATED SOUND INSTANCE', this)
this.#scope.run(() => { this.#scope.run(() => {
useEventListener(this.#audio, 'ended', () => this.#soundEndEventHook.trigger(this)) useEventListener(this.#audio, 'ended', () => this.#soundEndEventHook.trigger(this))
@ -84,19 +88,19 @@ export class HTMLSound implements Sound {
}) })
useEventListener(this.#audio, 'waiting', () => { useEventListener(this.#audio, 'waiting', () => {
console.log('>> AUDIO WAITING', this) logger.log('>> AUDIO WAITING', this)
}) })
useEventListener(this.#audio, 'playing', () => { useEventListener(this.#audio, 'playing', () => {
console.log('>> AUDIO PLAYING', this) logger.log('>> AUDIO PLAYING', this)
}) })
useEventListener(this.#audio, 'stalled', () => { useEventListener(this.#audio, 'stalled', () => {
console.log('>> AUDIO STALLED', this) logger.log('>> AUDIO STALLED', this)
}) })
useEventListener(this.#audio, 'suspend', () => { useEventListener(this.#audio, 'suspend', () => {
console.log('>> AUDIO SUSPEND', this) logger.log('>> AUDIO SUSPEND', this)
}) })
useEventListener(this.#audio, 'loadeddata', () => { useEventListener(this.#audio, 'loadeddata', () => {
@ -106,7 +110,7 @@ export class HTMLSound implements Sound {
useEventListener(this.#audio, 'error', (err) => { useEventListener(this.#audio, 'error', (err) => {
if (this.#ignoreError) return if (this.#ignoreError) return
console.error('>> AUDIO ERRORED', err, this) logger.error('>> AUDIO ERRORED', err, this)
this.isErrored.value = true this.isErrored.value = true
this.isLoaded.value = true this.isLoaded.value = true
}) })
@ -116,7 +120,7 @@ export class HTMLSound implements Sound {
async preload () { async preload () {
this.isDisposed.value = false this.isDisposed.value = false
this.isErrored.value = false this.isErrored.value = false
console.log('CALLING PRELOAD ON', this) logger.log('CALLING PRELOAD ON', this)
this.#audio.load() this.#audio.load()
} }
@ -141,7 +145,7 @@ export class HTMLSound implements Sound {
try { try {
await this.#audio.play() await this.#audio.play()
} catch (err) { } catch (err) {
console.error('>> AUDIO PLAY ERROR', err, this) logger.error('>> AUDIO PLAY ERROR', err, this)
this.isErrored.value = true this.isErrored.value = true
} }
} }

Wyświetl plik

@ -5,6 +5,7 @@ import ChannelsWidget from '~/components/audio/ChannelsWidget.vue'
import LoginForm from '~/components/auth/LoginForm.vue' import LoginForm from '~/components/auth/LoginForm.vue'
import SignupForm from '~/components/auth/SignupForm.vue' import SignupForm from '~/components/auth/SignupForm.vue'
import useMarkdown from '~/composables/useMarkdown' import useMarkdown from '~/composables/useMarkdown'
import useLogger from '~/composables/useLogger'
import { humanSize } from '~/utils/filters' import { humanSize } from '~/utils/filters'
import { useStore } from '~/store' import { useStore } from '~/store'
import { computed } from 'vue' import { computed } from 'vue'
@ -18,6 +19,7 @@ const labels = computed(() => ({
})) }))
const store = useStore() const store = useStore()
const logger = useLogger()
const nodeinfo = computed(() => store.state.instance.nodeinfo) const nodeinfo = computed(() => store.state.instance.nodeinfo)
const podName = computed(() => get(nodeinfo.value, 'metadata.nodeName') || 'Funkwhale') const podName = computed(() => get(nodeinfo.value, 'metadata.nodeName') || 'Funkwhale')
@ -54,7 +56,7 @@ const headerStyle = computed(() => {
// TODO (wvffle): Check if needed // TODO (wvffle): Check if needed
const router = useRouter() const router = useRouter()
whenever(() => store.state.auth.authenticated, () => { whenever(() => store.state.auth.authenticated, () => {
console.log('Authenticated, redirecting to /library…') logger.log('Authenticated, redirecting to /library…')
router.push('/library') router.push('/library')
}) })
</script> </script>

Wyświetl plik

@ -9,6 +9,7 @@ import { useStore } from '~/store'
import axios from 'axios' import axios from 'axios'
import updateQueryString from '~/composables/updateQueryString' import updateQueryString from '~/composables/updateQueryString'
import useLogger from '~/composables/useLogger'
type Type = 'rss' | 'artists' | 'both' type Type = 'rss' | 'artists' | 'both'
@ -37,6 +38,7 @@ const type = ref(props.initialType)
const id = ref(props.initialId) const id = ref(props.initialId)
const errors = ref([] as string[]) const errors = ref([] as string[])
const logger = useLogger()
const { t } = useI18n() const { t } = useI18n()
const labels = computed(() => ({ const labels = computed(() => ({
title: type.value === 'rss' title: type.value === 'rss'
@ -102,7 +104,7 @@ const submit = () => {
const isLoading = ref(false) const isLoading = ref(false)
const createFetch = async () => { const createFetch = async () => {
console.log(id.value, props.standalone) logger.debug(id.value, props.standalone)
if (!id.value) return if (!id.value) return
if (props.standalone) { if (props.standalone) {
history.replaceState(history.state, '', updateQueryString(location.href, 'id', id.value)) history.replaceState(history.state, '', updateQueryString(location.href, 'id', id.value))

Wyświetl plik

@ -18,15 +18,16 @@ const values = reactive({} as Record<string, unknown | Form | string>)
const result = ref<boolean | null>(null) const result = ref<boolean | null>(null)
const errors = ref([] as string[]) const errors = ref([] as string[])
const fileRefs = reactive({} as Record<string, HTMLInputElement>)
const setFileRef = (identifier: string) => (el: FunctionRef) => {
console.log(el)
fileRefs[identifier] = el as HTMLInputElement
}
const logger = useLogger() const logger = useLogger()
const store = useStore() const store = useStore()
// TODO (wvffle): Use VueUse
const fileRefs = reactive({} as Record<string, HTMLInputElement>)
const setFileRef = (identifier: string) => (el: FunctionRef) => {
logger.debug(el)
fileRefs[identifier] = el as HTMLInputElement
}
const settings = computed(() => { const settings = computed(() => {
const byIdentifier = props.settingsData.reduce((acc, entry) => { const byIdentifier = props.settingsData.reduce((acc, entry) => {
acc[entry.identifier] = entry acc[entry.identifier] = entry

Wyświetl plik

@ -71,6 +71,7 @@ watch(page, fetchData, { immediate: true })
<podcast-table <podcast-table
v-if="isPodcast" v-if="isPodcast"
v-model:page="page" v-model:page="page"
:paginate-by="limit"
:default-cover="defaultCover" :default-cover="defaultCover"
:is-podcast="isPodcast" :is-podcast="isPodcast"
:show-art="true" :show-art="true"
@ -80,7 +81,6 @@ watch(page, fetchData, { immediate: true })
:show-album="false" :show-album="false"
:paginate-results="true" :paginate-results="true"
:total="count" :total="count"
:paginate-by="limit"
/> />
<track-table <track-table
v-else v-else

Wyświetl plik

@ -13,6 +13,7 @@ import PlayButton from '~/components/audio/PlayButton.vue'
import useMarkdown from '~/composables/useMarkdown' import useMarkdown from '~/composables/useMarkdown'
import usePlayOptions from '~/composables/audio/usePlayOptions' import usePlayOptions from '~/composables/audio/usePlayOptions'
import useErrorHandler from '~/composables/useErrorHandler' import useErrorHandler from '~/composables/useErrorHandler'
import SanitizedHtml from '~/components/SanitizedHtml.vue'
interface Props extends PlayOptionsProps { interface Props extends PlayOptionsProps {
tracks: Track[] tracks: Track[]
@ -81,7 +82,7 @@ await fetchData()
@click.prevent.exact="activateTrack(track, index)" @click.prevent.exact="activateTrack(track, index)"
> >
<img <img
v-if="track.cover?.urls.original " v-if="track.cover?.urls.original"
v-lazy="$store.getters['instance/absoluteUrl'](track.cover.urls.medium_square_crop)" v-lazy="$store.getters['instance/absoluteUrl'](track.cover.urls.medium_square_crop)"
alt="" alt=""
class="ui artist-track mini image" class="ui artist-track mini image"
@ -111,7 +112,7 @@ await fetchData()
v-if="renderedDescription" v-if="renderedDescription"
class="podcast-episode-meta" class="podcast-episode-meta"
> >
{{ renderedDescription }} <SanitizedHtml :html="renderedDescription" />
</p> </p>
</div> </div>
<div <div

Wyświetl plik

@ -16,7 +16,6 @@ interface Props {
isPodcast?: boolean isPodcast?: boolean
paginateResults?: boolean paginateResults?: boolean
paginateBy?: number paginateBy?: number
page?: number
total?: number total?: number
} }
@ -30,9 +29,10 @@ withDefaults(defineProps<Props>(), {
isPodcast: true, isPodcast: true,
paginateResults: true, paginateResults: true,
paginateBy: 25, paginateBy: 25,
page: 1,
total: 0 total: 0
}) })
const { page } = defineModels<{ page: number, }>()
</script> </script>
<template> <template>
@ -44,9 +44,7 @@ withDefaults(defineProps<Props>(), {
<slot name="header" /> <slot name="header" />
<div> <div>
<div <div :class="['track-table', 'ui', 'unstackable', 'grid', 'tablet-and-up']">
:class="['track-table', 'ui', 'unstackable', 'grid', 'tablet-and-up']"
>
<!-- For each item, build a row --> <!-- For each item, build a row -->
<podcast-row <podcast-row
v-for="(track, index) in tracks" v-for="(track, index) in tracks"
@ -65,8 +63,8 @@ withDefaults(defineProps<Props>(), {
> >
<pagination <pagination
v-bind="$attrs" v-bind="$attrs"
v-model:current="page"
:total="total" :total="total"
:current="page"
:paginate-by="paginateBy" :paginate-by="paginateBy"
/> />
</div> </div>
@ -95,8 +93,8 @@ withDefaults(defineProps<Props>(), {
<pagination <pagination
v-if="paginateResults" v-if="paginateResults"
v-bind="$attrs" v-bind="$attrs"
v-model:current="page"
:total="total" :total="total"
:current="page"
:compact="true" :compact="true"
/> />
</div> </div>

Wyświetl plik

@ -9,6 +9,8 @@ import { useStore } from '~/store'
import ApplicationForm from '~/components/auth/ApplicationForm.vue' import ApplicationForm from '~/components/auth/ApplicationForm.vue'
import useLogger from '~/composables/useLogger'
interface Props { interface Props {
name?: string name?: string
scopes?: string scopes?: string
@ -27,6 +29,7 @@ const defaults = reactive({
redirectUris: props.redirectUris redirectUris: props.redirectUris
}) })
const logger = useLogger()
const { t } = useI18n() const { t } = useI18n()
const labels = computed(() => ({ const labels = computed(() => ({
title: t('components.auth.ApplicationNew.title') title: t('components.auth.ApplicationNew.title')
@ -37,7 +40,7 @@ const store = useStore()
const created = (application: Application) => { const created = (application: Application) => {
store.state.auth.applicationSecret = application.client_secret store.state.auth.applicationSecret = application.client_secret
console.log(application) logger.debug(application)
return router.push({ return router.push({
name: 'settings.applications.edit', name: 'settings.applications.edit',
params: { params: {

Wyświetl plik

@ -42,7 +42,7 @@ const labels = computed(() => ({
const signupRequiresApproval = computed(() => props.signupApprovalEnabled ?? store.state.instance.settings.moderation.signup_approval_enabled.value) const signupRequiresApproval = computed(() => props.signupApprovalEnabled ?? store.state.instance.settings.moderation.signup_approval_enabled.value)
const formCustomization = computed(() => props.customization ?? store.state.instance.settings.moderation.signup_form_customization.value) const formCustomization = computed(() => props.customization ?? store.state.instance.settings.moderation.signup_form_customization.value)
watchEffect(() => console.log(store.state.instance.settings.moderation.signup_approval_enabled.value)) watchEffect(() => logger.debug(store.state.instance.settings.moderation.signup_approval_enabled.value))
const payload = reactive({ const payload = reactive({
username: '', username: '',

Wyświetl plik

@ -4,6 +4,8 @@ import { useVModel, watchDebounced, useTextareaAutosize, syncRef } from '@vueuse
import { ref, computed, watchEffect, onMounted, nextTick, watch } from 'vue' import { ref, computed, watchEffect, onMounted, nextTick, watch } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import useLogger from '~/composables/useLogger'
interface Events { interface Events {
(e: 'update:modelValue', value: string): void (e: 'update:modelValue', value: string): void
} }
@ -26,6 +28,8 @@ const props = withDefaults(defineProps<Props>(), {
required: false required: false
}) })
const logger = useLogger()
const { t } = useI18n() const { t } = useI18n()
const { textarea, input } = useTextareaAutosize() const { textarea, input } = useTextareaAutosize()
const value = useVModel(props, 'modelValue', emit) const value = useVModel(props, 'modelValue', emit)
@ -47,7 +51,7 @@ const loadPreview = async () => {
const response = await axios.post('text-preview/', { text: value.value, permissive: props.permissive }) const response = await axios.post('text-preview/', { text: value.value, permissive: props.permissive })
preview.value = response.data.rendered preview.value = response.data.rendered
} catch (error) { } catch (error) {
console.error(error) logger.error(error)
} }
isLoadingPreview.value = false isLoadingPreview.value = false
} }

Wyświetl plik

@ -64,8 +64,8 @@ const fetchFavorites = async () => {
ordering: orderingString.value ordering: orderingString.value
} }
const measureLoading = logger.time('Loading user favorites')
try { try {
logger.time('Loading user favorites')
const response = await axios.get('tracks/', { params }) const response = await axios.get('tracks/', { params })
results.length = 0 results.length = 0
@ -81,7 +81,7 @@ const fetchFavorites = async () => {
} catch (error) { } catch (error) {
useErrorHandler(error as Error) useErrorHandler(error as Error)
} finally { } finally {
logger.timeEnd('Loading user favorites') measureLoading()
isLoading.value = false isLoading.value = false
} }
} }

Wyświetl plik

@ -15,6 +15,7 @@ import TagsList from '~/components/tags/List.vue'
import AlbumDropdown from './AlbumDropdown.vue' import AlbumDropdown from './AlbumDropdown.vue'
import useErrorHandler from '~/composables/useErrorHandler' import useErrorHandler from '~/composables/useErrorHandler'
import useLogger from '~/composables/useLogger'
interface Events { interface Events {
(e: 'deleted'): void (e: 'deleted'): void
@ -39,6 +40,8 @@ const isSerie = computed(() => object.value?.artist.content_category === 'podcas
const totalDuration = computed(() => sum((object.value?.tracks ?? []).map(track => track.uploads[0]?.duration ?? 0))) const totalDuration = computed(() => sum((object.value?.tracks ?? []).map(track => track.uploads[0]?.duration ?? 0)))
const publicLibraries = computed(() => libraries.value?.filter(library => library.privacy_level === 'everyone') ?? []) const publicLibraries = computed(() => libraries.value?.filter(library => library.privacy_level === 'everyone') ?? [])
const logger = useLogger()
const { t } = useI18n() const { t } = useI18n()
const labels = computed(() => ({ const labels = computed(() => ({
title: t('components.library.AlbumBase.title') title: t('components.library.AlbumBase.title')
@ -93,7 +96,7 @@ const fetchTracks = async () => {
tracks.push(...response.data.results) tracks.push(...response.data.results)
} }
} catch (error) { } catch (error) {
console.error(error) logger.error(error)
} finally { } finally {
isLoadingTracks.value = false isLoadingTracks.value = false
} }

Wyświetl plik

@ -72,7 +72,7 @@ const fetchData = async () => {
content_category: 'music' content_category: 'music'
} }
logger.time('Fetching albums') const measureLoading = logger.time('Fetching albums')
try { try {
const response = await axios.get('albums/', { const response = await axios.get('albums/', {
params, params,
@ -86,7 +86,7 @@ const fetchData = async () => {
useErrorHandler(error as Error) useErrorHandler(error as Error)
result.value = undefined result.value = undefined
} finally { } finally {
logger.timeEnd('Fetching albums') measureLoading()
isLoading.value = false isLoading.value = false
} }
} }

Wyświetl plik

@ -73,7 +73,7 @@ const fetchData = async () => {
has_albums: excludeCompilation.value has_albums: excludeCompilation.value
} }
logger.time('Fetching artists') const measureLoading = logger.time('Fetching artists')
try { try {
const response = await axios.get('artists/', { const response = await axios.get('artists/', {
params, params,
@ -87,7 +87,7 @@ const fetchData = async () => {
useErrorHandler(error as Error) useErrorHandler(error as Error)
result.value = undefined result.value = undefined
} finally { } finally {
logger.timeEnd('Fetching artists') measureLoading()
isLoading.value = false isLoading.value = false
} }
} }

Wyświetl plik

@ -32,7 +32,7 @@ const labels = computed(() => ({
const isLoading = ref(false) const isLoading = ref(false)
const fetchData = async () => { const fetchData = async () => {
isLoading.value = true isLoading.value = true
logger.time('Loading latest artists') const measureLoading = logger.time('Loading latest artists')
const params = { const params = {
ordering: '-creation_date', ordering: '-creation_date',
@ -47,7 +47,7 @@ const fetchData = async () => {
} }
isLoading.value = false isLoading.value = false
logger.timeEnd('Loading latest artists') measureLoading()
} }
fetchData() fetchData()

Wyświetl plik

@ -74,7 +74,7 @@ const fetchData = async () => {
content_category: 'podcast' content_category: 'podcast'
} }
logger.time('Fetching podcasts') const measureLoading = logger.time('Fetching podcasts')
try { try {
const response = await axios.get('artists/', { const response = await axios.get('artists/', {
params, params,
@ -88,7 +88,7 @@ const fetchData = async () => {
useErrorHandler(error as Error) useErrorHandler(error as Error)
result.value = undefined result.value = undefined
} finally { } finally {
logger.timeEnd('Fetching podcasts') measureLoading()
isLoading.value = false isLoading.value = false
} }
} }

Wyświetl plik

@ -64,7 +64,7 @@ const fetchData = async () => {
ordering: orderingString.value ordering: orderingString.value
} }
logger.time('Fetching radios') const measureLoading = logger.time('Fetching radios')
try { try {
const response = await axios.get('radios/radios/', { const response = await axios.get('radios/radios/', {
params params
@ -75,7 +75,7 @@ const fetchData = async () => {
useErrorHandler(error as Error) useErrorHandler(error as Error)
result.value = undefined result.value = undefined
} finally { } finally {
logger.timeEnd('Fetching radios') measureLoading()
isLoading.value = false isLoading.value = false
} }
} }

Wyświetl plik

@ -15,6 +15,7 @@ import NoteForm from '~/components/manage/moderation/NoteForm.vue'
import useReportConfigs from '~/composables/moderation/useReportConfigs' import useReportConfigs from '~/composables/moderation/useReportConfigs'
import useErrorHandler from '~/composables/useErrorHandler' import useErrorHandler from '~/composables/useErrorHandler'
import useMarkdown from '~/composables/useMarkdown' import useMarkdown from '~/composables/useMarkdown'
import useLogger from '~/composables/useLogger'
interface Events { interface Events {
(e: 'updated', updating: { type: string }): void (e: 'updated', updating: { type: string }): void
@ -29,6 +30,7 @@ const emit = defineEmits<Events>()
const props = defineProps<Props>() const props = defineProps<Props>()
const configs = useReportConfigs() const configs = useReportConfigs()
const logger = useLogger()
const obj = ref(props.initObj) const obj = ref(props.initObj)
const summary = useMarkdown(() => obj.value.summary ?? '') const summary = useMarkdown(() => obj.value.summary ?? '')
@ -77,11 +79,11 @@ const actions = computed(() => {
handler: async () => { handler: async () => {
try { try {
await axios.delete(deleteUrl) await axios.delete(deleteUrl)
console.log('Target deleted') logger.info('Target deleted')
obj.value.target = undefined obj.value.target = undefined
resolveReport(true) resolveReport(true)
} catch (error) { } catch (error) {
console.log('Error while deleting target', error) logger.error('Error while deleting target', error)
useErrorHandler(error as Error) useErrorHandler(error as Error)
} }
} }

Wyświetl plik

@ -9,6 +9,8 @@ import { useStore } from '~/store'
import axios from 'axios' import axios from 'axios'
import { useClamp } from '@vueuse/math' import { useClamp } from '@vueuse/math'
import useLogger from '~/composables/useLogger'
// Looping // Looping
export enum LoopingMode { export enum LoopingMode {
None, None,
@ -17,7 +19,6 @@ export enum LoopingMode {
} }
// Pausing // Pausing
export enum PauseReason { export enum PauseReason {
UserInput, UserInput,
EndOfQueue, EndOfQueue,
@ -26,6 +27,8 @@ export enum PauseReason {
EndOfRadio EndOfRadio
} }
const logger = useLogger()
const MODE_MAX = 1 + Math.max(...Object.values(LoopingMode).filter(mode => typeof mode === 'number') as number[]) const MODE_MAX = 1 + Math.max(...Object.values(LoopingMode).filter(mode => typeof mode === 'number') as number[])
export const looping: Ref<number> = useStorage('player:looping', LoopingMode.None) export const looping: Ref<number> = useStorage('player:looping', LoopingMode.None)
@ -131,12 +134,12 @@ export const usePlayer = createGlobalState(() => {
const trackListenSubmissions = () => { const trackListenSubmissions = () => {
const store = useStore() const store = useStore()
whenever(listenSubmitted, async () => { whenever(listenSubmitted, async () => {
console.log('Listening submitted!') logger.log('Listening submitted!')
if (!store.state.auth.authenticated) return if (!store.state.auth.authenticated) return
if (!currentTrack.value) return if (!currentTrack.value) return
await axios.post('history/listenings/', { track: currentTrack.value.id }) await axios.post('history/listenings/', { track: currentTrack.value.id })
.catch((error) => console.error('Could not record track in history', error)) .catch((error) => logger.error('Could not record track in history', error))
}) })
} }

Wyświetl plik

@ -11,6 +11,8 @@ import { delMany, getMany, setMany } from '~/composables/data/indexedDB'
import { setGain } from '~/composables/audio/audio-api' import { setGain } from '~/composables/audio/audio-api'
import { useTracks } from '~/composables/audio/tracks' import { useTracks } from '~/composables/audio/tracks'
import useLogger from '~/composables/useLogger'
import axios from 'axios' import axios from 'axios'
export interface QueueTrackSource { export interface QueueTrackSource {
@ -36,6 +38,8 @@ export interface QueueTrack {
sources: QueueTrackSource[] sources: QueueTrackSource[]
} }
const logger = useLogger()
// Queue // Queue
const tracks = useStorage('queue:tracks', [] as number[]) const tracks = useStorage('queue:tracks', [] as number[])
const shuffledIds = useStorage('queue:tracks:shuffled', [] as number[]) const shuffledIds = useStorage('queue:tracks:shuffled', [] as number[])
@ -69,7 +73,7 @@ watchEffect(async () => {
tracksById.set(track.id, track) tracksById.set(track.id, track)
} }
} catch (error) { } catch (error) {
console.error(error) logger.error(error)
} finally { } finally {
fetchingTracks.value = false fetchingTracks.value = false
} }
@ -329,6 +333,10 @@ export const useQueue = createGlobalState(() => {
clearRadio.value = true clearRadio.value = true
const lastTracks = [...tracks.value] const lastTracks = [...tracks.value]
// Clear shuffled tracks
shuffledIds.value.length = 0
tracks.value.length = 0 tracks.value.length = 0
await delMany(lastTracks) await delMany(lastTracks)
@ -340,7 +348,7 @@ export const useQueue = createGlobalState(() => {
const store = useStore() const store = useStore()
watchEffect(() => { watchEffect(() => {
if (store.state.radios.running && currentIndex.value === tracks.value.length - 1) { if (store.state.radios.running && currentIndex.value === tracks.value.length - 1) {
console.log('POPULATING QUEUE FROM RADIO') logger.log('POPULATING QUEUE FROM RADIO')
return store.dispatch('radios/populateQueue') return store.dispatch('radios/populateQueue')
} }
}) })
@ -375,7 +383,7 @@ export const useQueue = createGlobalState(() => {
currentIndex.value = index currentIndex.value = index
delete localStorage.queue delete localStorage.queue
})().catch((error) => console.error('Could not successfully migrate between queue versions', error)) })().catch((error) => logger.error('Could not successfully migrate between queue versions', error))
} }
if (localStorage.player) { if (localStorage.player) {
@ -385,7 +393,7 @@ export const useQueue = createGlobalState(() => {
setGain(volume ?? 0.7) setGain(volume ?? 0.7)
delete localStorage.player delete localStorage.player
} catch (error) { } catch (error) {
console.error('Could not successfully migrate between player versions', error) logger.error('Could not successfully migrate between player versions', error)
} }
} }
} }

Wyświetl plik

@ -11,6 +11,7 @@ import { useQueue } from '~/composables/audio/queue'
import { soundImplementation } from '~/api/player' import { soundImplementation } from '~/api/player'
import useLRUCache from '~/composables/data/useLRUCache' import useLRUCache from '~/composables/data/useLRUCache'
import useLogger from '~/composables/useLogger'
import store from '~/store' import store from '~/store'
import axios from 'axios' import axios from 'axios'
@ -18,6 +19,8 @@ import axios from 'axios'
const ALLOWED_PLAY_TYPES: (CanPlayTypeResult | undefined)[] = ['maybe', 'probably'] const ALLOWED_PLAY_TYPES: (CanPlayTypeResult | undefined)[] = ['maybe', 'probably']
const AUDIO_ELEMENT = document.createElement('audio') const AUDIO_ELEMENT = document.createElement('audio')
const logger = useLogger()
const soundPromises = new Map<number, Promise<Sound>>() const soundPromises = new Map<number, Promise<Sound>>()
const soundCache = useLRUCache<number, Sound>({ const soundCache = useLRUCache<number, Sound>({
max: 3, max: 3,
@ -95,7 +98,7 @@ export const useTracks = createGlobalState(() => {
const sound = new SoundImplementation(sources) const sound = new SoundImplementation(sources)
sound.onSoundEnd(() => { sound.onSoundEnd(() => {
console.log('TRACK ENDED, PLAYING NEXT') logger.log('TRACK ENDED, PLAYING NEXT')
// NOTE: We push it to the end of the job queue // NOTE: We push it to the end of the job queue
setTimeout(() => playNext(), 0) setTimeout(() => playNext(), 0)
@ -140,7 +143,7 @@ export const useTracks = createGlobalState(() => {
return sound return sound
} }
console.log('NO TRACK IN CACHE, CREATING', track) logger.log('NO TRACK IN CACHE, CREATING', track)
const soundPromise = createSoundPromise() const soundPromise = createSoundPromise()
soundPromises.set(track.id, soundPromise) soundPromises.set(track.id, soundPromise)
return soundPromise return soundPromise
@ -171,7 +174,7 @@ export const useTracks = createGlobalState(() => {
const { queue, currentIndex } = useQueue() const { queue, currentIndex } = useQueue()
if (queue.value.length <= index || index === -1) return if (queue.value.length <= index || index === -1) return
console.log('LOADING TRACK', index) logger.log('LOADING TRACK', index)
const track = queue.value[index] const track = queue.value[index]
const sound = await createSound(track) const sound = await createSound(track)
@ -181,7 +184,7 @@ export const useTracks = createGlobalState(() => {
return return
} }
console.log('CONNECTING NODE', sound) logger.log('CONNECTING NODE', sound)
sound.audioNode.disconnect() sound.audioNode.disconnect()
connectAudioSource(sound.audioNode) connectAudioSource(sound.audioNode)

Wyświetl plik

@ -4,6 +4,8 @@ import { AUDIO_CONTEXT, GAIN_NODE } from './audio-api'
import { useResizeObserver, useStorage } from '@vueuse/core' import { useResizeObserver, useStorage } from '@vueuse/core'
import { watchEffect, ref, markRaw } from 'vue' import { watchEffect, ref, markRaw } from 'vue'
import useLogger from '~/composables/useLogger'
// @ts-expect-error butterchurn has no typings // @ts-expect-error butterchurn has no typings
import butterchurnPresets from 'butterchurn-presets' import butterchurnPresets from 'butterchurn-presets'
@ -11,6 +13,8 @@ import butterchurnPresets from 'butterchurn-presets'
import butterchurn from 'butterchurn' import butterchurn from 'butterchurn'
export const useMilkDrop = (canvas: Ref<HTMLCanvasElement>) => { export const useMilkDrop = (canvas: Ref<HTMLCanvasElement>) => {
const logger = useLogger()
const presets = Object.keys(butterchurnPresets) const presets = Object.keys(butterchurnPresets)
const visualizer = ref() const visualizer = ref()
@ -24,7 +28,7 @@ export const useMilkDrop = (canvas: Ref<HTMLCanvasElement>) => {
const name = presetName.value const name = presetName.value
if (name === undefined) return if (name === undefined) return
console.log(`Switching to preset: '${name}'`) logger.log(`Switching to preset: '${name}'`)
visualizer.value?.loadPreset(butterchurnPresets[name], 1) visualizer.value?.loadPreset(butterchurnPresets[name], 1)
}) })
@ -67,7 +71,7 @@ export const useMilkDrop = (canvas: Ref<HTMLCanvasElement>) => {
try { try {
visualizer.value?.render() visualizer.value?.render()
} catch (error) { } catch (error) {
console.error(error) logger.error(error)
loadRandomPreset() loadRandomPreset()
} }
} }

Wyświetl plik

@ -3,71 +3,73 @@ import type { RouteRecordName } from 'vue-router'
import { toRefs, useStorage, syncRef } from '@vueuse/core' import { toRefs, useStorage, syncRef } from '@vueuse/core'
import { useRouteQuery } from '@vueuse/router' import { useRouteQuery } from '@vueuse/router'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { ref, watch } from 'vue' import { watch, readonly } from 'vue'
export interface OrderingProps { export interface OrderingProps {
orderingConfigName?: RouteRecordName orderingConfigName?: RouteRecordName
} }
export default (props: OrderingProps) => { export default <T extends string = string>(props: OrderingProps) => {
const route = useRoute() const route = useRoute()
const preferences = useStorage(`route-preferences:${props.orderingConfigName?.toString() ?? route.name?.toString() ?? '*'}`, { interface Preferences {
orderingDirection: '-' | '+'
ordering: T
paginateBy: number
}
const preferences = useStorage<Preferences>(`route-preferences:${props.orderingConfigName?.toString() ?? route.name?.toString() ?? '*'}`, () => ({
orderingDirection: route.meta.orderingDirection ?? '-', orderingDirection: route.meta.orderingDirection ?? '-',
ordering: route.meta.ordering ?? 'creation_date', ordering: route.meta.ordering ?? 'creation_date',
paginateBy: route.meta.paginateBy ?? 50 paginateBy: route.meta.paginateBy ?? 50
}) }))
const { const {
orderingDirection: perfOrderingDirection, orderingDirection: prefOrderingDirection,
paginateBy: perfPaginateBy, paginateBy: prefPaginateBy,
ordering: perfOrdering ordering: prefOrdering
} = toRefs(preferences) } = toRefs(preferences, {
replaceRef: false
const queryPaginateBy = useRouteQuery<string>('paginateBy', perfPaginateBy.value.toString())
const paginateBy = ref()
syncRef(queryPaginateBy, paginateBy, {
transform: {
ltr: (left) => +left,
rtl: (right) => right.toString()
}
}) })
const queryOrdering = useRouteQuery('ordering', perfOrderingDirection.value + perfOrdering.value) const normalizeDirection = (direction: string) => direction === '+' ? '' : '-'
console.log(queryOrdering.value)
const queryOrdering = useRouteQuery(
'ordering',
normalizeDirection(prefOrderingDirection.value) + prefOrdering.value,
{ transform: (value) => value.trim() }
)
const queryPaginateBy = useRouteQuery('paginateBy', prefPaginateBy.value, {
transform: Number
})
// NOTE: Sync paginateBy in query string and preferences. We're using `flush: 'post'` to make sure that we sync after all updates are done
syncRef(queryPaginateBy, prefPaginateBy, {
flush: 'post'
})
// NOTE: Sync ordering from preferences to query string
watch([prefOrderingDirection, prefOrdering], () => {
queryOrdering.value = normalizeDirection(prefOrderingDirection.value) + prefOrdering.value.trim()
})
// NOTE: Sync ordering from query string to preferences
watch(queryOrdering, (ordering) => { watch(queryOrdering, (ordering) => {
perfOrderingDirection.value = ordering[0] === '-' ? '-' : '+' prefOrderingDirection.value = ordering[0] === '-' ? '-' : '+'
perfOrdering.value = ordering[0] === '-' || ordering[0] === '+' prefOrdering.value = ordering.replace(/^[+-]/, '')
? ordering.slice(1) }, { immediate: true })
: ordering
// NOTE: We're using `flush: 'post'` to make sure that the `onOrderingUpdate` callback is called after all updates are done
const onOrderingUpdate = (fn: () => void) => watch(preferences, fn, {
flush: 'post'
}) })
watch(perfOrderingDirection, (direction) => {
if (direction === '-') {
queryOrdering.value = direction + perfOrdering.value
return
}
queryOrdering.value = perfOrdering.value
})
watch(perfOrdering, (field) => {
const direction = perfOrderingDirection.value
queryOrdering.value = (direction === '-' ? '-' : '') + field
})
watch(queryPaginateBy, (paginateBy) => {
perfPaginateBy.value = +paginateBy
})
const onOrderingUpdate = (fn: () => void) => watch(preferences, fn)
return { return {
paginateBy, paginateBy: prefPaginateBy,
ordering: perfOrdering, ordering: prefOrdering,
orderingDirection: perfOrderingDirection, orderingDirection: prefOrderingDirection,
orderingString: queryOrdering, orderingString: readonly(queryOrdering),
onOrderingUpdate onOrderingUpdate
} }
} }

Wyświetl plik

@ -2,6 +2,8 @@ import { DefaultMagicKeysAliasMap, tryOnScopeDispose, useEventListener } from '@
import { isEqual, isMatch } from 'lodash-es' import { isEqual, isMatch } from 'lodash-es'
import { reactive } from 'vue' import { reactive } from 'vue'
import useLogger from './useLogger'
type KeyFilter = string | string[] type KeyFilter = string | string[]
interface Entry { interface Entry {
@ -10,6 +12,7 @@ interface Entry {
__location?: string __location?: string
} }
const logger = useLogger()
const combinations = reactive(new Map()) const combinations = reactive(new Map())
const current = new Set() const current = new Set()
@ -59,7 +62,7 @@ export default (key: KeyFilter, handler: () => unknown, prevent = false) => {
} }
if (collisions.length) { if (collisions.length) {
console.warn([ logger.warn([
'onKeyboardShortcut detected a possible collision in:', 'onKeyboardShortcut detected a possible collision in:',
`${entry.__location}: ${combination.join(' + ')}`, `${entry.__location}: ${combination.join(' + ')}`,
...collisions ...collisions

Wyświetl plik

@ -1,11 +1,112 @@
import Logger from 'js-logger' type LogLevel = 'info' | 'warn' | 'error' | 'debug' | 'time'
Logger.useDefaults({ const LOG_LEVEL_LABELS: Record<LogLevel, string> = {
defaultLevel: import.meta.env.DEV info: ' INFO',
? Logger.DEBUG warn: ' WARN',
: Logger.WARN error: 'ERROR',
}) debug: 'DEBUG',
time: ' TIME'
}
export default (logger?: string) => logger const LOG_LEVEL_BACKGROUND: Record<LogLevel, string> = {
? Logger.get(logger) info: '#a6e22e',
: Logger warn: '#FF9800',
error: '#F44336',
debug: '#00BCD4',
time: '#00BCD4'
}
const LOG_LEVEL_COLOR: Record<LogLevel, string> = {
info: '#000',
warn: '#000',
error: '#fff',
debug: '#000',
time: '#000'
}
const TIMESTAMP_COLOR = '#9E9E9E'
const FILETYPE_BACKGROUND: Record<string, string> = {
js: '#f1e05a',
ts: '#2b7489',
vue: '#41b883',
html: '#e34c26',
default: '#ccc'
}
const FILETYPE_COLOR: Record<string, string> = {
js: '#000',
ts: '#fff',
vue: '#fff',
html: '#fff',
default: '#000'
}
const getFile = () => {
const { stack } = new Error()
const line = stack?.split('\n')[2] ?? ''
const [, method, url, lineNo] = line.match(/^(\w+)?(?:\/<)*@(.+?)(?:\?.*)?:(\d+):\d+$/) ?? []
const file = url.startsWith(location.origin) ? url.slice(location.origin.length) : url
return { method, file, lineNo }
}
// NOTE: We're pushing all logs to the end of the event loop
const createLoggerFn = (level: LogLevel) => {
// NOTE: We don't want to handle logs ourselves in tests
// eslint-disable-next-line no-console
if (import.meta.env.VITEST) return console[level]
return (...args: any[]) => {
const timestamp = new Date().toUTCString()
const { method, file, lineNo } = getFile()
const ext = file?.split('.').pop() ?? 'default'
// NOTE: Don't log time and debug in production
if (level === 'time' || level === 'debug') {
if (import.meta.env.PROD) return
}
// eslint-disable-next-line no-console
console[level === 'time' ? 'debug' : level](
'%c %c [%s] %c %s %c%s',
`background: ${LOG_LEVEL_BACKGROUND[level]};border-radius:1em`,
`color: ${TIMESTAMP_COLOR}`,
timestamp,
`background: ${LOG_LEVEL_BACKGROUND[level]}; color: ${LOG_LEVEL_COLOR[level]}; border-radius: 1em 0 0 1em`,
LOG_LEVEL_LABELS[level],
`background: ${FILETYPE_BACKGROUND[ext]}; color: ${FILETYPE_COLOR[ext]}; border-radius: 0 1em 1em 0`,
method !== undefined
? ` ${file}:${lineNo} ${method}() `
: ` ${file}:${lineNo} `,
...args
)
}
}
const infoLogger = createLoggerFn('info')
const warnLogger = createLoggerFn('warn')
const timeLogger = createLoggerFn('time')
const errorLogger = createLoggerFn('error')
const debugLogger = createLoggerFn('debug')
export const logger = {
log: infoLogger,
info: infoLogger,
warn: warnLogger,
error: errorLogger,
debug: debugLogger,
time: (label: string) => {
const now = performance.now()
timeLogger(`${label}: start`)
return () => {
const duration = performance.now() - now
timeLogger(`${label}: ${duration.toFixed(2)}ms`)
}
}
}
export default () => logger

Wyświetl plik

@ -1,12 +1,12 @@
import type { MaybeComputedRef } from '@vueuse/core' import type { MaybeRefOrGetter } from '@vueuse/core'
import { resolveUnref } from '@vueuse/core' import { toValue } from '@vueuse/core'
import { computed } from 'vue' import { computed } from 'vue'
import showdown from 'showdown' import showdown from 'showdown'
showdown.extension('openExternalInNewTab', { showdown.extension('openExternalInNewTab', {
type: 'output', type: 'output',
regex: /<a.+?href.+">/g, regex: /<a.+?href.+?">/g,
replace (text: string) { replace (text: string) {
const matches = text.match(/href="(.+)">/) ?? [] const matches = text.match(/href="(.+)">/) ?? []
@ -51,6 +51,6 @@ const markdown = new showdown.Converter({
}) })
export const useMarkdownRaw = (md: string) => markdown.makeHtml(md) export const useMarkdownRaw = (md: string) => markdown.makeHtml(md)
export const useMarkdownComputed = (md: MaybeComputedRef<string>) => computed(() => useMarkdownRaw(resolveUnref(md))) export const useMarkdownComputed = (md: MaybeRefOrGetter<string>) => computed(() => useMarkdownRaw(toValue(md)))
export default useMarkdownComputed export default useMarkdownComputed

Wyświetl plik

@ -118,7 +118,7 @@ export const install: InitModule = ({ store, router }) => {
const refreshAuth = async (failedRequest: AxiosError) => { const refreshAuth = async (failedRequest: AxiosError) => {
if (store.state.auth.oauth.accessToken) { if (store.state.auth.oauth.accessToken) {
console.log('Failed request, refreshing auth…') logger.warn('Failed request, refreshing auth…')
try { try {
// maybe the token was expired, let's try to refresh it // maybe the token was expired, let's try to refresh it

Wyświetl plik

@ -3,9 +3,12 @@ import type { InitModule } from '~/types'
import { watchEffect, watch } from 'vue' import { watchEffect, watch } from 'vue'
import { useWebSocket, whenever } from '@vueuse/core' import { useWebSocket, whenever } from '@vueuse/core'
import useWebSocketHandler from '~/composables/useWebSocketHandler' import useWebSocketHandler from '~/composables/useWebSocketHandler'
import useLogger from '~/composables/useLogger'
import { CLIENT_RADIOS } from '~/utils/clientRadios' import { CLIENT_RADIOS } from '~/utils/clientRadios'
export const install: InitModule = ({ store }) => { export const install: InitModule = ({ store }) => {
const logger = useLogger()
watch(() => store.state.instance.instanceUrl, () => { watch(() => store.state.instance.instanceUrl, () => {
const url = store.getters['instance/absoluteUrl']('/api/v1/activity') const url = store.getters['instance/absoluteUrl']('/api/v1/activity')
.replace(/^http/, 'ws') .replace(/^http/, 'ws')
@ -25,7 +28,7 @@ export const install: InitModule = ({ store }) => {
}) })
watchEffect(() => { watchEffect(() => {
console.log('Websocket status:', status.value) logger.log('Websocket status:', status.value)
}) })
}, { immediate: true }) }, { immediate: true })

Wyświetl plik

@ -1,4 +1,4 @@
import type { InitModule } from '~/types' import type { InitModule, InitModuleContext } from '~/types'
import store, { key } from '~/store' import store, { key } from '~/store'
import router from '~/router' import router from '~/router'
@ -24,6 +24,7 @@ const app = createApp({
data: () => ({ ready: false }), data: () => ({ ready: false }),
mounted () { mounted () {
this.ready = true this.ready = true
logger.info('Everything loaded!')
}, },
render () { render () {
if (this.ready) { if (this.ready) {
@ -37,19 +38,35 @@ const app = createApp({
app.use(router) app.use(router)
app.use(store, key) app.use(store, key)
const modules: Array<void | Promise<void>> = [] const modules: Record<string | 'axios', { install?: InitModule }> = import.meta.glob('./init/*.ts', { eager: true })
for (const module of Object.values(import.meta.glob('./init/*.ts', { eager: true })) as { install?: InitModule }[]) { const moduleContext: InitModuleContext = {
modules.push(module.install?.({ app,
app, router,
router, store
store
}))
} }
// Wait for all modules to load // NOTE: Other modules may depend on network requests and we need to ensure
Promise.all(modules).finally(() => { // that all axios interceptors are set before any requests are made
app.mount('#app') // and that the instance url is set before any requests are made
logger.info('Everything loaded!') const IMPORTANT_MODULES_QUEUE = ['axios', 'instance']
}) const waitForImportantModules = async () => {
for (const moduleName of IMPORTANT_MODULES_QUEUE) {
const path = `./init/${moduleName}.ts`
if (!(path in modules)) {
logger.error(`Failed to load important module: ${path}`)
continue
}
await modules[path].install?.(moduleContext)
delete modules[path]
}
}
waitForImportantModules()
// NOTE: We load the modules in parallel
.then(() => Promise.all(Object.values(modules).map(module => module.install?.(moduleContext))))
.catch(error => logger.error('Failed to load modules:', error))
// NOTE: We need to mount the app after all modules are loaded
.finally(() => app.mount('#app'))
// TODO (wvffle): Rename filters from useSharedLabels to filters from backend // TODO (wvffle): Rename filters from useSharedLabels to filters from backend

Wyświetl plik

@ -1,20 +1,23 @@
import type { NavigationGuardNext, RouteLocationNamedRaw, RouteLocationNormalized } from 'vue-router' import type { NavigationGuardNext, RouteLocationNamedRaw, RouteLocationNormalized } from 'vue-router'
import type { Permission } from '~/store/auth' import type { Permission } from '~/store/auth'
import useLogger from '~/composables/useLogger'
import store from '~/store' import store from '~/store'
const logger = useLogger()
export const hasPermissions = (permission: Permission) => (to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) => { export const hasPermissions = (permission: Permission) => (to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) => {
if (store.state.auth.authenticated && store.state.auth.availablePermissions[permission]) { if (store.state.auth.authenticated && store.state.auth.availablePermissions[permission]) {
return next() return next()
} }
console.log('Not authenticated. Redirecting to library.') logger.warn('Not authenticated. Redirecting to library.')
next({ name: 'library.index' }) next({ name: 'library.index' })
} }
export const requireLoggedIn = (fallbackLocation?: RouteLocationNamedRaw) => (to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) => { export const requireLoggedIn = (fallbackLocation?: RouteLocationNamedRaw) => (to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) => {
if (store.state.auth.authenticated) return next() if (store.state.auth.authenticated) return next()
console.log('!', to) logger.debug('!', to)
return next(fallbackLocation ?? { name: 'login', query: { next: to.fullPath } }) return next(fallbackLocation ?? { name: 'login', query: { next: to.fullPath } })
} }

Wyświetl plik

@ -168,7 +168,7 @@ const store: Module<State, RootState> = {
try { try {
await axios.post('users/logout') await axios.post('users/logout')
} catch (error) { } catch (error) {
console.log('Error while logging out, probably logged in via oauth') logger.error('Error while logging out, probably logged in via oauth', error)
} }
const modules = [ const modules = [
@ -249,11 +249,11 @@ const store: Module<State, RootState> = {
const redirectUri = encodeURIComponent(`${location.origin}/auth/callback`) const redirectUri = encodeURIComponent(`${location.origin}/auth/callback`)
const params = `response_type=code&scope=${encodeURIComponent(NEEDED_SCOPES)}&redirect_uri=${redirectUri}&state=${next}&client_id=${state.oauth.clientId}` const params = `response_type=code&scope=${encodeURIComponent(NEEDED_SCOPES)}&redirect_uri=${redirectUri}&state=${next}&client_id=${state.oauth.clientId}`
const authorizeUrl = `${rootState.instance.instanceUrl}authorize?${params}` const authorizeUrl = `${rootState.instance.instanceUrl}authorize?${params}`
console.log('Redirecting user...', authorizeUrl) logger.log('Redirecting user...', authorizeUrl)
window.location.href = authorizeUrl window.location.href = authorizeUrl
}, },
async handleOauthCallback ({ state, commit, dispatch }, authorizationCode) { async handleOauthCallback ({ state, commit, dispatch }, authorizationCode) {
console.log('Fetching token...') logger.log('Fetching token...')
const payload = { const payload = {
client_id: state.oauth.clientId, client_id: state.oauth.clientId,
client_secret: state.oauth.clientSecret, client_secret: state.oauth.clientSecret,

Wyświetl plik

@ -5,6 +5,8 @@ import type { SUPPORTED_LOCALES } from '~/init/locale'
import axios from 'axios' import axios from 'axios'
import moment from 'moment' import moment from 'moment'
import useLogger from '~/composables/useLogger'
type SupportedExtension = 'flac' | 'ogg' | 'mp3' | 'opus' | 'aac' | 'm4a' | 'aiff' | 'aif' type SupportedExtension = 'flac' | 'ogg' | 'mp3' | 'opus' | 'aac' | 'm4a' | 'aiff' | 'aif'
export type WebSocketEventName = 'inbox.item_added' | 'import.status_updated' | 'mutation.created' | 'mutation.updated' export type WebSocketEventName = 'inbox.item_added' | 'import.status_updated' | 'mutation.created' | 'mutation.updated'
@ -50,6 +52,8 @@ export interface State {
websocketEventsHandlers: Record<WebSocketEventName, WebSocketHandlers> websocketEventsHandlers: Record<WebSocketEventName, WebSocketHandlers>
} }
const logger = useLogger()
const store: Module<State, RootState> = { const store: Module<State, RootState> = {
namespaced: true, namespaced: true,
state: { state: {
@ -225,7 +229,9 @@ const store: Module<State, RootState> = {
commit('notifications', { type: 'pendingReviewRequests', count: response.data.count }) commit('notifications', { type: 'pendingReviewRequests', count: response.data.count })
}, },
async currentLanguage ({ commit, rootState }, value) { async currentLanguage ({ commit, rootState, state }, value) {
if (state.selectedLanguage && state.currentLanguage === value) return
commit('currentLanguage', value) commit('currentLanguage', value)
if (rootState.auth.authenticated) { if (rootState.auth.authenticated) {
await axios.post('users/settings', { language: value }) await axios.post('users/settings', { language: value })
@ -234,7 +240,7 @@ const store: Module<State, RootState> = {
websocketEvent ({ state }, event: WebSocketEvent) { websocketEvent ({ state }, event: WebSocketEvent) {
const handlers = state.websocketEventsHandlers[event.type] const handlers = state.websocketEventsHandlers[event.type]
console.log('Dispatching websocket event', event, handlers) logger.log('Dispatching websocket event', event, handlers)
if (!handlers) { if (!handlers) {
return return
} }

Wyświetl plik

@ -19,6 +19,7 @@ import RadioCard from '~/components/radios/Card.vue'
import TagsList from '~/components/tags/List.vue' import TagsList from '~/components/tags/List.vue'
import useErrorHandler from '~/composables/useErrorHandler' import useErrorHandler from '~/composables/useErrorHandler'
import useLogger from '~/composables/useLogger'
type QueryType = 'artists' | 'albums' | 'tracks' | 'playlists' | 'tags' | 'radios' | 'podcasts' | 'series' | 'rss' type QueryType = 'artists' | 'albums' | 'tracks' | 'playlists' | 'tags' | 'radios' | 'podcasts' | 'series' | 'rss'
@ -35,6 +36,8 @@ syncRef(pageQuery, page, {
direction: 'both' direction: 'both'
}) })
const logger = useLogger()
const q = useRouteQuery('q', '') const q = useRouteQuery('q', '')
const query = ref(q.value) const query = ref(q.value)
syncRef(q, query, { direction: 'ltr' }) syncRef(q, query, { direction: 'ltr' })
@ -209,8 +212,7 @@ const radioConfig = computed(() => {
} as RadioConfig } as RadioConfig
} }
// TODO (wvffle): Use logger logger.warn('This type is not yet supported for radio')
console.info('This type is not yet supported for radio')
} }
return null return null

Wyświetl plik

@ -20,6 +20,7 @@ import useSharedLabels from '~/composables/locale/useSharedLabels'
import useOrdering from '~/composables/navigation/useOrdering' import useOrdering from '~/composables/navigation/useOrdering'
import useErrorHandler from '~/composables/useErrorHandler' import useErrorHandler from '~/composables/useErrorHandler'
import usePage from '~/composables/navigation/usePage' import usePage from '~/composables/navigation/usePage'
import useLogger from '~/composables/useLogger'
interface Props extends SmartSearchProps, OrderingProps { interface Props extends SmartSearchProps, OrderingProps {
mode?: 'card' mode?: 'card'
@ -37,6 +38,8 @@ const props = withDefaults(defineProps<Props>(), {
orderingConfigName: undefined orderingConfigName: undefined
}) })
const logger = useLogger()
const search = ref() const search = ref()
const page = usePage() const page = usePage()
@ -68,7 +71,7 @@ const fetchData = async () => {
result.value = response.data result.value = response.data
if (query.value === 'resolved:no') { if (query.value === 'resolved:no') {
console.log('Refreshing sidebar notifications') logger.log('Refreshing sidebar notifications')
store.commit('ui/incrementNotifications', { store.commit('ui/incrementNotifications', {
type: 'pendingReviewReports', type: 'pendingReviewReports',
value: response.data.count value: response.data.count

Wyświetl plik

@ -12,6 +12,7 @@ import RadioButton from '~/components/radios/Button.vue'
import useErrorHandler from '~/composables/useErrorHandler' import useErrorHandler from '~/composables/useErrorHandler'
import useReport from '~/composables/moderation/useReport' import useReport from '~/composables/moderation/useReport'
import useLogger from '~/composables/useLogger'
interface Emits { interface Emits {
(e: 'followed'): void (e: 'followed'): void
@ -31,6 +32,8 @@ const props = withDefaults(defineProps<Props>(), {
displayCopyFid: true displayCopyFid: true
}) })
const logger = useLogger()
const { report, getReportableObjects } = useReport() const { report, getReportableObjects } = useReport()
const store = useStore() const store = useStore()
@ -80,7 +83,7 @@ const follow = async () => {
library.value.follow = response.data library.value.follow = response.data
emit('followed') emit('followed')
} catch (error) { } catch (error) {
console.error(error) logger.error(error)
store.commit('ui/addMessage', { store.commit('ui/addMessage', {
content: t('views.content.remote.Card.error.follow', { error }), content: t('views.content.remote.Card.error.follow', { error }),
date: new Date() date: new Date()

Wyświetl plik

@ -65,7 +65,7 @@ const fetchData = async () => {
playable: true playable: true
} }
logger.time('Fetching albums') const measureLoading = logger.time('Fetching albums')
try { try {
const response = await axios.get('playlists/', { const response = await axios.get('playlists/', {
params params
@ -76,7 +76,7 @@ const fetchData = async () => {
useErrorHandler(error as Error) useErrorHandler(error as Error)
result.value = undefined result.value = undefined
} finally { } finally {
logger.timeEnd('Fetching albums') measureLoading()
isLoading.value = false isLoading.value = false
} }
} }

Wyświetl plik

@ -0,0 +1,25 @@
import { useMarkdownRaw } from '~/composables/useMarkdown'
describe('useMarkdownRaw', () => {
describe('anchors', () => {
it('should add target="_blank" to external links', () => {
const html = useMarkdownRaw('https://open.audio')
expect(html).toBe('<p><a href="https://open.audio" target="_blank" rel="noopener noreferrer">https://open.audio</a></p>')
})
it('should not link raw path', () => {
const html = useMarkdownRaw('/library/tags')
expect(html).toBe('<p>/library/tags</p>')
})
it('should not add target="_blank" to internal links', () => {
const html = useMarkdownRaw('[/library/tags](/library/tags)')
expect(html).toBe('<p><a href="/library/tags">/library/tags</a></p>')
})
it('should handle multiple links', () => {
const html = useMarkdownRaw('https://open.audio https://funkwhale.audio')
expect(html).toBe('<p><a href="https://open.audio" target="_blank" rel="noopener noreferrer">https://open.audio</a> <a href="https://funkwhale.audio" target="_blank" rel="noopener noreferrer">https://funkwhale.audio</a></p>')
})
})
})

Wyświetl plik

@ -10,7 +10,8 @@
"vitest/globals", "vitest/globals",
"vite/client", "vite/client",
"vue/ref-macros", "vue/ref-macros",
"vite-plugin-pwa/client" "vite-plugin-pwa/client",
"unplugin-vue-macros/macros-global"
], ],
"paths": { "paths": {
"#/*": ["src/worker/*"], "#/*": ["src/worker/*"],
@ -24,5 +25,17 @@
"src/**/*.vue", "src/**/*.vue",
"vite.config.ts", "vite.config.ts",
"test/**/*.ts" "test/**/*.ts"
] ],
"vueCompilerOptions": {
"plugins": [
"@vue-macros/volar/define-options",
"@vue-macros/volar/define-models",
"@vue-macros/volar/define-props",
"@vue-macros/volar/define-props-refs",
"@vue-macros/volar/short-vmodel",
"@vue-macros/volar/define-slots",
"@vue-macros/volar/export-props",
"@vue-macros/volar/jsx-directive"
]
}
} }

Wyświetl plik

@ -7,6 +7,7 @@ import manifest from './pwa-manifest.json'
import VueI18n from '@intlify/unplugin-vue-i18n/vite' import VueI18n from '@intlify/unplugin-vue-i18n/vite'
import Vue from '@vitejs/plugin-vue' import Vue from '@vitejs/plugin-vue'
import VueMacros from 'unplugin-vue-macros/vite'
const port = +(process.env.VUE_PORT ?? 8080) const port = +(process.env.VUE_PORT ?? 8080)
@ -15,8 +16,13 @@ const port = +(process.env.VUE_PORT ?? 8080)
export default defineConfig(({ mode }) => ({ export default defineConfig(({ mode }) => ({
envPrefix: ['VUE_', 'FUNKWHALE_SENTRY_'], envPrefix: ['VUE_', 'FUNKWHALE_SENTRY_'],
plugins: [ plugins: [
// https://github.com/vitejs/vite/tree/main/packages/plugin-vue // https://vue-macros.sxzz.moe/
Vue(), VueMacros({
plugins: {
// https://github.com/vitejs/vite/tree/main/packages/plugin-vue
vue: Vue(),
}
}),
// https://github.com/intlify/bundle-tools/tree/main/packages/vite-plugin-vue-i18n // https://github.com/intlify/bundle-tools/tree/main/packages/vite-plugin-vue-i18n
VueI18n({ VueI18n({
@ -51,6 +57,7 @@ export default defineConfig(({ mode }) => ({
} }
}, },
build: { build: {
sourcemap: true,
// https://rollupjs.org/configuration-options/ // https://rollupjs.org/configuration-options/
rollupOptions: { rollupOptions: {
output: { output: {
@ -79,7 +86,7 @@ export default defineConfig(({ mode }) => ({
}, },
setupFiles: [ setupFiles: [
'./test/setup/mock-audio-context.ts', './test/setup/mock-audio-context.ts',
'./test/setup/mock-vue-i18n.ts', './test/setup/mock-vue-i18n.ts'
] ]
} }
})) }))

Plik diff jest za duży Load Diff