From 6579e3af7d6eb2774eae3d16bb1c9b7772fb58ec Mon Sep 17 00:00:00 2001
From: fusagiko / takayamaki <24884114+takayamaki@users.noreply.github.com>
Date: Tue, 9 May 2023 19:09:32 +0900
Subject: [PATCH 01/11] Add more detailed type annotation for Account (#24815)

---
 app/javascript/types/resources.ts | 52 ++++++++++++++++++++++++++++---
 1 file changed, 48 insertions(+), 4 deletions(-)

diff --git a/app/javascript/types/resources.ts b/app/javascript/types/resources.ts
index 28fad2719a..0906504150 100644
--- a/app/javascript/types/resources.ts
+++ b/app/javascript/types/resources.ts
@@ -1,10 +1,54 @@
 import type { Record } from 'immutable';
 
-type AccountValues = {
-  id: number;
+type CustomEmoji = Record<{
+  shortcode: string;
+  static_url: string;
+  url: string;
+}>;
+
+type AccountField = Record<{
+  name: string;
+  value: string;
+  verified_at: string | null;
+}>;
+
+type AccountApiResponseValues = {
+  acct: string;
   avatar: string;
   avatar_static: string;
-  [key: string]: any;
+  bot: boolean;
+  created_at: string;
+  discoverable: boolean;
+  display_name: string;
+  emojis: CustomEmoji[];
+  fields: AccountField[];
+  followers_count: number;
+  following_count: number;
+  group: boolean;
+  header: string;
+  header_static: string;
+  id: string;
+  last_status_at: string;
+  locked: boolean;
+  note: string;
+  statuses_count: number;
+  url: string;
+  username: string;
 };
 
-export type Account = Record<AccountValues>;
+type NormalizedAccountField = Record<{
+  name_emojified: string;
+  value_emojified: string;
+  value_plain: string;
+}>;
+
+type NormalizedAccountValues = {
+  display_name_html: string;
+  fields: NormalizedAccountField[];
+  note_emojified: string;
+  note_plain: string;
+};
+
+export type Account = Record<
+  AccountApiResponseValues & NormalizedAccountValues
+>;

From aec486b4ec327ca07b0cf8297f1b1dad3ebe0820 Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Tue, 9 May 2023 14:43:07 +0200
Subject: [PATCH 02/11] Upgrade `uuid` to 9.0.0 (#24917)

---
 .github/dependabot.yml |  4 ----
 package.json           |  4 ++--
 yarn.lock              | 16 ++++++++--------
 3 files changed, 10 insertions(+), 14 deletions(-)

diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index ef16f1d482..af7efbe6cf 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -17,10 +17,6 @@ updates:
       - dependency-name: '@rails/ujs'
         versions:
           - '>= 7'
-      # TODO: This was ignored in https://github.com/mastodon/mastodon/pull/19120
-      - dependency-name: 'uuid'
-        versions:
-          - '>= 9'
       # TODO: This requires code changes for migration
       - dependency-name: 'tesseract.js'
         versions:
diff --git a/package.json b/package.json
index 76deabc26b..b56b79d9fa 100644
--- a/package.json
+++ b/package.json
@@ -126,7 +126,7 @@
     "tesseract.js": "^2.1.5",
     "tiny-queue": "^0.2.1",
     "twitter-text": "3.1.0",
-    "uuid": "^8.3.1",
+    "uuid": "^9.0.0",
     "webpack": "^4.46.0",
     "webpack-assets-manifest": "^4.0.6",
     "webpack-bundle-analyzer": "^4.8.0",
@@ -176,7 +176,7 @@
     "@types/react-toggle": "^4.0.3",
     "@types/redux-immutable": "^4.0.3",
     "@types/requestidlecallback": "^0.3.5",
-    "@types/uuid": "^8.3.4",
+    "@types/uuid": "^9.0.0",
     "@types/webpack": "^4.41.33",
     "@types/yargs": "^17.0.24",
     "@typescript-eslint/eslint-plugin": "^5.59.2",
diff --git a/yarn.lock b/yarn.lock
index 3114f26a3e..be8ef990fd 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2425,10 +2425,10 @@
   dependencies:
     source-map "^0.6.1"
 
-"@types/uuid@^8.3.4":
-  version "8.3.4"
-  resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc"
-  integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==
+"@types/uuid@^9.0.0":
+  version "9.0.1"
+  resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.1.tgz#98586dc36aee8dacc98cc396dbca8d0429647aa6"
+  integrity sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==
 
 "@types/warning@^3.0.0":
   version "3.0.0"
@@ -11654,10 +11654,10 @@ uuid@^3.3.2, uuid@^3.4.0:
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
   integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
 
-uuid@^8.3.1:
-  version "8.3.2"
-  resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
-  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==
 
 v8-compile-cache@^2.1.1, v8-compile-cache@^2.3.0:
   version "2.3.0"

From ffb3fef7dba2f7ca2d927bc8432731962d2ee4f9 Mon Sep 17 00:00:00 2001
From: Daniel M Brasil <danielmbrasil@protonmail.com>
Date: Tue, 9 May 2023 09:45:47 -0300
Subject: [PATCH 03/11] Fix uncaught `ActiveRecord::StatementInvalid` in
 Mastodon::IpBlocksCLI (#24861)

---
 lib/mastodon/ip_blocks_cli.rb | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/lib/mastodon/ip_blocks_cli.rb b/lib/mastodon/ip_blocks_cli.rb
index 3b99595857..8a8685fe5a 100644
--- a/lib/mastodon/ip_blocks_cli.rb
+++ b/lib/mastodon/ip_blocks_cli.rb
@@ -36,6 +36,12 @@ module Mastodon
       failed    = 0
 
       addresses.each do |address|
+        unless valid_ip_address?(address)
+          say("#{address} is invalid", :red)
+          failed += 1
+          next
+        end
+
         ip_block = IpBlock.find_by(ip: address)
 
         if ip_block.present? && !options[:force]
@@ -79,6 +85,12 @@ module Mastodon
       skipped   = 0
 
       addresses.each do |address|
+        unless valid_ip_address?(address)
+          say("#{address} is invalid", :yellow)
+          skipped += 1
+          next
+        end
+
         ip_blocks = if options[:force]
                       IpBlock.where('ip >>= ?', address)
                     else
@@ -126,5 +138,12 @@ module Mastodon
         :red
       end
     end
+
+    def valid_ip_address?(ip_address)
+      IPAddr.new(ip_address)
+      true
+    rescue IPAddr::InvalidAddressError
+      false
+    end
   end
 end

From 536dd046d44c1fb5738ee7044b359b63fb4359c7 Mon Sep 17 00:00:00 2001
From: Daniel M Brasil <danielmbrasil@protonmail.com>
Date: Tue, 9 May 2023 09:46:00 -0300
Subject: [PATCH 04/11] Add ability to block sign-ups from IP using the CLI
 (#24870)

---
 lib/mastodon/ip_blocks_cli.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/mastodon/ip_blocks_cli.rb b/lib/mastodon/ip_blocks_cli.rb
index 8a8685fe5a..82a08753bc 100644
--- a/lib/mastodon/ip_blocks_cli.rb
+++ b/lib/mastodon/ip_blocks_cli.rb
@@ -11,7 +11,7 @@ module Mastodon
       true
     end
 
-    option :severity, required: true, enum: %w(no_access sign_up_requires_approval), desc: 'Severity of the block'
+    option :severity, required: true, enum: %w(no_access sign_up_requires_approval sign_up_block), desc: 'Severity of the block'
     option :comment, aliases: [:c], desc: 'Optional comment'
     option :duration, aliases: [:d], type: :numeric, desc: 'Duration of the block in seconds'
     option :force, type: :boolean, aliases: [:f], desc: 'Overwrite existing blocks'

From a3a2414f0ea91c26276728fc7f9d837f81828075 Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Tue, 9 May 2023 14:55:35 +0200
Subject: [PATCH 05/11] Rework polyfills loading (#24907)

---
 .../base_polyfills.ts}                        | 22 ++----
 .../extra_polyfills.ts}                       |  0
 .../{load_polyfills.js => polyfills/index.ts} | 16 ++---
 app/javascript/packs/application.js           |  2 +-
 app/javascript/packs/public.jsx               |  6 +-
 app/javascript/packs/share.jsx                |  2 +-
 package.json                                  |  5 +-
 tsconfig.json                                 |  1 +
 yarn.lock                                     | 70 ++-----------------
 9 files changed, 25 insertions(+), 99 deletions(-)
 rename app/javascript/mastodon/{base_polyfills.js => polyfills/base_polyfills.ts} (58%)
 rename app/javascript/mastodon/{extra_polyfills.js => polyfills/extra_polyfills.ts} (100%)
 rename app/javascript/mastodon/{load_polyfills.js => polyfills/index.ts} (82%)

diff --git a/app/javascript/mastodon/base_polyfills.js b/app/javascript/mastodon/polyfills/base_polyfills.ts
similarity index 58%
rename from app/javascript/mastodon/base_polyfills.js
rename to app/javascript/mastodon/polyfills/base_polyfills.ts
index 91bc5d6dc8..2e583f580d 100644
--- a/app/javascript/mastodon/base_polyfills.js
+++ b/app/javascript/mastodon/polyfills/base_polyfills.ts
@@ -1,26 +1,16 @@
 import 'intl';
 import 'intl/locale-data/jsonp/en';
-import 'es6-symbol/implement';
-import assign from 'object-assign';
-import values from 'object.values';
-import { decode as decodeBase64 } from './utils/base64';
-import promiseFinally from 'promise.prototype.finally';
-
-if (!Object.assign) {
-  Object.assign = assign;
-}
-
-if (!Object.values) {
-  values.shim();
-}
-
-promiseFinally.shim();
+import 'core-js/features/object/assign';
+import 'core-js/features/object/values';
+import 'core-js/features/symbol';
+import 'core-js/features/promise/finally';
+import { decode as decodeBase64 } from '../utils/base64';
 
 if (!HTMLCanvasElement.prototype.toBlob) {
   const BASE64_MARKER = ';base64,';
 
   Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
-    value(callback, type = 'image/png', quality) {
+    value(callback: BlobCallback, type = 'image/png', quality: any)  {
       const dataURL = this.toDataURL(type, quality);
       let data;
 
diff --git a/app/javascript/mastodon/extra_polyfills.js b/app/javascript/mastodon/polyfills/extra_polyfills.ts
similarity index 100%
rename from app/javascript/mastodon/extra_polyfills.js
rename to app/javascript/mastodon/polyfills/extra_polyfills.ts
diff --git a/app/javascript/mastodon/load_polyfills.js b/app/javascript/mastodon/polyfills/index.ts
similarity index 82%
rename from app/javascript/mastodon/load_polyfills.js
rename to app/javascript/mastodon/polyfills/index.ts
index 7909dc4ea3..6d2e5426e4 100644
--- a/app/javascript/mastodon/load_polyfills.js
+++ b/app/javascript/mastodon/polyfills/index.ts
@@ -10,14 +10,14 @@ function importExtraPolyfills() {
   return import(/* webpackChunkName: "extra_polyfills" */ './extra_polyfills');
 }
 
-function loadPolyfills() {
+export function loadPolyfills() {
   const needsBasePolyfills = !(
-    HTMLCanvasElement.prototype.toBlob &&
-    window.Intl &&
-    Object.assign &&
-    Object.values &&
-    window.Symbol &&
-    Promise.prototype.finally
+    'toBlob' in HTMLCanvasElement.prototype &&
+    'Intl' in window &&
+    'assign' in Object &&
+    'values' in Object &&
+    'Symbol' in window &&
+    'finally' in Promise.prototype
   );
 
   // Latest version of Firefox and Safari do not have IntersectionObserver.
@@ -36,5 +36,3 @@ function loadPolyfills() {
     needsExtraPolyfills && importExtraPolyfills(),
   ]);
 }
-
-export default loadPolyfills;
diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js
index 020f2b4a0e..ab87083659 100644
--- a/app/javascript/packs/application.js
+++ b/app/javascript/packs/application.js
@@ -1,5 +1,5 @@
 import './public-path';
-import loadPolyfills from '../mastodon/load_polyfills';
+import { loadPolyfills } from '../mastodon/polyfills';
 import { start } from '../mastodon/common';
 
 start();
diff --git a/app/javascript/packs/public.jsx b/app/javascript/packs/public.jsx
index 21c52fc12a..3c6fd36300 100644
--- a/app/javascript/packs/public.jsx
+++ b/app/javascript/packs/public.jsx
@@ -1,9 +1,9 @@
 import './public-path';
-import loadPolyfills from '../mastodon/load_polyfills';
+import escapeTextContentForBrowser from 'escape-html';
+import { loadPolyfills } from '../mastodon/polyfills';
+import ready from '../mastodon/ready';
 import { start } from '../mastodon/common';
 
-import escapeTextContentForBrowser from 'escape-html';
-import ready from '../mastodon/ready';
 import loadKeyboardExtensions from '../mastodon/load_keyboard_extensions';
 import 'cocoon-js-vanilla';
 import axios from 'axios';
diff --git a/app/javascript/packs/share.jsx b/app/javascript/packs/share.jsx
index 97c3c7b0e5..542a2f3ae8 100644
--- a/app/javascript/packs/share.jsx
+++ b/app/javascript/packs/share.jsx
@@ -1,5 +1,5 @@
 import './public-path';
-import loadPolyfills from '../mastodon/load_polyfills';
+import { loadPolyfills } from '../mastodon/polyfills';
 import { start } from '../mastodon/common';
 import ready from '../mastodon/ready';
 import ComposeContainer  from '../mastodon/containers/compose_container';
diff --git a/package.json b/package.json
index b56b79d9fa..8ca7727225 100644
--- a/package.json
+++ b/package.json
@@ -52,13 +52,13 @@
     "cocoon-js-vanilla": "^1.3.0",
     "color-blend": "^4.0.0",
     "compression-webpack-plugin": "^6.1.1",
+    "core-js": "^3.30.2",
     "cross-env": "^7.0.3",
     "css-loader": "^5.2.7",
     "cssnano": "^6.0.1",
     "detect-passive-events": "^2.0.3",
     "dotenv": "^16.0.3",
     "emoji-mart": "npm:emoji-mart-lazyload@latest",
-    "es6-symbol": "^3.1.3",
     "escape-html": "^1.0.3",
     "express": "^4.18.2",
     "file-loader": "^6.2.0",
@@ -80,14 +80,11 @@
     "mini-css-extract-plugin": "^1.6.2",
     "mkdirp": "^2.1.6",
     "npmlog": "^7.0.1",
-    "object-assign": "^4.1.1",
-    "object.values": "^1.1.6",
     "path-complete-extname": "^1.0.0",
     "pg": "^8.5.0",
     "pg-connection-string": "^2.5.0",
     "postcss": "^8.4.23",
     "postcss-loader": "^4.3.0",
-    "promise.prototype.finally": "^3.1.4",
     "prop-types": "^15.8.1",
     "punycode": "^2.3.0",
     "react": "^16.14.0",
diff --git a/tsconfig.json b/tsconfig.json
index 09cea2a75f..2c2193d55f 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -2,6 +2,7 @@
   "compilerOptions": {
     "jsx": "react",
     "target": "esnext",
+    "module": "CommonJS",
     "moduleResolution": "node",
     "allowJs": true,
     "noEmit": true,
diff --git a/yarn.lock b/yarn.lock
index be8ef990fd..380fc480a7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4135,6 +4135,11 @@ core-js@^2.5.0:
   resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
   integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
 
+core-js@^3.30.2:
+  version "3.30.2"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.30.2.tgz#6528abfda65e5ad728143ea23f7a14f0dcf503fc"
+  integrity sha512-uBJiDmwqsbJCWHAwjrx3cvjbMXP7xD72Dmsn5LOJpiRmE3WbBbN5rCqQ2Qh6Ek6/eOrjlWngEynBWo4VxerQhg==
+
 core-util-is@~1.0.0:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@@ -4409,14 +4414,6 @@ csstype@^3.0.2:
   resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.6.tgz#865d0b5833d7d8d40f4e5b8a6d76aea3de4725ef"
   integrity sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw==
 
-d@1, d@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a"
-  integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==
-  dependencies:
-    es5-ext "^0.10.50"
-    type "^1.0.1"
-
 damerau-levenshtein@^1.0.8:
   version "1.0.8"
   resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
@@ -4967,32 +4964,6 @@ es-to-primitive@^1.2.1:
     is-date-object "^1.0.1"
     is-symbol "^1.0.2"
 
-es5-ext@^0.10.35, es5-ext@^0.10.50:
-  version "0.10.53"
-  resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1"
-  integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==
-  dependencies:
-    es6-iterator "~2.0.3"
-    es6-symbol "~3.1.3"
-    next-tick "~1.0.0"
-
-es6-iterator@~2.0.3:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
-  integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
-  dependencies:
-    d "1"
-    es5-ext "^0.10.35"
-    es6-symbol "^3.1.1"
-
-es6-symbol@^3.1.1, es6-symbol@^3.1.3, es6-symbol@~3.1.3:
-  version "3.1.3"
-  resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18"
-  integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
-  dependencies:
-    d "^1.0.1"
-    ext "^1.1.2"
-
 escalade@^3.1.1:
   version "3.1.1"
   resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
@@ -5425,13 +5396,6 @@ express@^4.17.1, express@^4.18.2:
     utils-merge "1.0.1"
     vary "~1.1.2"
 
-ext@^1.1.2:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244"
-  integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==
-  dependencies:
-    type "^2.0.0"
-
 extend-shallow@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
@@ -8234,11 +8198,6 @@ neo-async@^2.5.0, neo-async@^2.6.1, neo-async@^2.6.2:
   resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
   integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
 
-next-tick@~1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
-  integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
-
 nice-try@^1.0.4:
   version "1.0.5"
   resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
@@ -9284,15 +9243,6 @@ promise-inflight@^1.0.1:
   resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
   integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
 
-promise.prototype.finally@^3.1.4:
-  version "3.1.4"
-  resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.4.tgz#4e756a154e4db27fae24c6b18703495c31da3927"
-  integrity sha512-nNc3YbgMfLzqtqvO/q5DP6RR0SiHI9pUPGzyDf1q+usTwCN2kjvAnJkBb7bHe3o+fFSBPpsGMoYtaSi+LTNqng==
-  dependencies:
-    call-bind "^1.0.2"
-    define-properties "^1.1.4"
-    es-abstract "^1.20.4"
-
 prompts@^2.0.1:
   version "2.3.2"
   resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068"
@@ -11426,16 +11376,6 @@ type-is@~1.6.18:
     media-typer "0.3.0"
     mime-types "~2.1.24"
 
-type@^1.0.1:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0"
-  integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==
-
-type@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3"
-  integrity sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==
-
 "typescript@^4.7 || 5", typescript@^5.0.4:
   version "5.0.4"
   resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b"

From af7bf59b3e4e9fb401248908146442eaf5f571e5 Mon Sep 17 00:00:00 2001
From: eggplants <w10776e8w@yahoo.co.jp>
Date: Tue, 9 May 2023 21:56:02 +0900
Subject: [PATCH 06/11] Fix wrong documentation link (#24924)

---
 .rubocop.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.rubocop.yml b/.rubocop.yml
index 966a2a43db..ceade6e582 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -157,7 +157,7 @@ Metrics/MethodLength:
     - 'lib/mastodon/*_cli.rb'
 
 # Reason:
-# https://docs.rubocop.org/rubocop/cops_style.html#stylerescuestandarderror
+# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsmodulelength
 Metrics/ModuleLength:
   CountAsOne: [array, heredoc]
 

From a5ba98d2df44d15a280ea46d8353698862555620 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 9 May 2023 15:25:49 +0200
Subject: [PATCH 07/11] Bump @typescript-eslint/parser from 5.59.2 to 5.59.5
 (#24921)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 package.json |  2 +-
 yarn.lock    | 48 +++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/package.json b/package.json
index 8ca7727225..9e14c16898 100644
--- a/package.json
+++ b/package.json
@@ -177,7 +177,7 @@
     "@types/webpack": "^4.41.33",
     "@types/yargs": "^17.0.24",
     "@typescript-eslint/eslint-plugin": "^5.59.2",
-    "@typescript-eslint/parser": "^5.59.2",
+    "@typescript-eslint/parser": "^5.59.5",
     "babel-jest": "^29.5.0",
     "eslint": "^8.39.0",
     "eslint-plugin-formatjs": "^4.10.1",
diff --git a/yarn.lock b/yarn.lock
index 380fc480a7..7551e9fa7f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2491,14 +2491,14 @@
     semver "^7.3.7"
     tsutils "^3.21.0"
 
-"@typescript-eslint/parser@^5.59.2":
-  version "5.59.2"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.2.tgz#c2c443247901d95865b9f77332d9eee7c55655e8"
-  integrity sha512-uq0sKyw6ao1iFOZZGk9F8Nro/8+gfB5ezl1cA06SrqbgJAt0SRoFhb9pXaHvkrxUpZaoLxt8KlovHNk8Gp6/HQ==
+"@typescript-eslint/parser@^5.59.5":
+  version "5.59.5"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.5.tgz#63064f5eafbdbfb5f9dfbf5c4503cdf949852981"
+  integrity sha512-NJXQC4MRnF9N9yWqQE2/KLRSOLvrrlZb48NGVfBa+RuPMN6B7ZcK5jZOvhuygv4D64fRKnZI4L4p8+M+rfeQuw==
   dependencies:
-    "@typescript-eslint/scope-manager" "5.59.2"
-    "@typescript-eslint/types" "5.59.2"
-    "@typescript-eslint/typescript-estree" "5.59.2"
+    "@typescript-eslint/scope-manager" "5.59.5"
+    "@typescript-eslint/types" "5.59.5"
+    "@typescript-eslint/typescript-estree" "5.59.5"
     debug "^4.3.4"
 
 "@typescript-eslint/scope-manager@5.59.2":
@@ -2509,6 +2509,14 @@
     "@typescript-eslint/types" "5.59.2"
     "@typescript-eslint/visitor-keys" "5.59.2"
 
+"@typescript-eslint/scope-manager@5.59.5":
+  version "5.59.5"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.5.tgz#33ffc7e8663f42cfaac873de65ebf65d2bce674d"
+  integrity sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A==
+  dependencies:
+    "@typescript-eslint/types" "5.59.5"
+    "@typescript-eslint/visitor-keys" "5.59.5"
+
 "@typescript-eslint/type-utils@5.59.2":
   version "5.59.2"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.2.tgz#0729c237503604cd9a7084b5af04c496c9a4cdcf"
@@ -2529,6 +2537,11 @@
   resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.2.tgz#b511d2b9847fe277c5cb002a2318bd329ef4f655"
   integrity sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w==
 
+"@typescript-eslint/types@5.59.5":
+  version "5.59.5"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.5.tgz#e63c5952532306d97c6ea432cee0981f6d2258c7"
+  integrity sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w==
+
 "@typescript-eslint/typescript-estree@5.59.0":
   version "5.59.0"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.0.tgz#8869156ee1dcfc5a95be3ed0e2809969ea28e965"
@@ -2555,6 +2568,19 @@
     semver "^7.3.7"
     tsutils "^3.21.0"
 
+"@typescript-eslint/typescript-estree@5.59.5":
+  version "5.59.5"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.5.tgz#9b252ce55dd765e972a7a2f99233c439c5101e42"
+  integrity sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg==
+  dependencies:
+    "@typescript-eslint/types" "5.59.5"
+    "@typescript-eslint/visitor-keys" "5.59.5"
+    debug "^4.3.4"
+    globby "^11.1.0"
+    is-glob "^4.0.3"
+    semver "^7.3.7"
+    tsutils "^3.21.0"
+
 "@typescript-eslint/utils@5.59.2":
   version "5.59.2"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.2.tgz#0c45178124d10cc986115885688db6abc37939f4"
@@ -2585,6 +2611,14 @@
     "@typescript-eslint/types" "5.59.2"
     eslint-visitor-keys "^3.3.0"
 
+"@typescript-eslint/visitor-keys@5.59.5":
+  version "5.59.5"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.5.tgz#ba5b8d6791a13cf9fea6716af1e7626434b29b9b"
+  integrity sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA==
+  dependencies:
+    "@typescript-eslint/types" "5.59.5"
+    eslint-visitor-keys "^3.3.0"
+
 "@webassemblyjs/ast@1.9.0":
   version "1.9.0"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964"

From 72dcb2ef5873300d4716697ee09d6c61303b33bf Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 9 May 2023 15:42:21 +0200
Subject: [PATCH 08/11] Bump @typescript-eslint/eslint-plugin from 5.59.2 to
 5.59.5 (#24922)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 package.json |  2 +-
 yarn.lock    | 74 ++++++++++++++--------------------------------------
 2 files changed, 21 insertions(+), 55 deletions(-)

diff --git a/package.json b/package.json
index 9e14c16898..9129c8b0a3 100644
--- a/package.json
+++ b/package.json
@@ -176,7 +176,7 @@
     "@types/uuid": "^9.0.0",
     "@types/webpack": "^4.41.33",
     "@types/yargs": "^17.0.24",
-    "@typescript-eslint/eslint-plugin": "^5.59.2",
+    "@typescript-eslint/eslint-plugin": "^5.59.5",
     "@typescript-eslint/parser": "^5.59.5",
     "babel-jest": "^29.5.0",
     "eslint": "^8.39.0",
diff --git a/yarn.lock b/yarn.lock
index 7551e9fa7f..72fb0a3335 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2475,15 +2475,15 @@
   dependencies:
     "@types/yargs-parser" "*"
 
-"@typescript-eslint/eslint-plugin@^5.59.2":
-  version "5.59.2"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.2.tgz#684a2ce7182f3b4dac342eef7caa1c2bae476abd"
-  integrity sha512-yVrXupeHjRxLDcPKL10sGQ/QlVrA8J5IYOEWVqk0lJaSZP7X5DfnP7Ns3cc74/blmbipQ1htFNVGsHX6wsYm0A==
+"@typescript-eslint/eslint-plugin@^5.59.5":
+  version "5.59.5"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.5.tgz#f156827610a3f8cefc56baeaa93cd4a5f32966b4"
+  integrity sha512-feA9xbVRWJZor+AnLNAr7A8JRWeZqHUf4T9tlP+TN04b05pFVhO5eN7/O93Y/1OUlLMHKbnJisgDURs/qvtqdg==
   dependencies:
     "@eslint-community/regexpp" "^4.4.0"
-    "@typescript-eslint/scope-manager" "5.59.2"
-    "@typescript-eslint/type-utils" "5.59.2"
-    "@typescript-eslint/utils" "5.59.2"
+    "@typescript-eslint/scope-manager" "5.59.5"
+    "@typescript-eslint/type-utils" "5.59.5"
+    "@typescript-eslint/utils" "5.59.5"
     debug "^4.3.4"
     grapheme-splitter "^1.0.4"
     ignore "^5.2.0"
@@ -2501,14 +2501,6 @@
     "@typescript-eslint/typescript-estree" "5.59.5"
     debug "^4.3.4"
 
-"@typescript-eslint/scope-manager@5.59.2":
-  version "5.59.2"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.2.tgz#f699fe936ee4e2c996d14f0fdd3a7da5ba7b9a4c"
-  integrity sha512-dB1v7ROySwQWKqQ8rEWcdbTsFjh2G0vn8KUyvTXdPoyzSL6lLGkiXEV5CvpJsEe9xIdKV+8Zqb7wif2issoOFA==
-  dependencies:
-    "@typescript-eslint/types" "5.59.2"
-    "@typescript-eslint/visitor-keys" "5.59.2"
-
 "@typescript-eslint/scope-manager@5.59.5":
   version "5.59.5"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.5.tgz#33ffc7e8663f42cfaac873de65ebf65d2bce674d"
@@ -2517,13 +2509,13 @@
     "@typescript-eslint/types" "5.59.5"
     "@typescript-eslint/visitor-keys" "5.59.5"
 
-"@typescript-eslint/type-utils@5.59.2":
-  version "5.59.2"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.2.tgz#0729c237503604cd9a7084b5af04c496c9a4cdcf"
-  integrity sha512-b1LS2phBOsEy/T381bxkkywfQXkV1dWda/z0PhnIy3bC5+rQWQDS7fk9CSpcXBccPY27Z6vBEuaPBCKCgYezyQ==
+"@typescript-eslint/type-utils@5.59.5":
+  version "5.59.5"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.5.tgz#485b0e2c5b923460bc2ea6b338c595343f06fc9b"
+  integrity sha512-4eyhS7oGym67/pSxA2mmNq7X164oqDYNnZCUayBwJZIRVvKpBCMBzFnFxjeoDeShjtO6RQBHBuwybuX3POnDqg==
   dependencies:
-    "@typescript-eslint/typescript-estree" "5.59.2"
-    "@typescript-eslint/utils" "5.59.2"
+    "@typescript-eslint/typescript-estree" "5.59.5"
+    "@typescript-eslint/utils" "5.59.5"
     debug "^4.3.4"
     tsutils "^3.21.0"
 
@@ -2532,11 +2524,6 @@
   resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.0.tgz#3fcdac7dbf923ec5251545acdd9f1d42d7c4fe32"
   integrity sha512-yR2h1NotF23xFFYKHZs17QJnB51J/s+ud4PYU4MqdZbzeNxpgUr05+dNeCN/bb6raslHvGdd6BFCkVhpPk/ZeA==
 
-"@typescript-eslint/types@5.59.2":
-  version "5.59.2"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.2.tgz#b511d2b9847fe277c5cb002a2318bd329ef4f655"
-  integrity sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w==
-
 "@typescript-eslint/types@5.59.5":
   version "5.59.5"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.5.tgz#e63c5952532306d97c6ea432cee0981f6d2258c7"
@@ -2555,19 +2542,6 @@
     semver "^7.3.7"
     tsutils "^3.21.0"
 
-"@typescript-eslint/typescript-estree@5.59.2":
-  version "5.59.2"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz#6e2fabd3ba01db5d69df44e0b654c0b051fe9936"
-  integrity sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q==
-  dependencies:
-    "@typescript-eslint/types" "5.59.2"
-    "@typescript-eslint/visitor-keys" "5.59.2"
-    debug "^4.3.4"
-    globby "^11.1.0"
-    is-glob "^4.0.3"
-    semver "^7.3.7"
-    tsutils "^3.21.0"
-
 "@typescript-eslint/typescript-estree@5.59.5":
   version "5.59.5"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.5.tgz#9b252ce55dd765e972a7a2f99233c439c5101e42"
@@ -2581,17 +2555,17 @@
     semver "^7.3.7"
     tsutils "^3.21.0"
 
-"@typescript-eslint/utils@5.59.2":
-  version "5.59.2"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.2.tgz#0c45178124d10cc986115885688db6abc37939f4"
-  integrity sha512-kSuF6/77TZzyGPhGO4uVp+f0SBoYxCDf+lW3GKhtKru/L8k/Hd7NFQxyWUeY7Z/KGB2C6Fe3yf2vVi4V9TsCSQ==
+"@typescript-eslint/utils@5.59.5":
+  version "5.59.5"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.5.tgz#15b3eb619bb223302e60413adb0accd29c32bcae"
+  integrity sha512-sCEHOiw+RbyTii9c3/qN74hYDPNORb8yWCoPLmB7BIflhplJ65u2PBpdRla12e3SSTJ2erRkPjz7ngLHhUegxA==
   dependencies:
     "@eslint-community/eslint-utils" "^4.2.0"
     "@types/json-schema" "^7.0.9"
     "@types/semver" "^7.3.12"
-    "@typescript-eslint/scope-manager" "5.59.2"
-    "@typescript-eslint/types" "5.59.2"
-    "@typescript-eslint/typescript-estree" "5.59.2"
+    "@typescript-eslint/scope-manager" "5.59.5"
+    "@typescript-eslint/types" "5.59.5"
+    "@typescript-eslint/typescript-estree" "5.59.5"
     eslint-scope "^5.1.1"
     semver "^7.3.7"
 
@@ -2603,14 +2577,6 @@
     "@typescript-eslint/types" "5.59.0"
     eslint-visitor-keys "^3.3.0"
 
-"@typescript-eslint/visitor-keys@5.59.2":
-  version "5.59.2"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.2.tgz#37a419dc2723a3eacbf722512b86d6caf7d3b750"
-  integrity sha512-EEpsO8m3RASrKAHI9jpavNv9NlEUebV4qmF1OWxSTtKSFBpC1NCmWazDQHFivRf0O1DV11BA645yrLEVQ0/Lig==
-  dependencies:
-    "@typescript-eslint/types" "5.59.2"
-    eslint-visitor-keys "^3.3.0"
-
 "@typescript-eslint/visitor-keys@5.59.5":
   version "5.59.5"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.5.tgz#ba5b8d6791a13cf9fea6716af1e7626434b29b9b"

From 224d458f7e351e8c88f71b44d338578525961c88 Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Tue, 9 May 2023 15:48:53 +0200
Subject: [PATCH 09/11] Remove unused iOS agent sniffing function (#24931)

---
 app/javascript/mastodon/is_mobile.ts | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/app/javascript/mastodon/is_mobile.ts b/app/javascript/mastodon/is_mobile.ts
index 43819f85db..b2918eb4bf 100644
--- a/app/javascript/mastodon/is_mobile.ts
+++ b/app/javascript/mastodon/is_mobile.ts
@@ -16,10 +16,6 @@ export const layoutFromWindow = (): LayoutType => {
   }
 };
 
-// eslint-disable-next-line @typescript-eslint/ban-ts-comment
-// @ts-expect-error
-const iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && window.MSStream != null;
-
 const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
 
 let userTouching = false;
@@ -33,5 +29,3 @@ const touchListener = () => {
 window.addEventListener('touchstart', touchListener, listenerOptions);
 
 export const isUserTouching = () => userTouching;
-
-export const isIOS = () => iOS;

From e1f466fbbe94a57f1552b28fc819dc90cd3294d3 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Tue, 9 May 2023 16:42:02 +0200
Subject: [PATCH 10/11] Fix javascript on moderation interface (#24933)

---
 app/javascript/packs/public.jsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/javascript/packs/public.jsx b/app/javascript/packs/public.jsx
index 3c6fd36300..1ea39e05a6 100644
--- a/app/javascript/packs/public.jsx
+++ b/app/javascript/packs/public.jsx
@@ -12,7 +12,7 @@ import { defineMessages } from 'react-intl';
 import * as IntlMessageFormat  from 'intl-messageformat';
 import { timeAgoString }  from '../mastodon/components/relative_timestamp';
 import { delegate }  from '@rails/ujs';
-import * as emojify  from '../mastodon/features/emoji/emoji';
+import emojify  from '../mastodon/features/emoji/emoji';
 import { getLocale }  from '../mastodon/locales';
 import React  from 'react';
 import ReactDOM  from 'react-dom';

From 6aeb162927e6f9bbfd597632a10d82d9656c2385 Mon Sep 17 00:00:00 2001
From: Renaud Chaput <renchap@gmail.com>
Date: Tue, 9 May 2023 16:56:26 +0200
Subject: [PATCH 11/11] Type Redux store and middleware (#24843)

---
 .../mastodon/containers/compose_container.jsx |  2 +-
 .../mastodon/containers/mastodon.jsx          |  2 +-
 app/javascript/mastodon/main.jsx              |  2 +-
 .../mastodon/reducers/{index.js => index.ts}  |  4 ++-
 .../mastodon/store/configureStore.js          | 16 ------------
 app/javascript/mastodon/store/index.ts        | 23 ++++++++++++++++
 .../errors.js => store/middlewares/errors.ts} |  9 ++++---
 .../middlewares/loading_bar.ts}               | 12 ++++++---
 .../sounds.js => store/middlewares/sounds.ts} | 26 +++++++++++++------
 9 files changed, 61 insertions(+), 35 deletions(-)
 rename app/javascript/mastodon/reducers/{index.js => index.ts} (97%)
 delete mode 100644 app/javascript/mastodon/store/configureStore.js
 create mode 100644 app/javascript/mastodon/store/index.ts
 rename app/javascript/mastodon/{middleware/errors.js => store/middlewares/errors.ts} (55%)
 rename app/javascript/mastodon/{middleware/loading_bar.js => store/middlewares/loading_bar.ts} (68%)
 rename app/javascript/mastodon/{middleware/sounds.js => store/middlewares/sounds.ts} (54%)

diff --git a/app/javascript/mastodon/containers/compose_container.jsx b/app/javascript/mastodon/containers/compose_container.jsx
index a4c5f3cb49..9213c5614e 100644
--- a/app/javascript/mastodon/containers/compose_container.jsx
+++ b/app/javascript/mastodon/containers/compose_container.jsx
@@ -1,7 +1,7 @@
 import React from 'react';
 import { Provider } from 'react-redux';
 import PropTypes from 'prop-types';
-import { store } from '../store/configureStore';
+import { store } from '../store';
 import { hydrateStore } from '../actions/store';
 import { IntlProvider, addLocaleData } from 'react-intl';
 import { getLocale } from '../locales';
diff --git a/app/javascript/mastodon/containers/mastodon.jsx b/app/javascript/mastodon/containers/mastodon.jsx
index 256ea8e2d9..9c6c9e5920 100644
--- a/app/javascript/mastodon/containers/mastodon.jsx
+++ b/app/javascript/mastodon/containers/mastodon.jsx
@@ -5,7 +5,7 @@ import { IntlProvider, addLocaleData } from 'react-intl';
 import { Provider as ReduxProvider } from 'react-redux';
 import { BrowserRouter, Route } from 'react-router-dom';
 import { ScrollContext } from 'react-router-scroll-4';
-import { store } from 'mastodon/store/configureStore';
+import { store } from 'mastodon/store';
 import UI from 'mastodon/features/ui';
 import { fetchCustomEmojis } from 'mastodon/actions/custom_emojis';
 import { hydrateStore } from 'mastodon/actions/store';
diff --git a/app/javascript/mastodon/main.jsx b/app/javascript/mastodon/main.jsx
index d8654adedb..c5960477db 100644
--- a/app/javascript/mastodon/main.jsx
+++ b/app/javascript/mastodon/main.jsx
@@ -2,7 +2,7 @@ import React from 'react';
 import ReactDOM from 'react-dom';
 import { setupBrowserNotifications } from 'mastodon/actions/notifications';
 import Mastodon from 'mastodon/containers/mastodon';
-import { store } from 'mastodon/store/configureStore';
+import { store } from 'mastodon/store';
 import { me } from 'mastodon/initial_state';
 import ready from 'mastodon/ready';
 import * as perf from 'mastodon/performance';
diff --git a/app/javascript/mastodon/reducers/index.js b/app/javascript/mastodon/reducers/index.ts
similarity index 97%
rename from app/javascript/mastodon/reducers/index.js
rename to app/javascript/mastodon/reducers/index.ts
index 4d705f0412..518d8cd792 100644
--- a/app/javascript/mastodon/reducers/index.js
+++ b/app/javascript/mastodon/reducers/index.ts
@@ -87,4 +87,6 @@ const reducers = {
   followed_tags,
 };
 
-export default combineReducers(reducers);
+const rootReducer = combineReducers(reducers);
+
+export { rootReducer };
diff --git a/app/javascript/mastodon/store/configureStore.js b/app/javascript/mastodon/store/configureStore.js
deleted file mode 100644
index cb17dd9ce8..0000000000
--- a/app/javascript/mastodon/store/configureStore.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import { configureStore } from '@reduxjs/toolkit';
-import thunk from 'redux-thunk';
-import appReducer from '../reducers';
-import loadingBarMiddleware from '../middleware/loading_bar';
-import errorsMiddleware from '../middleware/errors';
-import soundsMiddleware from '../middleware/sounds';
-
-export const store = configureStore({
-  reducer: appReducer,
-  middleware: [
-    thunk,
-    loadingBarMiddleware({ promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAIL'] }),
-    errorsMiddleware(),
-    soundsMiddleware(),
-  ],
-});
diff --git a/app/javascript/mastodon/store/index.ts b/app/javascript/mastodon/store/index.ts
new file mode 100644
index 0000000000..822c01aa90
--- /dev/null
+++ b/app/javascript/mastodon/store/index.ts
@@ -0,0 +1,23 @@
+import { configureStore } from '@reduxjs/toolkit';
+import { rootReducer } from '../reducers';
+import { loadingBarMiddleware } from './middlewares/loading_bar';
+import { errorsMiddleware } from './middlewares/errors';
+import { soundsMiddleware } from './middlewares/sounds';
+import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
+
+export const store = configureStore({
+  reducer: rootReducer,
+  middleware: getDefaultMiddleware =>
+    getDefaultMiddleware().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;
diff --git a/app/javascript/mastodon/middleware/errors.js b/app/javascript/mastodon/store/middlewares/errors.ts
similarity index 55%
rename from app/javascript/mastodon/middleware/errors.js
rename to app/javascript/mastodon/store/middlewares/errors.ts
index 708df6bb8d..b135fa2ee8 100644
--- a/app/javascript/mastodon/middleware/errors.js
+++ b/app/javascript/mastodon/store/middlewares/errors.ts
@@ -1,9 +1,11 @@
-import { showAlertForError } from '../actions/alerts';
+import { Middleware } from 'redux';
+import { showAlertForError } from '../../actions/alerts';
+import { RootState } from '..';
 
 const defaultFailSuffix = 'FAIL';
 
-export default function errorsMiddleware() {
-  return ({ dispatch }) => next => action => {
+export const errorsMiddleware: Middleware<Record<string, never>, RootState> =
+  ({ dispatch }) => next => action => {
     if (action.type && !action.skipAlert) {
       const isFail = new RegExp(`${defaultFailSuffix}$`, 'g');
 
@@ -14,4 +16,3 @@ export default function errorsMiddleware() {
 
     return next(action);
   };
-}
diff --git a/app/javascript/mastodon/middleware/loading_bar.js b/app/javascript/mastodon/store/middlewares/loading_bar.ts
similarity index 68%
rename from app/javascript/mastodon/middleware/loading_bar.js
rename to app/javascript/mastodon/store/middlewares/loading_bar.ts
index da8cc4c7d3..e860b31b6f 100644
--- a/app/javascript/mastodon/middleware/loading_bar.js
+++ b/app/javascript/mastodon/store/middlewares/loading_bar.ts
@@ -1,8 +1,14 @@
 import { showLoading, hideLoading } from 'react-redux-loading-bar';
+import { Middleware } from 'redux';
+import { RootState } from '..';
 
-const defaultTypeSuffixes = ['PENDING', 'FULFILLED', 'REJECTED'];
+interface Config {
+  promiseTypeSuffixes?: string[]
+}
 
-export default function loadingBarMiddleware(config = {}) {
+const defaultTypeSuffixes: Config['promiseTypeSuffixes'] = ['PENDING', 'FULFILLED', 'REJECTED'];
+
+export  const loadingBarMiddleware = (config: Config = {}): Middleware<Record<string, never>, RootState> => {
   const promiseTypeSuffixes = config.promiseTypeSuffixes || defaultTypeSuffixes;
 
   return ({ dispatch }) => next => (action) => {
@@ -22,4 +28,4 @@ export default function loadingBarMiddleware(config = {}) {
 
     return next(action);
   };
-}
+};
diff --git a/app/javascript/mastodon/middleware/sounds.js b/app/javascript/mastodon/store/middlewares/sounds.ts
similarity index 54%
rename from app/javascript/mastodon/middleware/sounds.js
rename to app/javascript/mastodon/store/middlewares/sounds.ts
index 7f23889836..c9d51f857f 100644
--- a/app/javascript/mastodon/middleware/sounds.js
+++ b/app/javascript/mastodon/store/middlewares/sounds.ts
@@ -1,4 +1,12 @@
-const createAudio = sources => {
+import { Middleware, AnyAction } from 'redux';
+import { RootState } from '..';
+
+interface AudioSource {
+  src: string
+  type: string
+}
+
+const createAudio = (sources: AudioSource[]) => {
   const audio = new Audio();
   sources.forEach(({ type, src }) => {
     const source = document.createElement('source');
@@ -9,7 +17,7 @@ const createAudio = sources => {
   return audio;
 };
 
-const play = audio => {
+const play = (audio: HTMLAudioElement) => {
   if (!audio.paused) {
     audio.pause();
     if (typeof audio.fastSeek === 'function') {
@@ -22,8 +30,8 @@ const play = audio => {
   audio.play();
 };
 
-export default function soundsMiddleware() {
-  const soundCache = {
+export  const soundsMiddleware = (): Middleware<Record<string, never>, RootState> => {
+  const soundCache: {[key: string]: HTMLAudioElement} = {
     boop: createAudio([
       {
         src: '/sounds/boop.ogg',
@@ -36,11 +44,13 @@ export default function soundsMiddleware() {
     ]),
   };
 
-  return () => next => action => {
-    if (action.meta && action.meta.sound && soundCache[action.meta.sound]) {
-      play(soundCache[action.meta.sound]);
+  return () => next => (action: AnyAction) => {
+    const sound = action?.meta?.sound;
+
+    if (sound && soundCache[sound]) {
+      play(soundCache[sound]);
     }
 
     return next(action);
   };
-}
+};