~cytrogen/masto-fe

e193c848fefe465a57e39634d65fa6a012197234 — Claire 2 years ago 7384015 + 97e4011
Merge commit '97e4011c3ce31c6d492d5f103e95a35b6ebdc9bd' into glitch-soc/merge-upstream

Conflicts:
- `config/initializers/content_security_policy.rb`:
  Upstream added some code to add the Identity Provider's sign-in endpoint to
  the `form-action` Content Security Policy directive but our version of the
  file is pretty different.
  Ported the change.
39 files changed, 318 insertions(+), 326 deletions(-)

M .github/workflows/build-container-image.yml
M .github/workflows/build-push-pr.yml
M .github/workflows/bundler-audit.yml
M .github/workflows/check-i18n.yml
M .github/workflows/codeql.yml
M .github/workflows/crowdin-download.yml
M .github/workflows/crowdin-upload.yml
M .github/workflows/lint-css.yml
M .github/workflows/lint-haml.yml
M .github/workflows/lint-js.yml
M .github/workflows/lint-json.yml
M .github/workflows/lint-md.yml
M .github/workflows/lint-ruby.yml
M .github/workflows/lint-yml.yml
M .github/workflows/test-js.yml
M .github/workflows/test-migrations-one-step.yml
M .github/workflows/test-migrations-two-step.yml
M .github/workflows/test-ruby.yml
M Gemfile.lock
M app/controllers/concerns/web_app_controller_concern.rb
D app/javascript/mastodon/actions/account_notes.js
A app/javascript/mastodon/actions/account_notes.ts
M app/javascript/mastodon/actions/notifications.js
R app/javascript/mastodon/{api.js => api.ts}
M app/javascript/mastodon/features/account/containers/account_note_container.js
M app/javascript/mastodon/main.jsx
M app/javascript/mastodon/reducers/relationships.js
M app/javascript/mastodon/store/index.ts
M app/javascript/mastodon/store/middlewares/errors.ts
M app/javascript/mastodon/store/middlewares/loading_bar.ts
M app/javascript/mastodon/store/middlewares/sounds.ts
A app/javascript/mastodon/store/store.ts
A app/javascript/mastodon/store/typed_functions.ts
M app/javascript/styles/mastodon/components.scss
M app/serializers/initial_state_serializer.rb
M app/services/notify_service.rb
M config/initializers/content_security_policy.rb
M lib/mastodon/cli/search.rb
M yarn.lock
M .github/workflows/build-container-image.yml => .github/workflows/build-container-image.yml +1 -1
@@ 24,7 24,7 @@ jobs:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3
      - uses: actions/checkout@v4

      - uses: docker/setup-qemu-action@v2
        if: contains(inputs.platforms, 'linux/arm64') && !inputs.use_native_arm64_builder

M .github/workflows/build-push-pr.yml => .github/workflows/build-push-pr.yml +1 -1
@@ 18,7 18,7 @@ jobs:
    steps:
      # Repository needs to be cloned so `git rev-parse` below works
      - name: Clone repository
        uses: actions/checkout@v3
        uses: actions/checkout@v4
      - id: version_vars
        run: |
          echo mastodon_version_metadata=pr-${{ github.event.pull_request.number }}-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT

M .github/workflows/bundler-audit.yml => .github/workflows/bundler-audit.yml +1 -1
@@ 25,7 25,7 @@ jobs:

    steps:
      - name: Clone repository
        uses: actions/checkout@v3
        uses: actions/checkout@v4

      - name: Install native Ruby dependencies
        run: sudo apt-get install -y libicu-dev libidn11-dev

M .github/workflows/check-i18n.yml => .github/workflows/check-i18n.yml +1 -1
@@ 17,7 17,7 @@ jobs:
    runs-on: ubuntu-22.04

    steps:
      - uses: actions/checkout@v3
      - uses: actions/checkout@v4

      - name: Install system dependencies
        run: |

M .github/workflows/codeql.yml => .github/workflows/codeql.yml +1 -1
@@ 27,7 27,7 @@ jobs:

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        uses: actions/checkout@v4

      # Initializes the CodeQL tools for scanning.
      - name: Initialize CodeQL

M .github/workflows/crowdin-download.yml => .github/workflows/crowdin-download.yml +1 -1
@@ 14,7 14,7 @@ jobs:

    steps:
      - name: Checkout
        uses: actions/checkout@v3
        uses: actions/checkout@v4

      - name: Increase Git http.postBuffer
        # This is needed due to a bug in Ubuntu's cURL version?

M .github/workflows/crowdin-upload.yml => .github/workflows/crowdin-upload.yml +1 -1
@@ 20,7 20,7 @@ jobs:

    steps:
      - name: Checkout
        uses: actions/checkout@v3
        uses: actions/checkout@v4

      - name: crowdin action
        uses: crowdin/github-action@v1

M .github/workflows/lint-css.yml => .github/workflows/lint-css.yml +1 -1
@@ 33,7 33,7 @@ jobs:

    steps:
      - name: Clone repository
        uses: actions/checkout@v3
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v3

M .github/workflows/lint-haml.yml => .github/workflows/lint-haml.yml +1 -1
@@ 28,7 28,7 @@ jobs:
    runs-on: ubuntu-latest
    steps:
      - name: Clone repository
        uses: actions/checkout@v3
        uses: actions/checkout@v4

      - name: Install native Ruby dependencies
        run: |

M .github/workflows/lint-js.yml => .github/workflows/lint-js.yml +1 -1
@@ 37,7 37,7 @@ jobs:

    steps:
      - name: Clone repository
        uses: actions/checkout@v3
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v3

M .github/workflows/lint-json.yml => .github/workflows/lint-json.yml +1 -1
@@ 29,7 29,7 @@ jobs:

    steps:
      - name: Clone repository
        uses: actions/checkout@v3
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v3

M .github/workflows/lint-md.yml => .github/workflows/lint-md.yml +1 -1
@@ 29,7 29,7 @@ jobs:

    steps:
      - name: Clone repository
        uses: actions/checkout@v3
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v3

M .github/workflows/lint-ruby.yml => .github/workflows/lint-ruby.yml +1 -1
@@ 29,7 29,7 @@ jobs:

    steps:
      - name: Clone repository
        uses: actions/checkout@v3
        uses: actions/checkout@v4

      - name: Install native Ruby dependencies
        run: sudo apt-get install -y libicu-dev libidn11-dev

M .github/workflows/lint-yml.yml => .github/workflows/lint-yml.yml +1 -1
@@ 31,7 31,7 @@ jobs:

    steps:
      - name: Clone repository
        uses: actions/checkout@v3
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v3

M .github/workflows/test-js.yml => .github/workflows/test-js.yml +1 -1
@@ 33,7 33,7 @@ jobs:

    steps:
      - name: Clone repository
        uses: actions/checkout@v3
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v3

M .github/workflows/test-migrations-one-step.yml => .github/workflows/test-migrations-one-step.yml +1 -1
@@ 70,7 70,7 @@ jobs:
      BUNDLE_RETRY: 3

    steps:
      - uses: actions/checkout@v3
      - uses: actions/checkout@v4

      - name: Install native Ruby dependencies
        run: |

