commit
e5e27e2bbe
15 changed files with 292 additions and 40 deletions
|
|
@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## v1.3.47 (2023-10-25)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Add filtering term length check for channel filter endpoints @Ferril ([#3192](https://github.com/grafana/oncall/pull/3192))
|
||||
|
||||
## v1.3.46 (2023-10-23)
|
||||
|
||||
### Added
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ PATHS_mimir='docs/sources/mimir'
|
|||
PATHS_plugins_grafana_jira_datasource='docs/sources'
|
||||
PATHS_plugins_grafana_mongodb_datasource='docs/sources'
|
||||
PATHS_plugins_grafana_splunk_datasource='docs/sources'
|
||||
Paths_tempo='docs/sources/tempo'
|
||||
PATHS_tempo='docs/sources/tempo'
|
||||
PATHS_website='content'
|
||||
|
||||
# identifier STR
|
||||
|
|
|
|||
|
|
@ -213,21 +213,22 @@ Grafana OnCall supports Twilio SMS and phone call notifications delivery. If you
|
|||
notifications using Twilio, complete the following steps:
|
||||
|
||||
1. Set `GRAFANA_CLOUD_NOTIFICATIONS_ENABLED` as **False** to ensure the Grafana OSS <-> Cloud connector is disabled.
|
||||
1. From your **OnCall** environment, select **Env Variables** and configure all variables starting with `TWILIO_`.
|
||||
2. From your **OnCall** environment, select **Env Variables** and configure all variables starting with `TWILIO_`.
|
||||
|
||||
### Zvonok.com
|
||||
|
||||
Grafana OnCall supports Zvonok.com phone call notifications delivery. To configure phone call notifications using
|
||||
Zvonok.com, complete the following steps:
|
||||
|
||||
1. Change `PHONE_PROVIDER` value to `zvonok`.
|
||||
2. Create a public API key on the Profile->Settings page, and assign its value to `ZVONOK_API_KEY`.
|
||||
3. Create campaign and assign its ID value to `ZVONOK_CAMPAIGN_ID`.
|
||||
4. If you are planning to use pre-recorded audio instead of a speech synthesizer, you can copy the ID of the audio clip
|
||||
1. Set `GRAFANA_CLOUD_NOTIFICATIONS_ENABLED` as **False** to ensure the Grafana OSS <-> Cloud connector is disabled.
|
||||
2. Change `PHONE_PROVIDER` value to `zvonok`.
|
||||
3. Create a public API key on the Profile->Settings page, and assign its value to `ZVONOK_API_KEY`.
|
||||
4. Create campaign and assign its ID value to `ZVONOK_CAMPAIGN_ID`.
|
||||
5. If you are planning to use pre-recorded audio instead of a speech synthesizer, you can copy the ID of the audio clip
|
||||
to the variable `ZVONOK_AUDIO_ID` (optional step).
|
||||
5. To make a call with a specific voice, you can set the `ZVONOK_SPEAKER_ID`.
|
||||
6. To make a call with a specific voice, you can set the `ZVONOK_SPEAKER_ID`.
|
||||
By default, the ID used is `Salli` (optional step).
|
||||
6. To process the call status, it is required to add a postback with the GET/POST method on the side of the zvonok.com
|
||||
7. To process the call status, it is required to add a postback with the GET/POST method on the side of the zvonok.com
|
||||
service with the following format (optional step):
|
||||
`${ONCALL_BASE_URL}/zvonok/call_status_events?campaign_id={ct_campaign_id}&call_id={ct_call_id}&status={ct_status}&user_choice={ct_user_choice}`
|
||||
|
||||
|
|
|
|||
|
|
@ -437,6 +437,8 @@ class AlertGroupSlackRenderer(AlertGroupBaseRenderer):
|
|||
data = {
|
||||
"organization_id": self.alert_group.channel.organization_id,
|
||||
"alert_group_pk": self.alert_group.pk,
|
||||
# eventually replace using alert_group_pk with alert_group_public_pk in slack payload
|
||||
"alert_group_ppk": self.alert_group.public_primary_key,
|
||||
**kwargs,
|
||||
}
|
||||
return json.dumps(data) # Slack block elements allow to pass value as string only (max 2000 chars)
|
||||
|
|
|
|||
|
|
@ -76,7 +76,9 @@ class ChannelFilter(OrderedModel):
|
|||
notification_backends = models.JSONField(null=True, default=None)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
filtering_term = models.CharField(max_length=1024, null=True, default=None)
|
||||
|
||||
FILTERING_TERM_MAX_LENGTH = 1024
|
||||
filtering_term = models.CharField(max_length=FILTERING_TERM_MAX_LENGTH, null=True, default=None)
|
||||
|
||||
FILTERING_TERM_TYPE_REGEX = 0
|
||||
FILTERING_TERM_TYPE_JINJA2 = 1
|
||||
|
|
|
|||
|
|
@ -60,6 +60,12 @@ class ChannelFilterSerializer(EagerLoadingMixin, serializers.ModelSerializer):
|
|||
def validate(self, data):
|
||||
filtering_term = data.get("filtering_term")
|
||||
filtering_term_type = data.get("filtering_term_type")
|
||||
if filtering_term is not None:
|
||||
if len(filtering_term) > ChannelFilter.FILTERING_TERM_MAX_LENGTH:
|
||||
raise serializers.ValidationError(
|
||||
f"Expression is too long. Maximum length: {ChannelFilter.FILTERING_TERM_MAX_LENGTH} characters, "
|
||||
f"current length: {len(filtering_term)}"
|
||||
)
|
||||
if filtering_term_type == ChannelFilter.FILTERING_TERM_TYPE_JINJA2:
|
||||
try:
|
||||
valid_jinja_template_for_serializer_method_field({"route_template": filtering_term})
|
||||
|
|
@ -141,7 +147,6 @@ class ChannelFilterSerializer(EagerLoadingMixin, serializers.ModelSerializer):
|
|||
class ChannelFilterCreateSerializer(ChannelFilterSerializer):
|
||||
alert_receive_channel = OrganizationFilteredPrimaryKeyRelatedField(queryset=AlertReceiveChannel.objects)
|
||||
slack_channel = serializers.CharField(allow_null=True, required=False, source="slack_channel_id")
|
||||
filtering_term = serializers.CharField(required=False, allow_null=True, allow_blank=True)
|
||||
|
||||
class Meta:
|
||||
model = ChannelFilter
|
||||
|
|
|
|||
|
|
@ -552,3 +552,41 @@ def test_channel_filter_convert_from_regex_to_jinja2(
|
|||
assert jinja2_channel_filter.filtering_term == final_filtering_term
|
||||
# Check if the same alert is matched to the channel filter (route) new jinja2
|
||||
assert bool(jinja2_channel_filter.is_satisfying(payload)) is True
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_channel_filter_long_filtering_term(
|
||||
make_organization_and_user_with_plugin_token,
|
||||
make_alert_receive_channel,
|
||||
make_escalation_chain,
|
||||
make_channel_filter,
|
||||
make_user_auth_headers,
|
||||
):
|
||||
organization, user, token = make_organization_and_user_with_plugin_token()
|
||||
alert_receive_channel = make_alert_receive_channel(organization)
|
||||
make_escalation_chain(organization)
|
||||
make_channel_filter(alert_receive_channel, is_default=True)
|
||||
client = APIClient()
|
||||
long_filtering_term = "a" * (ChannelFilter.FILTERING_TERM_MAX_LENGTH + 1)
|
||||
|
||||
url = reverse("api-internal:channel_filter-list")
|
||||
data_for_creation = {
|
||||
"alert_receive_channel": alert_receive_channel.public_primary_key,
|
||||
"filtering_term": long_filtering_term,
|
||||
}
|
||||
|
||||
response = client.post(url, data=data_for_creation, format="json", **make_user_auth_headers(user, token))
|
||||
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
assert "Expression is too long" in response.json()["non_field_errors"][0]
|
||||
|
||||
channel_filter = make_channel_filter(alert_receive_channel, filtering_term="a", is_default=False)
|
||||
url = reverse("api-internal:channel_filter-detail", kwargs={"pk": channel_filter.public_primary_key})
|
||||
data_for_update = {
|
||||
"filtering_term": long_filtering_term,
|
||||
}
|
||||
|
||||
response = client.put(url, data=data_for_update, format="json", **make_user_auth_headers(user, token))
|
||||
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
assert "Expression is too long" in response.json()["non_field_errors"][0]
|
||||
|
|
|
|||
|
|
@ -163,8 +163,14 @@ class ChannelFilterSerializer(BaseChannelFilterSerializer):
|
|||
return super().create(validated_data)
|
||||
|
||||
def validate(self, data):
|
||||
filtering_term = data.get("routing_regex")
|
||||
filtering_term_type = data.get("routing_type")
|
||||
filtering_term = data.get("filtering_term")
|
||||
filtering_term_type = data.get("filtering_term_type")
|
||||
if filtering_term is not None:
|
||||
if len(filtering_term) > ChannelFilter.FILTERING_TERM_MAX_LENGTH:
|
||||
raise serializers.ValidationError(
|
||||
f"Expression is too long. Maximum length: {ChannelFilter.FILTERING_TERM_MAX_LENGTH} characters, "
|
||||
f"current length: {len(filtering_term)}"
|
||||
)
|
||||
if filtering_term_type == ChannelFilter.FILTERING_TERM_TYPE_JINJA2:
|
||||
try:
|
||||
valid_jinja_template_for_serializer_method_field({"route_template": filtering_term})
|
||||
|
|
|
|||
|
|
@ -455,3 +455,36 @@ def test_update_route_with_manual_ordering(
|
|||
|
||||
response = client.put(url, format="json", HTTP_AUTHORIZATION=token, data=data_to_update)
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_routes_long_filtering_term(
|
||||
route_public_api_setup,
|
||||
make_channel_filter,
|
||||
):
|
||||
organization, _, token, alert_receive_channel, escalation_chain, _ = route_public_api_setup
|
||||
client = APIClient()
|
||||
long_filtering_term = "a" * (ChannelFilter.FILTERING_TERM_MAX_LENGTH + 1)
|
||||
|
||||
url = reverse("api-public:routes-list")
|
||||
data_for_creation = {
|
||||
"integration_id": alert_receive_channel.public_primary_key,
|
||||
"escalation_chain_id": escalation_chain.public_primary_key,
|
||||
"routing_regex": long_filtering_term,
|
||||
}
|
||||
|
||||
response = client.post(url, data=data_for_creation, format="json", HTTP_AUTHORIZATION=token)
|
||||
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
assert "Expression is too long" in response.json()["non_field_errors"][0]
|
||||
|
||||
channel_filter = make_channel_filter(alert_receive_channel, filtering_term="a", is_default=False)
|
||||
url = reverse("api-public:routes-detail", kwargs={"pk": channel_filter.public_primary_key})
|
||||
data_for_update = {
|
||||
"routing_regex": long_filtering_term,
|
||||
}
|
||||
|
||||
response = client.put(url, data=data_for_update, format="json", HTTP_AUTHORIZATION=token)
|
||||
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
assert "Expression is too long" in response.json()["non_field_errors"][0]
|
||||
|
|
|
|||
|
|
@ -98,12 +98,27 @@ class AlertGroupActionsMixin:
|
|||
except (TypeError, json.JSONDecodeError):
|
||||
return None
|
||||
|
||||
# New slack messages from OnCall contain alert group primary key
|
||||
try:
|
||||
alert_group_ppk = value["alert_group_ppk"]
|
||||
return AlertGroup.objects.get(public_primary_key=alert_group_ppk)
|
||||
except (KeyError, TypeError):
|
||||
pass
|
||||
|
||||
try:
|
||||
alert_group_pk = value["alert_group_pk"]
|
||||
organization_pk = value["organization_id"]
|
||||
except (KeyError, TypeError):
|
||||
return None
|
||||
|
||||
return AlertGroup.objects.get(pk=alert_group_pk)
|
||||
try:
|
||||
# check organization as well for cases when the organization was migrated from "us" cluster to "eu" and
|
||||
# slack message has an outdated payload with incorrect alert group id
|
||||
alert_group = AlertGroup.objects.get(pk=alert_group_pk, channel__organization_id=organization_pk)
|
||||
except AlertGroup.DoesNotExist:
|
||||
return None
|
||||
|
||||
return alert_group
|
||||
|
||||
def _get_alert_group_from_message(self, payload: EventPayload) -> AlertGroup | None:
|
||||
"""
|
||||
|
|
@ -128,12 +143,27 @@ class AlertGroupActionsMixin:
|
|||
except (TypeError, json.JSONDecodeError):
|
||||
continue
|
||||
|
||||
# New slack messages from OnCall contain alert group primary key
|
||||
try:
|
||||
alert_group_ppk = value["alert_group_ppk"]
|
||||
return AlertGroup.objects.get(public_primary_key=alert_group_ppk)
|
||||
except (KeyError, TypeError):
|
||||
pass
|
||||
|
||||
try:
|
||||
alert_group_pk = value["alert_group_pk"]
|
||||
organization_pk = value["organization_id"]
|
||||
except (KeyError, TypeError):
|
||||
continue
|
||||
|
||||
return AlertGroup.objects.get(pk=alert_group_pk)
|
||||
try:
|
||||
# check the organization as well for cases organization was migrated from "us" cluster to "eu" and
|
||||
# the slack message has an outdated payload with incorrect alert group id
|
||||
alert_group = AlertGroup.objects.get(pk=alert_group_pk, channel__organization_id=organization_pk)
|
||||
except AlertGroup.DoesNotExist:
|
||||
return None
|
||||
|
||||
return alert_group
|
||||
return None
|
||||
|
||||
def _get_alert_group_from_slack_message_in_db(
|
||||
|
|
|
|||
|
|
@ -191,7 +191,21 @@ def test_get_alert_group_from_message(
|
|||
],
|
||||
"message": {
|
||||
"ts": "RANDOM_MESSAGE_TS",
|
||||
"attachments": [{"blocks": [{"elements": [{"value": json.dumps({"alert_group_pk": alert_group.pk})}]}]}],
|
||||
"attachments": [
|
||||
{
|
||||
"blocks": [
|
||||
{
|
||||
"elements": [
|
||||
{
|
||||
"value": json.dumps(
|
||||
{"alert_group_pk": alert_group.pk, "organization_id": organization.pk}
|
||||
)
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
"channel": {"id": "RANDOM_CHANNEL_ID"},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,18 +81,16 @@ def manage_responders_setup(
|
|||
|
||||
@pytest.mark.django_db
|
||||
def test_initial_state(manage_responders_setup):
|
||||
organization, user, slack_team_identity, slack_user_identity = manage_responders_setup
|
||||
payload = {
|
||||
"trigger_id": TRIGGER_ID,
|
||||
"actions": [
|
||||
{
|
||||
"type": "button",
|
||||
"value": json.dumps({"organization_id": ORGANIZATION_ID, "alert_group_pk": ALERT_GROUP_ID}),
|
||||
"value": json.dumps({"organization_id": organization.pk, "alert_group_pk": ALERT_GROUP_ID}),
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
organization, user, slack_team_identity, slack_user_identity = manage_responders_setup
|
||||
|
||||
step = StartManageResponders(slack_team_identity, organization, user)
|
||||
with patch.object(step._slack_client, "views_open") as mock_slack_api_call:
|
||||
step.process_scenario(slack_user_identity, slack_team_identity, payload)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,11 @@ def test_slack_renderer_acknowledge_button(make_organization, make_alert_receive
|
|||
|
||||
button = elements[0]
|
||||
assert button["text"]["text"] == "Acknowledge"
|
||||
assert json.loads(button["value"]) == {"organization_id": organization.pk, "alert_group_pk": alert_group.pk}
|
||||
assert json.loads(button["value"]) == {
|
||||
"organization_id": organization.pk,
|
||||
"alert_group_pk": alert_group.pk,
|
||||
"alert_group_ppk": alert_group.public_primary_key,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
|
@ -33,7 +37,11 @@ def test_slack_renderer_unacknowledge_button(
|
|||
|
||||
button = elements[0]
|
||||
assert button["text"]["text"] == "Unacknowledge"
|
||||
assert json.loads(button["value"]) == {"organization_id": organization.pk, "alert_group_pk": alert_group.pk}
|
||||
assert json.loads(button["value"]) == {
|
||||
"organization_id": organization.pk,
|
||||
"alert_group_pk": alert_group.pk,
|
||||
"alert_group_ppk": alert_group.public_primary_key,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
|
@ -47,7 +55,11 @@ def test_slack_renderer_resolve_button(make_organization, make_alert_receive_cha
|
|||
|
||||
button = elements[1]
|
||||
assert button["text"]["text"] == "Resolve"
|
||||
assert json.loads(button["value"]) == {"organization_id": organization.pk, "alert_group_pk": alert_group.pk}
|
||||
assert json.loads(button["value"]) == {
|
||||
"organization_id": organization.pk,
|
||||
"alert_group_pk": alert_group.pk,
|
||||
"alert_group_ppk": alert_group.public_primary_key,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
|
@ -61,7 +73,11 @@ def test_slack_renderer_unresolve_button(make_organization, make_alert_receive_c
|
|||
|
||||
button = elements[0]
|
||||
assert button["text"]["text"] == "Unresolve"
|
||||
assert json.loads(button["value"]) == {"organization_id": organization.pk, "alert_group_pk": alert_group.pk}
|
||||
assert json.loads(button["value"]) == {
|
||||
"organization_id": organization.pk,
|
||||
"alert_group_pk": alert_group.pk,
|
||||
"alert_group_ppk": alert_group.public_primary_key,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
|
@ -96,6 +112,7 @@ def test_slack_renderer_stop_invite_button(
|
|||
assert json.loads(action["value"]) == {
|
||||
"organization_id": organization.pk,
|
||||
"alert_group_pk": alert_group.pk,
|
||||
"alert_group_ppk": alert_group.public_primary_key,
|
||||
"invitation_id": invitation.pk,
|
||||
}
|
||||
|
||||
|
|
@ -114,7 +131,12 @@ def test_slack_renderer_silence_button(make_organization, make_alert_receive_cha
|
|||
|
||||
values = [json.loads(option["value"]) for option in button["options"]]
|
||||
assert values == [
|
||||
{"organization_id": organization.pk, "alert_group_pk": alert_group.pk, "delay": delay}
|
||||
{
|
||||
"organization_id": organization.pk,
|
||||
"alert_group_pk": alert_group.pk,
|
||||
"alert_group_ppk": alert_group.public_primary_key,
|
||||
"delay": delay,
|
||||
}
|
||||
for delay, _ in AlertGroup.SILENCE_DELAY_OPTIONS
|
||||
]
|
||||
|
||||
|
|
@ -133,6 +155,7 @@ def test_slack_renderer_unsilence_button(make_organization, make_alert_receive_c
|
|||
assert json.loads(button["value"]) == {
|
||||
"organization_id": organization.pk,
|
||||
"alert_group_pk": alert_group.pk,
|
||||
"alert_group_ppk": alert_group.public_primary_key,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -150,6 +173,7 @@ def test_slack_renderer_attach_button(make_organization, make_alert_receive_chan
|
|||
assert json.loads(button["value"]) == {
|
||||
"organization_id": organization.pk,
|
||||
"alert_group_pk": alert_group.pk,
|
||||
"alert_group_ppk": alert_group.public_primary_key,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -170,6 +194,7 @@ def test_slack_renderer_unattach_button(make_organization, make_alert_receive_ch
|
|||
assert json.loads(action["value"]) == {
|
||||
"organization_id": organization.pk,
|
||||
"alert_group_pk": alert_group.pk,
|
||||
"alert_group_ppk": alert_group.public_primary_key,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -186,7 +211,11 @@ def test_slack_renderer_format_alert_button(
|
|||
|
||||
button = elements[5]
|
||||
assert button["text"]["text"] == ":mag: Format Alert"
|
||||
assert json.loads(button["value"]) == {"organization_id": organization.pk, "alert_group_pk": alert_group.pk}
|
||||
assert json.loads(button["value"]) == {
|
||||
"organization_id": organization.pk,
|
||||
"alert_group_pk": alert_group.pk,
|
||||
"alert_group_ppk": alert_group.public_primary_key,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
|
@ -205,5 +234,6 @@ def test_slack_renderer_resolution_notes_button(
|
|||
assert json.loads(button["value"]) == {
|
||||
"organization_id": organization.pk,
|
||||
"alert_group_pk": alert_group.pk,
|
||||
"alert_group_ppk": alert_group.public_primary_key,
|
||||
"resolution_note_window_action": "edit",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ django-anymail==8.6
|
|||
django-deprecate-fields==0.1.1
|
||||
pymdown-extensions==10.0
|
||||
requests==2.31.0
|
||||
urllib3==1.26.17
|
||||
urllib3==1.26.18
|
||||
prometheus_client==0.16.0
|
||||
lxml==4.9.2
|
||||
babel==2.12.1
|
||||
|
|
|
|||
|
|
@ -22,6 +22,14 @@
|
|||
dependencies:
|
||||
"@babel/highlight" "^7.18.6"
|
||||
|
||||
"@babel/code-frame@^7.22.13":
|
||||
version "7.22.13"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e"
|
||||
integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
|
||||
dependencies:
|
||||
"@babel/highlight" "^7.22.13"
|
||||
chalk "^2.4.2"
|
||||
|
||||
"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.18.8", "@babel/compat-data@^7.20.0", "@babel/compat-data@^7.20.1":
|
||||
version "7.20.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.1.tgz#f2e6ef7790d8c8dbf03d379502dcc246dcce0b30"
|
||||
|
|
@ -69,7 +77,7 @@
|
|||
json5 "^2.2.1"
|
||||
semver "^6.3.0"
|
||||
|
||||
"@babel/generator@^7.18.9", "@babel/generator@^7.20.1", "@babel/generator@^7.20.2", "@babel/generator@^7.7.2":
|
||||
"@babel/generator@^7.18.9", "@babel/generator@^7.20.2", "@babel/generator@^7.7.2":
|
||||
version "7.20.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.4.tgz#4d9f8f0c30be75fd90a0562099a26e5839602ab8"
|
||||
integrity sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==
|
||||
|
|
@ -78,6 +86,16 @@
|
|||
"@jridgewell/gen-mapping" "^0.3.2"
|
||||
jsesc "^2.5.1"
|
||||
|
||||
"@babel/generator@^7.23.0":
|
||||
version "7.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420"
|
||||
integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==
|
||||
dependencies:
|
||||
"@babel/types" "^7.23.0"
|
||||
"@jridgewell/gen-mapping" "^0.3.2"
|
||||
"@jridgewell/trace-mapping" "^0.3.17"
|
||||
jsesc "^2.5.1"
|
||||
|
||||
"@babel/helper-annotate-as-pure@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb"
|
||||
|
|
@ -141,6 +159,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
|
||||
integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
|
||||
|
||||
"@babel/helper-environment-visitor@^7.22.20":
|
||||
version "7.22.20"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
|
||||
integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
|
||||
|
||||
"@babel/helper-explode-assignable-expression@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096"
|
||||
|
|
@ -156,6 +179,14 @@
|
|||
"@babel/template" "^7.18.10"
|
||||
"@babel/types" "^7.19.0"
|
||||
|
||||
"@babel/helper-function-name@^7.23.0":
|
||||
version "7.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
|
||||
integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
|
||||
dependencies:
|
||||
"@babel/template" "^7.22.15"
|
||||
"@babel/types" "^7.23.0"
|
||||
|
||||
"@babel/helper-hoist-variables@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
|
||||
|
|
@ -163,6 +194,13 @@
|
|||
dependencies:
|
||||
"@babel/types" "^7.18.6"
|
||||
|
||||
"@babel/helper-hoist-variables@^7.22.5":
|
||||
version "7.22.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
|
||||
integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
|
||||
dependencies:
|
||||
"@babel/types" "^7.22.5"
|
||||
|
||||
"@babel/helper-member-expression-to-functions@^7.18.9":
|
||||
version "7.18.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815"
|
||||
|
|
@ -245,16 +283,33 @@
|
|||
dependencies:
|
||||
"@babel/types" "^7.18.6"
|
||||
|
||||
"@babel/helper-split-export-declaration@^7.22.6":
|
||||
version "7.22.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
|
||||
integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
|
||||
dependencies:
|
||||
"@babel/types" "^7.22.5"
|
||||
|
||||
"@babel/helper-string-parser@^7.19.4":
|
||||
version "7.19.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63"
|
||||
integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
|
||||
|
||||
"@babel/helper-string-parser@^7.22.5":
|
||||
version "7.22.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
|
||||
integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
|
||||
version "7.19.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
|
||||
integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.22.20":
|
||||
version "7.22.20"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
|
||||
integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
|
||||
|
||||
"@babel/helper-validator-option@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8"
|
||||
|
|
@ -288,11 +343,25 @@
|
|||
chalk "^2.0.0"
|
||||
js-tokens "^4.0.0"
|
||||
|
||||
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.18.9", "@babel/parser@^7.20.1", "@babel/parser@^7.20.2":
|
||||
"@babel/highlight@^7.22.13":
|
||||
version "7.22.20"
|
||||
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54"
|
||||
integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^7.22.20"
|
||||
chalk "^2.4.2"
|
||||
js-tokens "^4.0.0"
|
||||
|
||||
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.18.9", "@babel/parser@^7.20.2":
|
||||
version "7.20.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.3.tgz#5358cf62e380cf69efcb87a7bb922ff88bfac6e2"
|
||||
integrity sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==
|
||||
|
||||
"@babel/parser@^7.22.15", "@babel/parser@^7.23.0":
|
||||
version "7.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
|
||||
integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
|
||||
|
||||
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2"
|
||||
|
|
@ -1178,19 +1247,28 @@
|
|||
"@babel/parser" "^7.18.10"
|
||||
"@babel/types" "^7.18.10"
|
||||
|
||||
"@babel/traverse@^7.18.9", "@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.20.1", "@babel/traverse@^7.7.2":
|
||||
version "7.20.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.1.tgz#9b15ccbf882f6d107eeeecf263fbcdd208777ec8"
|
||||
integrity sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==
|
||||
"@babel/template@^7.22.15":
|
||||
version "7.22.15"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
|
||||
integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.18.6"
|
||||
"@babel/generator" "^7.20.1"
|
||||
"@babel/helper-environment-visitor" "^7.18.9"
|
||||
"@babel/helper-function-name" "^7.19.0"
|
||||
"@babel/helper-hoist-variables" "^7.18.6"
|
||||
"@babel/helper-split-export-declaration" "^7.18.6"
|
||||
"@babel/parser" "^7.20.1"
|
||||
"@babel/types" "^7.20.0"
|
||||
"@babel/code-frame" "^7.22.13"
|
||||
"@babel/parser" "^7.22.15"
|
||||
"@babel/types" "^7.22.15"
|
||||
|
||||
"@babel/traverse@^7.18.9", "@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.20.1", "@babel/traverse@^7.7.2":
|
||||
version "7.23.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8"
|
||||
integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.22.13"
|
||||
"@babel/generator" "^7.23.0"
|
||||
"@babel/helper-environment-visitor" "^7.22.20"
|
||||
"@babel/helper-function-name" "^7.23.0"
|
||||
"@babel/helper-hoist-variables" "^7.22.5"
|
||||
"@babel/helper-split-export-declaration" "^7.22.6"
|
||||
"@babel/parser" "^7.23.0"
|
||||
"@babel/types" "^7.23.0"
|
||||
debug "^4.1.0"
|
||||
globals "^11.1.0"
|
||||
|
||||
|
|
@ -1203,6 +1281,15 @@
|
|||
"@babel/helper-validator-identifier" "^7.19.1"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0":
|
||||
version "7.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
|
||||
integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.22.5"
|
||||
"@babel/helper-validator-identifier" "^7.22.20"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@bcoe/v8-coverage@^0.2.3":
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue