diff --git a/.config/cypress-devcontainer.yml b/.config/cypress-devcontainer.yml
index e8da5f5e27..91dce35155 100644
--- a/.config/cypress-devcontainer.yml
+++ b/.config/cypress-devcontainer.yml
@@ -103,6 +103,14 @@ redis:
# #prefix: example-prefix
# #db: 1
+#redisForReactions:
+# host: redis
+# port: 6379
+# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
+# #pass: example-pass
+# #prefix: example-prefix
+# #db: 1
+
# ┌───────────────────────────┐
#───┘ MeiliSearch configuration └─────────────────────────────
diff --git a/.config/docker_example.yml b/.config/docker_example.yml
index d347882d1a..3f8e5734ce 100644
--- a/.config/docker_example.yml
+++ b/.config/docker_example.yml
@@ -106,6 +106,14 @@ redis:
# #prefix: example-prefix
# #db: 1
+#redisForReactions:
+# host: redis
+# port: 6379
+# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
+# #pass: example-pass
+# #prefix: example-prefix
+# #db: 1
+
# ┌───────────────────────────┐
#───┘ MeiliSearch configuration └─────────────────────────────
diff --git a/.config/example.yml b/.config/example.yml
index b11cbd1373..7080159117 100644
--- a/.config/example.yml
+++ b/.config/example.yml
@@ -172,6 +172,16 @@ redis:
# # You can specify more ioredis options...
# #username: example-username
+#redisForReactions:
+# host: localhost
+# port: 6379
+# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
+# #pass: example-pass
+# #prefix: example-prefix
+# #db: 1
+# # You can specify more ioredis options...
+# #username: example-username
+
# ┌───────────────────────────┐
#───┘ MeiliSearch configuration └─────────────────────────────
diff --git a/.devcontainer/devcontainer.yml b/.devcontainer/devcontainer.yml
index beefcfd0a2..3eb4fc2879 100644
--- a/.devcontainer/devcontainer.yml
+++ b/.devcontainer/devcontainer.yml
@@ -103,6 +103,14 @@ redis:
# #prefix: example-prefix
# #db: 1
+#redisForReactions:
+# host: redis
+# port: 6379
+# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
+# #pass: example-pass
+# #prefix: example-prefix
+# #db: 1
+
# ┌───────────────────────────┐
#───┘ MeiliSearch configuration └─────────────────────────────
diff --git a/.github/workflows/api-misskey-js.yml b/.github/workflows/api-misskey-js.yml
index e7db18316c..8380a3bb23 100644
--- a/.github/workflows/api-misskey-js.yml
+++ b/.github/workflows/api-misskey-js.yml
@@ -21,7 +21,7 @@ jobs:
- run: corepack enable
- name: Setup Node.js
- uses: actions/setup-node@v4.0.3
+ uses: actions/setup-node@v4.0.4
with:
node-version-file: '.node-version'
cache: 'pnpm'
diff --git a/.github/workflows/changelog-check.yml b/.github/workflows/changelog-check.yml
index d4e99f966e..44cc1a04f2 100644
--- a/.github/workflows/changelog-check.yml
+++ b/.github/workflows/changelog-check.yml
@@ -14,7 +14,7 @@ jobs:
- name: Checkout head
uses: actions/checkout@v4.1.1
- name: Setup Node.js
- uses: actions/setup-node@v4.0.3
+ uses: actions/setup-node@v4.0.4
with:
node-version-file: '.node-version'
diff --git a/.github/workflows/check-misskey-js-autogen.yml b/.github/workflows/check-misskey-js-autogen.yml
index 3a2a2d5f8d..5afd7d2714 100644
--- a/.github/workflows/check-misskey-js-autogen.yml
+++ b/.github/workflows/check-misskey-js-autogen.yml
@@ -28,7 +28,7 @@ jobs:
- name: setup node
id: setup-node
- uses: actions/setup-node@v4.0.3
+ uses: actions/setup-node@v4.0.4
with:
node-version-file: '.node-version'
cache: pnpm
diff --git a/.github/workflows/get-api-diff.yml b/.github/workflows/get-api-diff.yml
index 81e8134fb7..1bcaa0d9c4 100644
--- a/.github/workflows/get-api-diff.yml
+++ b/.github/workflows/get-api-diff.yml
@@ -33,7 +33,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.3
+ uses: actions/setup-node@v4.0.4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 11903e3ec2..3064b0f6f4 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -33,7 +33,7 @@ jobs:
fetch-depth: 0
submodules: true
- uses: pnpm/action-setup@v4
- - uses: actions/setup-node@v4.0.3
+ - uses: actions/setup-node@v4.0.4
with:
node-version-file: '.node-version'
cache: 'pnpm'
@@ -62,7 +62,7 @@ jobs:
fetch-depth: 0
submodules: true
- uses: pnpm/action-setup@v4
- - uses: actions/setup-node@v4.0.3
+ - uses: actions/setup-node@v4.0.4
with:
node-version-file: '.node-version'
cache: 'pnpm'
@@ -92,7 +92,7 @@ jobs:
fetch-depth: 0
submodules: true
- uses: pnpm/action-setup@v4
- - uses: actions/setup-node@v4.0.3
+ - uses: actions/setup-node@v4.0.4
with:
node-version-file: '.node-version'
cache: 'pnpm'
diff --git a/.github/workflows/locale.yml b/.github/workflows/locale.yml
index 95251bfe31..6bc8860a11 100644
--- a/.github/workflows/locale.yml
+++ b/.github/workflows/locale.yml
@@ -19,7 +19,7 @@ jobs:
fetch-depth: 0
submodules: true
- uses: pnpm/action-setup@v4
- - uses: actions/setup-node@v4.0.3
+ - uses: actions/setup-node@v4.0.4
with:
node-version-file: '.node-version'
cache: 'pnpm'
diff --git a/.github/workflows/on-release-created.yml b/.github/workflows/on-release-created.yml
index 8dd9ed2513..ffaf7bc038 100644
--- a/.github/workflows/on-release-created.yml
+++ b/.github/workflows/on-release-created.yml
@@ -26,7 +26,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.3
+ uses: actions/setup-node@v4.0.4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
diff --git a/.github/workflows/report-api-diff.yml b/.github/workflows/report-api-diff.yml
index df9cc279e8..9fd1e28f01 100644
--- a/.github/workflows/report-api-diff.yml
+++ b/.github/workflows/report-api-diff.yml
@@ -70,18 +70,27 @@ jobs:
- id: out-diff
name: Build diff Comment
run: |
- cat <<- EOF > ./output.md
- このPRによるapi.jsonの差分
-
- 差分はこちら
-
- \`\`\`diff
- $(cat ./api.json.diff)
- \`\`\`
-
-
- [Get diff files from Workflow Page](https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})
- EOF
+ HEADER="このPRによるapi.jsonの差分"
+ FOOTER="[Get diff files from Workflow Page](https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})"
+ DIFF_BYTES="$(stat ./api.json.diff -c '%s' | tr -d '\n')"
+
+ echo "$HEADER" > ./output.md
+
+ if (( "$DIFF_BYTES" <= 1 )); then
+ echo '差分はありません。' >> ./output.md
+ else
+ cat <<- EOF >> ./output.md
+
+ 差分はこちら
+
+ \`\`\`diff
+ $(cat ./api.json.diff)
+ \`\`\`
+
+ EOF
+ fi
+
+ echo "$FOOTER" >> ./output.md
- uses: thollander/actions-comment-pull-request@v2
with:
pr_number: ${{ steps.load-pr-num.outputs.pr-number }}
diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml
index bea93f1456..c02f38ee0b 100644
--- a/.github/workflows/storybook.yml
+++ b/.github/workflows/storybook.yml
@@ -41,7 +41,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js 20.x
- uses: actions/setup-node@v4.0.3
+ uses: actions/setup-node@v4.0.4
with:
node-version-file: '.node-version'
cache: 'pnpm'
diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml
index 026550025c..d95d6676f9 100644
--- a/.github/workflows/test-backend.yml
+++ b/.github/workflows/test-backend.yml
@@ -46,7 +46,7 @@ jobs:
- name: Install FFmpeg
uses: FedericoCarboni/setup-ffmpeg@v3
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.3
+ uses: actions/setup-node@v4.0.4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
@@ -93,7 +93,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.3
+ uses: actions/setup-node@v4.0.4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml
index fcaef52969..c68e1a8ef1 100644
--- a/.github/workflows/test-frontend.yml
+++ b/.github/workflows/test-frontend.yml
@@ -35,7 +35,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.3
+ uses: actions/setup-node@v4.0.4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
@@ -90,7 +90,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.3
+ uses: actions/setup-node@v4.0.4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
diff --git a/.github/workflows/test-misskey-js.yml b/.github/workflows/test-misskey-js.yml
index 9ad71919df..63e81f8c92 100644
--- a/.github/workflows/test-misskey-js.yml
+++ b/.github/workflows/test-misskey-js.yml
@@ -31,7 +31,7 @@ jobs:
- run: corepack enable
- name: Setup Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.3
+ uses: actions/setup-node@v4.0.4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
diff --git a/.github/workflows/test-production.yml b/.github/workflows/test-production.yml
index 8ad8a64766..0abc09c5a6 100644
--- a/.github/workflows/test-production.yml
+++ b/.github/workflows/test-production.yml
@@ -25,7 +25,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.3
+ uses: actions/setup-node@v4.0.4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
diff --git a/.github/workflows/validate-api-json.yml b/.github/workflows/validate-api-json.yml
index 06e987f27e..f809af1063 100644
--- a/.github/workflows/validate-api-json.yml
+++ b/.github/workflows/validate-api-json.yml
@@ -27,7 +27,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.3
+ uses: actions/setup-node@v4.0.4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
diff --git a/.gitignore b/.gitignore
index 4d5bd1ce08..b270d5cb3a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,6 +65,10 @@ temp
tsdoc-metadata.json
misskey-assets
+# Vite temporary files
+vite.config.js.timestamp-*
+vite.config.ts.timestamp-*
+
# blender backups
*.blend1
*.blend2
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 52da58612d..3fcc2e62eb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,25 +1,35 @@
-## Unreleased
+## 2024.9.0
### General
--
+- Feat: UserWebhookとSystemWebhookのテスト送信機能を追加 (#14445)
+- Enhance: ユーザーによるコンテンツインポートの可否をロールポリシーで制御できるように
### Client
- Feat: ノート単体・ユーザーのノート・クリップのノートの埋め込み機能
- - 埋め込みコードやウェブサイトへの実装方法の詳細はMisskey Hubに掲載予定です
+ - 埋め込みコードやウェブサイトへの実装方法の詳細は https://misskey-hub.net/docs/for-users/features/embed/ をご覧ください
- Enhance: サイズ制限を超過するファイルをアップロードしようとした際にエラーを出すように
- Enhance: アイコンデコレーション管理画面にプレビューを追加
- Enhance: コントロールパネル内のファイル一覧でセンシティブなファイルを区別しやすく
+- Enhance: ScratchpadにUIインスペクターを追加
- Enhance: どこで投稿フォームを開いてもお気に入りに登録したチャンネルにノートできるように
- Enhance: チャンネルのページを開いている間はデフォルトの公開範囲がそのチャンネルになるように
- Fix: サーバーメトリクスが2つ以上あるとリロード直後の表示がおかしくなる問題を修正
- Fix: 月の違う同じ日はセパレータが表示されないのを修正
+- Fix: 縦横比が極端なカスタム絵文字を表示する際にレイアウトが崩れる箇所があるのを修正
+ (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/725)
+- Fix: 設定変更時のリロード確認ダイアログが複数個表示されることがある問題を修正
+- Fix: ファイルの詳細ページのファイルの説明で改行が正しく表示されない問題を修正
+ (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/commit/bde6bb0bd2e8b0d027e724d2acdb8ae0585a8110)
### Server
+- Feat: Misskey® Reactions Buffering Technology™ (RBT)により、リアクションの作成負荷を低減することが可能に
- Fix: アンテナの書き込み時にキーワードが与えられなかった場合のエラーをApiErrorとして投げるように
- この変更により、公式フロントエンドでは入力の不備が内部エラーとして報告される代わりに一般的なエラーダイアログで報告されます
- Fix: ファイルがサイズの制限を超えてアップロードされた際にエラーを返さなかった問題を修正
- Fix: 外部ページを解析する際に、ページに紐づけられた関連リソースも読み込まれてしまう問題を修正
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/commit/26e0412fbb91447c37e8fb06ffb0487346063bb8)
+- Fix: `Retry-After`ヘッダーが送信されなかった問題を修正
+ (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/commit/8a982c61c01909e7540ff1be9f019df07c3f0624)
## 2024.8.0
diff --git a/chart/files/default.yml b/chart/files/default.yml
index f98b8ebfee..4d17131c25 100644
--- a/chart/files/default.yml
+++ b/chart/files/default.yml
@@ -124,6 +124,14 @@ redis:
# #prefix: example-prefix
# #db: 1
+#redisForReactions:
+# host: redis
+# port: 6379
+# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
+# #pass: example-pass
+# #prefix: example-prefix
+# #db: 1
+
# ┌───────────────────────────┐
#───┘ MeiliSearch configuration └─────────────────────────────
diff --git a/locales/index.d.ts b/locales/index.d.ts
index f8f8c7a089..5abadfa31a 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -2384,6 +2384,14 @@ export interface Locale extends ILocale {
* スクラッチパッドは、AiScriptの実験環境を提供します。Misskeyと対話するコードの記述、実行、結果の確認ができます。
*/
"scratchpadDescription": string;
+ /**
+ * UIインスペクター
+ */
+ "uiInspector": string;
+ /**
+ * メモリ上に存在しているUIコンポーネントのインスタンスの一覧を見ることができます。UIコンポーネントはUi:C:系関数により生成されます。
+ */
+ "uiInspectorDescription": string;
/**
* 出力
*/
@@ -3121,7 +3129,7 @@ export interface Locale extends ILocale {
*/
"narrow": string;
/**
- * 設定はページリロード後に反映されます。今すぐリロードしますか?
+ * 設定はページリロード後に反映されます。
*/
"reloadToApplySetting": string;
/**
@@ -5575,6 +5583,10 @@ export interface Locale extends ILocale {
* 有効にすると、タイムラインがキャッシュされていない場合にDBへ追加で問い合わせを行うフォールバック処理を行います。無効にすると、フォールバック処理を行わないことでさらにサーバーの負荷を軽減することができますが、タイムラインが取得できる範囲に制限が生じます。
*/
"fanoutTimelineDbFallbackDescription": string;
+ /**
+ * 有効にすると、リアクション作成時のパフォーマンスが大幅に向上し、データベースへの負荷を軽減することが可能です。ただし、Redisのメモリ使用量は増加します。
+ */
+ "reactionsBufferingDescription": string;
/**
* 問い合わせ先URL
*/
@@ -6754,6 +6766,26 @@ export interface Locale extends ILocale {
* アイコンデコレーションの最大取付個数
*/
"avatarDecorationLimit": string;
+ /**
+ * アンテナのインポートを許可
+ */
+ "canImportAntennas": string;
+ /**
+ * ブロックのインポートを許可
+ */
+ "canImportBlocking": string;
+ /**
+ * フォローのインポートを許可
+ */
+ "canImportFollowing": string;
+ /**
+ * ミュートのインポートを許可
+ */
+ "canImportMuting": string;
+ /**
+ * リストのインポートを許可
+ */
+ "canImportUserLists": string;
};
"_condition": {
/**
@@ -9489,6 +9521,10 @@ export interface Locale extends ILocale {
* Webhookを削除しますか?
*/
"deleteConfirm": string;
+ /**
+ * スイッチの右にあるボタンをクリックするとダミーのデータを使用したテスト用Webhookを送信できます。
+ */
+ "testRemarks": string;
};
"_abuseReport": {
"_notificationRecipient": {
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index e1536af8b3..1223853d31 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -592,6 +592,8 @@ ascendingOrder: "昇順"
descendingOrder: "降順"
scratchpad: "スクラッチパッド"
scratchpadDescription: "スクラッチパッドは、AiScriptの実験環境を提供します。Misskeyと対話するコードの記述、実行、結果の確認ができます。"
+uiInspector: "UIインスペクター"
+uiInspectorDescription: "メモリ上に存在しているUIコンポーネントのインスタンスの一覧を見ることができます。UIコンポーネントはUi:C:系関数により生成されます。"
output: "出力"
script: "スクリプト"
disablePagesScript: "Pagesのスクリプトを無効にする"
@@ -776,7 +778,7 @@ left: "左"
center: "中央"
wide: "広い"
narrow: "狭い"
-reloadToApplySetting: "設定はページリロード後に反映されます。今すぐリロードしますか?"
+reloadToApplySetting: "設定はページリロード後に反映されます。"
needReloadToApply: "反映には再起動が必要です。"
showTitlebar: "タイトルバーを表示する"
clearCache: "キャッシュをクリア"
@@ -1409,6 +1411,7 @@ _serverSettings:
fanoutTimelineDescription: "有効にすると、各種タイムラインを取得する際のパフォーマンスが大幅に向上し、データベースへの負荷を軽減することが可能です。ただし、Redisのメモリ使用量は増加します。サーバーのメモリ容量が少ない場合、または動作が不安定な場合は無効にすることができます。"
fanoutTimelineDbFallback: "データベースへのフォールバック"
fanoutTimelineDbFallbackDescription: "有効にすると、タイムラインがキャッシュされていない場合にDBへ追加で問い合わせを行うフォールバック処理を行います。無効にすると、フォールバック処理を行わないことでさらにサーバーの負荷を軽減することができますが、タイムラインが取得できる範囲に制限が生じます。"
+ reactionsBufferingDescription: "有効にすると、リアクション作成時のパフォーマンスが大幅に向上し、データベースへの負荷を軽減することが可能です。ただし、Redisのメモリ使用量は増加します。"
inquiryUrl: "問い合わせ先URL"
inquiryUrlDescription: "サーバー運営者へのお問い合わせフォームのURLや、運営者の連絡先等が記載されたWebページのURLを指定します。"
@@ -1745,6 +1748,11 @@ _role:
canSearchNotes: "ノート検索の利用"
canUseTranslator: "翻訳機能の利用"
avatarDecorationLimit: "アイコンデコレーションの最大取付個数"
+ canImportAntennas: "アンテナのインポートを許可"
+ canImportBlocking: "ブロックのインポートを許可"
+ canImportFollowing: "フォローのインポートを許可"
+ canImportMuting: "ミュートのインポートを許可"
+ canImportUserLists: "リストのインポートを許可"
_condition:
roleAssignedTo: "マニュアルロールにアサイン済み"
isLocal: "ローカルユーザー"
@@ -2515,6 +2523,7 @@ _webhookSettings:
abuseReportResolved: "ユーザーからの通報を処理したとき"
userCreated: "ユーザーが作成されたとき"
deleteConfirm: "Webhookを削除しますか?"
+ testRemarks: "スイッチの右にあるボタンをクリックするとダミーのデータを使用したテスト用Webhookを送信できます。"
_abuseReport:
_notificationRecipient:
diff --git a/package.json b/package.json
index 85b4f62752..5c41a1d5bb 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "misskey",
- "version": "2024.8.0",
+ "version": "2024.9.0-alpha.2",
"codename": "nasubi",
"repository": {
"type": "git",
diff --git a/packages/backend/migration/1726804538569-reactions-buffering.js b/packages/backend/migration/1726804538569-reactions-buffering.js
new file mode 100644
index 0000000000..bc19e9cc8a
--- /dev/null
+++ b/packages/backend/migration/1726804538569-reactions-buffering.js
@@ -0,0 +1,16 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class ReactionsBuffering1726804538569 {
+ name = 'ReactionsBuffering1726804538569'
+
+ async up(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "meta" ADD "enableReactionsBuffering" boolean NOT NULL DEFAULT false`);
+ }
+
+ async down(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableReactionsBuffering"`);
+ }
+}
diff --git a/packages/backend/package.json b/packages/backend/package.json
index a06fd9156b..aee3854ef3 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -132,6 +132,7 @@
"json5": "2.2.3",
"jsonld": "8.3.2",
"jsrsasign": "11.1.0",
+ "juice": "11.0.0",
"meilisearch": "0.41.0",
"mfm-js": "0.24.0",
"microformats-parser": "2.0.2",
diff --git a/packages/backend/src/GlobalModule.ts b/packages/backend/src/GlobalModule.ts
index 09971e8ca0..2ecc1f4742 100644
--- a/packages/backend/src/GlobalModule.ts
+++ b/packages/backend/src/GlobalModule.ts
@@ -78,11 +78,19 @@ const $redisForTimelines: Provider = {
inject: [DI.config],
};
+const $redisForReactions: Provider = {
+ provide: DI.redisForReactions,
+ useFactory: (config: Config) => {
+ return new Redis.Redis(config.redisForReactions);
+ },
+ inject: [DI.config],
+};
+
@Global()
@Module({
imports: [RepositoryModule],
- providers: [$config, $db, $meilisearch, $redis, $redisForPub, $redisForSub, $redisForTimelines],
- exports: [$config, $db, $meilisearch, $redis, $redisForPub, $redisForSub, $redisForTimelines, RepositoryModule],
+ providers: [$config, $db, $meilisearch, $redis, $redisForPub, $redisForSub, $redisForTimelines, $redisForReactions],
+ exports: [$config, $db, $meilisearch, $redis, $redisForPub, $redisForSub, $redisForTimelines, $redisForReactions, RepositoryModule],
})
export class GlobalModule implements OnApplicationShutdown {
constructor(
@@ -91,6 +99,7 @@ export class GlobalModule implements OnApplicationShutdown {
@Inject(DI.redisForPub) private redisForPub: Redis.Redis,
@Inject(DI.redisForSub) private redisForSub: Redis.Redis,
@Inject(DI.redisForTimelines) private redisForTimelines: Redis.Redis,
+ @Inject(DI.redisForReactions) private redisForReactions: Redis.Redis,
) { }
public async dispose(): Promise {
@@ -103,6 +112,7 @@ export class GlobalModule implements OnApplicationShutdown {
this.redisForPub.disconnect(),
this.redisForSub.disconnect(),
this.redisForTimelines.disconnect(),
+ this.redisForReactions.disconnect(),
]);
}
diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts
index cbd6d1c086..97ba79c574 100644
--- a/packages/backend/src/config.ts
+++ b/packages/backend/src/config.ts
@@ -49,6 +49,7 @@ type Source = {
redisForPubsub?: RedisOptionsSource;
redisForJobQueue?: RedisOptionsSource;
redisForTimelines?: RedisOptionsSource;
+ redisForReactions?: RedisOptionsSource;
meilisearch?: {
host: string;
port: string;
@@ -171,6 +172,7 @@ export type Config = {
redisForPubsub: RedisOptions & RedisOptionsSource;
redisForJobQueue: RedisOptions & RedisOptionsSource;
redisForTimelines: RedisOptions & RedisOptionsSource;
+ redisForReactions: RedisOptions & RedisOptionsSource;
sentryForBackend: { options: Partial; enableNodeProfiling: boolean; } | undefined;
sentryForFrontend: { options: Partial } | undefined;
perChannelMaxNoteCacheCount: number;
@@ -251,6 +253,7 @@ export function loadConfig(): Config {
redisForPubsub: config.redisForPubsub ? convertRedisOptions(config.redisForPubsub, host) : redis,
redisForJobQueue: config.redisForJobQueue ? convertRedisOptions(config.redisForJobQueue, host) : redis,
redisForTimelines: config.redisForTimelines ? convertRedisOptions(config.redisForTimelines, host) : redis,
+ redisForReactions: config.redisForReactions ? convertRedisOptions(config.redisForReactions, host) : redis,
sentryForBackend: config.sentryForBackend,
sentryForFrontend: config.sentryForFrontend,
id: config.id,
diff --git a/packages/backend/src/const.ts b/packages/backend/src/const.ts
index a238f4973a..e3a61861f4 100644
--- a/packages/backend/src/const.ts
+++ b/packages/backend/src/const.ts
@@ -8,6 +8,8 @@ export const MAX_NOTE_TEXT_LENGTH = 3000;
export const USER_ONLINE_THRESHOLD = 1000 * 60 * 10; // 10min
export const USER_ACTIVE_THRESHOLD = 1000 * 60 * 60 * 24 * 3; // 3days
+export const PER_NOTE_REACTION_USER_PAIR_CACHE_MAX = 16;
+
//#region hard limits
// If you change DB_* values, you must also change the DB schema.
diff --git a/packages/backend/src/core/AntennaService.ts b/packages/backend/src/core/AntennaService.ts
index 793d8974b3..e827ffa68c 100644
--- a/packages/backend/src/core/AntennaService.ts
+++ b/packages/backend/src/core/AntennaService.ts
@@ -123,11 +123,14 @@ export class AntennaService implements OnApplicationShutdown {
if (antenna.src === 'home') {
// TODO
} else if (antenna.src === 'list') {
- const listUsers = (await this.userListMembershipsRepository.findBy({
- userListId: antenna.userListId!,
- })).map(x => x.userId);
-
- if (!listUsers.includes(note.userId)) return false;
+ if (antenna.userListId == null) return false;
+ const exists = await this.userListMembershipsRepository.exists({
+ where: {
+ userListId: antenna.userListId,
+ userId: note.userId,
+ },
+ });
+ if (!exists) return false;
} else if (antenna.src === 'users') {
const accts = antenna.users.map(x => {
const { username, host } = Acct.parse(x);
diff --git a/packages/backend/src/core/CoreModule.ts b/packages/backend/src/core/CoreModule.ts
index c9427bbeb7..3b3c35f976 100644
--- a/packages/backend/src/core/CoreModule.ts
+++ b/packages/backend/src/core/CoreModule.ts
@@ -13,6 +13,7 @@ import {
import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js';
import { SystemWebhookService } from '@/core/SystemWebhookService.js';
import { UserSearchService } from '@/core/UserSearchService.js';
+import { WebhookTestService } from '@/core/WebhookTestService.js';
import { AccountMoveService } from './AccountMoveService.js';
import { AccountUpdateService } from './AccountUpdateService.js';
import { AiService } from './AiService.js';
@@ -49,6 +50,7 @@ import { PollService } from './PollService.js';
import { PushNotificationService } from './PushNotificationService.js';
import { QueryService } from './QueryService.js';
import { ReactionService } from './ReactionService.js';
+import { ReactionsBufferingService } from './ReactionsBufferingService.js';
import { RelayService } from './RelayService.js';
import { RoleService } from './RoleService.js';
import { S3Service } from './S3Service.js';
@@ -192,6 +194,7 @@ const $ProxyAccountService: Provider = { provide: 'ProxyAccountService', useExis
const $PushNotificationService: Provider = { provide: 'PushNotificationService', useExisting: PushNotificationService };
const $QueryService: Provider = { provide: 'QueryService', useExisting: QueryService };
const $ReactionService: Provider = { provide: 'ReactionService', useExisting: ReactionService };
+const $ReactionsBufferingService: Provider = { provide: 'ReactionsBufferingService', useExisting: ReactionsBufferingService };
const $RelayService: Provider = { provide: 'RelayService', useExisting: RelayService };
const $RoleService: Provider = { provide: 'RoleService', useExisting: RoleService };
const $S3Service: Provider = { provide: 'S3Service', useExisting: S3Service };
@@ -211,6 +214,7 @@ const $UserAuthService: Provider = { provide: 'UserAuthService', useExisting: Us
const $VideoProcessingService: Provider = { provide: 'VideoProcessingService', useExisting: VideoProcessingService };
const $UserWebhookService: Provider = { provide: 'UserWebhookService', useExisting: UserWebhookService };
const $SystemWebhookService: Provider = { provide: 'SystemWebhookService', useExisting: SystemWebhookService };
+const $WebhookTestService: Provider = { provide: 'WebhookTestService', useExisting: WebhookTestService };
const $UtilityService: Provider = { provide: 'UtilityService', useExisting: UtilityService };
const $FileInfoService: Provider = { provide: 'FileInfoService', useExisting: FileInfoService };
const $SearchService: Provider = { provide: 'SearchService', useExisting: SearchService };
@@ -340,6 +344,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
PushNotificationService,
QueryService,
ReactionService,
+ ReactionsBufferingService,
RelayService,
RoleService,
S3Service,
@@ -359,6 +364,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
VideoProcessingService,
UserWebhookService,
SystemWebhookService,
+ WebhookTestService,
UtilityService,
FileInfoService,
SearchService,
@@ -484,6 +490,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$PushNotificationService,
$QueryService,
$ReactionService,
+ $ReactionsBufferingService,
$RelayService,
$RoleService,
$S3Service,
@@ -503,6 +510,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$VideoProcessingService,
$UserWebhookService,
$SystemWebhookService,
+ $WebhookTestService,
$UtilityService,
$FileInfoService,
$SearchService,
@@ -629,6 +637,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
PushNotificationService,
QueryService,
ReactionService,
+ ReactionsBufferingService,
RelayService,
RoleService,
S3Service,
@@ -648,6 +657,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
VideoProcessingService,
UserWebhookService,
SystemWebhookService,
+ WebhookTestService,
UtilityService,
FileInfoService,
SearchService,
@@ -772,6 +782,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$PushNotificationService,
$QueryService,
$ReactionService,
+ $ReactionsBufferingService,
$RelayService,
$RoleService,
$S3Service,
@@ -791,6 +802,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$VideoProcessingService,
$UserWebhookService,
$SystemWebhookService,
+ $WebhookTestService,
$UtilityService,
$FileInfoService,
$SearchService,
diff --git a/packages/backend/src/core/EmailService.ts b/packages/backend/src/core/EmailService.ts
index 435dbbae28..37fa58bb65 100644
--- a/packages/backend/src/core/EmailService.ts
+++ b/packages/backend/src/core/EmailService.ts
@@ -5,6 +5,7 @@
import { URLSearchParams } from 'node:url';
import * as nodemailer from 'nodemailer';
+import juice from 'juice';
import { Inject, Injectable } from '@nestjs/common';
import { validate as validateEmail } from 'deep-email-validator';
import { MetaService } from '@/core/MetaService.js';
@@ -61,14 +62,7 @@ export class EmailService {
} : undefined,
} as any);
- try {
- // TODO: htmlサニタイズ
- const info = await transporter.sendMail({
- from: meta.email!,
- to: to,
- subject: subject,
- text: text,
- html: `
+ const htmlContent = `
@@ -147,7 +141,18 @@ export class EmailService {
${ this.config.host }
-`,
+