M .github/workflows/test-migrations-two-step.yml => .github/workflows/test-migrations-two-step.yml +1 -1
@@ 69,7 69,7 @@ jobs:
      BUNDLE_RETRY: 3

    steps:
      - uses: actions/checkout@v3
      - uses: actions/checkout@v4

      - name: Install native Ruby dependencies
        run: |

M .github/workflows/test-ruby.yml => .github/workflows/test-ruby.yml +4 -4
@@ 32,7 32,7 @@ jobs:
      SECRET_KEY_BASE: precompile_placeholder

    steps:
      - uses: actions/checkout@v3
      - uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v3


@@ 127,7 127,7 @@ jobs:
          - 3
          - 4
    steps:
      - uses: actions/checkout@v3
      - uses: actions/checkout@v4

      - uses: actions/download-artifact@v3
        with:


@@ 202,7 202,7 @@ jobs:
          - '.ruby-version'

    steps:
      - uses: actions/checkout@v3
      - uses: actions/checkout@v4

      - uses: actions/download-artifact@v3
        with:


@@ 315,7 315,7 @@ jobs:
          - '.ruby-version'

    steps:
      - uses: actions/checkout@v3
      - uses: actions/checkout@v4

      - uses: actions/download-artifact@v3
        with:

M Gemfile.lock => Gemfile.lock +55 -55
@@ 39,47 39,47 @@ GIT
GEM
  remote: https://rubygems.org/
  specs:
    actioncable (7.0.7.2)
      actionpack (= 7.0.7.2)
      activesupport (= 7.0.7.2)
    actioncable (7.0.8)
      actionpack (= 7.0.8)
      activesupport (= 7.0.8)
      nio4r (~> 2.0)
      websocket-driver (>= 0.6.1)
    actionmailbox (7.0.7.2)
      actionpack (= 7.0.7.2)
      activejob (= 7.0.7.2)
      activerecord (= 7.0.7.2)
      activestorage (= 7.0.7.2)
      activesupport (= 7.0.7.2)
    actionmailbox (7.0.8)
      actionpack (= 7.0.8)
      activejob (= 7.0.8)
      activerecord (= 7.0.8)
      activestorage (= 7.0.8)
      activesupport (= 7.0.8)
      mail (>= 2.7.1)
      net-imap
      net-pop
      net-smtp
    actionmailer (7.0.7.2)
      actionpack (= 7.0.7.2)
      actionview (= 7.0.7.2)
      activejob (= 7.0.7.2)
      activesupport (= 7.0.7.2)
    actionmailer (7.0.8)
      actionpack (= 7.0.8)
      actionview (= 7.0.8)
      activejob (= 7.0.8)
      activesupport (= 7.0.8)
      mail (~> 2.5, >= 2.5.4)
      net-imap
      net-pop
      net-smtp
      rails-dom-testing (~> 2.0)
    actionpack (7.0.7.2)
      actionview (= 7.0.7.2)
      activesupport (= 7.0.7.2)
    actionpack (7.0.8)
      actionview (= 7.0.8)
      activesupport (= 7.0.8)
      rack (~> 2.0, >= 2.2.4)
      rack-test (>= 0.6.3)
      rails-dom-testing (~> 2.0)
      rails-html-sanitizer (~> 1.0, >= 1.2.0)
    actiontext (7.0.7.2)
      actionpack (= 7.0.7.2)
      activerecord (= 7.0.7.2)
      activestorage (= 7.0.7.2)
      activesupport (= 7.0.7.2)
    actiontext (7.0.8)
      actionpack (= 7.0.8)
      activerecord (= 7.0.8)
      activestorage (= 7.0.8)
      activesupport (= 7.0.8)
      globalid (>= 0.6.0)
      nokogiri (>= 1.8.5)
    actionview (7.0.7.2)
      activesupport (= 7.0.7.2)
    actionview (7.0.8)
      activesupport (= 7.0.8)
      builder (~> 3.1)
      erubi (~> 1.4)
      rails-dom-testing (~> 2.0)


@@ 89,22 89,22 @@ GEM
      activemodel (>= 4.1, < 7.1)
      case_transform (>= 0.2)
      jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
    activejob (7.0.7.2)
      activesupport (= 7.0.7.2)
    activejob (7.0.8)
      activesupport (= 7.0.8)
      globalid (>= 0.3.6)
    activemodel (7.0.7.2)
      activesupport (= 7.0.7.2)
    activerecord (7.0.7.2)
      activemodel (= 7.0.7.2)
      activesupport (= 7.0.7.2)
    activestorage (7.0.7.2)
      actionpack (= 7.0.7.2)
      activejob (= 7.0.7.2)
      activerecord (= 7.0.7.2)
      activesupport (= 7.0.7.2)
    activemodel (7.0.8)
      activesupport (= 7.0.8)
    activerecord (7.0.8)
      activemodel (= 7.0.8)
      activesupport (= 7.0.8)
    activestorage (7.0.8)
      actionpack (= 7.0.8)
      activejob (= 7.0.8)
      activerecord (= 7.0.8)
      activesupport (= 7.0.8)
      marcel (~> 1.0)
      mini_mime (>= 1.1.0)
    activesupport (7.0.7.2)
    activesupport (7.0.8)
      concurrent-ruby (~> 1.0, >= 1.0.2)
      i18n (>= 1.6, < 2)
      minitest (>= 5.1)


@@ 409,7 409,7 @@ GEM
      activerecord
      kaminari-core (= 1.2.2)
    kaminari-core (1.2.2)
    kt-paperclip (7.2.0)
    kt-paperclip (7.2.1)
      activemodel (>= 4.2.0)
      activesupport (>= 4.2.0)
      marcel (~> 1.0.1)


@@ 556,20 556,20 @@ GEM
      rack
    rack-test (2.1.0)
      rack (>= 1.3)
    rails (7.0.7.2)
      actioncable (= 7.0.7.2)
      actionmailbox (= 7.0.7.2)
      actionmailer (= 7.0.7.2)
      actionpack (= 7.0.7.2)
      actiontext (= 7.0.7.2)
      actionview (= 7.0.7.2)
      activejob (= 7.0.7.2)
      activemodel (= 7.0.7.2)
      activerecord (= 7.0.7.2)
      activestorage (= 7.0.7.2)
      activesupport (= 7.0.7.2)
    rails (7.0.8)
      actioncable (= 7.0.8)
      actionmailbox (= 7.0.8)
      actionmailer (= 7.0.8)
      actionpack (= 7.0.8)
      actiontext (= 7.0.8)
      actionview (= 7.0.8)
      activejob (= 7.0.8)
      activemodel (= 7.0.8)
      activerecord (= 7.0.8)
      activestorage (= 7.0.8)
      activesupport (= 7.0.8)
      bundler (>= 1.15.0)
      railties (= 7.0.7.2)
      railties (= 7.0.8)
    rails-controller-testing (1.0.5)
      actionpack (>= 5.0.1.rc1)
      actionview (>= 5.0.1.rc1)


