diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 263dd3c390..f68a877923 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -80,14 +80,12 @@ Rails/WhereExists: - 'app/lib/activitypub/activity/create.rb' - 'app/lib/delivery_failure_tracker.rb' - 'app/lib/feed_manager.rb' - - 'app/lib/status_cache_hydrator.rb' - 'app/lib/suspicious_sign_in_detector.rb' - 'app/models/poll.rb' - 'app/models/session_activation.rb' - 'app/models/status.rb' - 'app/policies/status_policy.rb' - 'app/serializers/rest/announcement_serializer.rb' - - 'app/serializers/rest/tag_serializer.rb' - 'app/services/activitypub/fetch_remote_status_service.rb' - 'app/services/vote_service.rb' - 'app/validators/reaction_validator.rb' diff --git a/Gemfile.lock b/Gemfile.lock index 6cf0504b51..93931d8724 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -150,7 +150,7 @@ GEM erubi (~> 1.4) parser (>= 2.4) smart_properties - bigdecimal (3.1.5) + bigdecimal (3.1.6) bindata (2.4.15) binding_of_caller (1.0.0) debug_inspector (>= 0.0.1) @@ -398,12 +398,12 @@ GEM activerecord kaminari-core (= 1.2.2) kaminari-core (1.2.2) - kt-paperclip (7.2.1) + kt-paperclip (7.2.2) activemodel (>= 4.2.0) activesupport (>= 4.2.0) marcel (~> 1.0.1) mime-types - terrapin (~> 0.6.0) + terrapin (>= 0.6.0, < 2.0) language_server-protocol (3.17.0.3) launchy (2.5.2) addressable (~> 2.8) @@ -600,8 +600,8 @@ GEM rdf (3.3.1) bcp47_spec (~> 0.2) link_header (~> 0.0, >= 0.0.8) - rdf-normalize (0.6.1) - rdf (~> 3.2) + rdf-normalize (0.7.0) + rdf (~> 3.3) rdoc (6.6.2) psych (>= 4.0.0) redcarpet (3.6.0) diff --git a/app/controllers/admin/action_logs_controller.rb b/app/controllers/admin/action_logs_controller.rb index 37a00ad225..8b8e83fde7 100644 --- a/app/controllers/admin/action_logs_controller.rb +++ b/app/controllers/admin/action_logs_controller.rb @@ -6,7 +6,7 @@ module Admin def index authorize :audit_log, :index? - @auditable_accounts = Account.where(id: Admin::ActionLog.select('distinct account_id')).select(:id, :username) + @auditable_accounts = Account.auditable.select(:id, :username) end private diff --git a/app/controllers/api/v1/accounts/follower_accounts_controller.rb b/app/controllers/api/v1/accounts/follower_accounts_controller.rb index 21b1095f18..d6a5a7176d 100644 --- a/app/controllers/api/v1/accounts/follower_accounts_controller.rb +++ b/app/controllers/api/v1/accounts/follower_accounts_controller.rb @@ -21,7 +21,7 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController return [] if hide_results? scope = default_accounts - scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil? || current_account.id == @account.id + scope = scope.not_excluded_by_account(current_account) unless current_account.nil? || current_account.id == @account.id scope.merge(paginated_follows).to_a end diff --git a/app/controllers/api/v1/accounts/following_accounts_controller.rb b/app/controllers/api/v1/accounts/following_accounts_controller.rb index 1db521f79c..b8578ef539 100644 --- a/app/controllers/api/v1/accounts/following_accounts_controller.rb +++ b/app/controllers/api/v1/accounts/following_accounts_controller.rb @@ -21,7 +21,7 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController return [] if hide_results? scope = default_accounts - scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil? || current_account.id == @account.id + scope = scope.not_excluded_by_account(current_account) unless current_account.nil? || current_account.id == @account.id scope.merge(paginated_follows).to_a end diff --git a/app/helpers/jsonld_helper.rb b/app/helpers/jsonld_helper.rb index ce3ff094f6..b3d0d032c4 100644 --- a/app/helpers/jsonld_helper.rb +++ b/app/helpers/jsonld_helper.rb @@ -155,7 +155,7 @@ module JsonLdHelper end end - def fetch_resource(uri, id, on_behalf_of = nil) + def fetch_resource(uri, id, on_behalf_of = nil, request_options: {}) unless id json = fetch_resource_without_id_validation(uri, on_behalf_of) @@ -164,14 +164,14 @@ module JsonLdHelper uri = json['id'] end - json = fetch_resource_without_id_validation(uri, on_behalf_of) + json = fetch_resource_without_id_validation(uri, on_behalf_of, request_options: request_options) json.present? && json['id'] == uri ? json : nil end - def fetch_resource_without_id_validation(uri, on_behalf_of = nil, raise_on_temporary_error = false) + def fetch_resource_without_id_validation(uri, on_behalf_of = nil, raise_on_temporary_error = false, request_options: {}) on_behalf_of ||= Account.representative - build_request(uri, on_behalf_of).perform do |response| + build_request(uri, on_behalf_of, options: request_options).perform do |response| raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response) || !raise_on_temporary_error body_to_json(response.body_with_limit) if response.code == 200 @@ -204,8 +204,8 @@ module JsonLdHelper response.code == 501 || ((400...500).cover?(response.code) && ![401, 408, 429].include?(response.code)) end - def build_request(uri, on_behalf_of = nil) - Request.new(:get, uri).tap do |request| + def build_request(uri, on_behalf_of = nil, options: {}) + Request.new(:get, uri, **options).tap do |request| request.on_behalf_of(on_behalf_of) if on_behalf_of request.add_headers('Accept' => 'application/activity+json, application/ld+json') end diff --git a/app/javascript/mastodon/store/typed_functions.ts b/app/javascript/mastodon/store/typed_functions.ts index 46a10b8b47..4859b82651 100644 --- a/app/javascript/mastodon/store/typed_functions.ts +++ b/app/javascript/mastodon/store/typed_functions.ts @@ -1,12 +1,11 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; -import type { TypedUseSelectorHook } from 'react-redux'; // eslint-disable-next-line @typescript-eslint/no-restricted-imports import { useDispatch, useSelector } from 'react-redux'; import type { AppDispatch, RootState } from './store'; -export const useAppDispatch: () => AppDispatch = useDispatch; -export const useAppSelector: TypedUseSelectorHook = useSelector; +export const useAppDispatch = useDispatch.withTypes(); +export const useAppSelector = useSelector.withTypes(); export const createAppAsyncThunk = createAsyncThunk.withTypes<{ state: RootState; diff --git a/app/javascript/styles/mailer.scss b/app/javascript/styles/mailer.scss index bd220bb1a8..a2cbb494b4 100644 --- a/app/javascript/styles/mailer.scss +++ b/app/javascript/styles/mailer.scss @@ -100,9 +100,8 @@ table + p { border-top-right-radius: 12px; height: 140px; vertical-align: bottom; - background-color: #f3f2f5; - background-position: center; - background-size: cover; + background-position: center !important; + background-size: cover !important; } .email-account-banner-inner-td { diff --git a/app/lib/status_cache_hydrator.rb b/app/lib/status_cache_hydrator.rb index 45b50cb379..34f6199ec0 100644 --- a/app/lib/status_cache_hydrator.rb +++ b/app/lib/status_cache_hydrator.rb @@ -26,11 +26,11 @@ class StatusCacheHydrator def hydrate_non_reblog_payload(empty_payload, account_id) empty_payload.tap do |payload| - payload[:favourited] = Favourite.where(account_id: account_id, status_id: @status.id).exists? - payload[:reblogged] = Status.where(account_id: account_id, reblog_of_id: @status.id).exists? - payload[:muted] = ConversationMute.where(account_id: account_id, conversation_id: @status.conversation_id).exists? - payload[:bookmarked] = Bookmark.where(account_id: account_id, status_id: @status.id).exists? - payload[:pinned] = StatusPin.where(account_id: account_id, status_id: @status.id).exists? if @status.account_id == account_id + payload[:favourited] = Favourite.exists?(account_id: account_id, status_id: @status.id) + payload[:reblogged] = Status.exists?(account_id: account_id, reblog_of_id: @status.id) + payload[:muted] = ConversationMute.exists?(account_id: account_id, conversation_id: @status.conversation_id) + payload[:bookmarked] = Bookmark.exists?(account_id: account_id, status_id: @status.id) + payload[:pinned] = StatusPin.exists?(account_id: account_id, status_id: @status.id) if @status.account_id == account_id payload[:filtered] = mapped_applied_custom_filter(account_id, @status) if payload[:poll] @@ -51,11 +51,11 @@ class StatusCacheHydrator # used to create the status, we need to hydrate it here too payload[:reblog][:application] = payload_reblog_application if payload[:reblog][:application].nil? && @status.reblog.account_id == account_id - payload[:reblog][:favourited] = Favourite.where(account_id: account_id, status_id: @status.reblog_of_id).exists? - payload[:reblog][:reblogged] = Status.where(account_id: account_id, reblog_of_id: @status.reblog_of_id).exists? - payload[:reblog][:muted] = ConversationMute.where(account_id: account_id, conversation_id: @status.reblog.conversation_id).exists? - payload[:reblog][:bookmarked] = Bookmark.where(account_id: account_id, status_id: @status.reblog_of_id).exists? - payload[:reblog][:pinned] = StatusPin.where(account_id: account_id, status_id: @status.reblog_of_id).exists? if @status.reblog.account_id == account_id + payload[:reblog][:favourited] = Favourite.exists?(account_id: account_id, status_id: @status.reblog_of_id) + payload[:reblog][:reblogged] = Status.exists?(account_id: account_id, reblog_of_id: @status.reblog_of_id) + payload[:reblog][:muted] = ConversationMute.exists?(account_id: account_id, conversation_id: @status.reblog.conversation_id) + payload[:reblog][:bookmarked] = Bookmark.exists?(account_id: account_id, status_id: @status.reblog_of_id) + payload[:reblog][:pinned] = StatusPin.exists?(account_id: account_id, status_id: @status.reblog_of_id) if @status.reblog.account_id == account_id payload[:reblog][:filtered] = payload[:filtered] if payload[:reblog][:poll] diff --git a/app/models/account.rb b/app/models/account.rb index 5264631785..83f29dc794 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -130,6 +130,7 @@ class Account < ApplicationRecord scope :matches_username, ->(value) { where('lower((username)::text) LIKE lower(?)', "#{value}%") } scope :matches_display_name, ->(value) { where(arel_table[:display_name].matches("#{value}%")) } scope :without_unapproved, -> { left_outer_joins(:user).merge(User.approved.confirmed).or(remote) } + scope :auditable, -> { where(id: Admin::ActionLog.select(:account_id).distinct) } scope :searchable, -> { without_unapproved.without_suspended.where(moved_to_account_id: nil) } scope :discoverable, -> { searchable.without_silenced.where(discoverable: true).joins(:account_stat) } scope :by_recent_status, -> { includes(:account_stat).merge(AccountStat.order('last_status_at DESC NULLS LAST')).references(:account_stat) } diff --git a/app/models/admin/action_log_filter.rb b/app/models/admin/action_log_filter.rb index d413cb386d..f581af74e8 100644 --- a/app/models/admin/action_log_filter.rb +++ b/app/models/admin/action_log_filter.rb @@ -72,7 +72,7 @@ class Admin::ActionLogFilter end def results - scope = latest_action_logs.includes(:target) + scope = latest_action_logs.includes(:target, :account) params.each do |key, value| next if key.to_s == 'page' diff --git a/app/serializers/rest/tag_serializer.rb b/app/serializers/rest/tag_serializer.rb index 7801e77d1f..017b572718 100644 --- a/app/serializers/rest/tag_serializer.rb +++ b/app/serializers/rest/tag_serializer.rb @@ -19,7 +19,7 @@ class REST::TagSerializer < ActiveModel::Serializer if instance_options && instance_options[:relationships] instance_options[:relationships].following_map[object.id] || false else - TagFollow.where(tag_id: object.id, account_id: current_user.account_id).exists? + TagFollow.exists?(tag_id: object.id, account_id: current_user.account_id) end end diff --git a/app/services/activitypub/fetch_replies_service.rb b/app/services/activitypub/fetch_replies_service.rb index b5c7759ec5..a9dd327e96 100644 --- a/app/services/activitypub/fetch_replies_service.rb +++ b/app/services/activitypub/fetch_replies_service.rb @@ -37,7 +37,20 @@ class ActivityPub::FetchRepliesService < BaseService return unless @allow_synchronous_requests return if non_matching_uri_hosts?(@account.uri, collection_or_uri) - fetch_resource_without_id_validation(collection_or_uri, nil, true) + # NOTE: For backward compatibility reasons, Mastodon signs outgoing + # queries incorrectly by default. + # + # While this is relevant for all URLs with query strings, this is + # the only code path where this happens in practice. + # + # Therefore, retry with correct signatures if this fails. + begin + fetch_resource_without_id_validation(collection_or_uri, nil, true) + rescue Mastodon::UnexpectedResponseError => e + raise unless e.response && e.response.code == 401 && Addressable::URI.parse(collection_or_uri).query.present? + + fetch_resource_without_id_validation(collection_or_uri, nil, true, request_options: { with_query_string: true }) + end end def filtered_replies diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index d360d934d6..8488ccea45 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -835,6 +835,25 @@ RSpec.describe Account do end describe 'scopes' do + describe 'auditable' do + let!(:alice) { Fabricate :account } + let!(:bob) { Fabricate :account } + + before do + 2.times { Fabricate :action_log, account: alice } + end + + it 'returns distinct accounts with action log records' do + results = described_class.auditable + + expect(results.size) + .to eq(1) + expect(results) + .to include(alice) + .and not_include(bob) + end + end + describe 'alphabetic' do it 'sorts by alphabetic order of domain and username' do matches = [ diff --git a/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb b/spec/requests/api/v1/accounts/follower_accounts_spec.rb similarity index 69% rename from spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb rename to spec/requests/api/v1/accounts/follower_accounts_spec.rb index 510a47566b..7ff92d6a48 100644 --- a/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb +++ b/spec/requests/api/v1/accounts/follower_accounts_spec.rb @@ -2,11 +2,11 @@ require 'rails_helper' -describe Api::V1::Accounts::FollowerAccountsController do - render_views - +describe 'API V1 Accounts FollowerAccounts' do let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:scopes) { 'read:accounts' } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } let(:account) { Fabricate(:account) } let(:alice) { Fabricate(:account) } let(:bob) { Fabricate(:account) } @@ -14,12 +14,11 @@ describe Api::V1::Accounts::FollowerAccountsController do before do alice.follow!(account) bob.follow!(account) - allow(controller).to receive(:doorkeeper_token) { token } end - describe 'GET #index' do + describe 'GET /api/v1/accounts/:acount_id/followers' do it 'returns accounts following the given account', :aggregate_failures do - get :index, params: { account_id: account.id, limit: 2 } + get "/api/v1/accounts/#{account.id}/followers", params: { limit: 2 }, headers: headers expect(response).to have_http_status(200) expect(body_as_json.size).to eq 2 @@ -28,7 +27,7 @@ describe Api::V1::Accounts::FollowerAccountsController do it 'does not return blocked users', :aggregate_failures do user.account.block!(bob) - get :index, params: { account_id: account.id, limit: 2 } + get "/api/v1/accounts/#{account.id}/followers", params: { limit: 2 }, headers: headers expect(response).to have_http_status(200) expect(body_as_json.size).to eq 1 @@ -41,7 +40,7 @@ describe Api::V1::Accounts::FollowerAccountsController do end it 'hides results' do - get :index, params: { account_id: account.id, limit: 2 } + get "/api/v1/accounts/#{account.id}/followers", params: { limit: 2 }, headers: headers expect(body_as_json.size).to eq 0 end end @@ -51,7 +50,7 @@ describe Api::V1::Accounts::FollowerAccountsController do it 'returns all accounts, including muted accounts' do account.mute!(bob) - get :index, params: { account_id: account.id, limit: 2 } + get "/api/v1/accounts/#{account.id}/followers", params: { limit: 2 }, headers: headers expect(body_as_json.size).to eq 2 expect([body_as_json[0][:id], body_as_json[1][:id]]).to contain_exactly(alice.id.to_s, bob.id.to_s) diff --git a/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb b/spec/requests/api/v1/accounts/following_accounts_spec.rb similarity index 69% rename from spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb rename to spec/requests/api/v1/accounts/following_accounts_spec.rb index a7d07a6bec..b343a48654 100644 --- a/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb +++ b/spec/requests/api/v1/accounts/following_accounts_spec.rb @@ -2,11 +2,11 @@ require 'rails_helper' -describe Api::V1::Accounts::FollowingAccountsController do - render_views - +describe 'API V1 Accounts FollowingAccounts' do let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:scopes) { 'read:accounts' } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } let(:account) { Fabricate(:account) } let(:alice) { Fabricate(:account) } let(:bob) { Fabricate(:account) } @@ -14,12 +14,11 @@ describe Api::V1::Accounts::FollowingAccountsController do before do account.follow!(alice) account.follow!(bob) - allow(controller).to receive(:doorkeeper_token) { token } end - describe 'GET #index' do + describe 'GET /api/v1/accounts/:account_id/following' do it 'returns accounts followed by the given account', :aggregate_failures do - get :index, params: { account_id: account.id, limit: 2 } + get "/api/v1/accounts/#{account.id}/following", params: { limit: 2 }, headers: headers expect(response).to have_http_status(200) expect(body_as_json.size).to eq 2 @@ -28,7 +27,7 @@ describe Api::V1::Accounts::FollowingAccountsController do it 'does not return blocked users', :aggregate_failures do user.account.block!(bob) - get :index, params: { account_id: account.id, limit: 2 } + get "/api/v1/accounts/#{account.id}/following", params: { limit: 2 }, headers: headers expect(response).to have_http_status(200) expect(body_as_json.size).to eq 1 @@ -41,7 +40,7 @@ describe Api::V1::Accounts::FollowingAccountsController do end it 'hides results' do - get :index, params: { account_id: account.id, limit: 2 } + get "/api/v1/accounts/#{account.id}/following", params: { limit: 2 }, headers: headers expect(body_as_json.size).to eq 0 end end @@ -51,7 +50,7 @@ describe Api::V1::Accounts::FollowingAccountsController do it 'returns all accounts, including muted accounts' do account.mute!(bob) - get :index, params: { account_id: account.id, limit: 2 } + get "/api/v1/accounts/#{account.id}/following", params: { limit: 2 }, headers: headers expect(body_as_json.size).to eq 2 expect([body_as_json[0][:id], body_as_json[1][:id]]).to contain_exactly(alice.id.to_s, bob.id.to_s) diff --git a/yarn.lock b/yarn.lock index 4167b2c492..0344360125 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3786,16 +3786,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:6.9.1": - version: 6.9.1 - resolution: "@typescript-eslint/scope-manager@npm:6.9.1" - dependencies: - "@typescript-eslint/types": "npm:6.9.1" - "@typescript-eslint/visitor-keys": "npm:6.9.1" - checksum: 53fa7c3813d22b119e464f9b6d7d23407dfe103ee8ad2dcacf9ad6d656fda20e2bb3346df39e62b0e6b6ce71572ce5838071c5d2cca6daa4e0ce117ff22eafe5 - languageName: node - linkType: hard - "@typescript-eslint/type-utils@npm:6.19.0": version: 6.19.0 resolution: "@typescript-eslint/type-utils@npm:6.19.0" @@ -3820,13 +3810,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:6.9.1": - version: 6.9.1 - resolution: "@typescript-eslint/types@npm:6.9.1" - checksum: 4ba21ba18e256da210a4caedfbc5d4927cf8cb4f2c4d74f8ccc865576f3659b974e79119d3c94db2b68a4cec9cd687e43971d355450b7082d6d1736a5dd6db85 - languageName: node - linkType: hard - "@typescript-eslint/typescript-estree@npm:6.19.0": version: 6.19.0 resolution: "@typescript-eslint/typescript-estree@npm:6.19.0" @@ -3846,25 +3829,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:6.9.1": - version: 6.9.1 - resolution: "@typescript-eslint/typescript-estree@npm:6.9.1" - dependencies: - "@typescript-eslint/types": "npm:6.9.1" - "@typescript-eslint/visitor-keys": "npm:6.9.1" - debug: "npm:^4.3.4" - globby: "npm:^11.1.0" - is-glob: "npm:^4.0.3" - semver: "npm:^7.5.4" - ts-api-utils: "npm:^1.0.1" - peerDependenciesMeta: - typescript: - optional: true - checksum: 850b1865a90107879186c3f2969968a2c08fc6fcc56d146483c297cf5be376e33d505ac81533ba8e8103ca4d2edfea7d21b178de9e52217f7ee2922f51a445fa - languageName: node - linkType: hard - -"@typescript-eslint/utils@npm:6.19.0": +"@typescript-eslint/utils@npm:6.19.0, @typescript-eslint/utils@npm:^6.5.0": version: 6.19.0 resolution: "@typescript-eslint/utils@npm:6.19.0" dependencies: @@ -3881,23 +3846,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:^6.5.0": - version: 6.9.1 - resolution: "@typescript-eslint/utils@npm:6.9.1" - dependencies: - "@eslint-community/eslint-utils": "npm:^4.4.0" - "@types/json-schema": "npm:^7.0.12" - "@types/semver": "npm:^7.5.0" - "@typescript-eslint/scope-manager": "npm:6.9.1" - "@typescript-eslint/types": "npm:6.9.1" - "@typescript-eslint/typescript-estree": "npm:6.9.1" - semver: "npm:^7.5.4" - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - checksum: 3d329d54c3d155ed29e2b456a602aef76bda1b88dfcf847145849362e4ddefabe5c95de236de750d08d5da9bedcfb2131bdfd784ce4eb87cf82728f0b6662033 - languageName: node - linkType: hard - "@typescript-eslint/visitor-keys@npm:6.19.0": version: 6.19.0 resolution: "@typescript-eslint/visitor-keys@npm:6.19.0" @@ -3908,16 +3856,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:6.9.1": - version: 6.9.1 - resolution: "@typescript-eslint/visitor-keys@npm:6.9.1" - dependencies: - "@typescript-eslint/types": "npm:6.9.1" - eslint-visitor-keys: "npm:^3.4.1" - checksum: ac5f375a177add30489e5b63cafa8d82a196b33624bb36418422ebe0d7973b3ba550dc7e0dda36ea75a94cf9b200b4fb5f5fb4d77c027fd801201c1a269d343b - languageName: node - linkType: hard - "@ungap/structured-clone@npm:^1.2.0": version: 1.2.0 resolution: "@ungap/structured-clone@npm:1.2.0" @@ -9377,7 +9315,7 @@ __metadata: languageName: node linkType: hard -"intl-messageformat@npm:10.5.10": +"intl-messageformat@npm:10.5.10, intl-messageformat@npm:^10.3.5": version: 10.5.10 resolution: "intl-messageformat@npm:10.5.10" dependencies: @@ -9389,18 +9327,6 @@ __metadata: languageName: node linkType: hard -"intl-messageformat@npm:^10.3.5": - version: 10.5.8 - resolution: "intl-messageformat@npm:10.5.8" - dependencies: - "@formatjs/ecma402-abstract": "npm:1.18.0" - "@formatjs/fast-memoize": "npm:2.2.0" - "@formatjs/icu-messageformat-parser": "npm:2.7.3" - tslib: "npm:^2.4.0" - checksum: 1d2854aae8471ec48165ca265760d6c5b1814eca831c88db698eb29b5ed20bee21ca8533090c9d28d9c6f1d844dda210b0bc58a2e036446158fae0845e5eed4f - languageName: node - linkType: hard - "invariant@npm:^2.2.2, invariant@npm:^2.2.4": version: 2.2.4 resolution: "invariant@npm:2.2.4" @@ -13897,8 +13823,8 @@ __metadata: linkType: hard "react-redux@npm:^9.0.4": - version: 9.0.4 - resolution: "react-redux@npm:9.0.4" + version: 9.1.0 + resolution: "react-redux@npm:9.1.0" dependencies: "@types/use-sync-external-store": "npm:^0.0.3" use-sync-external-store: "npm:^1.0.0" @@ -13914,7 +13840,7 @@ __metadata: optional: true redux: optional: true - checksum: 23af10014b129aeb051de729bde01de21175170b860deefb7ad83483feab5816253f770a4cea93333fc22a53ac9ac699b27f5c3705c388dab53dbcb2906a571a + checksum: 53161b5dc4d109020fbc42d26906ace92fed9ba1d7ab6274af60e9c0684583d20d1c8ec6d58601ac7b833c6468a652bbf3d4a102149d1793cb8a28b05b042f73 languageName: node linkType: hard @@ -14775,15 +14701,15 @@ __metadata: linkType: hard "sass@npm:^1.62.1": - version: 1.69.7 - resolution: "sass@npm:1.69.7" + version: 1.70.0 + resolution: "sass@npm:1.70.0" dependencies: chokidar: "npm:>=3.0.0 <4.0.0" immutable: "npm:^4.0.0" source-map-js: "npm:>=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 773d0938e7d4ff3972d3fda3132f34fe98a2f712e028a58e28fecd615434795eff3266eddc38d5e13f03b90c0d6360d0e737b30bff2949a47280c64a18e0fb18 + checksum: 7c309ee1c096d591746d122da9f1ebd65b4c4b3a60c2cc0ec720fd98fe1205fa8b44c9f563d113b9fdfeb25af1e32ec9b3e048bd4b8e05d267f020953bd7baf0 languageName: node linkType: hard