@@ 584,9 584,9 @@ GEM
    rails-i18n (7.0.7)
      i18n (>= 0.7, < 2)
      railties (>= 6.0.0, < 8)
    railties (7.0.7.2)
      actionpack (= 7.0.7.2)
      activesupport (= 7.0.7.2)
    railties (7.0.8)
      actionpack (= 7.0.8)
      activesupport (= 7.0.8)
      method_source
      rake (>= 12.2)
      thor (~> 1.0)


@@ 745,7 745,7 @@ GEM
      unicode-display_width (>= 1.1.1, < 3)
    terrapin (0.6.0)
      climate_control (>= 0.0.3, < 1.0)
    test-prof (1.2.2)
    test-prof (1.2.3)
    thor (1.2.2)
    tilt (2.2.0)
    timeout (0.4.0)

M app/controllers/concerns/web_app_controller_concern.rb => app/controllers/concerns/web_app_controller_concern.rb +1 -1
@@ 12,7 12,7 @@ module WebAppControllerConcern
  end

  def skip_csrf_meta_tags?
    !(ENV['OMNIAUTH_ONLY'] == 'true' && Devise.omniauth_providers.length == 1) && current_user.nil?
    !(ENV['ONE_CLICK_SSO_LOGIN'] == 'true' && ENV['OMNIAUTH_ONLY'] == 'true' && Devise.omniauth_providers.length == 1) && current_user.nil?
  end

  def set_app_body_class

D app/javascript/mastodon/actions/account_notes.js => app/javascript/mastodon/actions/account_notes.js +0 -37
@@ 1,37 0,0 @@
import api from '../api';

export const ACCOUNT_NOTE_SUBMIT_REQUEST = 'ACCOUNT_NOTE_SUBMIT_REQUEST';
export const ACCOUNT_NOTE_SUBMIT_SUCCESS = 'ACCOUNT_NOTE_SUBMIT_SUCCESS';
export const ACCOUNT_NOTE_SUBMIT_FAIL    = 'ACCOUNT_NOTE_SUBMIT_FAIL';

export function submitAccountNote(id, value) {
  return (dispatch, getState) => {
    dispatch(submitAccountNoteRequest());

    api(getState).post(`/api/v1/accounts/${id}/note`, {
      comment: value,
    }).then(response => {
      dispatch(submitAccountNoteSuccess(response.data));
    }).catch(error => dispatch(submitAccountNoteFail(error)));
  };
}

export function submitAccountNoteRequest() {
  return {
    type: ACCOUNT_NOTE_SUBMIT_REQUEST,
  };
}

export function submitAccountNoteSuccess(relationship) {
  return {
    type: ACCOUNT_NOTE_SUBMIT_SUCCESS,
    relationship,
  };
}

export function submitAccountNoteFail(error) {
  return {
    type: ACCOUNT_NOTE_SUBMIT_FAIL,
    error,
  };
}

A app/javascript/mastodon/actions/account_notes.ts => app/javascript/mastodon/actions/account_notes.ts +18 -0
@@ 0,0 1,18 @@
import { createAppAsyncThunk } from 'mastodon/store/typed_functions';

import api from '../api';

export const submitAccountNote = createAppAsyncThunk(
  'account_note/submit',
  async (args: { id: string; value: string }, { getState }) => {
    // TODO: replace `unknown` with `ApiRelationshipJSON` when it is merged
    const response = await api(getState).post<unknown>(
      `/api/v1/accounts/${args.id}/note`,
      {
        comment: args.value,
      },
    );

    return { relationship: response.data };
  },
);

M app/javascript/mastodon/actions/notifications.js => app/javascript/mastodon/actions/notifications.js +5 -0
@@ 18,6 18,7 @@ import {
  importFetchedStatuses,
} from './importer';
import { submitMarkers } from './markers';
import { register as registerPushNotifications } from './push_notifications';
import { saveSettings } from './settings';

export const NOTIFICATIONS_UPDATE      = 'NOTIFICATIONS_UPDATE';


@@ 293,6 294,10 @@ export function requestBrowserPermission(callback = noOp) {
    requestNotificationPermission((permission) => {
      dispatch(setBrowserPermission(permission));
      callback(permission);

      if (permission === 'granted') {
        dispatch(registerPushNotifications());
      }
    });
  };
}

R app/javascript/mastodon/api.js => app/javascript/mastodon/api.ts +18 -31
@@ 1,16 1,12 @@
// @ts-check

import type { AxiosResponse, RawAxiosRequestHeaders } from 'axios';
import axios from 'axios';
import LinkHeader from 'http-link-header';

import ready from './ready';
import type { GetState } from './store';

/**
 * @param {import('axios').AxiosResponse} response
 * @returns {LinkHeader}
 */
export const getLinks = response => {
  const value = response.headers.link;
export const getLinks = (response: AxiosResponse) => {
  const value = response.headers.link as string | undefined;

  if (!value) {
    return new LinkHeader();


@@ 19,44 15,35 @@ export const getLinks = response => {
  return LinkHeader.parse(value);
};

/** @type {import('axios').RawAxiosRequestHeaders} */
const csrfHeader = {};
const csrfHeader: RawAxiosRequestHeaders = {};

/**
 * @returns {void}
 */
const setCSRFHeader = () => {
  /** @type {HTMLMetaElement | null} */
  const csrfToken = document.querySelector('meta[name=csrf-token]');
  const csrfToken = document.querySelector<HTMLMetaElement>(
    'meta[name=csrf-token]',
  );

  if (csrfToken) {
    csrfHeader['X-CSRF-Token'] = csrfToken.content;
  }
};

ready(setCSRFHeader);
void ready(setCSRFHeader);

/**
 * @param {() => import('immutable').Map<string,any>} getState
 * @returns {import('axios').RawAxiosRequestHeaders}
 */
const authorizationHeaderFromState = getState => {
  const accessToken = getState && getState().getIn(['meta', 'access_token'], '');
const authorizationHeaderFromState = (getState?: GetState) => {
  const accessToken =
    getState && (getState().meta.get('access_token', '') as string);

  if (!accessToken) {
    return {};
  }

  return {
    'Authorization': `Bearer ${accessToken}`,
  };
    Authorization: `Bearer ${accessToken}`,
  } as RawAxiosRequestHeaders;
};

/**
 * @param {() => import('immutable').Map<string,any>} getState
 * @returns {import('axios').AxiosInstance}
 */
export default function api(getState) {
// eslint-disable-next-line import/no-default-export
export default function api(getState: GetState) {
  return axios.create({
    headers: {
      ...csrfHeader,


@@ 64,9 51,9 @@ export default function api(getState) {
    },

    transformResponse: [
      function (data) {
      function (data: unknown) {
        try {
          return JSON.parse(data);
          return JSON.parse(data as string) as unknown;
        } catch {
          return data;
        }

M app/javascript/mastodon/features/account/containers/account_note_container.js => app/javascript/mastodon/features/account/containers/account_note_container.js +1 -1
@@ 11,7 11,7 @@ const mapStateToProps = (state, { account }) => ({
const mapDispatchToProps = (dispatch, { account }) => ({

  onSave (value) {
    dispatch(submitAccountNote(account.get('id'), value));
    dispatch(submitAccountNote({ id: account.get('id'), value}));
  },

});

M app/javascript/mastodon/main.jsx => app/javascript/mastodon/main.jsx +1 -1
@@ 33,7 33,7 @@ function main() {
        console.error(err);
      }

      if (registration) {
      if (registration && 'Notification' in window && Notification.permission === 'granted') {
        const registerPushNotifications = await import('mastodon/actions/push_notifications');

        store.dispatch(registerPushNotifications.register());

M app/javascript/mastodon/reducers/relationships.js => app/javascript/mastodon/reducers/relationships.js +3 -2
@@ 1,7 1,7 @@
import { Map as ImmutableMap, fromJS } from 'immutable';

import {
  ACCOUNT_NOTE_SUBMIT_SUCCESS,
  submitAccountNote,
} from '../actions/account_notes';
import {
  ACCOUNT_FOLLOW_SUCCESS,


@@ 73,10 73,11 @@ export default function relationships(state = initialState, action) {
  case ACCOUNT_UNMUTE_SUCCESS:
  case ACCOUNT_PIN_SUCCESS:
  case ACCOUNT_UNPIN_SUCCESS:
  case ACCOUNT_NOTE_SUBMIT_SUCCESS:
    return normalizeRelationship(state, action.relationship);
  case RELATIONSHIPS_FETCH_SUCCESS:
    return normalizeRelationships(state, action.relationships);
  case submitAccountNote.fulfilled:
    return normalizeRelationship(state, action.payload.relationship);
  case DOMAIN_BLOCK_SUCCESS:
    return setDomainBlocking(state, action.accounts, true);
  case DOMAIN_UNBLOCK_SUCCESS:

M app/javascript/mastodon/store/index.ts => app/javascript/mastodon/store/index.ts +8 -45
@@ 1,45 1,8 @@
import type { TypedUseSelectorHook } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';

import { configureStore } from '@reduxjs/toolkit';

import { rootReducer } from '../reducers';

import { errorsMiddleware } from './middlewares/errors';
import { loadingBarMiddleware } from './middlewares/loading_bar';
import { soundsMiddleware } from './middlewares/sounds';

export const store = configureStore({
  reducer: rootReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      // In development, Redux Toolkit enables 2 default middlewares to detect
      // common issues with states. Unfortunately, our use of ImmutableJS for state
      // triggers both, so lets disable them until our state is fully refactored

      // https://redux-toolkit.js.org/api/serializabilityMiddleware
      // This checks recursively that every values in the state are serializable in JSON
      // Which is not the case, as we use ImmutableJS structures, but also File objects
      serializableCheck: false,

      // https://redux-toolkit.js.org/api/immutabilityMiddleware
      // This checks recursively if every value in the state is immutable (ie, a JS primitive type)
      // But this is not the case, as our Root State is an ImmutableJS map, which is an object
      immutableCheck: false,
    })
      .concat(
        loadingBarMiddleware({
          promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAIL'],
        }),
      )
      .concat(errorsMiddleware)
      .concat(soundsMiddleware()),
});

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof rootReducer>;
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch;

export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
export { store } from './store';
export type { GetState, AppDispatch, RootState } from './store';

export {
  createAppAsyncThunk,
  useAppDispatch,
  useAppSelector,
} from './typed_functions';

M app/javascript/mastodon/store/middlewares/errors.ts => app/javascript/mastodon/store/middlewares/errors.ts +1 -1
@@ 5,7 5,7 @@ import { showAlertForError } from '../../actions/alerts';

const defaultFailSuffix = 'FAIL';

export const errorsMiddleware: Middleware<Record<string, never>, RootState> =
export const errorsMiddleware: Middleware<unknown, RootState> =
  ({ dispatch }) =>
  (next) =>
  (action: AnyAction & { skipAlert?: boolean; skipNotFound?: boolean }) => {

M app/javascript/mastodon/store/middlewares/loading_bar.ts => app/javascript/mastodon/store/middlewares/loading_bar.ts +1 -1
@@ 15,7 15,7 @@ const defaultTypeSuffixes: Config['promiseTypeSuffixes'] = [

export const loadingBarMiddleware = (
  config: Config = {},
): Middleware<Record<string, never>, RootState> => {
): Middleware<unknown, RootState> => {
  const promiseTypeSuffixes = config.promiseTypeSuffixes ?? defaultTypeSuffixes;

  return ({ dispatch }) =>

M app/javascript/mastodon/store/middlewares/sounds.ts => app/javascript/mastodon/store/middlewares/sounds.ts +1 -4
@@ 34,10 34,7 @@ const play = (audio: HTMLAudioElement) => {
  void audio.play();
};

export const soundsMiddleware = (): Middleware<
  Record<string, never>,
  RootState
> => {
export const soundsMiddleware = (): Middleware<unknown, RootState> => {
  const soundCache: Record<string, HTMLAudioElement> = {};

  void ready(() => {

A app/javascript/mastodon/store/store.ts => app/javascript/mastodon/store/store.ts +40 -0
@@ 0,0 1,40 @@
import { configureStore } from '@reduxjs/toolkit';

import { rootReducer } from '../reducers';

import { errorsMiddleware } from './middlewares/errors';
import { loadingBarMiddleware } from './middlewares/loading_bar';
import { soundsMiddleware } from './middlewares/sounds';

export const store = configureStore({
  reducer: rootReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      // In development, Redux Toolkit enables 2 default middlewares to detect
      // common issues with states. Unfortunately, our use of ImmutableJS for state
      // triggers both, so lets disable them until our state is fully refactored

      // https://redux-toolkit.js.org/api/serializabilityMiddleware
      // This checks recursively that every values in the state are serializable in JSON
      // Which is not the case, as we use ImmutableJS structures, but also File objects
      serializableCheck: false,

      // https://redux-toolkit.js.org/api/immutabilityMiddleware
      // This checks recursively if every value in the state is immutable (ie, a JS primitive type)
      // But this is not the case, as our Root State is an ImmutableJS map, which is an object
      immutableCheck: false,
    })
      .concat(
        loadingBarMiddleware({
          promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAIL'],
        }),
      )
      .concat(errorsMiddleware)
      .concat(soundsMiddleware()),
});

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof rootReducer>;
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch;
export type GetState = typeof store.getState;

A app/javascript/mastodon/store/typed_functions.ts => app/javascript/mastodon/store/typed_functions.ts +15 -0
@@ 0,0 1,15 @@
import type { TypedUseSelectorHook } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';

import { createAsyncThunk } from '@reduxjs/toolkit';

import type { AppDispatch, RootState } from './store';

export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

export const createAppAsyncThunk = createAsyncThunk.withTypes<{
  state: RootState;
  dispatch: AppDispatch;
  rejectValue: string;
}>();

M app/javascript/styles/mastodon/components.scss => app/javascript/styles/mastodon/components.scss +5 -0
@@ 5061,6 5061,11 @@ a.status-card {
          font-weight: 700;
          color: $primary-text-color;
        }

        span {
          overflow: inherit;
          text-overflow: inherit;
        }
      }
    }
  }

M app/serializers/initial_state_serializer.rb => app/serializers/initial_state_serializer.rb +1 -1
@@ 130,6 130,6 @@ class InitialStateSerializer < ActiveModel::Serializer
  end

  def sso_redirect
    "/auth/auth/#{Devise.omniauth_providers[0]}" if ENV['OMNIAUTH_ONLY'] == 'true' && Devise.omniauth_providers.length == 1
    "/auth/auth/#{Devise.omniauth_providers[0]}" if ENV['ONE_CLICK_SSO_LOGIN'] == 'true' && ENV['OMNIAUTH_ONLY'] == 'true' && Devise.omniauth_providers.length == 1
  end
end

M app/services/notify_service.rb => app/services/notify_service.rb +1 -0
@@ 8,6 8,7 @@ class NotifyService < BaseService
    admin.sign_up
    update
    poll
    status
  ).freeze

  def call(recipient, type, activity)

M config/initializers/content_security_policy.rb => config/initializers/content_security_policy.rb +22 -1
@@ 4,6 4,22 @@
# For further information see the following documentation
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy

def sso_host
  return unless ENV['ONE_CLICK_SSO_LOGIN'] == 'true'
  return unless ENV['OMNIAUTH_ONLY'] == 'true'
  return unless Devise.omniauth_providers.length == 1

  provider = Devise.omniauth_configs[Devise.omniauth_providers[0]]
  @sso_host ||= begin
    # using CAS
    provider.cas_url if ENV['CAS_ENABLED'] == 'true'
    # using SAML
    provider.options[:idp_sso_target_url] if ENV['SAML_ENABLED'] == 'true'
    # or using OIDC
    ENV['OIDC_AUTH_ENDPOINT'] || (OpenIDConnect::Discovery::Provider::Config.discover!(ENV['OIDC_ISSUER']).authorization_endpoint if ENV['OIDC_ENABLED'] == 'true')
  end
end

unless Rails.env.development?
  assets_host = Rails.configuration.action_controller.asset_host || "https://#{ENV['WEB_DOMAIN'] || ENV['LOCAL_DOMAIN']}"
  data_hosts = [assets_host]


@@ 43,7 59,12 @@ unless Rails.env.development?
    p.worker_src      :self, :blob, assets_host
    p.connect_src     :self, :blob, :data, Rails.configuration.x.streaming_api_base_url, *data_hosts
    p.manifest_src    :self, assets_host
    p.form_action     :self

    if sso_host.present?
      p.form_action     :self, sso_host
    else
      p.form_action     :self
    end
  end
end


M lib/mastodon/cli/search.rb => lib/mastodon/cli/search.rb +1 -1
@@ 16,7 16,7 @@ module Mastodon::CLI

    option :concurrency, type: :numeric, default: 5, aliases: [:c], desc: 'Workload will be split between this number of threads'
    option :batch_size, type: :numeric, default: 100, aliases: [:b], desc: 'Number of records in each batch'
    option :only, type: :array, enum: %w(instances accounts tags statuses), desc: 'Only process these indices'
    option :only, type: :array, enum: %w(instances accounts tags statuses public_statuses), desc: 'Only process these indices'
    option :import, type: :boolean, default: true, desc: 'Import data from the database to the index'
    option :clean, type: :boolean, default: true, desc: 'Remove outdated documents from the index'
    option :reset_chewy, type: :boolean, default: false, desc: "Reset Chewy's internal index"

M yarn.lock => yarn.lock +99 -123
@@ 58,20 58,20 @@
  integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==

"@babel/core@^7.10.4", "@babel/core@^7.11.1", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.22.1":
  version "7.22.15"
  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.15.tgz#15d4fd03f478a459015a4b94cfbb3bd42c48d2f4"
  integrity sha512-PtZqMmgRrvj8ruoEOIwVA3yoF91O+Hgw9o7DAUTNBA6Mo2jpu31clx9a7Nz/9JznqetTR6zwfC4L3LAjKQXUwA==
  version "7.22.17"
  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.17.tgz#2f9b0b395985967203514b24ee50f9fd0639c866"
  integrity sha512-2EENLmhpwplDux5PSsZnSbnSkB3tZ6QTksgO25xwEL7pIDcNOMhF5v/s6RzwjMZzZzw9Ofc30gHv5ChCC8pifQ==
  dependencies:
    "@ampproject/remapping" "^2.2.0"
    "@babel/code-frame" "^7.22.13"
    "@babel/generator" "^7.22.15"
    "@babel/helper-compilation-targets" "^7.22.15"
    "@babel/helper-module-transforms" "^7.22.15"
    "@babel/helper-module-transforms" "^7.22.17"
    "@babel/helpers" "^7.22.15"
    "@babel/parser" "^7.22.15"
    "@babel/parser" "^7.22.16"
    "@babel/template" "^7.22.15"
    "@babel/traverse" "^7.22.15"
    "@babel/types" "^7.22.15"
    "@babel/traverse" "^7.22.17"
    "@babel/types" "^7.22.17"
    convert-source-map "^1.7.0"
    debug "^4.1.0"
    gensync "^1.0.0-beta.2"


@@ 207,7 207,18 @@
  dependencies:
    "@babel/types" "^7.22.15"

"@babel/helper-module-transforms@^7.22.15", "@babel/helper-module-transforms@^7.22.5", "@babel/helper-module-transforms@^7.22.9":
"@babel/helper-module-transforms@^7.22.15", "@babel/helper-module-transforms@^7.22.17":
  version "7.22.17"
  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz#7edf129097a51ccc12443adbc6320e90eab76693"
  integrity sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ==
  dependencies:
    "@babel/helper-environment-visitor" "^7.22.5"
    "@babel/helper-module-imports" "^7.22.15"
    "@babel/helper-simple-access" "^7.22.5"
    "@babel/helper-split-export-declaration" "^7.22.6"
    "@babel/helper-validator-identifier" "^7.22.15"

"@babel/helper-module-transforms@^7.22.5", "@babel/helper-module-transforms@^7.22.9":
  version "7.22.15"
  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.15.tgz#40ad2f6950f143900e9c1c72363c0b431a606082"
  integrity sha512-l1UiX4UyHSFsYt17iQ3Se5pQQZZHa22zyIXURmvkmLCD4t/aU+dvNWHatKac/D9Vm9UES7nvIqHs4jZqKviUmQ==


@@ 320,7 331,7 @@
    chalk "^2.4.2"
    js-tokens "^4.0.0"

"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.22.5":
"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.22.16", "@babel/parser@^7.22.5":
  version "7.22.16"
  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95"
  integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==


@@ 1112,10 1123,10 @@
    "@babel/parser" "^7.22.5"
    "@babel/types" "^7.22.5"

"@babel/traverse@7", "@babel/traverse@^7.22.15":
  version "7.22.15"
  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.15.tgz#75be4d2d6e216e880e93017f4e2389aeb77ef2d9"
  integrity sha512-DdHPwvJY0sEeN4xJU5uRLmZjgMMDIvMPniLuYzUVXj/GGzysPl0/fwt44JBkyUIzGJPV8QgHMcQdQ34XFuKTYQ==
"@babel/traverse@7", "@babel/traverse@^7.22.15", "@babel/traverse@^7.22.17":
  version "7.22.17"
  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.17.tgz#b23c203ab3707e3be816043081b4a994fcacec44"
  integrity sha512-xK4Uwm0JnAMvxYZxOVecss85WxTEIbTa7bnGyf/+EgCL5Zt3U7htUpEOWv9detPlamGKuRzCqw74xVglDWpPdg==
  dependencies:
    "@babel/code-frame" "^7.22.13"
    "@babel/generator" "^7.22.15"


@@ 1123,15 1134,15 @@
    "@babel/helper-function-name" "^7.22.5"
    "@babel/helper-hoist-variables" "^7.22.5"
    "@babel/helper-split-export-declaration" "^7.22.6"
    "@babel/parser" "^7.22.15"
    "@babel/types" "^7.22.15"
    "@babel/parser" "^7.22.16"
    "@babel/types" "^7.22.17"
    debug "^4.1.0"
    globals "^11.1.0"

"@babel/types@^7.0.0", "@babel/types@^7.12.11", "@babel/types@^7.20.7", "@babel/types@^7.22.10", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.4.4":
  version "7.22.15"
  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.15.tgz#266cb21d2c5fd0b3931e7a91b6dd72d2f617d282"
  integrity sha512-X+NLXr0N8XXmN5ZsaQdm9U2SSC3UbIYq/doL++sueHOTisgZHoKaQtZxGuV2cUPQHMfjKEfg/g6oy7Hm6SKFtA==
"@babel/types@^7.0.0", "@babel/types@^7.12.11", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.17", "@babel/types@^7.22.5":
  version "7.22.17"
  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.17.tgz#f753352c4610ffddf9c8bc6823f9ff03e2303eee"
  integrity sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==
  dependencies:
    "@babel/helper-string-parser" "^7.22.5"
    "@babel/helper-validator-identifier" "^7.22.15"


@@ 1146,6 1157,15 @@
    "@babel/helper-validator-identifier" "^7.22.5"
    to-fast-properties "^2.0.0"

"@babel/types@^7.22.10", "@babel/types@^7.4.4":
  version "7.22.15"
  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.15.tgz#266cb21d2c5fd0b3931e7a91b6dd72d2f617d282"
  integrity sha512-X+NLXr0N8XXmN5ZsaQdm9U2SSC3UbIYq/doL++sueHOTisgZHoKaQtZxGuV2cUPQHMfjKEfg/g6oy7Hm6SKFtA==
  dependencies:
    "@babel/helper-string-parser" "^7.22.5"
    "@babel/helper-validator-identifier" "^7.22.15"
    to-fast-properties "^2.0.0"

"@babel/types@^7.3.3":
  version "7.22.10"
  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.10.tgz#4a9e76446048f2c66982d1a989dd12b8a2d2dc03"


@@ 1331,14 1351,6 @@
  resolved "https://registry.yarnpkg.com/@formatjs/cli/-/cli-6.1.3.tgz#b4b95259398e222ec6c06cf5f23f76d987f53e96"
  integrity sha512-PdTXZTY8LqxwmvFqdifn89gjXnPUpGtGyFs0BnoeLuOuxZFSnBfIs5WQCVMaJnr1+0vNNlXyT0VAIAwjRpf6BA==

"@formatjs/ecma402-abstract@1.17.1":
  version "1.17.1"
  resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.17.1.tgz#6ac7d6a1d1c9c8eff76ab6ed949f2a5cbe424030"
  integrity sha512-N2sjSUrmsEoynG8Q61pkrKlJ9PxcUGxJke1x3301aGyprGgl58wHWhgGUnzTfS4OHNNNQDxzjcXVp1t5fGW6yQ==
  dependencies:
    "@formatjs/intl-localematcher" "0.4.1"
    tslib "^2.4.0"

"@formatjs/ecma402-abstract@1.17.2":
  version "1.17.2"
  resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.17.2.tgz#d197c6e26b9fd96ff7ba3b3a0cc2f25f1f2dcac3"


@@ 1354,15 1366,6 @@
  dependencies:
    tslib "^2.4.0"

"@formatjs/icu-messageformat-parser@2.6.1":
  version "2.6.1"
  resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.6.1.tgz#ca497d5a2bff641dc0978bd9b64d1d02597980cb"
  integrity sha512-dTDNupwdovxT1xDXC96zzPUua/XrxTQTOulJZSvaJP0pt3rr/cGR/tq4d7BnxY9oqPZpc4fjWBmrRlhcUyBSiw==
  dependencies:
    "@formatjs/ecma402-abstract" "1.17.1"
    "@formatjs/icu-skeleton-parser" "1.6.1"
    tslib "^2.4.0"

"@formatjs/icu-messageformat-parser@2.6.2":
  version "2.6.2"
  resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.6.2.tgz#9bbb29099416e4ce2c7df50029c48985d4f901b3"


@@ 1372,14 1375,6 @@
    "@formatjs/icu-skeleton-parser" "1.6.2"
    tslib "^2.4.0"

"@formatjs/icu-skeleton-parser@1.6.1":
  version "1.6.1"
  resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.6.1.tgz#3647f41b82e362c08bb80bd9b653c7eb6ff31118"
  integrity sha512-/LQ6ovxYd8FQjVLmbV+WmuFy86o+JTc0cIQuWixuLuUMfRRif8eUQw3vPK5hx7C/g1UVmKAaOcYRTEsvyEGz9g==
  dependencies:
    "@formatjs/ecma402-abstract" "1.17.1"
    tslib "^2.4.0"

"@formatjs/icu-skeleton-parser@1.6.2":
  version "1.6.2"
  resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.6.2.tgz#00303034dc08583973c8aa67b96534c49c0bad8d"


@@ 1388,29 1383,22 @@
    "@formatjs/ecma402-abstract" "1.17.2"
    tslib "^2.4.0"

"@formatjs/intl-displaynames@6.5.1":
  version "6.5.1"
  resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-6.5.1.tgz#d25d260b81845abf6f35a13dbc87c25b0ec22a33"
  integrity sha512-BD+coSUka8fppErGnXbWthd6YxTXdCGvQzGR/rSEdPgiZO5sh+0gVLjp0FgXi6cOf9C2z2axqhGifFsqyTVhkw==
"@formatjs/intl-displaynames@6.5.2":
  version "6.5.2"
  resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-6.5.2.tgz#b14ffd0962d5b5cfd71457efc389f0bca83a00db"
  integrity sha512-uC2VBlz+WydGTDDpJwMTQuPH3CUpTricr91WH1QMfz5oEHg2sB7mUERcZONE/lu8MOe1jREIx4vBciZEVTqkmA==
  dependencies:
    "@formatjs/ecma402-abstract" "1.17.1"
    "@formatjs/intl-localematcher" "0.4.1"
    tslib "^2.4.0"

"@formatjs/intl-listformat@7.4.1":
  version "7.4.1"
  resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-7.4.1.tgz#cb6f1399a41b9fd568cc4b4b80fc815d0c5b37ab"
  integrity sha512-mWd30ndvYw8JydOIVb5Y1ElK2iwsaDY+ajPR5aWWgEZaH04aL+4hzX/8VXPsilu7CF3DN1IP5ZSwJuj7ZyBIHw==
  dependencies:
    "@formatjs/ecma402-abstract" "1.17.1"
    "@formatjs/intl-localematcher" "0.4.1"
    "@formatjs/ecma402-abstract" "1.17.2"
    "@formatjs/intl-localematcher" "0.4.2"
    tslib "^2.4.0"

"@formatjs/intl-localematcher@0.4.1":
  version "0.4.1"
  resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.4.1.tgz#af63e2c065731a33f6fed36dc85058009a7f8062"
  integrity sha512-Fs4MhhHlLC0RrspX2u2KP7zlwL9eHrBZsOBxaPOeqrCZYLaOUK4cYXQ1ErpAB0HnGV/GUXNa5smzV/7jCuRzxg==
"@formatjs/intl-listformat@7.4.2":
  version "7.4.2"
  resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-7.4.2.tgz#c8d86d3b15eead41f74748d1c79d6450fd1bad82"
  integrity sha512-+6bSVudEQkf12Hh7kuKt8Xv/MyFlqdwA4V4NLnTZW8uYdF9RxlOELDD0rPaOc2++TMKIzI5o6XXwHPvpL6VrPA==
  dependencies:
    "@formatjs/ecma402-abstract" "1.17.2"
    "@formatjs/intl-localematcher" "0.4.2"
    tslib "^2.4.0"

"@formatjs/intl-localematcher@0.4.2":


@@ 1421,39 1409,26 @@
    tslib "^2.4.0"

"@formatjs/intl-pluralrules@^5.2.2":
  version "5.2.5"
  resolved "https://registry.yarnpkg.com/@formatjs/intl-pluralrules/-/intl-pluralrules-5.2.5.tgz#72ff79bec4c3383a46e6b3d6b0af73534e544302"
  integrity sha512-od9KJzKB5CF9Hfq3g6CJzWA0rW9yaNrF2hMZK3/26aTuZ4Fm3mPm/JI6QReF9qZSC1qkJyqS1GN0JtTm2sVyGQ==
  version "5.2.6"
  resolved "https://registry.yarnpkg.com/@formatjs/intl-pluralrules/-/intl-pluralrules-5.2.6.tgz#c08daf9f4feb8a858e8dcb90e50f1e33fd6dc469"
  integrity sha512-64i4JvWS1ibw774xnJaNdyIxPzyaO+uGgOtkuS0EbK076f3znEhu1GXh4vmnaCEGb9R3uLwOWU0GjOEbavFzbA==
  dependencies:
    "@formatjs/ecma402-abstract" "1.17.1"
    "@formatjs/intl-localematcher" "0.4.1"
    "@formatjs/ecma402-abstract" "1.17.2"
    "@formatjs/intl-localematcher" "0.4.2"
    tslib "^2.4.0"

"@formatjs/intl@2.9.1":
  version "2.9.1"
  resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-2.9.1.tgz#f224109620b71f48c049bd42df770f202e4b6d29"
  integrity sha512-NsDMke+lAiu+c6/9KXrp8aldd7sFeyxgQZqFUJSZIeaKrN+gEoYKqWgsiRa7/mxlWqWNJSGuNQnF1P2ChC/yaA==
"@formatjs/intl@2.9.2":
  version "2.9.2"
  resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-2.9.2.tgz#83fbd8fccb1088aee084508fd5a387d30c2f83e4"
  integrity sha512-brettBil92sd8i4dHEc6by8mqp4NbRvR2A94dZK9pQuSghkoqn2TIvwuaetmMNsBXexv7hYsehNQPi1qqkdPig==
  dependencies:
    "@formatjs/ecma402-abstract" "1.17.1"
    "@formatjs/ecma402-abstract" "1.17.2"
    "@formatjs/fast-memoize" "2.2.0"
    "@formatjs/icu-messageformat-parser" "2.6.1"
    "@formatjs/intl-displaynames" "6.5.1"
    "@formatjs/intl-listformat" "7.4.1"
    intl-messageformat "10.5.1"
    tslib "^2.4.0"

"@formatjs/ts-transformer@3.13.4":
  version "3.13.4"
  resolved "https://registry.yarnpkg.com/@formatjs/ts-transformer/-/ts-transformer-3.13.4.tgz#586582ab3aee75b7e24d37f7090ab270062a9bf5"
  integrity sha512-AOOHpHBJyjcNLkJcT82zeU7IlaogHI4qBjPlFgyeqcSbGwR4b+LGY7Frf7N5eM8Y9yGnTDVIUA/u3gHUA3SHQg==
  dependencies:
    "@formatjs/icu-messageformat-parser" "2.6.1"
    "@types/json-stable-stringify" "^1.0.32"
    "@types/node" "14 || 16 || 17"
    chalk "^4.0.0"
    json-stable-stringify "^1.0.1"
    "@formatjs/icu-messageformat-parser" "2.6.2"
    "@formatjs/intl-displaynames" "6.5.2"
    "@formatjs/intl-listformat" "7.4.2"
    intl-messageformat "10.5.2"
    tslib "^2.4.0"
    typescript "^4.7 || 5"

"@formatjs/ts-transformer@3.13.5":
  version "3.13.5"


@@ 1837,9 1812,9 @@
  integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==

"@rails/ujs@^7.0.6":
  version "7.0.7"
  resolved "https://registry.yarnpkg.com/@rails/ujs/-/ujs-7.0.7.tgz#54af8d66160a8a7bf7d8f184703d2bf4b3fab914"
  integrity sha512-J2v5Ca7HgejO7diGKiDylaVDQKmbQ5FJih6Oo3hXuBKEuXlcaccJu64lj8MNVLaPVyZx0g4gaOQZQz95QEb/hg==
  version "7.0.8"
  resolved "https://registry.yarnpkg.com/@rails/ujs/-/ujs-7.0.8.tgz#59853367d0827b3955d2c4bedfd5eba4a79d3422"
  integrity sha512-tOQQBVH8LsUpGXqDnk+kaOGVsgZ8maHAhEiw3Git3p88q+c0Slgu47HuDnL6sVxeCfz24zbq7dOjsVYDiTpDIA==

"@reduxjs/toolkit@^1.9.5":
  version "1.9.5"


@@ 3413,17 3388,17 @@ babel-loader@^8.3.0:
    schema-utils "^2.6.5"

babel-plugin-formatjs@^10.5.1:
  version "10.5.4"
  resolved "https://registry.yarnpkg.com/babel-plugin-formatjs/-/babel-plugin-formatjs-10.5.4.tgz#98837caedcdb64f118048f19e59ad0c94f55b5aa"
  integrity sha512-6JSpDS/YVjMu74NzHkuEduWqDsmUbUm1qc6sNeccgknixW9Z3hbQqv3Fvfjrh4opBzJ+CRaAZaUlQQL+xDTQzw==
  version "10.5.5"
  resolved "https://registry.yarnpkg.com/babel-plugin-formatjs/-/babel-plugin-formatjs-10.5.5.tgz#678e35d5a06103030d7d6205592779d235a25591"
  integrity sha512-p7q/kJ+ss1xY2b3tTePllIi2xWJDRRBGw2kFV8Ve18uYG0eMn3xoEq3zW1GLQTJpdWzL++qTyTJ0oj428nzU6Q==
  dependencies:
    "@babel/core" "^7.10.4"
    "@babel/helper-plugin-utils" "^7.10.4"
    "@babel/plugin-syntax-jsx" "7"
    "@babel/traverse" "7"
    "@babel/types" "^7.12.11"
    "@formatjs/icu-messageformat-parser" "2.6.1"
    "@formatjs/ts-transformer" "3.13.4"
    "@formatjs/icu-messageformat-parser" "2.6.2"
    "@formatjs/ts-transformer" "3.13.5"
    "@types/babel__core" "^7.1.7"
    "@types/babel__helper-plugin-utils" "^7.10.0"
    "@types/babel__traverse" "^7.1.7"


@@ 3962,9 3937,9 @@ caniuse-lite@^1.0.30001502:
  integrity sha512-eEFDwUOZbE24sb+Ecsx3+OvNETqjWIdabMy52oOkIgcUtAsQifjUG9q4U9dgTHJM2mfk4uEPxc0+xuFdJ629QA==

caniuse-lite@^1.0.30001517:
  version "1.0.30001528"
  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001528.tgz#479972fc705b996f1114336c0032418a215fd0aa"
  integrity sha512-0Db4yyjR9QMNlsxh+kKWzQtkyflkG/snYheSzkjmvdEtEXB1+jt7A2HmSEiO6XIJPIbo92lHNGNySvE5pZcs5Q==
  version "1.0.30001532"
  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz#c6a4d5d2da6d2b967f0ee5e12e7f680db6ad2fca"
  integrity sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw==

caniuse-lite@^1.0.30001520:
  version "1.0.30001520"


@@ 5109,9 5084,9 @@ electron-to-chromium@^1.4.428:
  integrity sha512-/g3UyNDmDd6ebeWapmAoiyy+Sy2HyJ+/X8KyvNeHfKRFfHaA2W8oF5fxD5F3tjBDcjpwo0iek6YNgxNXDBoEtA==

electron-to-chromium@^1.4.477:
  version "1.4.510"
  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.510.tgz#446c50d7533c1e71a84b00a3b37ab06dd601d890"
  integrity sha512-xPfLIPFcN/WLXBpQ/K4UgE98oUBO5Tia6BD4rkSR0wE7ep/PwBVlgvPJQrIBpmJGVAmUzwPKuDbVt9XV6+uC2g==
  version "1.4.513"
  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz#41a50bf749aa7d8058ffbf7a131fc3327a7b1675"
  integrity sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw==

elliptic@^6.5.3:
  version "6.5.4"


@@ 6842,14 6817,14 @@ intersection-observer@^0.12.0:
  resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.12.2.tgz#4a45349cc0cd91916682b1f44c28d7ec737dc375"
  integrity sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==

intl-messageformat@10.5.1, intl-messageformat@^10.3.5:
  version "10.5.1"
  resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.5.1.tgz#40304cbde01c8cb2236e11ac8c827642bed474d0"
  integrity sha512-irEmjxHq0f1MHviQr3Q4ToF9EgYbnXDq2/R9MRTTveGKHgy6VZ29hQxswu4trqWaX7T6njKxSoKVG92OSz0U5Q==
intl-messageformat@10.5.2, intl-messageformat@^10.3.5:
  version "10.5.2"
  resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.5.2.tgz#eb746b4b895bd37e8ef91be7b488e450aa4e9d7b"
  integrity sha512-X4rlUNbgCc8/RdMhmvUEEZ38yNDn5S4r0u8n8yQH2OOdhsR46SmOuQsCKG35nRXmL5u2nxPsNN6qNhHoMm6FMQ==
  dependencies:
    "@formatjs/ecma402-abstract" "1.17.1"
    "@formatjs/ecma402-abstract" "1.17.2"
    "@formatjs/fast-memoize" "2.2.0"
    "@formatjs/icu-messageformat-parser" "2.6.1"
    "@formatjs/icu-messageformat-parser" "2.6.2"
    tslib "^2.4.0"

invariant@^2.2.2, invariant@^2.2.4:


@@ 10035,19 10010,19 @@ react-immutable-pure-component@^2.2.2:
  integrity sha512-vkgoMJUDqHZfXXnjVlG3keCxSO/U6WeDQ5/Sl0GK2cH8TOxEzQ5jXqDXHEL/jqk6fsNxV05oH5kD7VNMUE2k+A==

react-intl@^6.4.2:
  version "6.4.5"
  resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-6.4.5.tgz#d8f61fce2fb3be08ef58deb35d96b964e1ef013a"
  integrity sha512-nUO2W57Tmdu6ErhsOFpsgkEtfQ4Lo7hPrXn8gGJQx59NRC0FNUxRc6+Ah3G8j6vqBiYRmxsLJpVZtIhLZjhYLA==
  dependencies:
    "@formatjs/ecma402-abstract" "1.17.1"
    "@formatjs/icu-messageformat-parser" "2.6.1"
    "@formatjs/intl" "2.9.1"
    "@formatjs/intl-displaynames" "6.5.1"
    "@formatjs/intl-listformat" "7.4.1"
  version "6.4.6"
  resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-6.4.6.tgz#64e3a615f1d30e0d75d081a5edaa85eb29c9c2eb"
  integrity sha512-8FiQ1GO6vm0wuO4B7yls9wIbINIo6ZH91geuwyR0VtwfhPc9+ONXKVfzwzkr/GZnwKW93nmH43MS+NSkmttIaA==
  dependencies:
    "@formatjs/ecma402-abstract" "1.17.2"
    "@formatjs/icu-messageformat-parser" "2.6.2"
    "@formatjs/intl" "2.9.2"
    "@formatjs/intl-displaynames" "6.5.2"
    "@formatjs/intl-listformat" "7.4.2"
    "@types/hoist-non-react-statics" "^3.3.1"
    "@types/react" "16 || 17 || 18"
    hoist-non-react-statics "^3.3.2"
    intl-messageformat "10.5.1"
    intl-messageformat "10.5.2"
    tslib "^2.4.0"

"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0, react-is@^18.2.0:


@@ 11434,6 11409,7 @@ stringz@^2.1.0:
    char-regex "^1.0.2"

"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
  name strip-ansi-cjs
  version "6.0.1"
  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
  integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==


@@ 12361,9 12337,9 @@ uuid@^8.3.2:
  integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==

uuid@^9.0.0:
  version "9.0.0"
  resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5"
  integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==
  version "9.0.1"
  resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
  integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==

v8-compile-cache@^2.1.1:
  version "2.3.0"