From efda2e9baa54945391a7c7c155e67e9ffc67a82e Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Sat, 2 Mar 2024 18:34:49 +0900
Subject: [PATCH 001/191] Update README.md

---
 README.md | 41 ++++-------------------------------------
 1 file changed, 4 insertions(+), 37 deletions(-)

diff --git a/README.md b/README.md
index 6fa804f1fa..24013a7bd8 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,11 @@
 <div align="center">
 <a href="https://misskey-hub.net">
-	<img src="./assets/title_float.svg" alt="Misskey logo" style="border-radius:50%" width="400"/>
+	<img src="./assets/title_float.svg" alt="Misskey logo" style="border-radius:50%" width="300"/>
 </a>
 
-**🌎 **[Misskey](https://misskey-hub.net/)** is an open source, decentralized social media platform that's free forever! 🚀**
+**🌎 **Misskey** is an open source, federated social media platform that's free forever! 🚀**
+
+[Learn more](https://misskey-hub.net/)
 
 ---
 
@@ -22,41 +24,6 @@
 <a href="https://www.patreon.com/syuilo">
 		<img src="https://custom-icon-badges.herokuapp.com/badge/become_a-patron-F96854?logoColor=F96854&style=for-the-badge&logo=patreon&labelColor=363B40" alt="become a patron"/></a>
 
----
-
-[![codecov](https://codecov.io/gh/misskey-dev/misskey/branch/develop/graph/badge.svg?token=R6IQZ3QJOL)](https://codecov.io/gh/misskey-dev/misskey)
-
-</div>
-
-<div>
-
-<a href="https://xn--931a.moe/"><img src="https://github.com/misskey-dev/misskey/blob/develop/assets/ai.png?raw=true" align="right" height="320px"/></a>
-
-## ✨ Features
-- **ActivityPub support**\
-Not on Misskey? No problem! Not only can Misskey instances talk to each other, but you can make friends with people on other networks like Mastodon and Pixelfed!
-- **Reactions**\
-You can add emoji reactions to any post! No longer are you bound by a like button, show everyone exactly how you feel with the tap of a button.
-- **Drive**\
-With Misskey's built in drive, you get cloud storage right in your social media, where you can upload any files, make folders, and find media from posts you've made!
-- **Rich Web UI**\
-	Misskey has a rich and easy to use Web UI!
-	It is highly customizable, from changing the layout and adding widgets to making custom themes.
-	Furthermore, plugins can be created using AiScript, an original programming language.
-- And much more...
-
-</div>
-
-<div style="clear: both;"></div>
-
-## Documentation
-
-Misskey Documentation can be found at [Misskey Hub](https://misskey-hub.net/docs/), some of the links and graphics above also lead to specific portions of it.
-
-## Sponsors
-
-<div align="center">
-	<a class="rss3" title="RSS3" href="https://rss3.io/" target="_blank"><img src="https://rss3.mypinata.cloud/ipfs/QmUG6H3Z7D5P511shn7sB4CPmpjH5uZWu4m5mWX7U3Gqbu" alt="RSS3" height="60"></a>
 </div>
 
 ## Thanks

From 38837bd388621f5ba49bd7bf0f657a08ec2f19c4 Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Sun, 3 Mar 2024 20:15:35 +0900
Subject: [PATCH 002/191] test(backend): refactor tests (#13499)

* test(backend): refactor tests

* fix: failed test
---
 packages/backend/test/e2e/2fa.ts              |  96 ++--
 packages/backend/test/e2e/antennas.ts         | 116 +++--
 packages/backend/test/e2e/api-visibility.ts   |  74 +--
 packages/backend/test/e2e/api.ts              |  43 +-
 packages/backend/test/e2e/block.ts            |  19 +-
 packages/backend/test/e2e/clips.ts            | 298 ++++++-----
 packages/backend/test/e2e/drive.ts            |  36 +-
 packages/backend/test/e2e/endpoints.ts        | 261 +++++-----
 packages/backend/test/e2e/exports.ts          |  38 +-
 packages/backend/test/e2e/fetch-resource.ts   |  18 +-
 packages/backend/test/e2e/ff-visibility.ts    | 206 ++++----
 packages/backend/test/e2e/move.ts             | 186 +++----
 packages/backend/test/e2e/mute.ts             |  87 ++--
 packages/backend/test/e2e/note.ts             | 169 +++----
 packages/backend/test/e2e/renote-mute.ts      |   6 +-
 packages/backend/test/e2e/streaming.ts        |   6 +-
 packages/backend/test/e2e/thread-mute.ts      |  18 +-
 packages/backend/test/e2e/timelines.ts        | 336 ++++++-------
 packages/backend/test/e2e/user-notes.ts       |   8 +-
 packages/backend/test/e2e/users.ts            | 461 +++++++++---------
 .../backend/test/unit/AnnouncementService.ts  |   2 +-
 .../test/unit/FetchInstanceMetadataService.ts |  19 +-
 packages/backend/test/unit/RoleService.ts     |   3 +
 packages/backend/test/utils.ts                |  61 ++-
 24 files changed, 1270 insertions(+), 1297 deletions(-)

diff --git a/packages/backend/test/e2e/2fa.ts b/packages/backend/test/e2e/2fa.ts
index 87a3c227d6..13c56b88a6 100644
--- a/packages/backend/test/e2e/2fa.ts
+++ b/packages/backend/test/e2e/2fa.ts
@@ -187,7 +187,7 @@ describe('2要素認証', () => {
 	}, 1000 * 60 * 2);
 
 	test('が設定でき、OTPでログインできる。', async () => {
-		const registerResponse = await api('/i/2fa/register', {
+		const registerResponse = await api('i/2fa/register', {
 			password,
 		}, alice);
 		assert.strictEqual(registerResponse.status, 200);
@@ -197,18 +197,18 @@ describe('2要素認証', () => {
 		assert.strictEqual(registerResponse.body.label, username);
 		assert.strictEqual(registerResponse.body.issuer, config.host);
 
-		const doneResponse = await api('/i/2fa/done', {
+		const doneResponse = await api('i/2fa/done', {
 			token: otpToken(registerResponse.body.secret),
 		}, alice);
 		assert.strictEqual(doneResponse.status, 200);
 
-		const usersShowResponse = await api('/users/show', {
+		const usersShowResponse = await api('users/show', {
 			username,
 		}, alice);
 		assert.strictEqual(usersShowResponse.status, 200);
 		assert.strictEqual(usersShowResponse.body.twoFactorEnabled, true);
 
-		const signinResponse = await api('/signin', {
+		const signinResponse = await api('signin', {
 			...signinParam(),
 			token: otpToken(registerResponse.body.secret),
 		});
@@ -216,24 +216,24 @@ describe('2要素認証', () => {
 		assert.notEqual(signinResponse.body.i, undefined);
 
 		// 後片付け
-		await api('/i/2fa/unregister', {
+		await api('i/2fa/unregister', {
 			password,
 			token: otpToken(registerResponse.body.secret),
 		}, alice);
 	});
 
 	test('が設定でき、セキュリティキーでログインできる。', async () => {
-		const registerResponse = await api('/i/2fa/register', {
+		const registerResponse = await api('i/2fa/register', {
 			password,
 		}, alice);
 		assert.strictEqual(registerResponse.status, 200);
 
-		const doneResponse = await api('/i/2fa/done', {
+		const doneResponse = await api('i/2fa/done', {
 			token: otpToken(registerResponse.body.secret),
 		}, alice);
 		assert.strictEqual(doneResponse.status, 200);
 
-		const registerKeyResponse = await api('/i/2fa/register-key', {
+		const registerKeyResponse = await api('i/2fa/register-key', {
 			password,
 			token: otpToken(registerResponse.body.secret),
 		}, alice);
@@ -243,23 +243,23 @@ describe('2要素認証', () => {
 
 		const keyName = 'example-key';
 		const credentialId = crypto.randomBytes(0x41);
-		const keyDoneResponse = await api('/i/2fa/key-done', keyDoneParam({
+		const keyDoneResponse = await api('i/2fa/key-done', keyDoneParam({
 			token: otpToken(registerResponse.body.secret),
 			keyName,
 			credentialId,
 			creationOptions: registerKeyResponse.body,
-		}), alice);
+		}) as any, alice);
 		assert.strictEqual(keyDoneResponse.status, 200);
 		assert.strictEqual(keyDoneResponse.body.id, credentialId.toString('base64url'));
 		assert.strictEqual(keyDoneResponse.body.name, keyName);
 
-		const usersShowResponse = await api('/users/show', {
+		const usersShowResponse = await api('users/show', {
 			username,
 		});
 		assert.strictEqual(usersShowResponse.status, 200);
 		assert.strictEqual(usersShowResponse.body.securityKeys, true);
 
-		const signinResponse = await api('/signin', {
+		const signinResponse = await api('signin', {
 			...signinParam(),
 		});
 		assert.strictEqual(signinResponse.status, 200);
@@ -268,7 +268,7 @@ describe('2要素認証', () => {
 		assert.notEqual(signinResponse.body.allowCredentials, undefined);
 		assert.strictEqual(signinResponse.body.allowCredentials[0].id, credentialId.toString('base64url'));
 
-		const signinResponse2 = await api('/signin', signinWithSecurityKeyParam({
+		const signinResponse2 = await api('signin', signinWithSecurityKeyParam({
 			keyName,
 			credentialId,
 			requestOptions: signinResponse.body,
@@ -277,24 +277,24 @@ describe('2要素認証', () => {
 		assert.notEqual(signinResponse2.body.i, undefined);
 
 		// 後片付け
-		await api('/i/2fa/unregister', {
+		await api('i/2fa/unregister', {
 			password,
 			token: otpToken(registerResponse.body.secret),
 		}, alice);
 	});
 
 	test('が設定でき、セキュリティキーでパスワードレスログインできる。', async () => {
-		const registerResponse = await api('/i/2fa/register', {
+		const registerResponse = await api('i/2fa/register', {
 			password,
 		}, alice);
 		assert.strictEqual(registerResponse.status, 200);
 
-		const doneResponse = await api('/i/2fa/done', {
+		const doneResponse = await api('i/2fa/done', {
 			token: otpToken(registerResponse.body.secret),
 		}, alice);
 		assert.strictEqual(doneResponse.status, 200);
 
-		const registerKeyResponse = await api('/i/2fa/register-key', {
+		const registerKeyResponse = await api('i/2fa/register-key', {
 			token: otpToken(registerResponse.body.secret),
 			password,
 		}, alice);
@@ -302,33 +302,33 @@ describe('2要素認証', () => {
 
 		const keyName = 'example-key';
 		const credentialId = crypto.randomBytes(0x41);
-		const keyDoneResponse = await api('/i/2fa/key-done', keyDoneParam({
+		const keyDoneResponse = await api('i/2fa/key-done', keyDoneParam({
 			token: otpToken(registerResponse.body.secret),
 			keyName,
 			credentialId,
 			creationOptions: registerKeyResponse.body,
-		}), alice);
+		}) as any, alice);
 		assert.strictEqual(keyDoneResponse.status, 200);
 
-		const passwordLessResponse = await api('/i/2fa/password-less', {
+		const passwordLessResponse = await api('i/2fa/password-less', {
 			value: true,
 		}, alice);
 		assert.strictEqual(passwordLessResponse.status, 204);
 
-		const usersShowResponse = await api('/users/show', {
+		const usersShowResponse = await api('users/show', {
 			username,
 		});
 		assert.strictEqual(usersShowResponse.status, 200);
 		assert.strictEqual(usersShowResponse.body.usePasswordLessLogin, true);
 
-		const signinResponse = await api('/signin', {
+		const signinResponse = await api('signin', {
 			...signinParam(),
 			password: '',
 		});
 		assert.strictEqual(signinResponse.status, 200);
 		assert.strictEqual(signinResponse.body.i, undefined);
 
-		const signinResponse2 = await api('/signin', {
+		const signinResponse2 = await api('signin', {
 			...signinWithSecurityKeyParam({
 				keyName,
 				credentialId,
@@ -340,24 +340,24 @@ describe('2要素認証', () => {
 		assert.notEqual(signinResponse2.body.i, undefined);
 
 		// 後片付け
-		await api('/i/2fa/unregister', {
+		await api('i/2fa/unregister', {
 			password,
 			token: otpToken(registerResponse.body.secret),
 		}, alice);
 	});
 
 	test('が設定でき、設定したセキュリティキーの名前を変更できる。', async () => {
-		const registerResponse = await api('/i/2fa/register', {
+		const registerResponse = await api('i/2fa/register', {
 			password,
 		}, alice);
 		assert.strictEqual(registerResponse.status, 200);
 
-		const doneResponse = await api('/i/2fa/done', {
+		const doneResponse = await api('i/2fa/done', {
 			token: otpToken(registerResponse.body.secret),
 		}, alice);
 		assert.strictEqual(doneResponse.status, 200);
 
-		const registerKeyResponse = await api('/i/2fa/register-key', {
+		const registerKeyResponse = await api('i/2fa/register-key', {
 			token: otpToken(registerResponse.body.secret),
 			password,
 		}, alice);
@@ -365,22 +365,22 @@ describe('2要素認証', () => {
 
 		const keyName = 'example-key';
 		const credentialId = crypto.randomBytes(0x41);
-		const keyDoneResponse = await api('/i/2fa/key-done', keyDoneParam({
+		const keyDoneResponse = await api('i/2fa/key-done', keyDoneParam({
 			token: otpToken(registerResponse.body.secret),
 			keyName,
 			credentialId,
 			creationOptions: registerKeyResponse.body,
-		}), alice);
+		}) as any, alice);
 		assert.strictEqual(keyDoneResponse.status, 200);
 
 		const renamedKey = 'other-key';
-		const updateKeyResponse = await api('/i/2fa/update-key', {
+		const updateKeyResponse = await api('i/2fa/update-key', {
 			name: renamedKey,
 			credentialId: credentialId.toString('base64url'),
 		}, alice);
 		assert.strictEqual(updateKeyResponse.status, 200);
 
-		const iResponse = await api('/i', {
+		const iResponse = await api('i', {
 		}, alice);
 		assert.strictEqual(iResponse.status, 200);
 		const securityKeys = iResponse.body.securityKeysList.filter((s: { id: string; }) => s.id === credentialId.toString('base64url'));
@@ -389,24 +389,24 @@ describe('2要素認証', () => {
 		assert.notEqual(securityKeys[0].lastUsed, undefined);
 
 		// 後片付け
-		await api('/i/2fa/unregister', {
+		await api('i/2fa/unregister', {
 			password,
 			token: otpToken(registerResponse.body.secret),
 		}, alice);
 	});
 
 	test('が設定でき、設定したセキュリティキーを削除できる。', async () => {
-		const registerResponse = await api('/i/2fa/register', {
+		const registerResponse = await api('i/2fa/register', {
 			password,
 		}, alice);
 		assert.strictEqual(registerResponse.status, 200);
 
-		const doneResponse = await api('/i/2fa/done', {
+		const doneResponse = await api('i/2fa/done', {
 			token: otpToken(registerResponse.body.secret),
 		}, alice);
 		assert.strictEqual(doneResponse.status, 200);
 
-		const registerKeyResponse = await api('/i/2fa/register-key', {
+		const registerKeyResponse = await api('i/2fa/register-key', {
 			token: otpToken(registerResponse.body.secret),
 			password,
 		}, alice);
@@ -414,20 +414,20 @@ describe('2要素認証', () => {
 
 		const keyName = 'example-key';
 		const credentialId = crypto.randomBytes(0x41);
-		const keyDoneResponse = await api('/i/2fa/key-done', keyDoneParam({
+		const keyDoneResponse = await api('i/2fa/key-done', keyDoneParam({
 			token: otpToken(registerResponse.body.secret),
 			keyName,
 			credentialId,
 			creationOptions: registerKeyResponse.body,
-		}), alice);
+		}) as any, alice);
 		assert.strictEqual(keyDoneResponse.status, 200);
 
 		// テストの実行順によっては複数残ってるので全部消す
-		const iResponse = await api('/i', {
+		const iResponse = await api('i', {
 		}, alice);
 		assert.strictEqual(iResponse.status, 200);
 		for (const key of iResponse.body.securityKeysList) {
-			const removeKeyResponse = await api('/i/2fa/remove-key', {
+			const removeKeyResponse = await api('i/2fa/remove-key', {
 				token: otpToken(registerResponse.body.secret),
 				password,
 				credentialId: key.id,
@@ -435,13 +435,13 @@ describe('2要素認証', () => {
 			assert.strictEqual(removeKeyResponse.status, 200);
 		}
 
-		const usersShowResponse = await api('/users/show', {
+		const usersShowResponse = await api('users/show', {
 			username,
 		});
 		assert.strictEqual(usersShowResponse.status, 200);
 		assert.strictEqual(usersShowResponse.body.securityKeys, false);
 
-		const signinResponse = await api('/signin', {
+		const signinResponse = await api('signin', {
 			...signinParam(),
 			token: otpToken(registerResponse.body.secret),
 		});
@@ -449,43 +449,43 @@ describe('2要素認証', () => {
 		assert.notEqual(signinResponse.body.i, undefined);
 
 		// 後片付け
-		await api('/i/2fa/unregister', {
+		await api('i/2fa/unregister', {
 			password,
 			token: otpToken(registerResponse.body.secret),
 		}, alice);
 	});
 
 	test('が設定でき、設定解除できる。(パスワードのみでログインできる。)', async () => {
-		const registerResponse = await api('/i/2fa/register', {
+		const registerResponse = await api('i/2fa/register', {
 			password,
 		}, alice);
 		assert.strictEqual(registerResponse.status, 200);
 
-		const doneResponse = await api('/i/2fa/done', {
+		const doneResponse = await api('i/2fa/done', {
 			token: otpToken(registerResponse.body.secret),
 		}, alice);
 		assert.strictEqual(doneResponse.status, 200);
 
-		const usersShowResponse = await api('/users/show', {
+		const usersShowResponse = await api('users/show', {
 			username,
 		});
 		assert.strictEqual(usersShowResponse.status, 200);
 		assert.strictEqual(usersShowResponse.body.twoFactorEnabled, true);
 
-		const unregisterResponse = await api('/i/2fa/unregister', {
+		const unregisterResponse = await api('i/2fa/unregister', {
 			token: otpToken(registerResponse.body.secret),
 			password,
 		}, alice);
 		assert.strictEqual(unregisterResponse.status, 204);
 
-		const signinResponse = await api('/signin', {
+		const signinResponse = await api('signin', {
 			...signinParam(),
 		});
 		assert.strictEqual(signinResponse.status, 200);
 		assert.notEqual(signinResponse.body.i, undefined);
 
 		// 後片付け
-		await api('/i/2fa/unregister', {
+		await api('i/2fa/unregister', {
 			password,
 			token: otpToken(registerResponse.body.secret),
 		}, alice);
diff --git a/packages/backend/test/e2e/antennas.ts b/packages/backend/test/e2e/antennas.ts
index 1a9d5bf1f0..7370b1963c 100644
--- a/packages/backend/test/e2e/antennas.ts
+++ b/packages/backend/test/e2e/antennas.ts
@@ -7,7 +7,6 @@ process.env.NODE_ENV = 'test';
 
 import * as assert from 'assert';
 import { DEFAULT_POLICIES } from '@/core/RoleService.js';
-import type { Packed } from '@/misc/json-schema.js';
 import {
 	api,
 	failedApiCall,
@@ -29,10 +28,7 @@ describe('アンテナ', () => {
 	// エンティティとしてのアンテナを主眼においたテストを記述する
 	// (Antennaを返すエンドポイント、Antennaエンティティを書き換えるエンドポイント、Antennaからノートを取得するエンドポイントをテストする)
 
-	// BUG misskey-jsとjson-schemaが一致していない。
-	// - srcのenumにgroupが残っている
-	// - userGroupIdが残っている, isActiveがない
-	type Antenna = misskey.entities.Antenna | Packed<'Antenna'>;
+	type Antenna = misskey.entities.Antenna;
 	type User = misskey.entities.SignupResponse;
 	type Note = misskey.entities.Note;
 
@@ -80,7 +76,7 @@ describe('アンテナ', () => {
 		aliceList = await userList(alice, {});
 		bob = await signup({ username: 'bob' });
 		aliceList = await userList(alice, {});
-		bobFile = (await uploadFile(bob)).body;
+		bobFile = (await uploadFile(bob)).body!;
 		bobList = await userList(bob);
 		carol = await signup({ username: 'carol' });
 		await api('users/lists/push', { listId: aliceList.id, userId: bob.id }, alice);
@@ -129,9 +125,9 @@ describe('アンテナ', () => {
 	beforeEach(async () => {
 		// テスト間で影響し合わないように毎回全部消す。
 		for (const user of [alice, bob]) {
-			const list = await api('/antennas/list', {}, user);
+			const list = await api('antennas/list', {}, user);
 			for (const antenna of list.body) {
-				await api('/antennas/delete', { antennaId: antenna.id }, user);
+				await api('antennas/delete', { antennaId: antenna.id }, user);
 			}
 		}
 	});
@@ -141,11 +137,11 @@ describe('アンテナ', () => {
 	test('が作成できること、キーが過不足なく入っていること。', async () => {
 		const response = await successfulApiCall({
 			endpoint: 'antennas/create',
-			parameters: { ...defaultParam },
+			parameters: defaultParam,
 			user: alice,
 		});
 		assert.match(response.id, /[0-9a-z]{10}/);
-		const expected = {
+		const expected: Antenna = {
 			id: response.id,
 			caseSensitive: false,
 			createdAt: new Date(response.createdAt).toISOString(),
@@ -161,7 +157,7 @@ describe('アンテナ', () => {
 			withFile: false,
 			withReplies: false,
 			localOnly: false,
-		} as Antenna;
+		};
 		assert.deepStrictEqual(response, expected);
 	});
 
@@ -202,27 +198,27 @@ describe('アンテナ', () => {
 	});
 
 	const antennaParamPattern = [
-		{ parameters: (): object => ({ name: 'x'.repeat(100) }) },
-		{ parameters: (): object => ({ name: 'x' }) },
-		{ parameters: (): object => ({ src: 'home' }) },
-		{ parameters: (): object => ({ src: 'all' }) },
-		{ parameters: (): object => ({ src: 'users' }) },
-		{ parameters: (): object => ({ src: 'list' }) },
-		{ parameters: (): object => ({ userListId: null }) },
-		{ parameters: (): object => ({ src: 'list', userListId: aliceList.id }) },
-		{ parameters: (): object => ({ keywords: [['x']] }) },
-		{ parameters: (): object => ({ keywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) },
-		{ parameters: (): object => ({ excludeKeywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) },
-		{ parameters: (): object => ({ users: [alice.username] }) },
-		{ parameters: (): object => ({ users: [alice.username, bob.username, carol.username] }) },
-		{ parameters: (): object => ({ caseSensitive: false }) },
-		{ parameters: (): object => ({ caseSensitive: true }) },
-		{ parameters: (): object => ({ withReplies: false }) },
-		{ parameters: (): object => ({ withReplies: true }) },
-		{ parameters: (): object => ({ withFile: false }) },
-		{ parameters: (): object => ({ withFile: true }) },
-		{ parameters: (): object => ({ notify: false }) },
-		{ parameters: (): object => ({ notify: true }) },
+		{ parameters: () => ({ name: 'x'.repeat(100) }) },
+		{ parameters: () => ({ name: 'x' }) },
+		{ parameters: () => ({ src: 'home' as const }) },
+		{ parameters: () => ({ src: 'all' as const }) },
+		{ parameters: () => ({ src: 'users' as const }) },
+		{ parameters: () => ({ src: 'list' as const }) },
+		{ parameters: () => ({ userListId: null }) },
+		{ parameters: () => ({ src: 'list' as const, userListId: aliceList.id }) },
+		{ parameters: () => ({ keywords: [['x']] }) },
+		{ parameters: () => ({ keywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) },
+		{ parameters: () => ({ excludeKeywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) },
+		{ parameters: () => ({ users: [alice.username] }) },
+		{ parameters: () => ({ users: [alice.username, bob.username, carol.username] }) },
+		{ parameters: () => ({ caseSensitive: false }) },
+		{ parameters: () => ({ caseSensitive: true }) },
+		{ parameters: () => ({ withReplies: false }) },
+		{ parameters: () => ({ withReplies: true }) },
+		{ parameters: () => ({ withFile: false }) },
+		{ parameters: () => ({ withFile: true }) },
+		{ parameters: () => ({ notify: false }) },
+		{ parameters: () => ({ notify: true }) },
 	];
 	test.each(antennaParamPattern)('を作成できること($#)', async ({ parameters }) => {
 		const response = await successfulApiCall({
@@ -335,7 +331,7 @@ describe('アンテナ', () => {
 		test.each([
 			{
 				label: '全体から',
-				parameters: (): object => ({ src: 'all' }),
+				parameters: () => ({ src: 'all' }),
 				posts: [
 					{ note: (): Promise<Note> => post(alice, { text: `${keyword}` }), included: true },
 					{ note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}` }), included: true },
@@ -346,7 +342,7 @@ describe('アンテナ', () => {
 			{
 				// BUG e4144a1 以降home指定は壊れている(allと同じ)
 				label: 'ホーム指定はallと同じ',
-				parameters: (): object => ({ src: 'home' }),
+				parameters: () => ({ src: 'home' }),
 				posts: [
 					{ note: (): Promise<Note> => post(alice, { text: `${keyword}` }), included: true },
 					{ note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}` }), included: true },
@@ -357,7 +353,7 @@ describe('アンテナ', () => {
 			{
 				// https://github.com/misskey-dev/misskey/issues/9025
 				label: 'ただし、フォロワー限定投稿とDM投稿を含まない。フォロワーであっても。',
-				parameters: (): object => ({}),
+				parameters: () => ({}),
 				posts: [
 					{ note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}`, visibility: 'public' }), included: true },
 					{ note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}`, visibility: 'home' }), included: true },
@@ -367,56 +363,56 @@ describe('アンテナ', () => {
 			},
 			{
 				label: 'ブロックしているユーザーのノートは含む',
-				parameters: (): object => ({}),
+				parameters: () => ({}),
 				posts: [
 					{ note: (): Promise<Note> => post(userBlockedByAlice, { text: `${keyword}` }), included: true },
 				],
 			},
 			{
 				label: 'ブロックされているユーザーのノートは含まない',
-				parameters: (): object => ({}),
+				parameters: () => ({}),
 				posts: [
 					{ note: (): Promise<Note> => post(userBlockingAlice, { text: `${keyword}` }) },
 				],
 			},
 			{
 				label: 'ミュートしているユーザーのノートは含まない',
-				parameters: (): object => ({}),
+				parameters: () => ({}),
 				posts: [
 					{ note: (): Promise<Note> => post(userMutedByAlice, { text: `${keyword}` }) },
 				],
 			},
 			{
 				label: 'ミュートされているユーザーのノートは含む',
-				parameters: (): object => ({}),
+				parameters: () => ({}),
 				posts: [
 					{ note: (): Promise<Note> => post(userMutingAlice, { text: `${keyword}` }), included: true },
 				],
 			},
 			{
 				label: '「見つけやすくする」がOFFのユーザーのノートも含まれる',
-				parameters: (): object => ({}),
+				parameters: () => ({}),
 				posts: [
 					{ note: (): Promise<Note> => post(userNotExplorable, { text: `${keyword}` }), included: true },
 				],
 			},
 			{
 				label: '鍵付きユーザーのノートも含まれる',
-				parameters: (): object => ({}),
+				parameters: () => ({}),
 				posts: [
 					{ note: (): Promise<Note> => post(userLocking, { text: `${keyword}` }), included: true },
 				],
 			},
 			{
 				label: 'サイレンスのノートも含まれる',
-				parameters: (): object => ({}),
+				parameters: () => ({}),
 				posts: [
 					{ note: (): Promise<Note> => post(userSilenced, { text: `${keyword}` }), included: true },
 				],
 			},
 			{
 				label: '削除ユーザーのノートも含まれる',
-				parameters: (): object => ({}),
+				parameters: () => ({}),
 				posts: [
 					{ note: (): Promise<Note> => post(userDeletedBySelf, { text: `${keyword}` }), included: true },
 					{ note: (): Promise<Note> => post(userDeletedByAdmin, { text: `${keyword}` }), included: true },
@@ -424,7 +420,7 @@ describe('アンテナ', () => {
 			},
 			{
 				label: 'ユーザー指定で',
-				parameters: (): object => ({ src: 'users', users: [`@${bob.username}`, `@${carol.username}`] }),
+				parameters: () => ({ src: 'users', users: [`@${bob.username}`, `@${carol.username}`] }),
 				posts: [
 					{ note: (): Promise<Note> => post(alice, { text: `test ${keyword}` }) },
 					{ note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true },
@@ -433,7 +429,7 @@ describe('アンテナ', () => {
 			},
 			{
 				label: 'リスト指定で',
-				parameters: (): object => ({ src: 'list', userListId: aliceList.id }),
+				parameters: () => ({ src: 'list', userListId: aliceList.id }),
 				posts: [
 					{ note: (): Promise<Note> => post(alice, { text: `test ${keyword}` }) },
 					{ note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true },
@@ -442,14 +438,14 @@ describe('アンテナ', () => {
 			},
 			{
 				label: 'CWにもマッチする',
-				parameters: (): object => ({ keywords: [[keyword]] }),
+				parameters: () => ({ keywords: [[keyword]] }),
 				posts: [
 					{ note: (): Promise<Note> => post(bob, { text: 'test', cw: `cw ${keyword}` }), included: true },
 				],
 			},
 			{
 				label: 'キーワード1つ',
-				parameters: (): object => ({ keywords: [[keyword]] }),
+				parameters: () => ({ keywords: [[keyword]] }),
 				posts: [
 					{ note: (): Promise<Note> => post(alice, { text: 'test' }) },
 					{ note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true },
@@ -458,7 +454,7 @@ describe('アンテナ', () => {
 			},
 			{
 				label: 'キーワード3つ(AND)',
-				parameters: (): object => ({ keywords: [['A', 'B', 'C']] }),
+				parameters: () => ({ keywords: [['A', 'B', 'C']] }),
 				posts: [
 					{ note: (): Promise<Note> => post(bob, { text: 'test A' }) },
 					{ note: (): Promise<Note> => post(bob, { text: 'test A B' }) },
@@ -469,7 +465,7 @@ describe('アンテナ', () => {
 			},
 			{
 				label: 'キーワード3つ(OR)',
-				parameters: (): object => ({ keywords: [['A'], ['B'], ['C']] }),
+				parameters: () => ({ keywords: [['A'], ['B'], ['C']] }),
 				posts: [
 					{ note: (): Promise<Note> => post(bob, { text: 'test' }) },
 					{ note: (): Promise<Note> => post(bob, { text: 'test A' }), included: true },
@@ -482,7 +478,7 @@ describe('アンテナ', () => {
 			},
 			{
 				label: '除外ワード3つ(AND)',
-				parameters: (): object => ({ excludeKeywords: [['A', 'B', 'C']] }),
+				parameters: () => ({ excludeKeywords: [['A', 'B', 'C']] }),
 				posts: [
 					{ note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true },
 					{ note: (): Promise<Note> => post(bob, { text: `test ${keyword} A` }), included: true },
@@ -495,7 +491,7 @@ describe('アンテナ', () => {
 			},
 			{
 				label: '除外ワード3つ(OR)',
-				parameters: (): object => ({ excludeKeywords: [['A'], ['B'], ['C']] }),
+				parameters: () => ({ excludeKeywords: [['A'], ['B'], ['C']] }),
 				posts: [
 					{ note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true },
 					{ note: (): Promise<Note> => post(bob, { text: `test ${keyword} A` }) },
@@ -508,7 +504,7 @@ describe('アンテナ', () => {
 			},
 			{
 				label: 'キーワード1つ(大文字小文字区別する)',
-				parameters: (): object => ({ keywords: [['KEYWORD']], caseSensitive: true }),
+				parameters: () => ({ keywords: [['KEYWORD']], caseSensitive: true }),
 				posts: [
 					{ note: (): Promise<Note> => post(bob, { text: 'keyword' }) },
 					{ note: (): Promise<Note> => post(bob, { text: 'kEyWoRd' }) },
@@ -517,7 +513,7 @@ describe('アンテナ', () => {
 			},
 			{
 				label: 'キーワード1つ(大文字小文字区別しない)',
-				parameters: (): object => ({ keywords: [['KEYWORD']], caseSensitive: false }),
+				parameters: () => ({ keywords: [['KEYWORD']], caseSensitive: false }),
 				posts: [
 					{ note: (): Promise<Note> => post(bob, { text: 'keyword' }), included: true },
 					{ note: (): Promise<Note> => post(bob, { text: 'kEyWoRd' }), included: true },
@@ -526,7 +522,7 @@ describe('アンテナ', () => {
 			},
 			{
 				label: '除外ワード1つ(大文字小文字区別する)',
-				parameters: (): object => ({ excludeKeywords: [['KEYWORD']], caseSensitive: true }),
+				parameters: () => ({ excludeKeywords: [['KEYWORD']], caseSensitive: true }),
 				posts: [
 					{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true },
 					{ note: (): Promise<Note> => post(bob, { text: `${keyword} keyword` }), included: true },
@@ -536,7 +532,7 @@ describe('アンテナ', () => {
 			},
 			{
 				label: '除外ワード1つ(大文字小文字区別しない)',
-				parameters: (): object => ({ excludeKeywords: [['KEYWORD']], caseSensitive: false }),
+				parameters: () => ({ excludeKeywords: [['KEYWORD']], caseSensitive: false }),
 				posts: [
 					{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true },
 					{ note: (): Promise<Note> => post(bob, { text: `${keyword} keyword` }) },
@@ -546,7 +542,7 @@ describe('アンテナ', () => {
 			},
 			{
 				label: '添付ファイルを問わない',
-				parameters: (): object => ({ withFile: false }),
+				parameters: () => ({ withFile: false }),
 				posts: [
 					{ note: (): Promise<Note> => post(bob, { text: `${keyword}`, fileIds: [bobFile.id] }), included: true },
 					{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true },
@@ -554,7 +550,7 @@ describe('アンテナ', () => {
 			},
 			{
 				label: '添付ファイル付きのみ',
-				parameters: (): object => ({ withFile: true }),
+				parameters: () => ({ withFile: true }),
 				posts: [
 					{ note: (): Promise<Note> => post(bob, { text: `${keyword}`, fileIds: [bobFile.id] }), included: true },
 					{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }) },
@@ -562,7 +558,7 @@ describe('アンテナ', () => {
 			},
 			{
 				label: 'リプライ以外',
-				parameters: (): object => ({ withReplies: false }),
+				parameters: () => ({ withReplies: false }),
 				posts: [
 					{ note: (): Promise<Note> => post(bob, { text: `${keyword}`, replyId: alicePost.id }) },
 					{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true },
@@ -570,7 +566,7 @@ describe('アンテナ', () => {
 			},
 			{
 				label: 'リプライも含む',
-				parameters: (): object => ({ withReplies: true }),
+				parameters: () => ({ withReplies: true }),
 				posts: [
 					{ note: (): Promise<Note> => post(bob, { text: `${keyword}`, replyId: alicePost.id }), included: true },
 					{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true },
@@ -633,7 +629,7 @@ describe('アンテナ', () => {
 					endpoint: 'antennas/notes',
 					parameters: { antennaId: antenna.id, ...paginationParam },
 					user: alice,
-				}) as any as Note[];
+				});
 			}, offsetBy, 'desc');
 		});
 
diff --git a/packages/backend/test/e2e/api-visibility.ts b/packages/backend/test/e2e/api-visibility.ts
index f92384525c..c61b0c2a86 100644
--- a/packages/backend/test/e2e/api-visibility.ts
+++ b/packages/backend/test/e2e/api-visibility.ts
@@ -6,7 +6,7 @@
 process.env.NODE_ENV = 'test';
 
 import * as assert from 'assert';
-import { api, post, signup } from '../utils.js';
+import { UserToken, api, post, signup } from '../utils.js';
 import type * as misskey from 'misskey-js';
 
 describe('API visibility', () => {
@@ -24,38 +24,38 @@ describe('API visibility', () => {
 		let target2: misskey.entities.SignupResponse;
 
 		/** public-post */
-		let pub: any;
+		let pub: misskey.entities.Note;
 		/** home-post */
-		let home: any;
+		let home: misskey.entities.Note;
 		/** followers-post */
-		let fol: any;
+		let fol: misskey.entities.Note;
 		/** specified-post */
-		let spe: any;
+		let spe: misskey.entities.Note;
 
 		/** public-reply to target's post */
-		let pubR: any;
+		let pubR: misskey.entities.Note;
 		/** home-reply to target's post */
-		let homeR: any;
+		let homeR: misskey.entities.Note;
 		/** followers-reply to target's post */
-		let folR: any;
+		let folR: misskey.entities.Note;
 		/** specified-reply to target's post */
-		let speR: any;
+		let speR: misskey.entities.Note;
 
 		/** public-mention to target */
-		let pubM: any;
+		let pubM: misskey.entities.Note;
 		/** home-mention to target */
-		let homeM: any;
+		let homeM: misskey.entities.Note;
 		/** followers-mention to target */
-		let folM: any;
+		let folM: misskey.entities.Note;
 		/** specified-mention to target */
-		let speM: any;
+		let speM: misskey.entities.Note;
 
 		/** reply target post */
-		let tgt: any;
+		let tgt: misskey.entities.Note;
 		//#endregion
 
-		const show = async (noteId: any, by: any) => {
-			return await api('/notes/show', {
+		const show = async (noteId: misskey.entities.Note['id'], by?: UserToken) => {
+			return await api('notes/show', {
 				noteId,
 			}, by);
 		};
@@ -70,7 +70,7 @@ describe('API visibility', () => {
 			target2 = await signup({ username: 'target2' });
 
 			// follow alice <= follower
-			await api('/following/create', { userId: alice.id }, follower);
+			await api('following/create', { userId: alice.id }, follower);
 
 			// normal posts
 			pub = await post(alice, { text: 'x', visibility: 'public' });
@@ -111,7 +111,7 @@ describe('API visibility', () => {
 		});
 
 		test('[show] public-postを未認証が見れる', async () => {
-			const res = await show(pub.id, null);
+			const res = await show(pub.id);
 			assert.strictEqual(res.body.text, 'x');
 		});
 
@@ -132,7 +132,7 @@ describe('API visibility', () => {
 		});
 
 		test('[show] home-postを未認証が見れる', async () => {
-			const res = await show(home.id, null);
+			const res = await show(home.id);
 			assert.strictEqual(res.body.text, 'x');
 		});
 
@@ -153,7 +153,7 @@ describe('API visibility', () => {
 		});
 
 		test('[show] followers-postを未認証が見れない', async () => {
-			const res = await show(fol.id, null);
+			const res = await show(fol.id);
 			assert.strictEqual(res.body.isHidden, true);
 		});
 
@@ -179,7 +179,7 @@ describe('API visibility', () => {
 		});
 
 		test('[show] specified-postを未認証が見れない', async () => {
-			const res = await show(spe.id, null);
+			const res = await show(spe.id);
 			assert.strictEqual(res.body.isHidden, true);
 		});
 		//#endregion
@@ -207,7 +207,7 @@ describe('API visibility', () => {
 		});
 
 		test('[show] public-replyを未認証が見れる', async () => {
-			const res = await show(pubR.id, null);
+			const res = await show(pubR.id);
 			assert.strictEqual(res.body.text, 'x');
 		});
 
@@ -233,7 +233,7 @@ describe('API visibility', () => {
 		});
 
 		test('[show] home-replyを未認証が見れる', async () => {
-			const res = await show(homeR.id, null);
+			const res = await show(homeR.id);
 			assert.strictEqual(res.body.text, 'x');
 		});
 
@@ -259,7 +259,7 @@ describe('API visibility', () => {
 		});
 
 		test('[show] followers-replyを未認証が見れない', async () => {
-			const res = await show(folR.id, null);
+			const res = await show(folR.id);
 			assert.strictEqual(res.body.isHidden, true);
 		});
 
@@ -290,7 +290,7 @@ describe('API visibility', () => {
 		});
 
 		test('[show] specified-replyを未認証が見れない', async () => {
-			const res = await show(speR.id, null);
+			const res = await show(speR.id);
 			assert.strictEqual(res.body.isHidden, true);
 		});
 		//#endregion
@@ -318,7 +318,7 @@ describe('API visibility', () => {
 		});
 
 		test('[show] public-mentionを未認証が見れる', async () => {
-			const res = await show(pubM.id, null);
+			const res = await show(pubM.id);
 			assert.strictEqual(res.body.text, '@target x');
 		});
 
@@ -344,7 +344,7 @@ describe('API visibility', () => {
 		});
 
 		test('[show] home-mentionを未認証が見れる', async () => {
-			const res = await show(homeM.id, null);
+			const res = await show(homeM.id);
 			assert.strictEqual(res.body.text, '@target x');
 		});
 
@@ -370,7 +370,7 @@ describe('API visibility', () => {
 		});
 
 		test('[show] followers-mentionを未認証が見れない', async () => {
-			const res = await show(folM.id, null);
+			const res = await show(folM.id);
 			assert.strictEqual(res.body.isHidden, true);
 		});
 
@@ -401,28 +401,28 @@ describe('API visibility', () => {
 		});
 
 		test('[show] specified-mentionを未認証が見れない', async () => {
-			const res = await show(speM.id, null);
+			const res = await show(speM.id);
 			assert.strictEqual(res.body.isHidden, true);
 		});
 		//#endregion
 
 		//#region HTL
 		test('[HTL] public-post が 自分が見れる', async () => {
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 			assert.strictEqual(res.status, 200);
 			const notes = res.body.filter((n: any) => n.id === pub.id);
 			assert.strictEqual(notes[0].text, 'x');
 		});
 
 		test('[HTL] public-post が 非フォロワーから見れない', async () => {
-			const res = await api('/notes/timeline', { limit: 100 }, other);
+			const res = await api('notes/timeline', { limit: 100 }, other);
 			assert.strictEqual(res.status, 200);
 			const notes = res.body.filter((n: any) => n.id === pub.id);
 			assert.strictEqual(notes.length, 0);
 		});
 
 		test('[HTL] followers-post が フォロワーから見れる', async () => {
-			const res = await api('/notes/timeline', { limit: 100 }, follower);
+			const res = await api('notes/timeline', { limit: 100 }, follower);
 			assert.strictEqual(res.status, 200);
 			const notes = res.body.filter((n: any) => n.id === fol.id);
 			assert.strictEqual(notes[0].text, 'x');
@@ -431,21 +431,21 @@ describe('API visibility', () => {
 
 		//#region RTL
 		test('[replies] followers-reply が フォロワーから見れる', async () => {
-			const res = await api('/notes/replies', { noteId: tgt.id, limit: 100 }, follower);
+			const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, follower);
 			assert.strictEqual(res.status, 200);
 			const notes = res.body.filter((n: any) => n.id === folR.id);
 			assert.strictEqual(notes[0].text, 'x');
 		});
 
 		test('[replies] followers-reply が 非フォロワー (リプライ先ではない) から見れない', async () => {
-			const res = await api('/notes/replies', { noteId: tgt.id, limit: 100 }, other);
+			const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, other);
 			assert.strictEqual(res.status, 200);
 			const notes = res.body.filter((n: any) => n.id === folR.id);
 			assert.strictEqual(notes.length, 0);
 		});
 
 		test('[replies] followers-reply が 非フォロワー (リプライ先である) から見れる', async () => {
-			const res = await api('/notes/replies', { noteId: tgt.id, limit: 100 }, target);
+			const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, target);
 			assert.strictEqual(res.status, 200);
 			const notes = res.body.filter((n: any) => n.id === folR.id);
 			assert.strictEqual(notes[0].text, 'x');
@@ -454,14 +454,14 @@ describe('API visibility', () => {
 
 		//#region MTL
 		test('[mentions] followers-reply が 非フォロワー (リプライ先である) から見れる', async () => {
-			const res = await api('/notes/mentions', { limit: 100 }, target);
+			const res = await api('notes/mentions', { limit: 100 }, target);
 			assert.strictEqual(res.status, 200);
 			const notes = res.body.filter((n: any) => n.id === folR.id);
 			assert.strictEqual(notes[0].text, 'x');
 		});
 
 		test('[mentions] followers-mention が 非フォロワー (メンション先である) から見れる', async () => {
-			const res = await api('/notes/mentions', { limit: 100 }, target);
+			const res = await api('notes/mentions', { limit: 100 }, target);
 			assert.strictEqual(res.status, 200);
 			const notes = res.body.filter((n: any) => n.id === folM.id);
 			assert.strictEqual(notes[0].text, '@target x');
diff --git a/packages/backend/test/e2e/api.ts b/packages/backend/test/e2e/api.ts
index b6eeec99d7..49c6a0636b 100644
--- a/packages/backend/test/e2e/api.ts
+++ b/packages/backend/test/e2e/api.ts
@@ -23,32 +23,32 @@ import type * as misskey from 'misskey-js';
 describe('API', () => {
 	let alice: misskey.entities.SignupResponse;
 	let bob: misskey.entities.SignupResponse;
-	let carol: misskey.entities.SignupResponse;
 
 	beforeAll(async () => {
 		alice = await signup({ username: 'alice' });
 		bob = await signup({ username: 'bob' });
-		carol = await signup({ username: 'carol' });
 	}, 1000 * 60 * 2);
 
 	describe('General validation', () => {
 		test('wrong type', async () => {
-			const res = await api('/test', {
+			const res = await api('test', {
 				required: true,
+				// @ts-expect-error string must be string
 				string: 42,
 			});
 			assert.strictEqual(res.status, 400);
 		});
 
 		test('missing require param', async () => {
-			const res = await api('/test', {
+			// @ts-expect-error required is required
+			const res = await api('test', {
 				string: 'a',
 			});
 			assert.strictEqual(res.status, 400);
 		});
 
 		test('invalid misskey:id (empty string)', async () => {
-			const res = await api('/test', {
+			const res = await api('test', {
 				required: true,
 				id: '',
 			});
@@ -56,7 +56,7 @@ describe('API', () => {
 		});
 
 		test('valid misskey:id', async () => {
-			const res = await api('/test', {
+			const res = await api('test', {
 				required: true,
 				id: '8wvhjghbxu',
 			});
@@ -64,7 +64,7 @@ describe('API', () => {
 		});
 
 		test('default value', async () => {
-			const res = await api('/test', {
+			const res = await api('test', {
 				required: true,
 				string: 'a',
 			});
@@ -73,7 +73,7 @@ describe('API', () => {
 		});
 
 		test('can set null even if it has default value', async () => {
-			const res = await api('/test', {
+			const res = await api('test', {
 				required: true,
 				nullableDefault: null,
 			});
@@ -82,7 +82,7 @@ describe('API', () => {
 		});
 
 		test('cannot set undefined if it has default value', async () => {
-			const res = await api('/test', {
+			const res = await api('test', {
 				required: true,
 				nullableDefault: undefined,
 			});
@@ -99,14 +99,14 @@ describe('API', () => {
 
 		// aliceは管理者、APIを使える
 		await successfulApiCall({
-			endpoint: '/admin/get-index-stats',
+			endpoint: 'admin/get-index-stats',
 			parameters: {},
 			user: alice,
 		});
 
 		// bobは一般ユーザーだからダメ
 		await failedApiCall({
-			endpoint: '/admin/get-index-stats',
+			endpoint: 'admin/get-index-stats',
 			parameters: {},
 			user: bob,
 		}, {
@@ -117,7 +117,7 @@ describe('API', () => {
 
 		// publicアクセスももちろんダメ
 		await failedApiCall({
-			endpoint: '/admin/get-index-stats',
+			endpoint: 'admin/get-index-stats',
 			parameters: {},
 			user: undefined,
 		}, {
@@ -128,7 +128,7 @@ describe('API', () => {
 
 		// ごまがしもダメ
 		await failedApiCall({
-			endpoint: '/admin/get-index-stats',
+			endpoint: 'admin/get-index-stats',
 			parameters: {},
 			user: { token: 'tsukawasete' },
 		}, {
@@ -138,13 +138,13 @@ describe('API', () => {
 		});
 
 		await successfulApiCall({
-			endpoint: '/admin/get-index-stats',
+			endpoint: 'admin/get-index-stats',
 			parameters: {},
 			user: { token: application2 },
 		});
 
 		await failedApiCall({
-			endpoint: '/admin/get-index-stats',
+			endpoint: 'admin/get-index-stats',
 			parameters: {},
 			user: { token: application },
 		}, {
@@ -154,7 +154,7 @@ describe('API', () => {
 		});
 
 		await failedApiCall({
-			endpoint: '/admin/get-index-stats',
+			endpoint: 'admin/get-index-stats',
 			parameters: {},
 			user: { token: application3 },
 		}, {
@@ -164,7 +164,7 @@ describe('API', () => {
 		});
 
 		await failedApiCall({
-			endpoint: '/admin/get-index-stats',
+			endpoint: 'admin/get-index-stats',
 			parameters: {},
 			user: { token: application4 },
 		}, {
@@ -177,7 +177,7 @@ describe('API', () => {
 	describe('Authentication header', () => {
 		test('一般リクエスト', async () => {
 			await successfulApiCall({
-				endpoint: '/admin/get-index-stats',
+				endpoint: 'admin/get-index-stats',
 				parameters: {},
 				user: {
 					token: alice.token,
@@ -211,7 +211,7 @@ describe('API', () => {
 	describe('tokenエラー応答でWWW-Authenticate headerを送る', () => {
 		describe('invalid_token', () => {
 			test('一般リクエスト', async () => {
-				const result = await api('/admin/get-index-stats', {}, {
+				const result = await api('admin/get-index-stats', {}, {
 					token: 'syuilo',
 					bearer: true,
 				});
@@ -246,7 +246,7 @@ describe('API', () => {
 
 		describe('tokenがないとrealmだけおくる', () => {
 			test('一般リクエスト', async () => {
-				const result = await api('/admin/get-index-stats', {});
+				const result = await api('admin/get-index-stats', {});
 				assert.strictEqual(result.status, 401);
 				assert.strictEqual(result.headers.get('WWW-Authenticate'), 'Bearer realm="Misskey"');
 			});
@@ -259,7 +259,8 @@ describe('API', () => {
 		});
 
 		test('invalid_request', async () => {
-			const result = await api('/notes/create', { text: true }, {
+			// @ts-expect-error text must be string
+			const result = await api('notes/create', { text: true }, {
 				token: alice.token,
 				bearer: true,
 			});
diff --git a/packages/backend/test/e2e/block.ts b/packages/backend/test/e2e/block.ts
index cbd91e6e42..e4f798498f 100644
--- a/packages/backend/test/e2e/block.ts
+++ b/packages/backend/test/e2e/block.ts
@@ -22,7 +22,7 @@ describe('Block', () => {
 	}, 1000 * 60 * 2);
 
 	test('Block作成', async () => {
-		const res = await api('/blocking/create', {
+		const res = await api('blocking/create', {
 			userId: bob.id,
 		}, alice);
 
@@ -30,7 +30,7 @@ describe('Block', () => {
 	});
 
 	test('ブロックされているユーザーをフォローできない', async () => {
-		const res = await api('/following/create', { userId: alice.id }, bob);
+		const res = await api('following/create', { userId: alice.id }, bob);
 
 		assert.strictEqual(res.status, 400);
 		assert.strictEqual(res.body.error.id, 'c4ab57cc-4e41-45e9-bfd9-584f61e35ce0');
@@ -39,7 +39,7 @@ describe('Block', () => {
 	test('ブロックされているユーザーにリアクションできない', async () => {
 		const note = await post(alice, { text: 'hello' });
 
-		const res = await api('/notes/reactions/create', { noteId: note.id, reaction: '👍' }, bob);
+		const res = await api('notes/reactions/create', { noteId: note.id, reaction: '👍' }, bob);
 
 		assert.strictEqual(res.status, 400);
 		assert.strictEqual(res.body.error.id, '20ef5475-9f38-4e4c-bd33-de6d979498ec');
@@ -48,7 +48,7 @@ describe('Block', () => {
 	test('ブロックされているユーザーに返信できない', async () => {
 		const note = await post(alice, { text: 'hello' });
 
-		const res = await api('/notes/create', { replyId: note.id, text: 'yo' }, bob);
+		const res = await api('notes/create', { replyId: note.id, text: 'yo' }, bob);
 
 		assert.strictEqual(res.status, 400);
 		assert.strictEqual(res.body.error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3');
@@ -57,7 +57,7 @@ describe('Block', () => {
 	test('ブロックされているユーザーのノートをRenoteできない', async () => {
 		const note = await post(alice, { text: 'hello' });
 
-		const res = await api('/notes/create', { renoteId: note.id, text: 'yo' }, bob);
+		const res = await api('notes/create', { renoteId: note.id, text: 'yo' }, bob);
 
 		assert.strictEqual(res.status, 400);
 		assert.strictEqual(res.body.error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3');
@@ -72,12 +72,13 @@ describe('Block', () => {
 		const bobNote = await post(bob, { text: 'hi' });
 		const carolNote = await post(carol, { text: 'hi' });
 
-		const res = await api('/notes/local-timeline', {}, bob);
+		const res = await api('notes/local-timeline', {}, bob);
+		const body = res.body as misskey.entities.Note[];
 
 		assert.strictEqual(res.status, 200);
 		assert.strictEqual(Array.isArray(res.body), true);
-		assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), false);
-		assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
-		assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
+		assert.strictEqual(body.some(note => note.id === aliceNote.id), false);
+		assert.strictEqual(body.some(note => note.id === bobNote.id), true);
+		assert.strictEqual(body.some(note => note.id === carolNote.id), true);
 	});
 });
diff --git a/packages/backend/test/e2e/clips.ts b/packages/backend/test/e2e/clips.ts
index 2cf397e22d..ba6f9d6a65 100644
--- a/packages/backend/test/e2e/clips.ts
+++ b/packages/backend/test/e2e/clips.ts
@@ -6,47 +6,34 @@
 process.env.NODE_ENV = 'test';
 
 import * as assert from 'assert';
-import { JTDDataType } from 'ajv/dist/jtd';
 import { DEFAULT_POLICIES } from '@/core/RoleService.js';
-import type { Packed } from '@/misc/json-schema.js';
-import { paramDef as CreateParamDef } from '@/server/api/endpoints/clips/create.js';
-import { paramDef as UpdateParamDef } from '@/server/api/endpoints/clips/update.js';
-import { paramDef as DeleteParamDef } from '@/server/api/endpoints/clips/delete.js';
-import { paramDef as ShowParamDef } from '@/server/api/endpoints/clips/show.js';
-import { paramDef as FavoriteParamDef } from '@/server/api/endpoints/clips/favorite.js';
-import { paramDef as UnfavoriteParamDef } from '@/server/api/endpoints/clips/unfavorite.js';
-import { paramDef as AddNoteParamDef } from '@/server/api/endpoints/clips/add-note.js';
-import { paramDef as RemoveNoteParamDef } from '@/server/api/endpoints/clips/remove-note.js';
-import { paramDef as NotesParamDef } from '@/server/api/endpoints/clips/notes.js';
 import { api, ApiRequest, failedApiCall, hiddenNote, post, signup, successfulApiCall } from '../utils.js';
+import type * as Misskey from 'misskey-js';
+
+type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
 
 describe('クリップ', () => {
-	type User = Packed<'User'>;
-	type Note = Packed<'Note'>;
-	type Clip = Packed<'Clip'>;
-
-	let alice: User;
-	let bob: User;
-	let aliceNote: Note;
-	let aliceHomeNote: Note;
-	let aliceFollowersNote: Note;
-	let aliceSpecifiedNote: Note;
-	let bobNote: Note;
-	let bobHomeNote: Note;
-	let bobFollowersNote: Note;
-	let bobSpecifiedNote: Note;
+	let alice: Misskey.entities.SignupResponse;
+	let bob: Misskey.entities.SignupResponse;
+	let aliceNote: Misskey.entities.Note;
+	let aliceHomeNote: Misskey.entities.Note;
+	let aliceFollowersNote: Misskey.entities.Note;
+	let aliceSpecifiedNote: Misskey.entities.Note;
+	let bobNote: Misskey.entities.Note;
+	let bobHomeNote: Misskey.entities.Note;
+	let bobFollowersNote: Misskey.entities.Note;
+	let bobSpecifiedNote: Misskey.entities.Note;
 
 	const compareBy = <T extends { id: string }, >(selector: (s: T) => string = (s: T): string => s.id) => (a: T, b: T): number => {
 		return selector(a).localeCompare(selector(b));
 	};
 
-	type CreateParam = JTDDataType<typeof CreateParamDef>;
-	const defaultCreate = (): Partial<CreateParam> => ({
+	const defaultCreate = (): Pick<Misskey.entities.ClipsCreateRequest, 'name'> => ({
 		name: 'test',
 	});
-	const create = async (parameters: Partial<CreateParam> = {}, request: Partial<ApiRequest> = {}): Promise<Clip> => {
-		const clip = await successfulApiCall<Clip>({
-			endpoint: '/clips/create',
+	const create = async (parameters: Partial<Misskey.entities.ClipsCreateRequest> = {}, request: Partial<ApiRequest<'clips/create'>> = {}): Promise<Misskey.entities.Clip> => {
+		const clip = await successfulApiCall({
+			endpoint: 'clips/create',
 			parameters: {
 				...defaultCreate(),
 				...parameters,
@@ -64,17 +51,16 @@ describe('クリップ', () => {
 		return clip;
 	};
 
-	const createMany = async (parameters: Partial<CreateParam>, count = 10, user = alice): Promise<Clip[]> => {
+	const createMany = async (parameters: Partial<Misskey.entities.ClipsCreateRequest>, count = 10, user = alice): Promise<Misskey.entities.Clip[]> => {
 		return await Promise.all([...Array(count)].map((_, i) => create({
 			name: `test${i}`,
 			...parameters,
 		}, { user })));
 	};
 
-	type UpdateParam = JTDDataType<typeof UpdateParamDef>;
-	const update = async (parameters: Partial<UpdateParam>, request: Partial<ApiRequest> = {}): Promise<Clip> => {
-		const clip = await successfulApiCall<Clip>({
-			endpoint: '/clips/update',
+	const update = async (parameters: Optional<Misskey.entities.ClipsUpdateRequest, 'name'>, request: Partial<ApiRequest<'clips/update'>> = {}): Promise<Misskey.entities.Clip> => {
+		const clip = await successfulApiCall({
+			endpoint: 'clips/update',
 			parameters: {
 				name: 'updated',
 				...parameters,
@@ -92,41 +78,39 @@ describe('クリップ', () => {
 		return clip;
 	};
 
-	type DeleteParam = JTDDataType<typeof DeleteParamDef>;
-	const deleteClip = async (parameters: DeleteParam, request: Partial<ApiRequest> = {}): Promise<void> => {
-		return await successfulApiCall<void>({
-			endpoint: '/clips/delete',
+	const deleteClip = async (parameters: Misskey.entities.ClipsDeleteRequest, request: Partial<ApiRequest<'clips/delete'>> = {}): Promise<void> => {
+		return await successfulApiCall({
+			endpoint: 'clips/delete',
 			parameters,
 			user: alice,
 			...request,
 		}, {
 			status: 204,
-		});
+		}) as any as void;
 	};
 
-	type ShowParam = JTDDataType<typeof ShowParamDef>;
-	const show = async (parameters: ShowParam, request: Partial<ApiRequest> = {}): Promise<Clip> => {
-		return await successfulApiCall<Clip>({
-			endpoint: '/clips/show',
+	const show = async (parameters: Misskey.entities.ClipsShowRequest, request: Partial<ApiRequest<'clips/show'>> = {}): Promise<Misskey.entities.Clip> => {
+		return await successfulApiCall({
+			endpoint: 'clips/show',
 			parameters,
 			user: alice,
 			...request,
 		});
 	};
 
-	const list = async (request: Partial<ApiRequest>): Promise<Clip[]> => {
-		return successfulApiCall<Clip[]>({
-			endpoint: '/clips/list',
+	const list = async (request: Partial<ApiRequest<'clips/list'>>): Promise<Misskey.entities.Clip[]> => {
+		return successfulApiCall({
+			endpoint: 'clips/list',
 			parameters: {},
 			user: alice,
 			...request,
 		});
 	};
 
-	const usersClips = async (request: Partial<ApiRequest>): Promise<Clip[]> => {
-		return await successfulApiCall<Clip[]>({
-			endpoint: '/users/clips',
-			parameters: {},
+	const usersClips = async (parameters: Misskey.entities.UsersClipsRequest, request: Partial<ApiRequest<'users/clips'>> = {}): Promise<Misskey.entities.Clip[]> => {
+		return await successfulApiCall({
+			endpoint: 'users/clips',
+			parameters,
 			user: alice,
 			...request,
 		});
@@ -136,23 +120,22 @@ describe('クリップ', () => {
 		alice = await signup({ username: 'alice' });
 		bob = await signup({ username: 'bob' });
 
-		// FIXME: misskey-jsのNoteはoutdatedなので直接変換できない
-		aliceNote = await post(alice, { text: 'test' }) as any;
-		aliceHomeNote = await post(alice, { text: 'home only', visibility: 'home' }) as any;
-		aliceFollowersNote = await post(alice, { text: 'followers only', visibility: 'followers' }) as any;
-		aliceSpecifiedNote = await post(alice, { text: 'specified only', visibility: 'specified' }) as any;
-		bobNote = await post(bob, { text: 'test' }) as any;
-		bobHomeNote = await post(bob, { text: 'home only', visibility: 'home' }) as any;
-		bobFollowersNote = await post(bob, { text: 'followers only', visibility: 'followers' }) as any;
-		bobSpecifiedNote = await post(bob, { text: 'specified only', visibility: 'specified' }) as any;
+		aliceNote = await post(alice, { text: 'test' });
+		aliceHomeNote = await post(alice, { text: 'home only', visibility: 'home' });
+		aliceFollowersNote = await post(alice, { text: 'followers only', visibility: 'followers' });
+		aliceSpecifiedNote = await post(alice, { text: 'specified only', visibility: 'specified' });
+		bobNote = await post(bob, { text: 'test' });
+		bobHomeNote = await post(bob, { text: 'home only', visibility: 'home' });
+		bobFollowersNote = await post(bob, { text: 'followers only', visibility: 'followers' });
+		bobSpecifiedNote = await post(bob, { text: 'specified only', visibility: 'specified' });
 	}, 1000 * 60 * 2);
 
 	afterEach(async () => {
 		// テスト間で影響し合わないように毎回全部消す。
 		for (const user of [alice, bob]) {
-			const list = await api('/clips/list', { limit: 11 }, user);
+			const list = await api('clips/list', { limit: 11 }, user);
 			for (const clip of list.body) {
-				await api('/clips/delete', { clipId: clip.id }, user);
+				await api('clips/delete', { clipId: clip.id }, user);
 			}
 		}
 	});
@@ -177,7 +160,7 @@ describe('クリップ', () => {
 		}
 
 		await failedApiCall({
-			endpoint: '/clips/create',
+			endpoint: 'clips/create',
 			parameters: defaultCreate(),
 			user: alice,
 		}, {
@@ -204,7 +187,8 @@ describe('クリップ', () => {
 		{ label: 'descriptionが最大長+1', parameters: { description: 'a'.repeat(2049) } },
 	];
 	test.each(createClipDenyPattern)('の作成は$labelならできない', async ({ parameters }) => failedApiCall({
-		endpoint: '/clips/create',
+		endpoint: 'clips/create',
+		// @ts-expect-error invalid params
 		parameters: {
 			...defaultCreate(),
 			...parameters,
@@ -246,15 +230,15 @@ describe('クリップ', () => {
 			code: 'NO_SUCH_CLIP',
 			id: 'b4d92d70-b216-46fa-9a3f-a8c811699257',
 		} },
-		{ label: '他人のクリップ', user: (): User => bob, assertion: {
+		{ label: '他人のクリップ', user: () => bob, assertion: {
 			code: 'NO_SUCH_CLIP',
 			id: 'b4d92d70-b216-46fa-9a3f-a8c811699257',
 		} },
 		...createClipDenyPattern as any,
 	])('の更新は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({
-		endpoint: '/clips/update',
+		endpoint: 'clips/update',
 		parameters: {
-			clipId: (await create({}, { user: (user ?? ((): User => alice))() })).id,
+			clipId: (await create({}, { user: (user ?? (() => alice))() })).id,
 			name: 'updated',
 			...parameters,
 		},
@@ -279,14 +263,15 @@ describe('クリップ', () => {
 			code: 'NO_SUCH_CLIP',
 			id: '70ca08ba-6865-4630-b6fb-8494759aa754',
 		} },
-		{ label: '他人のクリップ', user: (): User => bob, assertion: {
+		{ label: '他人のクリップ', user: () => bob, assertion: {
 			code: 'NO_SUCH_CLIP',
 			id: '70ca08ba-6865-4630-b6fb-8494759aa754',
 		} },
 	])('の削除は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({
-		endpoint: '/clips/delete',
+		endpoint: 'clips/delete',
 		parameters: {
-			clipId: (await create({}, { user: (user ?? ((): User => alice))() })).id,
+			// @ts-expect-error clipId must not be null
+			clipId: (await create({}, { user: (user ?? (() => alice))() })).id,
 			...parameters,
 		},
 		user: alice,
@@ -306,7 +291,7 @@ describe('クリップ', () => {
 	test('のID指定取得は他人のPrivateなクリップは取得できない', async () => {
 		const clip = await create({ isPublic: false }, { user: bob } );
 		failedApiCall({
-			endpoint: '/clips/show',
+			endpoint: 'clips/show',
 			parameters: { clipId: clip.id },
 			user: alice,
 		}, {
@@ -323,7 +308,8 @@ describe('クリップ', () => {
 			id: 'c3c5fe33-d62c-44d2-9ea5-d997703f5c20',
 		} },
 	])('のID指定取得は$labelならできない', async ({ parameters, assetion }) => failedApiCall({
-		endpoint: '/clips/show',
+		endpoint: 'clips/show',
+		// @ts-expect-error clipId must not be undefined
 		parameters: {
 			...parameters,
 		},
@@ -356,27 +342,23 @@ describe('クリップ', () => {
 
 	test('の一覧が取得できる(空)', async () => {
 		const res = await usersClips({
-			parameters: {
-				userId: alice.id,
-			},
+			userId: alice.id,
 		});
 		assert.deepStrictEqual(res, []);
 	});
 
 	test.each([
 		{ label: '' },
-		{ label: '他人アカウントから', user: (): User => bob },
+		{ label: '他人アカウントから', user: () => bob },
 	])('の一覧が$label取得できる', async () => {
 		const clips = await createMany({ isPublic: true });
 		const res = await usersClips({
-			parameters: {
-				userId: alice.id,
-			},
+			userId: alice.id,
 		});
 
 		// 返ってくる配列には順序保障がないのでidでソートして厳密比較
 		assert.deepStrictEqual(
-			res.sort(compareBy<Clip>(s => s.id)),
+			res.sort(compareBy<Misskey.entities.Clip>(s => s.id)),
 			clips.sort(compareBy(s => s.id)));
 
 		// 認証状態で見たときだけisFavoritedが入っている
@@ -386,17 +368,16 @@ describe('クリップ', () => {
 	});
 
 	test.each([
-		{ label: '未認証', user: (): undefined => undefined },
+		{ label: '未認証', user: () => undefined },
 		{ label: '存在しないユーザーのもの', parameters: { userId: 'xxxxxxx' } },
 	])('の一覧は$labelでも取得できる', async ({ parameters, user }) => {
 		const clips = await createMany({ isPublic: true });
 		const res = await usersClips({
-			parameters: {
-				userId: alice.id,
-				limit: clips.length,
-				...parameters,
-			},
-			user: (user ?? ((): User => alice))(),
+			userId: alice.id,
+			limit: clips.length,
+			...parameters,
+		}, {
+			user: (user ?? (() => alice))(),
 		});
 
 		// 未認証で見たときはisFavoritedは入らない
@@ -409,10 +390,8 @@ describe('クリップ', () => {
 		await create({ isPublic: false });
 		const aliceClip = await create({ isPublic: true });
 		const res = await usersClips({
-			parameters: {
-				userId: alice.id,
-				limit: 2,
-			},
+			userId: alice.id,
+			limit: 2,
 		});
 		assert.deepStrictEqual(res, [aliceClip]);
 	});
@@ -421,17 +400,15 @@ describe('クリップ', () => {
 		const clips = await createMany({ isPublic: true }, 7);
 		clips.sort(compareBy(s => s.id));
 		const res = await usersClips({
-			parameters: {
-				userId: alice.id,
-				sinceId: clips[1].id,
-				untilId: clips[5].id,
-				limit: 4,
-			},
+			userId: alice.id,
+			sinceId: clips[1].id,
+			untilId: clips[5].id,
+			limit: 4,
 		});
 
 		// Promise.allで返ってくる配列には順序保障がないのでidでソートして厳密比較
 		assert.deepStrictEqual(
-			res.sort(compareBy<Clip>(s => s.id)),
+			res.sort(compareBy<Misskey.entities.Clip>(s => s.id)),
 			[clips[2], clips[3], clips[4]], // sinceIdとuntilId自体は結果に含まれない
 			clips[1].id + ' ... ' + clips[3].id + ' with ' + clips.map(s => s.id) + ' vs. ' + res.map(s => s.id));
 	});
@@ -441,8 +418,9 @@ describe('クリップ', () => {
 		{ label: 'limitゼロ', parameters: { limit: 0 } },
 		{ label: 'limit最大+1', parameters: { limit: 101 } },
 	])('の一覧は$labelだと取得できない', async ({ parameters }) => failedApiCall({
-		endpoint: '/users/clips',
+		endpoint: 'users/clips',
 		parameters: {
+			// @ts-expect-error userId must not be undefined
 			userId: alice.id,
 			...parameters,
 		},
@@ -454,15 +432,15 @@ describe('クリップ', () => {
 	}));
 
 	test.each([
-		{ label: '作成', endpoint: '/clips/create' },
-		{ label: '更新', endpoint: '/clips/update' },
-		{ label: '削除', endpoint: '/clips/delete' },
-		{ label: '取得', endpoint: '/clips/list' },
-		{ label: 'お気に入り設定', endpoint: '/clips/favorite' },
-		{ label: 'お気に入り解除', endpoint: '/clips/unfavorite' },
-		{ label: 'お気に入り取得', endpoint: '/clips/my-favorites' },
-		{ label: 'ノート追加', endpoint: '/clips/add-note' },
-		{ label: 'ノート削除', endpoint: '/clips/remove-note' },
+		{ label: '作成', endpoint: 'clips/create' as const },
+		{ label: '更新', endpoint: 'clips/update' as const },
+		{ label: '削除', endpoint: 'clips/delete' as const },
+		{ label: '取得', endpoint: 'clips/list' as const },
+		{ label: 'お気に入り設定', endpoint: 'clips/favorite' as const },
+		{ label: 'お気に入り解除', endpoint: 'clips/unfavorite' as const },
+		{ label: 'お気に入り取得', endpoint: 'clips/my-favorites' as const },
+		{ label: 'ノート追加', endpoint: 'clips/add-note' as const },
+		{ label: 'ノート削除', endpoint: 'clips/remove-note' as const },
 	])('の$labelは未認証ではできない', async ({ endpoint }) => await failedApiCall({
 		endpoint: endpoint,
 		parameters: {},
@@ -474,35 +452,33 @@ describe('クリップ', () => {
 	}));
 
 	describe('のお気に入り', () => {
-		let aliceClip: Clip;
+		let aliceClip: Misskey.entities.Clip;
 
-		type FavoriteParam = JTDDataType<typeof FavoriteParamDef>;
-		const favorite = async (parameters: FavoriteParam, request: Partial<ApiRequest> = {}): Promise<void> => {
-			return successfulApiCall<void>({
-				endpoint: '/clips/favorite',
+		const favorite = async (parameters: Misskey.entities.ClipsFavoriteRequest, request: Partial<ApiRequest<'clips/favorite'>> = {}): Promise<void> => {
+			return successfulApiCall({
+				endpoint: 'clips/favorite',
 				parameters,
 				user: alice,
 				...request,
 			}, {
 				status: 204,
-			});
+			}) as any as void;
 		};
 
-		type UnfavoriteParam = JTDDataType<typeof UnfavoriteParamDef>;
-		const unfavorite = async (parameters: UnfavoriteParam, request: Partial<ApiRequest> = {}): Promise<void> => {
-			return successfulApiCall<void>({
-				endpoint: '/clips/unfavorite',
+		const unfavorite = async (parameters: Misskey.entities.ClipsUnfavoriteRequest, request: Partial<ApiRequest<'clips/unfavorite'>> = {}): Promise<void> => {
+			return successfulApiCall({
+				endpoint: 'clips/unfavorite',
 				parameters,
 				user: alice,
 				...request,
 			}, {
 				status: 204,
-			});
+			}) as any as void;
 		};
 
-		const myFavorites = async (request: Partial<ApiRequest> = {}): Promise<Clip[]> => {
-			return successfulApiCall<Clip[]>({
-				endpoint: '/clips/my-favorites',
+		const myFavorites = async (request: Partial<ApiRequest<'clips/my-favorites'>> = {}): Promise<Misskey.entities.Clip[]> => {
+			return successfulApiCall({
+				endpoint: 'clips/my-favorites',
 				parameters: {},
 				user: alice,
 				...request,
@@ -568,7 +544,7 @@ describe('クリップ', () => {
 		test('は同じクリップに対して二回設定できない。', async () => {
 			await favorite({ clipId: aliceClip.id });
 			await failedApiCall({
-				endpoint: '/clips/favorite',
+				endpoint: 'clips/favorite',
 				parameters: {
 					clipId: aliceClip.id,
 				},
@@ -586,14 +562,15 @@ describe('クリップ', () => {
 				code: 'NO_SUCH_CLIP',
 				id: '4c2aaeae-80d8-4250-9606-26cb1fdb77a5',
 			} },
-			{ label: '他人のクリップ', user: (): User => bob, assertion: {
+			{ label: '他人のクリップ', user: () => bob, assertion: {
 				code: 'NO_SUCH_CLIP',
 				id: '4c2aaeae-80d8-4250-9606-26cb1fdb77a5',
 			} },
 		])('の設定は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({
-			endpoint: '/clips/favorite',
+			endpoint: 'clips/favorite',
 			parameters: {
-				clipId: (await create({}, { user: (user ?? ((): User => alice))() })).id,
+				// @ts-expect-error clipId must not be null
+				clipId: (await create({}, { user: (user ?? (() => alice))() })).id,
 				...parameters,
 			},
 			user: alice,
@@ -619,7 +596,7 @@ describe('クリップ', () => {
 				code: 'NO_SUCH_CLIP',
 				id: '2603966e-b865-426c-94a7-af4a01241dc1',
 			} },
-			{ label: '他人のクリップ', user: (): User => bob, assertion: {
+			{ label: '他人のクリップ', user: () => bob, assertion: {
 				code: 'NOT_FAVORITED',
 				id: '90c3a9e8-b321-4dae-bf57-2bf79bbcc187',
 			} },
@@ -628,9 +605,10 @@ describe('クリップ', () => {
 				id: '90c3a9e8-b321-4dae-bf57-2bf79bbcc187',
 			} },
 		])('の設定解除は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({
-			endpoint: '/clips/unfavorite',
+			endpoint: 'clips/unfavorite',
 			parameters: {
-				clipId: (await create({}, { user: (user ?? ((): User => alice))() })).id,
+				// @ts-expect-error clipId must not be null
+				clipId: (await create({}, { user: (user ?? (() => alice))() })).id,
 				...parameters,
 			},
 			user: alice,
@@ -655,41 +633,38 @@ describe('クリップ', () => {
 	});
 
 	describe('に紐づくノート', () => {
-		let aliceClip: Clip;
+		let aliceClip: Misskey.entities.Clip;
 
-		const sampleNotes = (): Note[] => [
+		const sampleNotes = (): Misskey.entities.Note[] => [
 			aliceNote, aliceHomeNote, aliceFollowersNote, aliceSpecifiedNote,
 			bobNote, bobHomeNote, bobFollowersNote, bobSpecifiedNote,
 		];
 
-		type AddNoteParam = JTDDataType<typeof AddNoteParamDef>;
-		const addNote = async (parameters: AddNoteParam, request: Partial<ApiRequest> = {}): Promise<void> => {
-			return successfulApiCall<void>({
-				endpoint: '/clips/add-note',
+		const addNote = async (parameters: Misskey.entities.ClipsAddNoteRequest, request: Partial<ApiRequest<'clips/add-note'>> = {}): Promise<void> => {
+			return successfulApiCall({
+				endpoint: 'clips/add-note',
 				parameters,
 				user: alice,
 				...request,
 			}, {
 				status: 204,
-			});
+			}) as any as void;
 		};
 
-		type RemoveNoteParam = JTDDataType<typeof RemoveNoteParamDef>;
-		const removeNote = async (parameters: RemoveNoteParam, request: Partial<ApiRequest> = {}): Promise<void> => {
-			return successfulApiCall<void>({
-				endpoint: '/clips/remove-note',
+		const removeNote = async (parameters: Misskey.entities.ClipsRemoveNoteRequest, request: Partial<ApiRequest<'clips/remove-note'>> = {}): Promise<void> => {
+			return successfulApiCall({
+				endpoint: 'clips/remove-note',
 				parameters,
 				user: alice,
 				...request,
 			}, {
 				status: 204,
-			});
+			}) as any as void;
 		};
 
-		type NotesParam = JTDDataType<typeof NotesParamDef>;
-		const notes = async (parameters: Partial<NotesParam>, request: Partial<ApiRequest> = {}): Promise<Note[]> => {
-			return successfulApiCall<Note[]>({
-				endpoint: '/clips/notes',
+		const notes = async (parameters: Misskey.entities.ClipsNotesRequest, request: Partial<ApiRequest<'clips/notes'>> = {}): Promise<Misskey.entities.Note[]> => {
+			return successfulApiCall({
+				endpoint: 'clips/notes',
 				parameters,
 				user: alice,
 				...request,
@@ -715,7 +690,7 @@ describe('クリップ', () => {
 		test('として同じノートを二回紐づけることはできない', async () => {
 			await addNote({ clipId: aliceClip.id, noteId: aliceNote.id });
 			await failedApiCall({
-				endpoint: '/clips/add-note',
+				endpoint: 'clips/add-note',
 				parameters: {
 					clipId: aliceClip.id,
 					noteId: aliceNote.id,
@@ -733,11 +708,11 @@ describe('クリップ', () => {
 			const noteLimit = DEFAULT_POLICIES.noteEachClipsLimit + 1;
 			const noteList = await Promise.all([...Array(noteLimit)].map((_, i) => post(alice, {
 				text: `test ${i}`,
-			}) as unknown)) as Note[];
+			}) as unknown)) as Misskey.entities.Note[];
 			await Promise.all(noteList.map(s => addNote({ clipId: aliceClip.id, noteId: s.id })));
 
 			await failedApiCall({
-				endpoint: '/clips/add-note',
+				endpoint: 'clips/add-note',
 				parameters: {
 					clipId: aliceClip.id,
 					noteId: aliceNote.id,
@@ -751,7 +726,7 @@ describe('クリップ', () => {
 		});
 
 		test('は他人のクリップへ追加できない。', async () => await failedApiCall({
-			endpoint: '/clips/add-note',
+			endpoint: 'clips/add-note',
 			parameters: {
 				clipId: aliceClip.id,
 				noteId: aliceNote.id,
@@ -774,18 +749,20 @@ describe('クリップ', () => {
 				code: 'NO_SUCH_NOTE',
 				id: 'fc8c0b49-c7a3-4664-a0a6-b418d386bb8b',
 			} },
-			{ label: '他人のクリップ', user: (): object => bob, assetion: {
+			{ label: '他人のクリップ', user: () => bob, assetion: {
 				code: 'NO_SUCH_CLIP',
 				id: 'd6e76cc0-a1b5-4c7c-a287-73fa9c716dcf',
 			} },
 		])('の追加は$labelだとできない', async ({ parameters, user, assetion }) => failedApiCall({
-			endpoint: '/clips/add-note',
+			endpoint: 'clips/add-note',
 			parameters: {
+				// @ts-expect-error clipId must not be undefined
 				clipId: aliceClip.id,
+				// @ts-expect-error noteId must not be undefined
 				noteId: aliceNote.id,
 				...parameters,
 			},
-			user: (user ?? ((): User => alice))(),
+			user: (user ?? (() => alice))(),
 		}, {
 			status: 400,
 			code: 'INVALID_PARAM',
@@ -810,18 +787,20 @@ describe('クリップ', () => {
 				code: 'NO_SUCH_NOTE',
 				id: 'aff017de-190e-434b-893e-33a9ff5049d8', // add-noteと異なる
 			} },
-			{ label: '他人のクリップ', user: (): object => bob, assetion: {
+			{ label: '他人のクリップ', user: () => bob, assetion: {
 				code: 'NO_SUCH_CLIP',
 				id: 'b80525c6-97f7-49d7-a42d-ebccd49cfd52', // add-noteと異なる
 			} },
 		])('の削除は$labelだとできない', async ({ parameters, user, assetion }) => failedApiCall({
-			endpoint: '/clips/remove-note',
+			endpoint: 'clips/remove-note',
 			parameters: {
+				// @ts-expect-error clipId must not be undefined
 				clipId: aliceClip.id,
+				// @ts-expect-error noteId must not be undefined
 				noteId: aliceNote.id,
 				...parameters,
 			},
-			user: (user ?? ((): User => alice))(),
+			user: (user ?? (() => alice))(),
 		}, {
 			status: 400,
 			code: 'INVALID_PARAM',
@@ -925,21 +904,22 @@ describe('クリップ', () => {
 				code: 'NO_SUCH_CLIP',
 				id: '1d7645e6-2b6d-4635-b0fe-fe22b0e72e00',
 			} },
-			{ label: '他人のPrivateなクリップから', user: (): object => bob, assertion: {
+			{ label: '他人のPrivateなクリップから', user: () => bob, assertion: {
 				code: 'NO_SUCH_CLIP',
 				id: '1d7645e6-2b6d-4635-b0fe-fe22b0e72e00',
 			} },
-			{ label: '未認証でPrivateなクリップから', user: (): undefined => undefined, assertion: {
+			{ label: '未認証でPrivateなクリップから', user: () => undefined, assertion: {
 				code: 'NO_SUCH_CLIP',
 				id: '1d7645e6-2b6d-4635-b0fe-fe22b0e72e00',
 			} },
 		])('は$labelだと取得できない', async ({ parameters, user, assertion }) => failedApiCall({
-			endpoint: '/clips/notes',
+			endpoint: 'clips/notes',
 			parameters: {
+				// @ts-expect-error clipId must not be undefined
 				clipId: aliceClip.id,
 				...parameters,
 			},
-			user: (user ?? ((): User => alice))(),
+			user: (user ?? (() => alice))(),
 		}, {
 			status: 400,
 			code: 'INVALID_PARAM',
diff --git a/packages/backend/test/e2e/drive.ts b/packages/backend/test/e2e/drive.ts
index 22ec66e2af..828c5200ef 100644
--- a/packages/backend/test/e2e/drive.ts
+++ b/packages/backend/test/e2e/drive.ts
@@ -6,22 +6,14 @@
 process.env.NODE_ENV = 'test';
 
 import * as assert from 'assert';
-import { MiNote } from '@/models/Note.js';
-import { api, initTestDb, makeStreamCatcher, post, signup, uploadFile } from '../utils.js';
+import { api, makeStreamCatcher, post, signup, uploadFile } from '../utils.js';
 import type * as misskey from 'misskey-js';
-import type{ Repository } from 'typeorm'
-import type { Packed } from '@/misc/json-schema.js';
-
 
 describe('Drive', () => {
-	let Notes: Repository<MiNote>;
-
 	let alice: misskey.entities.SignupResponse;
 	let bob: misskey.entities.SignupResponse;
 
 	beforeAll(async () => {
-		const connection = await initTestDb(true);
-		Notes = connection.getRepository(MiNote);
 		alice = await signup({ username: 'alice' });
 		bob = await signup({ username: 'bob' });
 	}, 1000 * 60 * 2);
@@ -31,13 +23,13 @@ describe('Drive', () => {
 
 		const marker = Math.random().toString();
 
-		const url = 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg'
+		const url = 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg';
 
 		const catcher = makeStreamCatcher(
 			alice,
 			'main',
 			(msg) => msg.type === 'urlUploadFinished' && msg.body.marker === marker,
-			(msg) => msg.body.file as Packed<'DriveFile'>,
+			(msg) => msg.body.file,
 			10 * 1000);
 
 		const res = await api('drive/files/upload-from-url', {
@@ -51,7 +43,7 @@ describe('Drive', () => {
 		assert.strictEqual(res.status, 204);
 		assert.strictEqual(file.name, 'Lenna.jpg');
 		assert.strictEqual(file.type, 'image/jpeg');
-	})
+	});
 
 	test('ローカルからアップロードできる', async () => {
 		// APIレスポンスを直接使用するので utils.js uploadFile が通過することで成功とする
@@ -59,27 +51,27 @@ describe('Drive', () => {
 		const res = await uploadFile(alice, { path: 'Lenna.jpg', name: 'テスト画像' });
 
 		assert.strictEqual(res.body?.name, 'テスト画像.jpg');
-		assert.strictEqual(res.body?.type, 'image/jpeg');
-	})
+		assert.strictEqual(res.body.type, 'image/jpeg');
+	});
 
 	test('添付ノート一覧を取得できる', async () => {
-		const ids = (await Promise.all([uploadFile(alice), uploadFile(alice), uploadFile(alice)])).map(elm => elm.body!.id)
+		const ids = (await Promise.all([uploadFile(alice), uploadFile(alice), uploadFile(alice)])).map(elm => elm.body!.id);
 
 		const note0 = await post(alice, { fileIds: [ids[0]] });
 		const note1 = await post(alice, { fileIds: [ids[0], ids[1]] });
 
 		const attached0 = await api('drive/files/attached-notes', { fileId: ids[0] }, alice);
 		assert.strictEqual(attached0.body.length, 2);
-		assert.strictEqual(attached0.body[0].id, note1.id)
-		assert.strictEqual(attached0.body[1].id, note0.id)
+		assert.strictEqual(attached0.body[0].id, note1.id);
+		assert.strictEqual(attached0.body[1].id, note0.id);
 
 		const attached1 = await api('drive/files/attached-notes', { fileId: ids[1] }, alice);
 		assert.strictEqual(attached1.body.length, 1);
-		assert.strictEqual(attached1.body[0].id, note1.id)
+		assert.strictEqual(attached1.body[0].id, note1.id);
 
 		const attached2 = await api('drive/files/attached-notes', { fileId: ids[2] }, alice);
-		assert.strictEqual(attached2.body.length, 0)
-	})
+		assert.strictEqual(attached2.body.length, 0);
+	});
 
 	test('添付ノート一覧は他の人から見えない', async () => {
 		const file = await uploadFile(alice);
@@ -89,7 +81,5 @@ describe('Drive', () => {
 		const res = await api('drive/files/attached-notes', { fileId: file.body!.id }, bob);
 		assert.strictEqual(res.status, 400);
 		assert.strictEqual('error' in res.body, true);
-
-	})
+	});
 });
-
diff --git a/packages/backend/test/e2e/endpoints.ts b/packages/backend/test/e2e/endpoints.ts
index d469597805..bc89dc37f4 100644
--- a/packages/backend/test/e2e/endpoints.ts
+++ b/packages/backend/test/e2e/endpoints.ts
@@ -79,6 +79,7 @@ describe('Endpoints', () => {
 		test('クエリをインジェクションできない', async () => {
 			const res = await api('signin', {
 				username: 'test1',
+				// @ts-expect-error password must be string
 				password: {
 					$gt: '',
 				},
@@ -103,7 +104,7 @@ describe('Endpoints', () => {
 			const myLocation = '七森中';
 			const myBirthday = '2000-09-07';
 
-			const res = await api('/i/update', {
+			const res = await api('i/update', {
 				name: myName,
 				location: myLocation,
 				birthday: myBirthday,
@@ -117,7 +118,7 @@ describe('Endpoints', () => {
 		});
 
 		test('名前を空白にできる', async () => {
-			const res = await api('/i/update', {
+			const res = await api('i/update', {
 				name: ' ',
 			}, alice);
 			assert.strictEqual(res.status, 200);
@@ -125,11 +126,11 @@ describe('Endpoints', () => {
 		});
 
 		test('誕生日の設定を削除できる', async () => {
-			await api('/i/update', {
+			await api('i/update', {
 				birthday: '2000-09-07',
 			}, alice);
 
-			const res = await api('/i/update', {
+			const res = await api('i/update', {
 				birthday: null,
 			}, alice);
 
@@ -139,7 +140,7 @@ describe('Endpoints', () => {
 		});
 
 		test('不正な誕生日の形式で怒られる', async () => {
-			const res = await api('/i/update', {
+			const res = await api('i/update', {
 				birthday: '2000/09/07',
 			}, alice);
 			assert.strictEqual(res.status, 400);
@@ -148,7 +149,7 @@ describe('Endpoints', () => {
 
 	describe('users/show', () => {
 		test('ユーザーが取得できる', async () => {
-			const res = await api('/users/show', {
+			const res = await api('users/show', {
 				userId: alice.id,
 			}, alice);
 
@@ -158,14 +159,14 @@ describe('Endpoints', () => {
 		});
 
 		test('ユーザーが存在しなかったら怒る', async () => {
-			const res = await api('/users/show', {
+			const res = await api('users/show', {
 				userId: '000000000000000000000000',
 			});
 			assert.strictEqual(res.status, 404);
 		});
 
 		test('間違ったIDで怒られる', async () => {
-			const res = await api('/users/show', {
+			const res = await api('users/show', {
 				userId: 'kyoppie',
 			});
 			assert.strictEqual(res.status, 404);
@@ -178,7 +179,7 @@ describe('Endpoints', () => {
 				text: 'test',
 			});
 
-			const res = await api('/notes/show', {
+			const res = await api('notes/show', {
 				noteId: myPost.id,
 			}, alice);
 
@@ -189,14 +190,14 @@ describe('Endpoints', () => {
 		});
 
 		test('投稿が存在しなかったら怒る', async () => {
-			const res = await api('/notes/show', {
+			const res = await api('notes/show', {
 				noteId: '000000000000000000000000',
 			});
 			assert.strictEqual(res.status, 400);
 		});
 
 		test('間違ったIDで怒られる', async () => {
-			const res = await api('/notes/show', {
+			const res = await api('notes/show', {
 				noteId: 'kyoppie',
 			});
 			assert.strictEqual(res.status, 400);
@@ -207,14 +208,14 @@ describe('Endpoints', () => {
 		test('リアクションできる', async () => {
 			const bobPost = await post(bob, { text: 'hi' });
 
-			const res = await api('/notes/reactions/create', {
+			const res = await api('notes/reactions/create', {
 				noteId: bobPost.id,
 				reaction: '🚀',
 			}, alice);
 
 			assert.strictEqual(res.status, 204);
 
-			const resNote = await api('/notes/show', {
+			const resNote = await api('notes/show', {
 				noteId: bobPost.id,
 			}, alice);
 
@@ -225,7 +226,7 @@ describe('Endpoints', () => {
 		test('自分の投稿にもリアクションできる', async () => {
 			const myPost = await post(alice, { text: 'hi' });
 
-			const res = await api('/notes/reactions/create', {
+			const res = await api('notes/reactions/create', {
 				noteId: myPost.id,
 				reaction: '🚀',
 			}, alice);
@@ -236,19 +237,19 @@ describe('Endpoints', () => {
 		test('二重にリアクションすると上書きされる', async () => {
 			const bobPost = await post(bob, { text: 'hi' });
 
-			await api('/notes/reactions/create', {
+			await api('notes/reactions/create', {
 				noteId: bobPost.id,
 				reaction: '🥰',
 			}, alice);
 
-			const res = await api('/notes/reactions/create', {
+			const res = await api('notes/reactions/create', {
 				noteId: bobPost.id,
 				reaction: '🚀',
 			}, alice);
 
 			assert.strictEqual(res.status, 204);
 
-			const resNote = await api('/notes/show', {
+			const resNote = await api('notes/show', {
 				noteId: bobPost.id,
 			}, alice);
 
@@ -257,7 +258,7 @@ describe('Endpoints', () => {
 		});
 
 		test('存在しない投稿にはリアクションできない', async () => {
-			const res = await api('/notes/reactions/create', {
+			const res = await api('notes/reactions/create', {
 				noteId: '000000000000000000000000',
 				reaction: '🚀',
 			}, alice);
@@ -266,13 +267,14 @@ describe('Endpoints', () => {
 		});
 
 		test('空のパラメータで怒られる', async () => {
-			const res = await api('/notes/reactions/create', {}, alice);
+			// @ts-expect-error param must not be empty
+			const res = await api('notes/reactions/create', {}, alice);
 
 			assert.strictEqual(res.status, 400);
 		});
 
 		test('間違ったIDで怒られる', async () => {
-			const res = await api('/notes/reactions/create', {
+			const res = await api('notes/reactions/create', {
 				noteId: 'kyoppie',
 				reaction: '🚀',
 			}, alice);
@@ -283,7 +285,7 @@ describe('Endpoints', () => {
 
 	describe('following/create', () => {
 		test('フォローできる', async () => {
-			const res = await api('/following/create', {
+			const res = await api('following/create', {
 				userId: alice.id,
 			}, bob);
 
@@ -301,7 +303,7 @@ describe('Endpoints', () => {
 		});
 
 		test('既にフォローしている場合は怒る', async () => {
-			const res = await api('/following/create', {
+			const res = await api('following/create', {
 				userId: alice.id,
 			}, bob);
 
@@ -309,7 +311,7 @@ describe('Endpoints', () => {
 		});
 
 		test('存在しないユーザーはフォローできない', async () => {
-			const res = await api('/following/create', {
+			const res = await api('following/create', {
 				userId: '000000000000000000000000',
 			}, alice);
 
@@ -317,7 +319,7 @@ describe('Endpoints', () => {
 		});
 
 		test('自分自身はフォローできない', async () => {
-			const res = await api('/following/create', {
+			const res = await api('following/create', {
 				userId: alice.id,
 			}, alice);
 
@@ -325,13 +327,14 @@ describe('Endpoints', () => {
 		});
 
 		test('空のパラメータで怒られる', async () => {
-			const res = await api('/following/create', {}, alice);
+			// @ts-expect-error params must not be empty
+			const res = await api('following/create', {}, alice);
 
 			assert.strictEqual(res.status, 400);
 		});
 
 		test('間違ったIDで怒られる', async () => {
-			const res = await api('/following/create', {
+			const res = await api('following/create', {
 				userId: 'foo',
 			}, alice);
 
@@ -341,11 +344,11 @@ describe('Endpoints', () => {
 
 	describe('following/delete', () => {
 		test('フォロー解除できる', async () => {
-			await api('/following/create', {
+			await api('following/create', {
 				userId: alice.id,
 			}, bob);
 
-			const res = await api('/following/delete', {
+			const res = await api('following/delete', {
 				userId: alice.id,
 			}, bob);
 
@@ -363,7 +366,7 @@ describe('Endpoints', () => {
 		});
 
 		test('フォローしていない場合は怒る', async () => {
-			const res = await api('/following/delete', {
+			const res = await api('following/delete', {
 				userId: alice.id,
 			}, bob);
 
@@ -371,7 +374,7 @@ describe('Endpoints', () => {
 		});
 
 		test('存在しないユーザーはフォロー解除できない', async () => {
-			const res = await api('/following/delete', {
+			const res = await api('following/delete', {
 				userId: '000000000000000000000000',
 			}, alice);
 
@@ -379,7 +382,7 @@ describe('Endpoints', () => {
 		});
 
 		test('自分自身はフォロー解除できない', async () => {
-			const res = await api('/following/delete', {
+			const res = await api('following/delete', {
 				userId: alice.id,
 			}, alice);
 
@@ -387,13 +390,14 @@ describe('Endpoints', () => {
 		});
 
 		test('空のパラメータで怒られる', async () => {
-			const res = await api('/following/delete', {}, alice);
+			// @ts-expect-error params must not be empty
+			const res = await api('following/delete', {}, alice);
 
 			assert.strictEqual(res.status, 400);
 		});
 
 		test('間違ったIDで怒られる', async () => {
-			const res = await api('/following/delete', {
+			const res = await api('following/delete', {
 				userId: 'kyoppie',
 			}, alice);
 
@@ -403,20 +407,20 @@ describe('Endpoints', () => {
 
 	describe('channels/search', () => {
 		test('空白検索で一覧を取得できる', async () => {
-			await api('/channels/create', {
+			await api('channels/create', {
 				name: 'aaa',
 				description: 'bbb',
 			}, bob);
-			await api('/channels/create', {
+			await api('channels/create', {
 				name: 'ccc1',
 				description: 'ddd1',
 			}, bob);
-			await api('/channels/create', {
+			await api('channels/create', {
 				name: 'ccc2',
 				description: 'ddd2',
 			}, bob);
 
-			const res = await api('/channels/search', {
+			const res = await api('channels/search', {
 				query: '',
 			}, bob);
 
@@ -425,7 +429,7 @@ describe('Endpoints', () => {
 			assert.strictEqual(res.body.length, 3);
 		});
 		test('名前のみの検索で名前を検索できる', async () => {
-			const res = await api('/channels/search', {
+			const res = await api('channels/search', {
 				query: 'aaa',
 				type: 'nameOnly',
 			}, bob);
@@ -436,7 +440,7 @@ describe('Endpoints', () => {
 			assert.strictEqual(res.body[0].name, 'aaa');
 		});
 		test('名前のみの検索で名前を複数検索できる', async () => {
-			const res = await api('/channels/search', {
+			const res = await api('channels/search', {
 				query: 'ccc',
 				type: 'nameOnly',
 			}, bob);
@@ -446,7 +450,7 @@ describe('Endpoints', () => {
 			assert.strictEqual(res.body.length, 2);
 		});
 		test('名前のみの検索で説明は検索できない', async () => {
-			const res = await api('/channels/search', {
+			const res = await api('channels/search', {
 				query: 'bbb',
 				type: 'nameOnly',
 			}, bob);
@@ -456,7 +460,7 @@ describe('Endpoints', () => {
 			assert.strictEqual(res.body.length, 0);
 		});
 		test('名前と説明の検索で名前を検索できる', async () => {
-			const res = await api('/channels/search', {
+			const res = await api('channels/search', {
 				query: 'ccc1',
 			}, bob);
 
@@ -466,7 +470,7 @@ describe('Endpoints', () => {
 			assert.strictEqual(res.body[0].name, 'ccc1');
 		});
 		test('名前と説明での検索で説明を検索できる', async () => {
-			const res = await api('/channels/search', {
+			const res = await api('channels/search', {
 				query: 'ddd1',
 			}, bob);
 
@@ -476,7 +480,7 @@ describe('Endpoints', () => {
 			assert.strictEqual(res.body[0].name, 'ccc1');
 		});
 		test('名前と説明の検索で名前を複数検索できる', async () => {
-			const res = await api('/channels/search', {
+			const res = await api('channels/search', {
 				query: 'ccc',
 			}, bob);
 
@@ -485,7 +489,7 @@ describe('Endpoints', () => {
 			assert.strictEqual(res.body.length, 2);
 		});
 		test('名前と説明での検索で説明を複数検索できる', async () => {
-			const res = await api('/channels/search', {
+			const res = await api('channels/search', {
 				query: 'ddd',
 			}, bob);
 
@@ -506,7 +510,7 @@ describe('Endpoints', () => {
 			await uploadFile(alice, {
 				blob: new Blob([new Uint8Array(1024)]),
 			});
-			const res = await api('/drive', {}, alice);
+			const res = await api('drive', {}, alice);
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
 			expect(res.body).toHaveProperty('usage', 1792);
@@ -519,7 +523,7 @@ describe('Endpoints', () => {
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
-			assert.strictEqual(res.body.name, 'Lenna.jpg');
+			assert.strictEqual(res.body!.name, 'Lenna.jpg');
 		});
 
 		test('ファイルに名前を付けられる', async () => {
@@ -527,7 +531,7 @@ describe('Endpoints', () => {
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
-			assert.strictEqual(res.body.name, 'Belmond.jpg');
+			assert.strictEqual(res.body!.name, 'Belmond.jpg');
 		});
 
 		test('ファイルに名前を付けられるが、拡張子は正しいものになる', async () => {
@@ -535,11 +539,12 @@ describe('Endpoints', () => {
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
-			assert.strictEqual(res.body.name, 'Belmond.png.jpg');
+			assert.strictEqual(res.body!.name, 'Belmond.png.jpg');
 		});
 
 		test('ファイル無しで怒られる', async () => {
-			const res = await api('/drive/files/create', {}, alice);
+			// @ts-expect-error params must not be empty
+			const res = await api('drive/files/create', {}, alice);
 
 			assert.strictEqual(res.status, 400);
 		});
@@ -549,14 +554,14 @@ describe('Endpoints', () => {
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
-			assert.strictEqual(res.body.name, 'image.svg');
-			assert.strictEqual(res.body.type, 'image/svg+xml');
+			assert.strictEqual(res.body!.name, 'image.svg');
+			assert.strictEqual(res.body!.type, 'image/svg+xml');
 		});
 
 		for (const type of ['webp', 'avif']) {
 			const mediaType = `image/${type}`;
 
-			const getWebpublicType = async (user: any, fileId: string): Promise<string> => {
+			const getWebpublicType = async (user: misskey.entities.SignupResponse, fileId: string): Promise<string> => {
 				// drive/files/create does not expose webpublicType directly, so get it by posting it
 				const res = await post(user, {
 					text: mediaType,
@@ -573,10 +578,10 @@ describe('Endpoints', () => {
 				const res = await uploadFile(alice, { path });
 
 				assert.strictEqual(res.status, 200);
-				assert.strictEqual(res.body.name, path);
-				assert.strictEqual(res.body.type, mediaType);
+				assert.strictEqual(res.body!.name, path);
+				assert.strictEqual(res.body!.type, mediaType);
 
-				const webpublicType = await getWebpublicType(alice, res.body.id);
+				const webpublicType = await getWebpublicType(alice, res.body!.id);
 				assert.strictEqual(webpublicType, 'image/webp');
 			});
 
@@ -584,10 +589,10 @@ describe('Endpoints', () => {
 				const path = `without-alpha.${type}`;
 				const res = await uploadFile(alice, { path });
 				assert.strictEqual(res.status, 200);
-				assert.strictEqual(res.body.name, path);
-				assert.strictEqual(res.body.type, mediaType);
+				assert.strictEqual(res.body!.name, path);
+				assert.strictEqual(res.body!.type, mediaType);
 
-				const webpublicType = await getWebpublicType(alice, res.body.id);
+				const webpublicType = await getWebpublicType(alice, res.body!.id);
 				assert.strictEqual(webpublicType, 'image/webp');
 			});
 		}
@@ -598,8 +603,8 @@ describe('Endpoints', () => {
 			const file = (await uploadFile(alice)).body;
 			const newName = 'いちごパスタ.png';
 
-			const res = await api('/drive/files/update', {
-				fileId: file.id,
+			const res = await api('drive/files/update', {
+				fileId: file!.id,
 				name: newName,
 			}, alice);
 
@@ -611,8 +616,8 @@ describe('Endpoints', () => {
 		test('他人のファイルは更新できない', async () => {
 			const file = (await uploadFile(alice)).body;
 
-			const res = await api('/drive/files/update', {
-				fileId: file.id,
+			const res = await api('drive/files/update', {
+				fileId: file!.id,
 				name: 'いちごパスタ.png',
 			}, bob);
 
@@ -621,12 +626,12 @@ describe('Endpoints', () => {
 
 		test('親フォルダを更新できる', async () => {
 			const file = (await uploadFile(alice)).body;
-			const folder = (await api('/drive/folders/create', {
+			const folder = (await api('drive/folders/create', {
 				name: 'test',
 			}, alice)).body;
 
-			const res = await api('/drive/files/update', {
-				fileId: file.id,
+			const res = await api('drive/files/update', {
+				fileId: file!.id,
 				folderId: folder.id,
 			}, alice);
 
@@ -638,17 +643,17 @@ describe('Endpoints', () => {
 		test('親フォルダを無しにできる', async () => {
 			const file = (await uploadFile(alice)).body;
 
-			const folder = (await api('/drive/folders/create', {
+			const folder = (await api('drive/folders/create', {
 				name: 'test',
 			}, alice)).body;
 
-			await api('/drive/files/update', {
-				fileId: file.id,
+			await api('drive/files/update', {
+				fileId: file!.id,
 				folderId: folder.id,
 			}, alice);
 
-			const res = await api('/drive/files/update', {
-				fileId: file.id,
+			const res = await api('drive/files/update', {
+				fileId: file!.id,
 				folderId: null,
 			}, alice);
 
@@ -659,12 +664,12 @@ describe('Endpoints', () => {
 
 		test('他人のフォルダには入れられない', async () => {
 			const file = (await uploadFile(alice)).body;
-			const folder = (await api('/drive/folders/create', {
+			const folder = (await api('drive/folders/create', {
 				name: 'test',
 			}, bob)).body;
 
-			const res = await api('/drive/files/update', {
-				fileId: file.id,
+			const res = await api('drive/files/update', {
+				fileId: file!.id,
 				folderId: folder.id,
 			}, alice);
 
@@ -674,8 +679,8 @@ describe('Endpoints', () => {
 		test('存在しないフォルダで怒られる', async () => {
 			const file = (await uploadFile(alice)).body;
 
-			const res = await api('/drive/files/update', {
-				fileId: file.id,
+			const res = await api('drive/files/update', {
+				fileId: file!.id,
 				folderId: '000000000000000000000000',
 			}, alice);
 
@@ -685,8 +690,8 @@ describe('Endpoints', () => {
 		test('不正なフォルダIDで怒られる', async () => {
 			const file = (await uploadFile(alice)).body;
 
-			const res = await api('/drive/files/update', {
-				fileId: file.id,
+			const res = await api('drive/files/update', {
+				fileId: file!.id,
 				folderId: 'foo',
 			}, alice);
 
@@ -694,7 +699,7 @@ describe('Endpoints', () => {
 		});
 
 		test('ファイルが存在しなかったら怒る', async () => {
-			const res = await api('/drive/files/update', {
+			const res = await api('drive/files/update', {
 				fileId: '000000000000000000000000',
 				name: 'いちごパスタ.png',
 			}, alice);
@@ -706,8 +711,8 @@ describe('Endpoints', () => {
 			const file = (await uploadFile(alice)).body;
 			const newName = '';
 
-			const res = await api('/drive/files/update', {
-				fileId: file.id,
+			const res = await api('drive/files/update', {
+				fileId: file!.id,
 				name: newName,
 			}, alice);
 
@@ -715,7 +720,7 @@ describe('Endpoints', () => {
 		});
 
 		test('間違ったIDで怒られる', async () => {
-			const res = await api('/drive/files/update', {
+			const res = await api('drive/files/update', {
 				fileId: 'kyoppie',
 				name: 'いちごパスタ.png',
 			}, alice);
@@ -726,7 +731,7 @@ describe('Endpoints', () => {
 
 	describe('drive/folders/create', () => {
 		test('フォルダを作成できる', async () => {
-			const res = await api('/drive/folders/create', {
+			const res = await api('drive/folders/create', {
 				name: 'test',
 			}, alice);
 
@@ -738,11 +743,11 @@ describe('Endpoints', () => {
 
 	describe('drive/folders/update', () => {
 		test('名前を更新できる', async () => {
-			const folder = (await api('/drive/folders/create', {
+			const folder = (await api('drive/folders/create', {
 				name: 'test',
 			}, alice)).body;
 
-			const res = await api('/drive/folders/update', {
+			const res = await api('drive/folders/update', {
 				folderId: folder.id,
 				name: 'new name',
 			}, alice);
@@ -753,11 +758,11 @@ describe('Endpoints', () => {
 		});
 
 		test('他人のフォルダを更新できない', async () => {
-			const folder = (await api('/drive/folders/create', {
+			const folder = (await api('drive/folders/create', {
 				name: 'test',
 			}, bob)).body;
 
-			const res = await api('/drive/folders/update', {
+			const res = await api('drive/folders/update', {
 				folderId: folder.id,
 				name: 'new name',
 			}, alice);
@@ -766,14 +771,14 @@ describe('Endpoints', () => {
 		});
 
 		test('親フォルダを更新できる', async () => {
-			const folder = (await api('/drive/folders/create', {
+			const folder = (await api('drive/folders/create', {
 				name: 'test',
 			}, alice)).body;
-			const parentFolder = (await api('/drive/folders/create', {
+			const parentFolder = (await api('drive/folders/create', {
 				name: 'parent',
 			}, alice)).body;
 
-			const res = await api('/drive/folders/update', {
+			const res = await api('drive/folders/update', {
 				folderId: folder.id,
 				parentId: parentFolder.id,
 			}, alice);
@@ -784,18 +789,18 @@ describe('Endpoints', () => {
 		});
 
 		test('親フォルダを無しに更新できる', async () => {
-			const folder = (await api('/drive/folders/create', {
+			const folder = (await api('drive/folders/create', {
 				name: 'test',
 			}, alice)).body;
-			const parentFolder = (await api('/drive/folders/create', {
+			const parentFolder = (await api('drive/folders/create', {
 				name: 'parent',
 			}, alice)).body;
-			await api('/drive/folders/update', {
+			await api('drive/folders/update', {
 				folderId: folder.id,
 				parentId: parentFolder.id,
 			}, alice);
 
-			const res = await api('/drive/folders/update', {
+			const res = await api('drive/folders/update', {
 				folderId: folder.id,
 				parentId: null,
 			}, alice);
@@ -806,14 +811,14 @@ describe('Endpoints', () => {
 		});
 
 		test('他人のフォルダを親フォルダに設定できない', async () => {
-			const folder = (await api('/drive/folders/create', {
+			const folder = (await api('drive/folders/create', {
 				name: 'test',
 			}, alice)).body;
-			const parentFolder = (await api('/drive/folders/create', {
+			const parentFolder = (await api('drive/folders/create', {
 				name: 'parent',
 			}, bob)).body;
 
-			const res = await api('/drive/folders/update', {
+			const res = await api('drive/folders/update', {
 				folderId: folder.id,
 				parentId: parentFolder.id,
 			}, alice);
@@ -822,18 +827,18 @@ describe('Endpoints', () => {
 		});
 
 		test('フォルダが循環するような構造にできない', async () => {
-			const folder = (await api('/drive/folders/create', {
+			const folder = (await api('drive/folders/create', {
 				name: 'test',
 			}, alice)).body;
-			const parentFolder = (await api('/drive/folders/create', {
+			const parentFolder = (await api('drive/folders/create', {
 				name: 'parent',
 			}, alice)).body;
-			await api('/drive/folders/update', {
+			await api('drive/folders/update', {
 				folderId: parentFolder.id,
 				parentId: folder.id,
 			}, alice);
 
-			const res = await api('/drive/folders/update', {
+			const res = await api('drive/folders/update', {
 				folderId: folder.id,
 				parentId: parentFolder.id,
 			}, alice);
@@ -842,25 +847,25 @@ describe('Endpoints', () => {
 		});
 
 		test('フォルダが循環するような構造にできない(再帰的)', async () => {
-			const folderA = (await api('/drive/folders/create', {
+			const folderA = (await api('drive/folders/create', {
 				name: 'test',
 			}, alice)).body;
-			const folderB = (await api('/drive/folders/create', {
+			const folderB = (await api('drive/folders/create', {
 				name: 'test',
 			}, alice)).body;
-			const folderC = (await api('/drive/folders/create', {
+			const folderC = (await api('drive/folders/create', {
 				name: 'test',
 			}, alice)).body;
-			await api('/drive/folders/update', {
+			await api('drive/folders/update', {
 				folderId: folderB.id,
 				parentId: folderA.id,
 			}, alice);
-			await api('/drive/folders/update', {
+			await api('drive/folders/update', {
 				folderId: folderC.id,
 				parentId: folderB.id,
 			}, alice);
 
-			const res = await api('/drive/folders/update', {
+			const res = await api('drive/folders/update', {
 				folderId: folderA.id,
 				parentId: folderC.id,
 			}, alice);
@@ -869,11 +874,11 @@ describe('Endpoints', () => {
 		});
 
 		test('フォルダが循環するような構造にできない(自身)', async () => {
-			const folderA = (await api('/drive/folders/create', {
+			const folderA = (await api('drive/folders/create', {
 				name: 'test',
 			}, alice)).body;
 
-			const res = await api('/drive/folders/update', {
+			const res = await api('drive/folders/update', {
 				folderId: folderA.id,
 				parentId: folderA.id,
 			}, alice);
@@ -882,11 +887,11 @@ describe('Endpoints', () => {
 		});
 
 		test('存在しない親フォルダを設定できない', async () => {
-			const folder = (await api('/drive/folders/create', {
+			const folder = (await api('drive/folders/create', {
 				name: 'test',
 			}, alice)).body;
 
-			const res = await api('/drive/folders/update', {
+			const res = await api('drive/folders/update', {
 				folderId: folder.id,
 				parentId: '000000000000000000000000',
 			}, alice);
@@ -895,11 +900,11 @@ describe('Endpoints', () => {
 		});
 
 		test('不正な親フォルダIDで怒られる', async () => {
-			const folder = (await api('/drive/folders/create', {
+			const folder = (await api('drive/folders/create', {
 				name: 'test',
 			}, alice)).body;
 
-			const res = await api('/drive/folders/update', {
+			const res = await api('drive/folders/update', {
 				folderId: folder.id,
 				parentId: 'foo',
 			}, alice);
@@ -908,7 +913,7 @@ describe('Endpoints', () => {
 		});
 
 		test('存在しないフォルダを更新できない', async () => {
-			const res = await api('/drive/folders/update', {
+			const res = await api('drive/folders/update', {
 				folderId: '000000000000000000000000',
 			}, alice);
 
@@ -916,7 +921,7 @@ describe('Endpoints', () => {
 		});
 
 		test('不正なフォルダIDで怒られる', async () => {
-			const res = await api('/drive/folders/update', {
+			const res = await api('drive/folders/update', {
 				folderId: 'foo',
 			}, alice);
 
@@ -937,7 +942,7 @@ describe('Endpoints', () => {
 				visibleUserIds: [alice.id],
 			});
 
-			const res = await api('/notes/replies', {
+			const res = await api('notes/replies', {
 				noteId: alicePost.id,
 			}, carol);
 
@@ -949,7 +954,7 @@ describe('Endpoints', () => {
 
 	describe('notes/timeline', () => {
 		test('フォロワー限定投稿が含まれる', async () => {
-			await api('/following/create', {
+			await api('following/create', {
 				userId: carol.id,
 			}, dave);
 
@@ -958,7 +963,7 @@ describe('Endpoints', () => {
 				visibility: 'followers',
 			});
 
-			const res = await api('/notes/timeline', {}, dave);
+			const res = await api('notes/timeline', {}, dave);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(Array.isArray(res.body), true);
@@ -979,12 +984,12 @@ describe('Endpoints', () => {
 		test('他者に関するメモを更新できる', async () => {
 			const memo = '10月まで低浮上とのこと。';
 
-			const res1 = await api('/users/update-memo', {
+			const res1 = await api('users/update-memo', {
 				memo,
 				userId: bob.id,
 			}, alice);
 
-			const res2 = await api('/users/show', {
+			const res2 = await api('users/show', {
 				userId: bob.id,
 			}, alice);
 			assert.strictEqual(res1.status, 204);
@@ -994,12 +999,12 @@ describe('Endpoints', () => {
 		test('自分に関するメモを更新できる', async () => {
 			const memo = 'チケットを月末までに買う。';
 
-			const res1 = await api('/users/update-memo', {
+			const res1 = await api('users/update-memo', {
 				memo,
 				userId: alice.id,
 			}, alice);
 
-			const res2 = await api('/users/show', {
+			const res2 = await api('users/show', {
 				userId: alice.id,
 			}, alice);
 			assert.strictEqual(res1.status, 204);
@@ -1009,17 +1014,17 @@ describe('Endpoints', () => {
 		test('メモを削除できる', async () => {
 			const memo = '10月まで低浮上とのこと。';
 
-			await api('/users/update-memo', {
+			await api('users/update-memo', {
 				memo,
 				userId: bob.id,
 			}, alice);
 
-			await api('/users/update-memo', {
+			await api('users/update-memo', {
 				memo: '',
 				userId: bob.id,
 			}, alice);
 
-			const res = await api('/users/show', {
+			const res = await api('users/show', {
 				userId: bob.id,
 			}, alice);
 
@@ -1032,21 +1037,21 @@ describe('Endpoints', () => {
 			const memoCarolToBob = '例の件について今度問いただす。';
 
 			await Promise.all([
-				api('/users/update-memo', {
+				api('users/update-memo', {
 					memo: memoAliceToBob,
 					userId: bob.id,
 				}, alice),
-				api('/users/update-memo', {
+				api('users/update-memo', {
 					memo: memoCarolToBob,
 					userId: bob.id,
 				}, carol),
 			]);
 
 			const [resAlice, resCarol] = await Promise.all([
-				api('/users/show', {
+				api('users/show', {
 					userId: bob.id,
 				}, alice),
-				api('/users/show', {
+				api('users/show', {
 					userId: bob.id,
 				}, carol),
 			]);
diff --git a/packages/backend/test/e2e/exports.ts b/packages/backend/test/e2e/exports.ts
index eb03935a2a..80a5331a6d 100644
--- a/packages/backend/test/e2e/exports.ts
+++ b/packages/backend/test/e2e/exports.ts
@@ -18,7 +18,7 @@ describe('export-clips', () => {
 	// XXX: Any better way to get the result?
 	async function pollFirstDriveFile() {
 		while (true) {
-			const files = (await api('/drive/files', {}, alice)).body;
+			const files = (await api('drive/files', {}, alice)).body;
 			if (!files.length) {
 				await new Promise(r => setTimeout(r, 100));
 				continue;
@@ -26,7 +26,7 @@ describe('export-clips', () => {
 			if (files.length > 1) {
 				throw new Error('Too many files?');
 			}
-			const file = (await api('/drive/files/show', { fileId: files[0].id }, alice)).body;
+			const file = (await api('drive/files/show', { fileId: files[0].id }, alice)).body;
 			const res = await fetch(new URL(new URL(file.url).pathname, `http://127.0.0.1:${port}`));
 			return await res.json();
 		}
@@ -44,16 +44,16 @@ describe('export-clips', () => {
 
 	beforeEach(async () => {
 		// Clean all clips and files of alice
-		const clips = (await api('/clips/list', {}, alice)).body;
+		const clips = (await api('clips/list', {}, alice)).body;
 		for (const clip of clips) {
-			const res = await api('/clips/delete', { clipId: clip.id }, alice);
+			const res = await api('clips/delete', { clipId: clip.id }, alice);
 			if (res.status !== 204) {
 				throw new Error('Failed to delete clip');
 			}
 		}
-		const files = (await api('/drive/files', {}, alice)).body;
+		const files = (await api('drive/files', {}, alice)).body;
 		for (const file of files) {
-			const res = await api('/drive/files/delete', { fileId: file.id }, alice);
+			const res = await api('drive/files/delete', { fileId: file.id }, alice);
 			if (res.status !== 204) {
 				throw new Error('Failed to delete file');
 			}
@@ -61,13 +61,13 @@ describe('export-clips', () => {
 	});
 
 	test('basic export', async () => {
-		let res = await api('/clips/create', {
+		let res = await api('clips/create', {
 			name: 'foo',
 			description: 'bar',
 		}, alice);
 		assert.strictEqual(res.status, 200);
 
-		res = await api('/i/export-clips', {}, alice);
+		res = await api('i/export-clips', {}, alice);
 		assert.strictEqual(res.status, 204);
 
 		const exported = await pollFirstDriveFile();
@@ -77,7 +77,7 @@ describe('export-clips', () => {
 	});
 
 	test('export with notes', async () => {
-		let res = await api('/clips/create', {
+		let res = await api('clips/create', {
 			name: 'foo',
 			description: 'bar',
 		}, alice);
@@ -96,14 +96,14 @@ describe('export-clips', () => {
 		});
 
 		for (const note of [note1, note2]) {
-			res = await api('/clips/add-note', {
+			res = await api('clips/add-note', {
 				clipId: clip.id,
 				noteId: note.id,
 			}, alice);
 			assert.strictEqual(res.status, 204);
 		}
 
-		res = await api('/i/export-clips', {}, alice);
+		res = await api('i/export-clips', {}, alice);
 		assert.strictEqual(res.status, 204);
 
 		const exported = await pollFirstDriveFile();
@@ -116,14 +116,14 @@ describe('export-clips', () => {
 	});
 
 	test('multiple clips', async () => {
-		let res = await api('/clips/create', {
+		let res = await api('clips/create', {
 			name: 'kawaii',
 			description: 'kawaii',
 		}, alice);
 		assert.strictEqual(res.status, 200);
 		const clip1 = res.body;
 
-		res = await api('/clips/create', {
+		res = await api('clips/create', {
 			name: 'yuri',
 			description: 'yuri',
 		}, alice);
@@ -138,19 +138,19 @@ describe('export-clips', () => {
 			text: 'baz2',
 		});
 
-		res = await api('/clips/add-note', {
+		res = await api('clips/add-note', {
 			clipId: clip1.id,
 			noteId: note1.id,
 		}, alice);
 		assert.strictEqual(res.status, 204);
 
-		res = await api('/clips/add-note', {
+		res = await api('clips/add-note', {
 			clipId: clip2.id,
 			noteId: note2.id,
 		}, alice);
 		assert.strictEqual(res.status, 204);
 
-		res = await api('/i/export-clips', {}, alice);
+		res = await api('i/export-clips', {}, alice);
 		assert.strictEqual(res.status, 204);
 
 		const exported = await pollFirstDriveFile();
@@ -163,7 +163,7 @@ describe('export-clips', () => {
 	});
 
 	test('Clipping other user\'s note', async () => {
-		let res = await api('/clips/create', {
+		let res = await api('clips/create', {
 			name: 'kawaii',
 			description: 'kawaii',
 		}, alice);
@@ -175,13 +175,13 @@ describe('export-clips', () => {
 			visibility: 'followers',
 		});
 
-		res = await api('/clips/add-note', {
+		res = await api('clips/add-note', {
 			clipId: clip.id,
 			noteId: note.id,
 		}, alice);
 		assert.strictEqual(res.status, 204);
 
-		res = await api('/i/export-clips', {}, alice);
+		res = await api('i/export-clips', {}, alice);
 		assert.strictEqual(res.status, 204);
 
 		const exported = await pollFirstDriveFile();
diff --git a/packages/backend/test/e2e/fetch-resource.ts b/packages/backend/test/e2e/fetch-resource.ts
index 74033b7dff..4851ed14be 100644
--- a/packages/backend/test/e2e/fetch-resource.ts
+++ b/packages/backend/test/e2e/fetch-resource.ts
@@ -23,13 +23,13 @@ const JSON_UTF8 = 'application/json; charset=utf-8';
 
 describe('Webリソース', () => {
 	let alice: misskey.entities.SignupResponse;
-	let aliceUploadedFile: any;
-	let alicesPost: any;
-	let alicePage: any;
-	let alicePlay: any;
-	let aliceClip: any;
-	let aliceGalleryPost: any;
-	let aliceChannel: any;
+	let aliceUploadedFile: misskey.entities.DriveFile | null;
+	let alicesPost: misskey.entities.Note;
+	let alicePage: misskey.entities.Page;
+	let alicePlay: misskey.entities.Flash;
+	let aliceClip: misskey.entities.Clip;
+	let aliceGalleryPost: misskey.entities.GalleryPost;
+	let aliceChannel: misskey.entities.Channel;
 
 	let bob: misskey.entities.SignupResponse;
 
@@ -77,7 +77,7 @@ describe('Webリソース', () => {
 
 	beforeAll(async () => {
 		alice = await signup({ username: 'alice' });
-		aliceUploadedFile = await uploadFile(alice);
+		aliceUploadedFile = (await uploadFile(alice)).body;
 		alicesPost = await post(alice, {
 			text: 'test',
 		});
@@ -85,7 +85,7 @@ describe('Webリソース', () => {
 		alicePlay = await play(alice, {});
 		aliceClip = await clip(alice, {});
 		aliceGalleryPost = await galleryPost(alice, {
-			fileIds: [aliceUploadedFile.body.id],
+			fileIds: [aliceUploadedFile!.id],
 		});
 		aliceChannel = await channel(alice, {});
 
diff --git a/packages/backend/test/e2e/ff-visibility.ts b/packages/backend/test/e2e/ff-visibility.ts
index b59dd8824a..5d0c70a3c2 100644
--- a/packages/backend/test/e2e/ff-visibility.ts
+++ b/packages/backend/test/e2e/ff-visibility.ts
@@ -19,15 +19,15 @@ describe('FF visibility', () => {
 	}, 1000 * 60 * 2);
 
 	test('followingVisibility, followersVisibility がともに public なユーザーのフォロー/フォロワーを誰でも見れる', async () => {
-		await api('/i/update', {
+		await api('i/update', {
 			followingVisibility: 'public',
 			followersVisibility: 'public',
 		}, alice);
 
-		const followingRes = await api('/users/following', {
+		const followingRes = await api('users/following', {
 			userId: alice.id,
 		}, bob);
-		const followersRes = await api('/users/followers', {
+		const followersRes = await api('users/followers', {
 			userId: alice.id,
 		}, bob);
 
@@ -39,36 +39,36 @@ describe('FF visibility', () => {
 
 	test('followingVisibility が public であれば followersVisibility の設定に関わらずユーザーのフォローを誰でも見れる', async () => {
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'public',
 				followersVisibility: 'public',
 			}, alice);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followingRes.status, 200);
 			assert.strictEqual(Array.isArray(followingRes.body), true);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'public',
 				followersVisibility: 'followers',
 			}, alice);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followingRes.status, 200);
 			assert.strictEqual(Array.isArray(followingRes.body), true);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'public',
 				followersVisibility: 'private',
 			}, alice);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followingRes.status, 200);
@@ -78,36 +78,36 @@ describe('FF visibility', () => {
 
 	test('followersVisibility が public であれば followingVisibility の設定に関わらずユーザーのフォロワーを誰でも見れる', async () => {
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'public',
 				followersVisibility: 'public',
 			}, alice);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followersRes.status, 200);
 			assert.strictEqual(Array.isArray(followersRes.body), true);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'followers',
 				followersVisibility: 'public',
 			}, alice);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followersRes.status, 200);
 			assert.strictEqual(Array.isArray(followersRes.body), true);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'private',
 				followersVisibility: 'public',
 			}, alice);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followersRes.status, 200);
@@ -116,15 +116,15 @@ describe('FF visibility', () => {
 	});
 
 	test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーを自分で見れる', async () => {
-		await api('/i/update', {
+		await api('i/update', {
 			followingVisibility: 'followers',
 			followersVisibility: 'followers',
 		}, alice);
 
-		const followingRes = await api('/users/following', {
+		const followingRes = await api('users/following', {
 			userId: alice.id,
 		}, alice);
-		const followersRes = await api('/users/followers', {
+		const followersRes = await api('users/followers', {
 			userId: alice.id,
 		}, alice);
 
@@ -136,36 +136,36 @@ describe('FF visibility', () => {
 
 	test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらず自分で見れる', async () => {
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'followers',
 				followersVisibility: 'public',
 			}, alice);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, alice);
 			assert.strictEqual(followingRes.status, 200);
 			assert.strictEqual(Array.isArray(followingRes.body), true);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'followers',
 				followersVisibility: 'followers',
 			}, alice);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, alice);
 			assert.strictEqual(followingRes.status, 200);
 			assert.strictEqual(Array.isArray(followingRes.body), true);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'followers',
 				followersVisibility: 'private',
 			}, alice);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, alice);
 			assert.strictEqual(followingRes.status, 200);
@@ -175,36 +175,36 @@ describe('FF visibility', () => {
 
 	test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらず自分で見れる', async () => {
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'public',
 				followersVisibility: 'followers',
 			}, alice);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, alice);
 			assert.strictEqual(followersRes.status, 200);
 			assert.strictEqual(Array.isArray(followersRes.body), true);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'followers',
 				followersVisibility: 'followers',
 			}, alice);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, alice);
 			assert.strictEqual(followersRes.status, 200);
 			assert.strictEqual(Array.isArray(followersRes.body), true);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'private',
 				followersVisibility: 'followers',
 			}, alice);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, alice);
 			assert.strictEqual(followersRes.status, 200);
@@ -213,15 +213,15 @@ describe('FF visibility', () => {
 	});
 
 	test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーを非フォロワーが見れない', async () => {
-		await api('/i/update', {
+		await api('i/update', {
 			followingVisibility: 'followers',
 			followersVisibility: 'followers',
 		}, alice);
 
-		const followingRes = await api('/users/following', {
+		const followingRes = await api('users/following', {
 			userId: alice.id,
 		}, bob);
-		const followersRes = await api('/users/followers', {
+		const followersRes = await api('users/followers', {
 			userId: alice.id,
 		}, bob);
 
@@ -231,34 +231,34 @@ describe('FF visibility', () => {
 
 	test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらず非フォロワーが見れない', async () => {
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'followers',
 				followersVisibility: 'public',
 			}, alice);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followingRes.status, 400);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'followers',
 				followersVisibility: 'followers',
 			}, alice);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followingRes.status, 400);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'followers',
 				followersVisibility: 'private',
 			}, alice);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followingRes.status, 400);
@@ -267,34 +267,34 @@ describe('FF visibility', () => {
 
 	test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらず非フォロワーが見れない', async () => {
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'public',
 				followersVisibility: 'followers',
 			}, alice);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followersRes.status, 400);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'followers',
 				followersVisibility: 'followers',
 			}, alice);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followersRes.status, 400);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'private',
 				followersVisibility: 'followers',
 			}, alice);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followersRes.status, 400);
@@ -302,19 +302,19 @@ describe('FF visibility', () => {
 	});
 
 	test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーをフォロワーが見れる', async () => {
-		await api('/i/update', {
+		await api('i/update', {
 			followingVisibility: 'followers',
 			followersVisibility: 'followers',
 		}, alice);
 
-		await api('/following/create', {
+		await api('following/create', {
 			userId: alice.id,
 		}, bob);
 
-		const followingRes = await api('/users/following', {
+		const followingRes = await api('users/following', {
 			userId: alice.id,
 		}, bob);
-		const followersRes = await api('/users/followers', {
+		const followersRes = await api('users/followers', {
 			userId: alice.id,
 		}, bob);
 
@@ -326,45 +326,45 @@ describe('FF visibility', () => {
 
 	test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらずフォロワーが見れる', async () => {
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'followers',
 				followersVisibility: 'public',
 			}, alice);
-			await api('/following/create', {
+			await api('following/create', {
 				userId: alice.id,
 			}, bob);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followingRes.status, 200);
 			assert.strictEqual(Array.isArray(followingRes.body), true);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'followers',
 				followersVisibility: 'followers',
 			}, alice);
-			await api('/following/create', {
+			await api('following/create', {
 				userId: alice.id,
 			}, bob);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followingRes.status, 200);
 			assert.strictEqual(Array.isArray(followingRes.body), true);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'followers',
 				followersVisibility: 'private',
 			}, alice);
-			await api('/following/create', {
+			await api('following/create', {
 				userId: alice.id,
 			}, bob);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followingRes.status, 200);
@@ -374,45 +374,45 @@ describe('FF visibility', () => {
 
 	test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらずフォロワーが見れる', async () => {
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'public',
 				followersVisibility: 'followers',
 			}, alice);
-			await api('/following/create', {
+			await api('following/create', {
 				userId: alice.id,
 			}, bob);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followersRes.status, 200);
 			assert.strictEqual(Array.isArray(followersRes.body), true);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'followers',
 				followersVisibility: 'followers',
 			}, alice);
-			await api('/following/create', {
+			await api('following/create', {
 				userId: alice.id,
 			}, bob);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followersRes.status, 200);
 			assert.strictEqual(Array.isArray(followersRes.body), true);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'private',
 				followersVisibility: 'followers',
 			}, alice);
-			await api('/following/create', {
+			await api('following/create', {
 				userId: alice.id,
 			}, bob);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followersRes.status, 200);
@@ -421,15 +421,15 @@ describe('FF visibility', () => {
 	});
 
 	test('followingVisibility, followersVisibility がともに private なユーザーのフォロー/フォロワーを自分で見れる', async () => {
-		await api('/i/update', {
+		await api('i/update', {
 			followingVisibility: 'private',
 			followersVisibility: 'private',
 		}, alice);
 
-		const followingRes = await api('/users/following', {
+		const followingRes = await api('users/following', {
 			userId: alice.id,
 		}, alice);
-		const followersRes = await api('/users/followers', {
+		const followersRes = await api('users/followers', {
 			userId: alice.id,
 		}, alice);
 
@@ -441,36 +441,36 @@ describe('FF visibility', () => {
 
 	test('followingVisibility が private なユーザーのフォローを followersVisibility の設定に関わらず自分で見れる', async () => {
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'private',
 				followersVisibility: 'public',
 			}, alice);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, alice);
 			assert.strictEqual(followingRes.status, 200);
 			assert.strictEqual(Array.isArray(followingRes.body), true);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'private',
 				followersVisibility: 'followers',
 			}, alice);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, alice);
 			assert.strictEqual(followingRes.status, 200);
 			assert.strictEqual(Array.isArray(followingRes.body), true);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'private',
 				followersVisibility: 'private',
 			}, alice);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, alice);
 			assert.strictEqual(followingRes.status, 200);
@@ -480,36 +480,36 @@ describe('FF visibility', () => {
 
 	test('followersVisibility が private なユーザーのフォロワーを followingVisibility の設定に関わらず自分で見れる', async () => {
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'public',
 				followersVisibility: 'private',
 			}, alice);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, alice);
 			assert.strictEqual(followersRes.status, 200);
 			assert.strictEqual(Array.isArray(followersRes.body), true);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'followers',
 				followersVisibility: 'private',
 			}, alice);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, alice);
 			assert.strictEqual(followersRes.status, 200);
 			assert.strictEqual(Array.isArray(followersRes.body), true);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'private',
 				followersVisibility: 'private',
 			}, alice);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, alice);
 			assert.strictEqual(followersRes.status, 200);
@@ -518,15 +518,15 @@ describe('FF visibility', () => {
 	});
 
 	test('followingVisibility, followersVisibility がともに private なユーザーのフォロー/フォロワーを他人が見れない', async () => {
-		await api('/i/update', {
+		await api('i/update', {
 			followingVisibility: 'private',
 			followersVisibility: 'private',
 		}, alice);
 
-		const followingRes = await api('/users/following', {
+		const followingRes = await api('users/following', {
 			userId: alice.id,
 		}, bob);
-		const followersRes = await api('/users/followers', {
+		const followersRes = await api('users/followers', {
 			userId: alice.id,
 		}, bob);
 
@@ -536,34 +536,34 @@ describe('FF visibility', () => {
 
 	test('followingVisibility が private なユーザーのフォローを followersVisibility の設定に関わらず他人が見れない', async () => {
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'private',
 				followersVisibility: 'public',
 			}, alice);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followingRes.status, 400);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'private',
 				followersVisibility: 'followers',
 			}, alice);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followingRes.status, 400);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'private',
 				followersVisibility: 'private',
 			}, alice);
 
-			const followingRes = await api('/users/following', {
+			const followingRes = await api('users/following', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followingRes.status, 400);
@@ -572,34 +572,34 @@ describe('FF visibility', () => {
 
 	test('followersVisibility が private なユーザーのフォロワーを followingVisibility の設定に関わらず他人が見れない', async () => {
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'public',
 				followersVisibility: 'private',
 			}, alice);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followersRes.status, 400);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'followers',
 				followersVisibility: 'private',
 			}, alice);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followersRes.status, 400);
 		}
 		{
-			await api('/i/update', {
+			await api('i/update', {
 				followingVisibility: 'private',
 				followersVisibility: 'private',
 			}, alice);
 
-			const followersRes = await api('/users/followers', {
+			const followersRes = await api('users/followers', {
 				userId: alice.id,
 			}, bob);
 			assert.strictEqual(followersRes.status, 400);
@@ -609,7 +609,7 @@ describe('FF visibility', () => {
 	describe('AP', () => {
 		test('followingVisibility が public 以外ならばAPからはフォローを取得できない', async () => {
 			{
-				await api('/i/update', {
+				await api('i/update', {
 					followingVisibility: 'public',
 				}, alice);
 
@@ -617,7 +617,7 @@ describe('FF visibility', () => {
 				assert.strictEqual(followingRes.status, 200);
 			}
 			{
-				await api('/i/update', {
+				await api('i/update', {
 					followingVisibility: 'followers',
 				}, alice);
 
@@ -625,7 +625,7 @@ describe('FF visibility', () => {
 				assert.strictEqual(followingRes.status, 403);
 			}
 			{
-				await api('/i/update', {
+				await api('i/update', {
 					followingVisibility: 'private',
 				}, alice);
 
@@ -636,7 +636,7 @@ describe('FF visibility', () => {
 
 		test('followersVisibility が public 以外ならばAPからはフォロワーを取得できない', async () => {
 			{
-				await api('/i/update', {
+				await api('i/update', {
 					followersVisibility: 'public',
 				}, alice);
 
@@ -644,7 +644,7 @@ describe('FF visibility', () => {
 				assert.strictEqual(followersRes.status, 200);
 			}
 			{
-				await api('/i/update', {
+				await api('i/update', {
 					followersVisibility: 'followers',
 				}, alice);
 
@@ -652,7 +652,7 @@ describe('FF visibility', () => {
 				assert.strictEqual(followersRes.status, 403);
 			}
 			{
-				await api('/i/update', {
+				await api('i/update', {
 					followersVisibility: 'private',
 				}, alice);
 
diff --git a/packages/backend/test/e2e/move.ts b/packages/backend/test/e2e/move.ts
index f6417e39b5..4e5306da97 100644
--- a/packages/backend/test/e2e/move.ts
+++ b/packages/backend/test/e2e/move.ts
@@ -55,7 +55,7 @@ describe('Account Move', () => {
 		}, 1000 * 10);
 
 		test('Able to create an alias', async () => {
-			const res = await api('/i/update', {
+			const res = await api('i/update', {
 				alsoKnownAs: [`@alice@${url.hostname}`],
 			}, bob);
 
@@ -67,7 +67,7 @@ describe('Account Move', () => {
 		});
 
 		test('Able to create a local alias without hostname', async () => {
-			await api('/i/update', {
+			await api('i/update', {
 				alsoKnownAs: ['@alice'],
 			}, bob);
 
@@ -77,7 +77,7 @@ describe('Account Move', () => {
 		});
 
 		test('Able to create a local alias without @', async () => {
-			await api('/i/update', {
+			await api('i/update', {
 				alsoKnownAs: ['alice'],
 			}, bob);
 
@@ -87,7 +87,7 @@ describe('Account Move', () => {
 		});
 
 		test('Able to set remote user (but may fail)', async () => {
-			const res = await api('/i/update', {
+			const res = await api('i/update', {
 				alsoKnownAs: ['@syuilo@example.com'],
 			}, bob);
 
@@ -97,7 +97,7 @@ describe('Account Move', () => {
 		});
 
 		test('Unable to add duplicated aliases to alsoKnownAs', async () => {
-			const res = await api('/i/update', {
+			const res = await api('i/update', {
 				alsoKnownAs: [`@alice@${url.hostname}`, `@alice@${url.hostname}`],
 			}, bob);
 
@@ -107,7 +107,7 @@ describe('Account Move', () => {
 		});
 
 		test('Unable to add itself', async () => {
-			const res = await api('/i/update', {
+			const res = await api('i/update', {
 				alsoKnownAs: [`@bob@${url.hostname}`],
 			}, bob);
 
@@ -117,7 +117,7 @@ describe('Account Move', () => {
 		});
 
 		test('Unable to add a nonexisting local account to alsoKnownAs', async () => {
-			const res1 = await api('/i/update', {
+			const res1 = await api('i/update', {
 				alsoKnownAs: [`@nonexist@${url.hostname}`],
 			}, bob);
 
@@ -125,7 +125,7 @@ describe('Account Move', () => {
 			assert.strictEqual(res1.body.error.code, 'NO_SUCH_USER');
 			assert.strictEqual(res1.body.error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5');
 
-			const res2 = await api('/i/update', {
+			const res2 = await api('i/update', {
 				alsoKnownAs: ['@alice', 'nonexist'],
 			}, bob);
 
@@ -135,7 +135,7 @@ describe('Account Move', () => {
 		});
 
 		test('Able to add two existing local account to alsoKnownAs', async () => {
-			await api('/i/update', {
+			await api('i/update', {
 				alsoKnownAs: [`@alice@${url.hostname}`, `@carol@${url.hostname}`],
 			}, bob);
 
@@ -146,10 +146,10 @@ describe('Account Move', () => {
 		});
 
 		test('Able to properly overwrite alsoKnownAs', async () => {
-			await api('/i/update', {
+			await api('i/update', {
 				alsoKnownAs: [`@alice@${url.hostname}`],
 			}, bob);
-			await api('/i/update', {
+			await api('i/update', {
 				alsoKnownAs: [`@carol@${url.hostname}`, `@dave@${url.hostname}`],
 			}, bob);
 
@@ -164,27 +164,27 @@ describe('Account Move', () => {
 		let antennaId = '';
 
 		beforeAll(async () => {
-			await api('/i/update', {
+			await api('i/update', {
 				alsoKnownAs: [`@alice@${url.hostname}`],
 			}, root);
-			const listRoot = await api('/users/lists/create', {
+			const listRoot = await api('users/lists/create', {
 				name: secureRndstr(8),
 			}, root);
-			await api('/users/lists/push', {
+			await api('users/lists/push', {
 				listId: listRoot.body.id,
 				userId: alice.id,
 			}, root);
 
-			await api('/following/create', {
+			await api('following/create', {
 				userId: root.id,
 			}, alice);
-			await api('/following/create', {
+			await api('following/create', {
 				userId: eve.id,
 			}, alice);
-			const antenna = await api('/antennas/create', {
+			const antenna = await api('antennas/create', {
 				name: secureRndstr(8),
 				src: 'home',
-				keywords: [secureRndstr(8)],
+				keywords: [[secureRndstr(8)]],
 				excludeKeywords: [],
 				users: [],
 				caseSensitive: false,
@@ -195,48 +195,48 @@ describe('Account Move', () => {
 			}, alice);
 			antennaId = antenna.body.id;
 
-			await api('/i/update', {
+			await api('i/update', {
 				alsoKnownAs: [`@alice@${url.hostname}`],
 			}, bob);
 
-			await api('/following/create', {
+			await api('following/create', {
 				userId: alice.id,
 			}, carol);
 
-			await api('/mute/create', {
+			await api('mute/create', {
 				userId: alice.id,
 			}, dave);
-			await api('/blocking/create', {
+			await api('blocking/create', {
 				userId: alice.id,
 			}, dave);
-			await api('/following/create', {
+			await api('following/create', {
 				userId: eve.id,
 			}, dave);
 
-			await api('/following/create', {
+			await api('following/create', {
 				userId: dave.id,
 			}, eve);
-			const listEve = await api('/users/lists/create', {
+			const listEve = await api('users/lists/create', {
 				name: secureRndstr(8),
 			}, eve);
-			await api('/users/lists/push', {
+			await api('users/lists/push', {
 				listId: listEve.body.id,
 				userId: bob.id,
 			}, eve);
 
-			await api('/i/update', {
+			await api('i/update', {
 				isLocked: true,
 			}, frank);
-			await api('/following/create', {
+			await api('following/create', {
 				userId: frank.id,
 			}, alice);
-			await api('/following/requests/accept', {
+			await api('following/requests/accept', {
 				userId: alice.id,
 			}, frank);
 		}, 1000 * 10);
 
 		test('Prohibit the root account from moving', async () => {
-			const res = await api('/i/move', {
+			const res = await api('i/move', {
 				moveToAccount: `@bob@${url.hostname}`,
 			}, root);
 
@@ -246,7 +246,7 @@ describe('Account Move', () => {
 		});
 
 		test('Unable to move to a nonexisting local account', async () => {
-			const res = await api('/i/move', {
+			const res = await api('i/move', {
 				moveToAccount: `@nonexist@${url.hostname}`,
 			}, alice);
 
@@ -256,7 +256,7 @@ describe('Account Move', () => {
 		});
 
 		test('Unable to move if alsoKnownAs is invalid', async () => {
-			const res = await api('/i/move', {
+			const res = await api('i/move', {
 				moveToAccount: `@carol@${url.hostname}`,
 			}, alice);
 
@@ -266,7 +266,7 @@ describe('Account Move', () => {
 		});
 
 		test('Relationships have been properly migrated', async () => {
-			const move = await api('/i/move', {
+			const move = await api('i/move', {
 				moveToAccount: `@bob@${url.hostname}`,
 			}, alice);
 
@@ -275,13 +275,13 @@ describe('Account Move', () => {
 			await sleep(1000 * 3); // wait for jobs to finish
 
 			// Unfollow delayed?
-			const aliceFollowings = await api('/users/following', {
+			const aliceFollowings = await api('users/following', {
 				userId: alice.id,
 			}, alice);
 			assert.strictEqual(aliceFollowings.status, 200);
 			assert.strictEqual(aliceFollowings.body.length, 3);
 
-			const carolFollowings = await api('/users/following', {
+			const carolFollowings = await api('users/following', {
 				userId: carol.id,
 			}, carol);
 			assert.strictEqual(carolFollowings.status, 200);
@@ -289,25 +289,25 @@ describe('Account Move', () => {
 			assert.strictEqual(carolFollowings.body[0].followeeId, bob.id);
 			assert.strictEqual(carolFollowings.body[1].followeeId, alice.id);
 
-			const blockings = await api('/blocking/list', {}, dave);
+			const blockings = await api('blocking/list', {}, dave);
 			assert.strictEqual(blockings.status, 200);
 			assert.strictEqual(blockings.body.length, 2);
 			assert.strictEqual(blockings.body[0].blockeeId, bob.id);
 			assert.strictEqual(blockings.body[1].blockeeId, alice.id);
 
-			const mutings = await api('/mute/list', {}, dave);
+			const mutings = await api('mute/list', {}, dave);
 			assert.strictEqual(mutings.status, 200);
 			assert.strictEqual(mutings.body.length, 2);
 			assert.strictEqual(mutings.body[0].muteeId, bob.id);
 			assert.strictEqual(mutings.body[1].muteeId, alice.id);
 
-			const rootLists = await api('/users/lists/list', {}, root);
+			const rootLists = await api('users/lists/list', {}, root);
 			assert.strictEqual(rootLists.status, 200);
 			assert.strictEqual(rootLists.body[0].userIds.length, 2);
 			assert.ok(rootLists.body[0].userIds.find((id: string) => id === bob.id));
 			assert.ok(rootLists.body[0].userIds.find((id: string) => id === alice.id));
 
-			const eveLists = await api('/users/lists/list', {}, eve);
+			const eveLists = await api('users/lists/list', {}, eve);
 			assert.strictEqual(eveLists.status, 200);
 			assert.strictEqual(eveLists.body[0].userIds.length, 1);
 			assert.ok(eveLists.body[0].userIds.find((id: string) => id === bob.id));
@@ -315,13 +315,13 @@ describe('Account Move', () => {
 
 		test('A locked account automatically accept the follow request if it had already accepted the old account.', async () => {
 			await successfulApiCall({
-				endpoint: '/following/create',
+				endpoint: 'following/create',
 				parameters: {
 					userId: frank.id,
 				},
 				user: bob,
 			});
-			const followers = await api('/users/followers', {
+			const followers = await api('users/followers', {
 				userId: frank.id,
 			}, frank);
 
@@ -333,7 +333,7 @@ describe('Account Move', () => {
 		test('Unfollowed after 10 sec (24 hours in production).', async () => {
 			await sleep(1000 * 8);
 
-			const following = await api('/users/following', {
+			const following = await api('users/following', {
 				userId: alice.id,
 			}, alice);
 
@@ -342,7 +342,7 @@ describe('Account Move', () => {
 		});
 
 		test('Unable to move if the destination account has already moved.', async () => {
-			const res = await api('/i/move', {
+			const res = await api('i/move', {
 				moveToAccount: `@alice@${url.hostname}`,
 			}, bob);
 
@@ -352,7 +352,7 @@ describe('Account Move', () => {
 		});
 
 		test('Follow and follower counts are properly adjusted', async () => {
-			await api('/following/create', {
+			await api('following/create', {
 				userId: alice.id,
 			}, eve);
 			const newAlice = await Users.findOneByOrFail({ id: alice.id });
@@ -365,7 +365,7 @@ describe('Account Move', () => {
 			assert.strictEqual(newEve.followingCount, 1);
 			assert.strictEqual(newEve.followersCount, 1);
 
-			await api('/following/delete', {
+			await api('following/delete', {
 				userId: alice.id,
 			}, eve);
 			newEve = await Users.findOneByOrFail({ id: eve.id });
@@ -374,49 +374,49 @@ describe('Account Move', () => {
 		});
 
 		test.each([
-			'/antennas/create',
-			'/channels/create',
-			'/channels/favorite',
-			'/channels/follow',
-			'/channels/unfavorite',
-			'/channels/unfollow',
-			'/clips/add-note',
-			'/clips/create',
-			'/clips/favorite',
-			'/clips/remove-note',
-			'/clips/unfavorite',
-			'/clips/update',
-			'/drive/files/upload-from-url',
-			'/flash/create',
-			'/flash/like',
-			'/flash/unlike',
-			'/flash/update',
-			'/following/create',
-			'/gallery/posts/create',
-			'/gallery/posts/like',
-			'/gallery/posts/unlike',
-			'/gallery/posts/update',
-			'/i/claim-achievement',
-			'/i/move',
-			'/i/import-blocking',
-			'/i/import-following',
-			'/i/import-muting',
-			'/i/import-user-lists',
-			'/i/pin',
-			'/mute/create',
-			'/notes/create',
-			'/notes/favorites/create',
-			'/notes/polls/vote',
-			'/notes/reactions/create',
-			'/pages/create',
-			'/pages/like',
-			'/pages/unlike',
-			'/pages/update',
-			'/renote-mute/create',
-			'/users/lists/create',
-			'/users/lists/pull',
-			'/users/lists/push',
-		])('Prohibit access after moving: %s', async (endpoint) => {
+			'antennas/create',
+			'channels/create',
+			'channels/favorite',
+			'channels/follow',
+			'channels/unfavorite',
+			'channels/unfollow',
+			'clips/add-note',
+			'clips/create',
+			'clips/favorite',
+			'clips/remove-note',
+			'clips/unfavorite',
+			'clips/update',
+			'drive/files/upload-from-url',
+			'flash/create',
+			'flash/like',
+			'flash/unlike',
+			'flash/update',
+			'following/create',
+			'gallery/posts/create',
+			'gallery/posts/like',
+			'gallery/posts/unlike',
+			'gallery/posts/update',
+			'i/claim-achievement',
+			'i/move',
+			'i/import-blocking',
+			'i/import-following',
+			'i/import-muting',
+			'i/import-user-lists',
+			'i/pin',
+			'mute/create',
+			'notes/create',
+			'notes/favorites/create',
+			'notes/polls/vote',
+			'notes/reactions/create',
+			'pages/create',
+			'pages/like',
+			'pages/unlike',
+			'pages/update',
+			'renote-mute/create',
+			'users/lists/create',
+			'users/lists/pull',
+			'users/lists/push',
+		] as const)('Prohibit access after moving: %s', async (endpoint) => {
 			const res = await api(endpoint, {}, alice);
 			assert.strictEqual(res.status, 403);
 			assert.strictEqual(res.body.error.code, 'YOUR_ACCOUNT_MOVED');
@@ -424,11 +424,11 @@ describe('Account Move', () => {
 		});
 
 		test('Prohibit access after moving: /antennas/update', async () => {
-			const res = await api('/antennas/update', {
+			const res = await api('antennas/update', {
 				antennaId,
 				name: secureRndstr(8),
 				src: 'users',
-				keywords: [secureRndstr(8)],
+				keywords: [[secureRndstr(8)]],
 				excludeKeywords: [],
 				users: [eve.id],
 				caseSensitive: false,
@@ -447,12 +447,12 @@ describe('Account Move', () => {
 			const res = await uploadFile(alice);
 
 			assert.strictEqual(res.status, 403);
-			assert.strictEqual(res.body.error.code, 'YOUR_ACCOUNT_MOVED');
-			assert.strictEqual(res.body.error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31');
+			assert.strictEqual((res.body! as any as { error: misskey.api.APIError }).error.code, 'YOUR_ACCOUNT_MOVED');
+			assert.strictEqual((res.body! as any as { error: misskey.api.APIError }).error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31');
 		});
 
 		test('Prohibit updating alsoKnownAs after moving', async () => {
-			const res = await api('/i/update', {
+			const res = await api('i/update', {
 				alsoKnownAs: [`@eve@${url.hostname}`],
 			}, alice);
 
diff --git a/packages/backend/test/e2e/mute.ts b/packages/backend/test/e2e/mute.ts
index 1d28e07b7d..0e52c5decc 100644
--- a/packages/backend/test/e2e/mute.ts
+++ b/packages/backend/test/e2e/mute.ts
@@ -19,21 +19,31 @@ describe('Mute', () => {
 		alice = await signup({ username: 'alice' });
 		bob = await signup({ username: 'bob' });
 		carol = await signup({ username: 'carol' });
+
+		// Mute: alice ==> carol
+		await api('mute/create', {
+			userId: carol.id,
+		}, alice);
 	}, 1000 * 60 * 2);
 
 	test('ミュート作成', async () => {
-		const res = await api('/mute/create', {
-			userId: carol.id,
+		const res = await api('mute/create', {
+			userId: bob.id,
 		}, alice);
 
 		assert.strictEqual(res.status, 204);
+
+		// 単体でも走らせられるように副作用消す
+		await api('mute/delete', {
+			userId: bob.id,
+		}, alice);
 	});
 
 	test('「自分宛ての投稿」にミュートしているユーザーの投稿が含まれない', async () => {
 		const bobNote = await post(bob, { text: '@alice hi' });
 		const carolNote = await post(carol, { text: '@alice hi' });
 
-		const res = await api('/notes/mentions', {}, alice);
+		const res = await api('notes/mentions', {}, alice);
 
 		assert.strictEqual(res.status, 200);
 		assert.strictEqual(Array.isArray(res.body), true);
@@ -43,11 +53,11 @@ describe('Mute', () => {
 
 	test('ミュートしているユーザーからメンションされても、hasUnreadMentions が true にならない', async () => {
 		// 状態リセット
-		await api('/i/read-all-unread-notes', {}, alice);
+		await api('i/read-all-unread-notes', {}, alice);
 
 		await post(carol, { text: '@alice hi' });
 
-		const res = await api('/i', {}, alice);
+		const res = await api('i', {}, alice);
 
 		assert.strictEqual(res.status, 200);
 		assert.strictEqual(res.body.hasUnreadMentions, false);
@@ -55,7 +65,7 @@ describe('Mute', () => {
 
 	test('ミュートしているユーザーからメンションされても、ストリームに unreadMention イベントが流れてこない', async () => {
 		// 状態リセット
-		await api('/i/read-all-unread-notes', {}, alice);
+		await api('i/read-all-unread-notes', {}, alice);
 
 		const fired = await waitFire(alice, 'main', () => post(carol, { text: '@alice hi' }), msg => msg.type === 'unreadMention');
 
@@ -64,8 +74,8 @@ describe('Mute', () => {
 
 	test('ミュートしているユーザーからメンションされても、ストリームに unreadNotification イベントが流れてこない', async () => {
 		// 状態リセット
-		await api('/i/read-all-unread-notes', {}, alice);
-		await api('/notifications/mark-all-as-read', {}, alice);
+		await api('i/read-all-unread-notes', {}, alice);
+		await api('notifications/mark-all-as-read', {}, alice);
 
 		const fired = await waitFire(alice, 'main', () => post(carol, { text: '@alice hi' }), msg => msg.type === 'unreadNotification');
 
@@ -78,7 +88,7 @@ describe('Mute', () => {
 			const bobNote = await post(bob, { text: 'hi' });
 			const carolNote = await post(carol, { text: 'hi' });
 
-			const res = await api('/notes/local-timeline', {}, alice);
+			const res = await api('notes/local-timeline', {}, alice);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(Array.isArray(res.body), true);
@@ -94,7 +104,7 @@ describe('Mute', () => {
 				renoteId: carolNote.id,
 			});
 
-			const res = await api('/notes/local-timeline', {}, alice);
+			const res = await api('notes/local-timeline', {}, alice);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(Array.isArray(res.body), true);
@@ -110,7 +120,7 @@ describe('Mute', () => {
 			await react(bob, aliceNote, 'like');
 			await react(carol, aliceNote, 'like');
 
-			const res = await api('/i/notifications', {}, alice);
+			const res = await api('i/notifications', {}, alice);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(Array.isArray(res.body), true);
@@ -123,7 +133,7 @@ describe('Mute', () => {
 			await post(bob, { text: '@alice hi', replyId: aliceNote.id });
 			await post(carol, { text: '@alice hi', replyId: aliceNote.id });
 
-			const res = await api('/i/notifications', {}, alice);
+			const res = await api('i/notifications', {}, alice);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(Array.isArray(res.body), true);
@@ -137,7 +147,7 @@ describe('Mute', () => {
 			await post(bob, { text: '@alice hi' });
 			await post(carol, { text: '@alice hi' });
 
-			const res = await api('/i/notifications', {}, alice);
+			const res = await api('i/notifications', {}, alice);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(Array.isArray(res.body), true);
@@ -151,7 +161,7 @@ describe('Mute', () => {
 			await post(bob, { text: 'hi', renoteId: aliceNote.id });
 			await post(carol, { text: 'hi', renoteId: aliceNote.id });
 
-			const res = await api('/i/notifications', {}, alice);
+			const res = await api('i/notifications', {}, alice);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(Array.isArray(res.body), true);
@@ -165,7 +175,7 @@ describe('Mute', () => {
 			await post(bob, { renoteId: aliceNote.id });
 			await post(carol, { renoteId: aliceNote.id });
 
-			const res = await api('/i/notifications', {}, alice);
+			const res = await api('i/notifications', {}, alice);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(Array.isArray(res.body), true);
@@ -175,30 +185,36 @@ describe('Mute', () => {
 		});
 
 		test('通知にミュートしているユーザーからのフォロー通知が含まれない', async () => {
-			await api('/i/follow', { userId: alice.id }, bob);
-			await api('/i/follow', { userId: alice.id }, carol);
+			await api('following/create', { userId: alice.id }, bob);
+			await api('following/create', { userId: alice.id }, carol);
 
-			const res = await api('/i/notifications', {}, alice);
+			const res = await api('i/notifications', {}, alice);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(Array.isArray(res.body), true);
 
 			assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
 			assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+
+			await api('following/delete', { userId: alice.id }, bob);
+			await api('following/delete', { userId: alice.id }, carol);
 		});
 
 		test('通知にミュートしているユーザーからのフォローリクエストが含まれない', async () => {
-			await api('/i/update/', { isLocked: true }, alice);
-			await api('/following/create', { userId: alice.id }, bob);
-			await api('/following/create', { userId: alice.id }, carol);
+			await api('i/update', { isLocked: true }, alice);
+			await api('following/create', { userId: alice.id }, bob);
+			await api('following/create', { userId: alice.id }, carol);
 
-			const res = await api('/i/notifications', {}, alice);
+			const res = await api('i/notifications', {}, alice);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(Array.isArray(res.body), true);
 
 			assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
 			assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+
+			await api('following/delete', { userId: alice.id }, bob);
+			await api('following/delete', { userId: alice.id }, carol);
 		});
 	});
 
@@ -208,7 +224,7 @@ describe('Mute', () => {
 			await react(bob, aliceNote, 'like');
 			await react(carol, aliceNote, 'like');
 
-			const res = await api('/i/notifications-grouped', {}, alice);
+			const res = await api('i/notifications-grouped', {}, alice);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(Array.isArray(res.body), true);
@@ -220,7 +236,7 @@ describe('Mute', () => {
 			await post(bob, { text: '@alice hi', replyId: aliceNote.id });
 			await post(carol, { text: '@alice hi', replyId: aliceNote.id });
 
-			const res = await api('/i/notifications-grouped', {}, alice);
+			const res = await api('i/notifications-grouped', {}, alice);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(Array.isArray(res.body), true);
@@ -234,7 +250,7 @@ describe('Mute', () => {
 			await post(bob, { text: '@alice hi' });
 			await post(carol, { text: '@alice hi' });
 
-			const res = await api('/i/notifications-grouped', {}, alice);
+			const res = await api('i/notifications-grouped', {}, alice);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(Array.isArray(res.body), true);
@@ -248,7 +264,7 @@ describe('Mute', () => {
 			await post(bob, { text: 'hi', renoteId: aliceNote.id });
 			await post(carol, { text: 'hi', renoteId: aliceNote.id });
 
-			const res = await api('/i/notifications-grouped', {}, alice);
+			const res = await api('i/notifications-grouped', {}, alice);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(Array.isArray(res.body), true);
@@ -262,7 +278,7 @@ describe('Mute', () => {
 			await post(bob, { renoteId: aliceNote.id });
 			await post(carol, { renoteId: aliceNote.id });
 
-			const res = await api('/i/notifications-grouped', {}, alice);
+			const res = await api('i/notifications-grouped', {}, alice);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(Array.isArray(res.body), true);
@@ -272,24 +288,27 @@ describe('Mute', () => {
 		});
 
 		test('通知にミュートしているユーザーからのフォロー通知が含まれない', async () => {
-			await api('/i/follow', { userId: alice.id }, bob);
-			await api('/i/follow', { userId: alice.id }, carol);
+			await api('following/create', { userId: alice.id }, bob);
+			await api('following/create', { userId: alice.id }, carol);
 
-			const res = await api('/i/notifications-grouped', {}, alice);
+			const res = await api('i/notifications-grouped', {}, alice);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(Array.isArray(res.body), true);
 
 			assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
 			assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+
+			await api('following/delete', { userId: alice.id }, bob);
+			await api('following/delete', { userId: alice.id }, carol);
 		});
 
 		test('通知にミュートしているユーザーからのフォローリクエストが含まれない', async () => {
-			await api('/i/update/', { isLocked: true }, alice);
-			await api('/following/create', { userId: alice.id }, bob);
-			await api('/following/create', { userId: alice.id }, carol);
+			await api('i/update', { isLocked: true }, alice);
+			await api('following/create', { userId: alice.id }, bob);
+			await api('following/create', { userId: alice.id }, carol);
 
-			const res = await api('/i/notifications-grouped', {}, alice);
+			const res = await api('i/notifications-grouped', {}, alice);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(Array.isArray(res.body), true);
diff --git a/packages/backend/test/e2e/note.ts b/packages/backend/test/e2e/note.ts
index 2406204f41..973bcbd750 100644
--- a/packages/backend/test/e2e/note.ts
+++ b/packages/backend/test/e2e/note.ts
@@ -31,7 +31,7 @@ describe('Note', () => {
 			text: 'test',
 		};
 
-		const res = await api('/notes/create', post, alice);
+		const res = await api('notes/create', post, alice);
 
 		assert.strictEqual(res.status, 200);
 		assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
@@ -41,7 +41,7 @@ describe('Note', () => {
 	test('ファイルを添付できる', async () => {
 		const file = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg');
 
-		const res = await api('/notes/create', {
+		const res = await api('notes/create', {
 			fileIds: [file.id],
 		}, alice);
 
@@ -53,7 +53,7 @@ describe('Note', () => {
 	test('他人のファイルで怒られる', async () => {
 		const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg');
 
-		const res = await api('/notes/create', {
+		const res = await api('notes/create', {
 			text: 'test',
 			fileIds: [file.id],
 		}, alice);
@@ -64,7 +64,7 @@ describe('Note', () => {
 	}, 1000 * 10);
 
 	test('存在しないファイルで怒られる', async () => {
-		const res = await api('/notes/create', {
+		const res = await api('notes/create', {
 			text: 'test',
 			fileIds: ['000000000000000000000000'],
 		}, alice);
@@ -75,7 +75,7 @@ describe('Note', () => {
 	});
 
 	test('不正なファイルIDで怒られる', async () => {
-		const res = await api('/notes/create', {
+		const res = await api('notes/create', {
 			fileIds: ['kyoppie'],
 		}, alice);
 		assert.strictEqual(res.status, 400);
@@ -93,7 +93,7 @@ describe('Note', () => {
 			replyId: bobPost.id,
 		};
 
-		const res = await api('/notes/create', alicePost, alice);
+		const res = await api('notes/create', alicePost, alice);
 
 		assert.strictEqual(res.status, 200);
 		assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
@@ -111,7 +111,7 @@ describe('Note', () => {
 			renoteId: bobPost.id,
 		};
 
-		const res = await api('/notes/create', alicePost, alice);
+		const res = await api('notes/create', alicePost, alice);
 
 		assert.strictEqual(res.status, 200);
 		assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
@@ -129,7 +129,7 @@ describe('Note', () => {
 			renoteId: bobPost.id,
 		};
 
-		const res = await api('/notes/create', alicePost, alice);
+		const res = await api('notes/create', alicePost, alice);
 
 		assert.strictEqual(res.status, 200);
 		assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
@@ -142,7 +142,7 @@ describe('Note', () => {
 		const bobPost = await post(bob, {
 			text: 'test',
 		});
-		const res = await api('/notes/create', {
+		const res = await api('notes/create', {
 			text: ' ',
 			renoteId: bobPost.id,
 		}, alice);
@@ -152,7 +152,7 @@ describe('Note', () => {
 	});
 
 	test('visibility: followersでrenoteできる', async () => {
-		const createRes = await api('/notes/create', {
+		const createRes = await api('notes/create', {
 			text: 'test',
 			visibility: 'followers',
 		}, alice);
@@ -160,7 +160,7 @@ describe('Note', () => {
 		assert.strictEqual(createRes.status, 200);
 
 		const renoteId = createRes.body.createdNote.id;
-		const renoteRes = await api('/notes/create', {
+		const renoteRes = await api('notes/create', {
 			visibility: 'followers',
 			renoteId,
 		}, alice);
@@ -169,7 +169,7 @@ describe('Note', () => {
 		assert.strictEqual(renoteRes.body.createdNote.renoteId, renoteId);
 		assert.strictEqual(renoteRes.body.createdNote.visibility, 'followers');
 
-		const deleteRes = await api('/notes/delete', {
+		const deleteRes = await api('notes/delete', {
 			noteId: renoteRes.body.createdNote.id,
 		}, alice);
 
@@ -177,11 +177,11 @@ describe('Note', () => {
 	});
 
 	test('visibility: followersなノートに対してフォロワーはリプライできる', async () => {
-		await api('/following/create', {
+		await api('following/create', {
 			userId: alice.id,
 		}, bob);
 
-		const aliceNote = await api('/notes/create', {
+		const aliceNote = await api('notes/create', {
 			text: 'direct note to bob',
 			visibility: 'followers',
 		}, alice);
@@ -189,7 +189,7 @@ describe('Note', () => {
 		assert.strictEqual(aliceNote.status, 200);
 
 		const replyId = aliceNote.body.createdNote.id;
-		const bobReply = await api('/notes/create', {
+		const bobReply = await api('notes/create', {
 			text: 'reply to alice note',
 			replyId,
 		}, bob);
@@ -197,20 +197,20 @@ describe('Note', () => {
 		assert.strictEqual(bobReply.status, 200);
 		assert.strictEqual(bobReply.body.createdNote.replyId, replyId);
 
-		await api('/following/delete', {
+		await api('following/delete', {
 			userId: alice.id,
 		}, bob);
 	});
 
 	test('visibility: followersなノートに対してフォロワーでないユーザーがリプライしようとすると怒られる', async () => {
-		const aliceNote = await api('/notes/create', {
+		const aliceNote = await api('notes/create', {
 			text: 'direct note to bob',
 			visibility: 'followers',
 		}, alice);
 
 		assert.strictEqual(aliceNote.status, 200);
 
-		const bobReply = await api('/notes/create', {
+		const bobReply = await api('notes/create', {
 			text: 'reply to alice note',
 			replyId: aliceNote.body.createdNote.id,
 		}, bob);
@@ -220,7 +220,7 @@ describe('Note', () => {
 	});
 
 	test('visibility: specifiedなノートに対してvisibility: specifiedで返信できる', async () => {
-		const aliceNote = await api('/notes/create', {
+		const aliceNote = await api('notes/create', {
 			text: 'direct note to bob',
 			visibility: 'specified',
 			visibleUserIds: [bob.id],
@@ -228,7 +228,7 @@ describe('Note', () => {
 
 		assert.strictEqual(aliceNote.status, 200);
 
-		const bobReply = await api('/notes/create', {
+		const bobReply = await api('notes/create', {
 			text: 'reply to alice note',
 			replyId: aliceNote.body.createdNote.id,
 			visibility: 'specified',
@@ -239,7 +239,7 @@ describe('Note', () => {
 	});
 
 	test('visibility: specifiedなノートに対してvisibility: follwersで返信しようとすると怒られる', async () => {
-		const aliceNote = await api('/notes/create', {
+		const aliceNote = await api('notes/create', {
 			text: 'direct note to bob',
 			visibility: 'specified',
 			visibleUserIds: [bob.id],
@@ -247,7 +247,7 @@ describe('Note', () => {
 
 		assert.strictEqual(aliceNote.status, 200);
 
-		const bobReply = await api('/notes/create', {
+		const bobReply = await api('notes/create', {
 			text: 'reply to alice note with visibility: followers',
 			replyId: aliceNote.body.createdNote.id,
 			visibility: 'followers',
@@ -261,7 +261,7 @@ describe('Note', () => {
 		const post = {
 			text: '!'.repeat(MAX_NOTE_TEXT_LENGTH), // 3000文字
 		};
-		const res = await api('/notes/create', post, alice);
+		const res = await api('notes/create', post, alice);
 		assert.strictEqual(res.status, 200);
 	});
 
@@ -269,7 +269,7 @@ describe('Note', () => {
 		const post = {
 			text: '!'.repeat(MAX_NOTE_TEXT_LENGTH + 1), // 3001文字
 		};
-		const res = await api('/notes/create', post, alice);
+		const res = await api('notes/create', post, alice);
 		assert.strictEqual(res.status, 400);
 	});
 
@@ -278,7 +278,7 @@ describe('Note', () => {
 			text: 'test',
 			replyId: '000000000000000000000000',
 		};
-		const res = await api('/notes/create', post, alice);
+		const res = await api('notes/create', post, alice);
 		assert.strictEqual(res.status, 400);
 	});
 
@@ -286,7 +286,7 @@ describe('Note', () => {
 		const post = {
 			renoteId: '000000000000000000000000',
 		};
-		const res = await api('/notes/create', post, alice);
+		const res = await api('notes/create', post, alice);
 		assert.strictEqual(res.status, 400);
 	});
 
@@ -295,7 +295,7 @@ describe('Note', () => {
 			text: 'test',
 			replyId: 'foo',
 		};
-		const res = await api('/notes/create', post, alice);
+		const res = await api('notes/create', post, alice);
 		assert.strictEqual(res.status, 400);
 	});
 
@@ -303,7 +303,7 @@ describe('Note', () => {
 		const post = {
 			renoteId: 'foo',
 		};
-		const res = await api('/notes/create', post, alice);
+		const res = await api('notes/create', post, alice);
 		assert.strictEqual(res.status, 400);
 	});
 
@@ -312,7 +312,7 @@ describe('Note', () => {
 			text: '@ghost yo',
 		};
 
-		const res = await api('/notes/create', post, alice);
+		const res = await api('notes/create', post, alice);
 
 		assert.strictEqual(res.status, 200);
 		assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
@@ -324,7 +324,7 @@ describe('Note', () => {
 			text: '@bob @bob @bob yo',
 		};
 
-		const res = await api('/notes/create', post, alice);
+		const res = await api('notes/create', post, alice);
 
 		assert.strictEqual(res.status, 200);
 		assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
@@ -337,25 +337,25 @@ describe('Note', () => {
 	describe('添付ファイル情報', () => {
 		test('ファイルを添付した場合、投稿成功時にファイル情報入りのレスポンスが帰ってくる', async () => {
 			const file = await uploadFile(alice);
-			const res = await api('/notes/create', {
-				fileIds: [file.body.id],
+			const res = await api('notes/create', {
+				fileIds: [file.body!.id],
 			}, alice);
 
 			assert.strictEqual(res.status, 200);
 			assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
 			assert.strictEqual(res.body.createdNote.files.length, 1);
-			assert.strictEqual(res.body.createdNote.files[0].id, file.body.id);
+			assert.strictEqual(res.body.createdNote.files[0].id, file.body!.id);
 		});
 
 		test('ファイルを添付した場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => {
 			const file = await uploadFile(alice);
-			const createdNote = await api('/notes/create', {
-				fileIds: [file.body.id],
+			const createdNote = await api('notes/create', {
+				fileIds: [file.body!.id],
 			}, alice);
 
 			assert.strictEqual(createdNote.status, 200);
 
-			const res = await api('/notes', {
+			const res = await api('notes', {
 				withFiles: true,
 			}, alice);
 
@@ -364,23 +364,23 @@ describe('Note', () => {
 			const myNote = res.body.find((note: { id: string; files: { id: string }[] }) => note.id === createdNote.body.createdNote.id);
 			assert.notEqual(myNote, null);
 			assert.strictEqual(myNote.files.length, 1);
-			assert.strictEqual(myNote.files[0].id, file.body.id);
+			assert.strictEqual(myNote.files[0].id, file.body!.id);
 		});
 
 		test('ファイルが添付されたノートをリノートした場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => {
 			const file = await uploadFile(alice);
-			const createdNote = await api('/notes/create', {
-				fileIds: [file.body.id],
+			const createdNote = await api('notes/create', {
+				fileIds: [file.body!.id],
 			}, alice);
 
 			assert.strictEqual(createdNote.status, 200);
 
-			const renoted = await api('/notes/create', {
+			const renoted = await api('notes/create', {
 				renoteId: createdNote.body.createdNote.id,
 			}, alice);
 			assert.strictEqual(renoted.status, 200);
 
-			const res = await api('/notes', {
+			const res = await api('notes', {
 				renote: true,
 			}, alice);
 
@@ -389,24 +389,24 @@ describe('Note', () => {
 			const myNote = res.body.find((note: { id: string }) => note.id === renoted.body.createdNote.id);
 			assert.notEqual(myNote, null);
 			assert.strictEqual(myNote.renote.files.length, 1);
-			assert.strictEqual(myNote.renote.files[0].id, file.body.id);
+			assert.strictEqual(myNote.renote.files[0].id, file.body!.id);
 		});
 
 		test('ファイルが添付されたノートに返信した場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => {
 			const file = await uploadFile(alice);
-			const createdNote = await api('/notes/create', {
-				fileIds: [file.body.id],
+			const createdNote = await api('notes/create', {
+				fileIds: [file.body!.id],
 			}, alice);
 
 			assert.strictEqual(createdNote.status, 200);
 
-			const reply = await api('/notes/create', {
+			const reply = await api('notes/create', {
 				replyId: createdNote.body.createdNote.id,
 				text: 'this is reply',
 			}, alice);
 			assert.strictEqual(reply.status, 200);
 
-			const res = await api('/notes', {
+			const res = await api('notes', {
 				reply: true,
 			}, alice);
 
@@ -415,29 +415,29 @@ describe('Note', () => {
 			const myNote = res.body.find((note: { id: string }) => note.id === reply.body.createdNote.id);
 			assert.notEqual(myNote, null);
 			assert.strictEqual(myNote.reply.files.length, 1);
-			assert.strictEqual(myNote.reply.files[0].id, file.body.id);
+			assert.strictEqual(myNote.reply.files[0].id, file.body!.id);
 		});
 
 		test('ファイルが添付されたノートへの返信をリノートした場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => {
 			const file = await uploadFile(alice);
-			const createdNote = await api('/notes/create', {
-				fileIds: [file.body.id],
+			const createdNote = await api('notes/create', {
+				fileIds: [file.body!.id],
 			}, alice);
 
 			assert.strictEqual(createdNote.status, 200);
 
-			const reply = await api('/notes/create', {
+			const reply = await api('notes/create', {
 				replyId: createdNote.body.createdNote.id,
 				text: 'this is reply',
 			}, alice);
 			assert.strictEqual(reply.status, 200);
 
-			const renoted = await api('/notes/create', {
+			const renoted = await api('notes/create', {
 				renoteId: reply.body.createdNote.id,
 			}, alice);
 			assert.strictEqual(renoted.status, 200);
 
-			const res = await api('/notes', {
+			const res = await api('notes', {
 				renote: true,
 			}, alice);
 
@@ -446,7 +446,7 @@ describe('Note', () => {
 			const myNote = res.body.find((note: { id: string }) => note.id === renoted.body.createdNote.id);
 			assert.notEqual(myNote, null);
 			assert.strictEqual(myNote.renote.reply.files.length, 1);
-			assert.strictEqual(myNote.renote.reply.files[0].id, file.body.id);
+			assert.strictEqual(myNote.renote.reply.files[0].id, file.body!.id);
 		});
 
 		test('NSFWが強制されている場合変更できない', async () => {
@@ -483,15 +483,15 @@ describe('Note', () => {
 			}, alice);
 
 			assert.strictEqual(assign.status, 204);
-			assert.strictEqual(file.body.isSensitive, false);
+			assert.strictEqual(file.body!.isSensitive, false);
 
 			const nsfwfile = await uploadFile(alice);
 
 			assert.strictEqual(nsfwfile.status, 200);
-			assert.strictEqual(nsfwfile.body.isSensitive, true);
+			assert.strictEqual(nsfwfile.body!.isSensitive, true);
 
 			const liftnsfw = await api('drive/files/update', {
-				fileId: nsfwfile.body.id,
+				fileId: nsfwfile.body!.id,
 				isSensitive: false,
 			}, alice);
 
@@ -499,7 +499,7 @@ describe('Note', () => {
 			assert.strictEqual(liftnsfw.body.error.code, 'RESTRICTED_BY_ROLE');
 
 			const oldaddnsfw = await api('drive/files/update', {
-				fileId: file.body.id,
+				fileId: file.body!.id,
 				isSensitive: true,
 			}, alice);
 
@@ -518,7 +518,7 @@ describe('Note', () => {
 
 	describe('notes/create', () => {
 		test('投票を添付できる', async () => {
-			const res = await api('/notes/create', {
+			const res = await api('notes/create', {
 				text: 'test',
 				poll: {
 					choices: ['foo', 'bar'],
@@ -531,14 +531,15 @@ describe('Note', () => {
 		});
 
 		test('投票の選択肢が無くて怒られる', async () => {
-			const res = await api('/notes/create', {
+			const res = await api('notes/create', {
+				// @ts-expect-error poll must not be empty
 				poll: {},
 			}, alice);
 			assert.strictEqual(res.status, 400);
 		});
 
 		test('投票の選択肢が無くて怒られる (空の配列)', async () => {
-			const res = await api('/notes/create', {
+			const res = await api('notes/create', {
 				poll: {
 					choices: [],
 				},
@@ -547,7 +548,7 @@ describe('Note', () => {
 		});
 
 		test('投票の選択肢が1つで怒られる', async () => {
-			const res = await api('/notes/create', {
+			const res = await api('notes/create', {
 				poll: {
 					choices: ['Strawberry Pasta'],
 				},
@@ -556,14 +557,14 @@ describe('Note', () => {
 		});
 
 		test('投票できる', async () => {
-			const { body } = await api('/notes/create', {
+			const { body } = await api('notes/create', {
 				text: 'test',
 				poll: {
 					choices: ['sakura', 'izumi', 'ako'],
 				},
 			}, alice);
 
-			const res = await api('/notes/polls/vote', {
+			const res = await api('notes/polls/vote', {
 				noteId: body.createdNote.id,
 				choice: 1,
 			}, alice);
@@ -572,19 +573,19 @@ describe('Note', () => {
 		});
 
 		test('複数投票できない', async () => {
-			const { body } = await api('/notes/create', {
+			const { body } = await api('notes/create', {
 				text: 'test',
 				poll: {
 					choices: ['sakura', 'izumi', 'ako'],
 				},
 			}, alice);
 
-			await api('/notes/polls/vote', {
+			await api('notes/polls/vote', {
 				noteId: body.createdNote.id,
 				choice: 0,
 			}, alice);
 
-			const res = await api('/notes/polls/vote', {
+			const res = await api('notes/polls/vote', {
 				noteId: body.createdNote.id,
 				choice: 2,
 			}, alice);
@@ -593,7 +594,7 @@ describe('Note', () => {
 		});
 
 		test('許可されている場合は複数投票できる', async () => {
-			const { body } = await api('/notes/create', {
+			const { body } = await api('notes/create', {
 				text: 'test',
 				poll: {
 					choices: ['sakura', 'izumi', 'ako'],
@@ -601,17 +602,17 @@ describe('Note', () => {
 				},
 			}, alice);
 
-			await api('/notes/polls/vote', {
+			await api('notes/polls/vote', {
 				noteId: body.createdNote.id,
 				choice: 0,
 			}, alice);
 
-			await api('/notes/polls/vote', {
+			await api('notes/polls/vote', {
 				noteId: body.createdNote.id,
 				choice: 1,
 			}, alice);
 
-			const res = await api('/notes/polls/vote', {
+			const res = await api('notes/polls/vote', {
 				noteId: body.createdNote.id,
 				choice: 2,
 			}, alice);
@@ -620,7 +621,7 @@ describe('Note', () => {
 		});
 
 		test('締め切られている場合は投票できない', async () => {
-			const { body } = await api('/notes/create', {
+			const { body } = await api('notes/create', {
 				text: 'test',
 				poll: {
 					choices: ['sakura', 'izumi', 'ako'],
@@ -630,7 +631,7 @@ describe('Note', () => {
 
 			await new Promise(x => setTimeout(x, 2));
 
-			const res = await api('/notes/polls/vote', {
+			const res = await api('notes/polls/vote', {
 				noteId: body.createdNote.id,
 				choice: 1,
 			}, alice);
@@ -649,7 +650,7 @@ describe('Note', () => {
 
 			await new Promise(x => setTimeout(x, 2));
 
-			const note1 = await api('/notes/create', {
+			const note1 = await api('notes/create', {
 				text: 'hogetesthuge',
 			}, alice);
 
@@ -666,7 +667,7 @@ describe('Note', () => {
 
 			assert.strictEqual(sensitive.status, 204);
 
-			const note2 = await api('/notes/create', {
+			const note2 = await api('notes/create', {
 				text: 'hogetesthuge',
 			}, alice);
 
@@ -683,7 +684,7 @@ describe('Note', () => {
 
 			assert.strictEqual(sensitive.status, 204);
 
-			const note2 = await api('/notes/create', {
+			const note2 = await api('notes/create', {
 				text: 'hogeTesthuge',
 			}, alice);
 
@@ -702,7 +703,7 @@ describe('Note', () => {
 
 			await new Promise(x => setTimeout(x, 2));
 
-			const note1 = await api('/notes/create', {
+			const note1 = await api('notes/create', {
 				text: 'hogetesthuge',
 			}, alice);
 
@@ -719,7 +720,7 @@ describe('Note', () => {
 
 			assert.strictEqual(prohibited.status, 204);
 
-			const note2 = await api('/notes/create', {
+			const note2 = await api('notes/create', {
 				text: 'hogetesthuge',
 			}, alice);
 
@@ -736,7 +737,7 @@ describe('Note', () => {
 
 			assert.strictEqual(prohibited.status, 204);
 
-			const note2 = await api('/notes/create', {
+			const note2 = await api('notes/create', {
 				text: 'hogeTesthuge',
 			}, alice);
 
@@ -755,7 +756,7 @@ describe('Note', () => {
 
 			await new Promise(x => setTimeout(x, 2));
 
-			const note1 = await api('/notes/create', {
+			const note1 = await api('notes/create', {
 				text: 'hogetesthuge',
 			}, tom);
 
@@ -799,7 +800,7 @@ describe('Note', () => {
 
 			await new Promise(x => setTimeout(x, 2));
 
-			const note = await api('/notes/create', {
+			const note = await api('notes/create', {
 				text: '@bob potentially annoying text',
 			}, alice);
 
@@ -853,10 +854,10 @@ describe('Note', () => {
 
 			await new Promise(x => setTimeout(x, 2));
 
-			const note = await api('/notes/create', {
+			const note = await api('notes/create', {
 				text: 'potentially annoying text',
 				visibility: 'specified',
-				visibleUserIds: [ bob.id ],
+				visibleUserIds: [bob.id],
 			}, alice);
 
 			assert.strictEqual(note.status, 400);
@@ -909,10 +910,10 @@ describe('Note', () => {
 
 			await new Promise(x => setTimeout(x, 2));
 
-			const note = await api('/notes/create', {
+			const note = await api('notes/create', {
 				text: '@bob potentially annoying text',
 				visibility: 'specified',
-				visibleUserIds: [ bob.id ],
+				visibleUserIds: [bob.id],
 			}, alice);
 
 			assert.strictEqual(note.status, 200);
diff --git a/packages/backend/test/e2e/renote-mute.ts b/packages/backend/test/e2e/renote-mute.ts
index 403de0cb8d..9826068e48 100644
--- a/packages/backend/test/e2e/renote-mute.ts
+++ b/packages/backend/test/e2e/renote-mute.ts
@@ -22,7 +22,7 @@ describe('Renote Mute', () => {
 	}, 1000 * 60 * 2);
 
 	test('ミュート作成', async () => {
-		const res = await api('/renote-mute/create', {
+		const res = await api('renote-mute/create', {
 			userId: carol.id,
 		}, alice);
 
@@ -37,7 +37,7 @@ describe('Renote Mute', () => {
 		// redisに追加されるのを待つ
 		await sleep(100);
 
-		const res = await api('/notes/local-timeline', {}, alice);
+		const res = await api('notes/local-timeline', {}, alice);
 
 		assert.strictEqual(res.status, 200);
 		assert.strictEqual(Array.isArray(res.body), true);
@@ -54,7 +54,7 @@ describe('Renote Mute', () => {
 		// redisに追加されるのを待つ
 		await sleep(100);
 
-		const res = await api('/notes/local-timeline', {}, alice);
+		const res = await api('notes/local-timeline', {}, alice);
 
 		assert.strictEqual(res.status, 200);
 		assert.strictEqual(Array.isArray(res.body), true);
diff --git a/packages/backend/test/e2e/streaming.ts b/packages/backend/test/e2e/streaming.ts
index 57ce73ba60..edb930617f 100644
--- a/packages/backend/test/e2e/streaming.ts
+++ b/packages/backend/test/e2e/streaming.ts
@@ -601,7 +601,7 @@ describe('Streaming', () => {
 
 			// #10443
 			test('ミュートしているサーバのノートがリストTLに流れない', async () => {
-				await api('/i/update', {
+				await api('i/update', {
 					mutedInstances: ['example.com'],
 				}, chitose);
 
@@ -618,7 +618,7 @@ describe('Streaming', () => {
 
 			// #10443
 			test('ミュートしているサーバのノートに対するリプライがリストTLに流れない', async () => {
-				await api('/i/update', {
+				await api('i/update', {
 					mutedInstances: ['example.com'],
 				}, chitose);
 
@@ -635,7 +635,7 @@ describe('Streaming', () => {
 
 			// #10443
 			test('ミュートしているサーバのノートに対するリノートがリストTLに流れない', async () => {
-				await api('/i/update', {
+				await api('i/update', {
 					mutedInstances: ['example.com'],
 				}, chitose);
 
diff --git a/packages/backend/test/e2e/thread-mute.ts b/packages/backend/test/e2e/thread-mute.ts
index b4570cdef1..53bb6eb765 100644
--- a/packages/backend/test/e2e/thread-mute.ts
+++ b/packages/backend/test/e2e/thread-mute.ts
@@ -24,12 +24,12 @@ describe('Note thread mute', () => {
 		const bobNote = await post(bob, { text: '@alice @carol root note' });
 		const aliceReply = await post(alice, { replyId: bobNote.id, text: '@bob @carol child note' });
 
-		await api('/notes/thread-muting/create', { noteId: bobNote.id }, alice);
+		await api('notes/thread-muting/create', { noteId: bobNote.id }, alice);
 
 		const carolReply = await post(carol, { replyId: bobNote.id, text: '@bob @alice child note' });
 		const carolReplyWithoutMention = await post(carol, { replyId: aliceReply.id, text: 'child note' });
 
-		const res = await api('/notes/mentions', {}, alice);
+		const res = await api('notes/mentions', {}, alice);
 
 		assert.strictEqual(res.status, 200);
 		assert.strictEqual(Array.isArray(res.body), true);
@@ -40,15 +40,15 @@ describe('Note thread mute', () => {
 
 	test('ミュートしているスレッドからメンションされても、hasUnreadMentions が true にならない', async () => {
 		// 状態リセット
-		await api('/i/read-all-unread-notes', {}, alice);
+		await api('i/read-all-unread-notes', {}, alice);
 
 		const bobNote = await post(bob, { text: '@alice @carol root note' });
 
-		await api('/notes/thread-muting/create', { noteId: bobNote.id }, alice);
+		await api('notes/thread-muting/create', { noteId: bobNote.id }, alice);
 
 		const carolReply = await post(carol, { replyId: bobNote.id, text: '@bob @alice child note' });
 
-		const res = await api('/i', {}, alice);
+		const res = await api('i', {}, alice);
 
 		assert.strictEqual(res.status, 200);
 		assert.strictEqual(res.body.hasUnreadMentions, false);
@@ -56,11 +56,11 @@ describe('Note thread mute', () => {
 
 	test('ミュートしているスレッドからメンションされても、ストリームに unreadMention イベントが流れてこない', () => new Promise<void>(async done => {
 		// 状態リセット
-		await api('/i/read-all-unread-notes', {}, alice);
+		await api('i/read-all-unread-notes', {}, alice);
 
 		const bobNote = await post(bob, { text: '@alice @carol root note' });
 
-		await api('/notes/thread-muting/create', { noteId: bobNote.id }, alice);
+		await api('notes/thread-muting/create', { noteId: bobNote.id }, alice);
 
 		let fired = false;
 
@@ -84,12 +84,12 @@ describe('Note thread mute', () => {
 		const bobNote = await post(bob, { text: '@alice @carol root note' });
 		const aliceReply = await post(alice, { replyId: bobNote.id, text: '@bob @carol child note' });
 
-		await api('/notes/thread-muting/create', { noteId: bobNote.id }, alice);
+		await api('notes/thread-muting/create', { noteId: bobNote.id }, alice);
 
 		const carolReply = await post(carol, { replyId: bobNote.id, text: '@bob @alice child note' });
 		const carolReplyWithoutMention = await post(carol, { replyId: aliceReply.id, text: 'child note' });
 
-		const res = await api('/i/notifications', {}, alice);
+		const res = await api('i/notifications', {}, alice);
 
 		assert.strictEqual(res.status, 200);
 		assert.strictEqual(Array.isArray(res.body), true);
diff --git a/packages/backend/test/e2e/timelines.ts b/packages/backend/test/e2e/timelines.ts
index 0e71d707dd..d413703ede 100644
--- a/packages/backend/test/e2e/timelines.ts
+++ b/packages/backend/test/e2e/timelines.ts
@@ -26,7 +26,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
 			assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi');
@@ -35,14 +35,14 @@ describe('Timelines', () => {
 		test.concurrent('フォローしているユーザーのノートが含まれる', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote = await post(bob, { text: 'hi' });
 			const carolNote = await post(carol, { text: 'hi' });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 			assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -51,14 +51,14 @@ describe('Timelines', () => {
 		test.concurrent('フォローしているユーザーの visibility: followers なノートが含まれる', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote = await post(bob, { text: 'hi', visibility: 'followers' });
 			const carolNote = await post(carol, { text: 'hi' });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 			assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi');
@@ -68,14 +68,14 @@ describe('Timelines', () => {
 		test.concurrent('withReplies: false でフォローしているユーザーの他人への返信が含まれない', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 			assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -84,15 +84,15 @@ describe('Timelines', () => {
 		test.concurrent('withReplies: true でフォローしているユーザーの他人への返信が含まれる', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
-			await api('/following/update', { userId: bob.id, withReplies: true }, alice);
+			await api('following/create', { userId: bob.id }, alice);
+			await api('following/update', { userId: bob.id, withReplies: true }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 			assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -101,15 +101,15 @@ describe('Timelines', () => {
 		test.concurrent('withReplies: true でフォローしているユーザーの他人へのDM返信が含まれない', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
-			await api('/following/update', { userId: bob.id, withReplies: true }, alice);
+			await api('following/create', { userId: bob.id }, alice);
+			await api('following/update', { userId: bob.id, withReplies: true }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id, visibility: 'specified', visibleUserIds: [carolNote.id] });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 			assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -118,15 +118,15 @@ describe('Timelines', () => {
 		test.concurrent('withReplies: true でフォローしているユーザーの他人の visibility: followers な投稿への返信が含まれない', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
-			await api('/following/update', { userId: bob.id, withReplies: true }, alice);
+			await api('following/create', { userId: bob.id }, alice);
+			await api('following/update', { userId: bob.id, withReplies: true }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi', visibility: 'followers' });
 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 			assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -135,17 +135,17 @@ describe('Timelines', () => {
 		test.concurrent('withReplies: true でフォローしているユーザーの行った別のフォローしているユーザーの visibility: followers な投稿への返信が含まれる', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
-			await api('/following/create', { userId: carol.id }, alice);
-			await api('/following/create', { userId: carol.id }, bob);
-			await api('/following/update', { userId: bob.id, withReplies: true }, alice);
+			await api('following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: carol.id }, alice);
+			await api('following/create', { userId: carol.id }, bob);
+			await api('following/update', { userId: bob.id, withReplies: true }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi', visibility: 'followers' });
 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 			assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
@@ -155,16 +155,16 @@ describe('Timelines', () => {
 		test.concurrent('withReplies: true でフォローしているユーザーの行った別のフォローしているユーザーの投稿への visibility: specified な返信が含まれない', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
-			await api('/following/create', { userId: carol.id }, alice);
-			await api('/following/update', { userId: bob.id, withReplies: true }, alice);
+			await api('following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: carol.id }, alice);
+			await api('following/update', { userId: bob.id, withReplies: true }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id, visibility: 'specified', visibleUserIds: [carolNote.id] });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 			assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
@@ -173,14 +173,14 @@ describe('Timelines', () => {
 		test.concurrent('withReplies: false でフォローしているユーザーのそのユーザー自身への返信が含まれる', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote1 = await post(bob, { text: 'hi' });
 			const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -189,14 +189,14 @@ describe('Timelines', () => {
 		test.concurrent('withReplies: false でフォローしているユーザーからの自分への返信が含まれる', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const aliceNote = await post(alice, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
@@ -210,7 +210,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 			assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
@@ -219,14 +219,14 @@ describe('Timelines', () => {
 		test.concurrent('フォローしているユーザーの他人の投稿のリノートが含まれる', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi' });
 			const bobNote = await post(bob, { renoteId: carolNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 			assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -235,14 +235,14 @@ describe('Timelines', () => {
 		test.concurrent('[withRenotes: false] フォローしているユーザーの他人の投稿のリノートが含まれない', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi' });
 			const bobNote = await post(bob, { renoteId: carolNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', {
+			const res = await api('notes/timeline', {
 				withRenotes: false,
 			}, alice);
 
@@ -253,14 +253,14 @@ describe('Timelines', () => {
 		test.concurrent('[withRenotes: false] フォローしているユーザーの他人の投稿の引用が含まれる', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', {
+			const res = await api('notes/timeline', {
 				withRenotes: false,
 			}, alice);
 
@@ -271,13 +271,13 @@ describe('Timelines', () => {
 		test.concurrent('フォローしているユーザーの他人への visibility: specified なノートが含まれない', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
@@ -285,15 +285,15 @@ describe('Timelines', () => {
 		test.concurrent('フォローしているユーザーが行ったミュートしているユーザーのリノートが含まれない', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
-			await api('/mute/create', { userId: carol.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
+			await api('mute/create', { userId: carol.id }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 			assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -302,16 +302,16 @@ describe('Timelines', () => {
 		test.concurrent('withReplies: true でフォローしているユーザーが行ったミュートしているユーザーの投稿への返信が含まれない', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
-			await api('/following/update', { userId: bob.id, withReplies: true }, alice);
-			await api('/mute/create', { userId: carol.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
+			await api('following/update', { userId: bob.id, withReplies: true }, alice);
+			await api('mute/create', { userId: carol.id }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 			assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -321,13 +321,13 @@ describe('Timelines', () => {
 			const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]);
 
 			await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' });
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 
 			const bobNote = await post(bob, { text: 'hi' });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 		});
@@ -336,13 +336,13 @@ describe('Timelines', () => {
 			const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]);
 
 			await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' });
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 
 			const bobNote = await post(bob, { text: 'hi', visibility: 'home' });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 		});
@@ -350,7 +350,7 @@ describe('Timelines', () => {
 		test.concurrent('[withFiles: true] フォローしているユーザーのファイル付きノートのみ含まれる', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const [bobFile, carolFile] = await Promise.all([
 				uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'),
@@ -363,7 +363,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100, withFiles: true }, alice);
+			const res = await api('notes/timeline', { limit: 100, withFiles: true }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false);
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -374,14 +374,14 @@ describe('Timelines', () => {
 		test.concurrent('フォローしているユーザーのチャンネル投稿が含まれない', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			const channel = await api('/channels/create', { name: 'channel' }, bob).then(x => x.body);
-			await api('/following/create', { userId: bob.id }, alice);
+			const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body);
+			await api('following/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote = await post(bob, { text: 'hi', channelId: channel.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
@@ -393,7 +393,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
 			assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi');
@@ -402,13 +402,13 @@ describe('Timelines', () => {
 		test.concurrent('フォローしているユーザーの自身を visibleUserIds に指定した visibility: specified なノートが含まれる', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [alice.id] });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 			assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi');
@@ -421,7 +421,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
@@ -429,13 +429,13 @@ describe('Timelines', () => {
 		test.concurrent('フォローしているユーザーの自身を visibleUserIds に指定していない visibility: specified なノートが含まれない', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
@@ -448,7 +448,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
 			assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'ok');
@@ -463,7 +463,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 			assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'ok');
@@ -479,7 +479,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/timeline', { limit: 100 }, alice);
+			const res = await api('notes/timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
@@ -494,7 +494,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+			const res = await api('notes/local-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 			assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -508,7 +508,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+			const res = await api('notes/local-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 			assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
@@ -522,7 +522,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+			const res = await api('notes/local-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -531,12 +531,12 @@ describe('Timelines', () => {
 		test.concurrent('チャンネル投稿が含まれない', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			const channel = await api('/channels/create', { name: 'channel' }, bob).then(x => x.body);
+			const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body);
 			const bobNote = await post(bob, { text: 'hi', channelId: channel.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+			const res = await api('notes/local-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
@@ -548,7 +548,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+			const res = await api('notes/local-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
@@ -557,14 +557,14 @@ describe('Timelines', () => {
 		test.concurrent('フォローしているユーザーの visibility: home なノートが含まれない', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: carol.id }, alice);
+			await api('following/create', { userId: carol.id }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi', visibility: 'home' });
 			const bobNote = await post(bob, { text: 'hi' });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+			const res = await api('notes/local-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 			assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -573,14 +573,14 @@ describe('Timelines', () => {
 		test.concurrent('ミュートしているユーザーのノートが含まれない', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/mute/create', { userId: carol.id }, alice);
+			await api('mute/create', { userId: carol.id }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi' });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+			const res = await api('notes/local-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 			assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -589,15 +589,15 @@ describe('Timelines', () => {
 		test.concurrent('フォローしているユーザーが行ったミュートしているユーザーのリノートが含まれない', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
-			await api('/mute/create', { userId: carol.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
+			await api('mute/create', { userId: carol.id }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+			const res = await api('notes/local-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 			assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -606,16 +606,16 @@ describe('Timelines', () => {
 		test.concurrent('withReplies: true でフォローしているユーザーが行ったミュートしているユーザーの投稿への返信が含まれない', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
-			await api('/following/update', { userId: bob.id, withReplies: true }, alice);
-			await api('/mute/create', { userId: carol.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
+			await api('following/update', { userId: bob.id, withReplies: true }, alice);
+			await api('mute/create', { userId: carol.id }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+			const res = await api('notes/local-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 			assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -624,14 +624,14 @@ describe('Timelines', () => {
 		test.concurrent('withReplies: false でフォローしているユーザーからの自分への返信が含まれる', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const aliceNote = await post(alice, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+			const res = await api('notes/local-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
@@ -645,7 +645,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/local-timeline', { limit: 100, withReplies: true }, alice);
+			const res = await api('notes/local-timeline', { limit: 100, withReplies: true }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 		});
@@ -659,7 +659,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/local-timeline', { limit: 100, withFiles: true }, alice);
+			const res = await api('notes/local-timeline', { limit: 100, withFiles: true }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false);
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -674,7 +674,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice);
+			const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 		});
@@ -686,7 +686,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice);
+			const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
@@ -694,13 +694,13 @@ describe('Timelines', () => {
 		test.concurrent('フォローしているローカルユーザーの visibility: home なノートが含まれる', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote = await post(bob, { text: 'hi', visibility: 'home' });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice);
+			const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 		});
@@ -708,14 +708,14 @@ describe('Timelines', () => {
 		test.concurrent('withReplies: false でフォローしているユーザーからの自分への返信が含まれる', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const aliceNote = await post(alice, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice);
+			const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
@@ -729,7 +729,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice);
+			const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 			assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
@@ -742,7 +742,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+			const res = await api('notes/local-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
@@ -751,13 +751,13 @@ describe('Timelines', () => {
 			const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]);
 
 			await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' });
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 
 			const bobNote = await post(bob, { text: 'hi' });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice);
+			const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 		});
@@ -766,13 +766,13 @@ describe('Timelines', () => {
 			const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]);
 
 			await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' });
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 
 			const bobNote = await post(bob, { text: 'hi', visibility: 'home' });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice);
+			const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 		});
@@ -785,7 +785,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/hybrid-timeline', { limit: 100, withReplies: true }, alice);
+			const res = await api('notes/hybrid-timeline', { limit: 100, withReplies: true }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 		});
@@ -799,7 +799,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/hybrid-timeline', { limit: 100, withFiles: true }, alice);
+			const res = await api('notes/hybrid-timeline', { limit: 100, withFiles: true }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false);
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -810,14 +810,14 @@ describe('Timelines', () => {
 		test.concurrent('リスインしているフォローしていないユーザーのノートが含まれる', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
-			await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote = await post(bob, { text: 'hi' });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+			const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 		});
@@ -825,14 +825,14 @@ describe('Timelines', () => {
 		test.concurrent('リスインしているフォローしていないユーザーの visibility: home なノートが含まれる', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
-			await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote = await post(bob, { text: 'hi', visibility: 'home' });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+			const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 		});
@@ -840,14 +840,14 @@ describe('Timelines', () => {
 		test.concurrent('リスインしているフォローしていないユーザーの visibility: followers なノートが含まれない', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
-			await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote = await post(bob, { text: 'hi', visibility: 'followers' });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+			const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
@@ -855,15 +855,15 @@ describe('Timelines', () => {
 		test.concurrent('リスインしているフォローしていないユーザーの他人への返信が含まれない', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
-			await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+			const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
@@ -871,15 +871,15 @@ describe('Timelines', () => {
 		test.concurrent('リスインしているフォローしていないユーザーのユーザー自身への返信が含まれる', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
-			await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote1 = await post(bob, { text: 'hi' });
 			const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+			const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -888,15 +888,15 @@ describe('Timelines', () => {
 		test.concurrent('withReplies: false でリスインしているフォローしていないユーザーからの自分への返信が含まれる', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
-			await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
 			await sleep(1000);
 			const aliceNote = await post(alice, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/user-list-timeline', { listId: list.id, withReplies: false }, alice);
+			const res = await api('notes/user-list-timeline', { listId: list.id, withReplies: false }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 		});
@@ -904,16 +904,16 @@ describe('Timelines', () => {
 		test.concurrent('withReplies: true でリスインしているフォローしていないユーザーの他人への返信が含まれる', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
-			await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
-			await api('/users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: true }, alice);
+			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
+			await api('users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: true }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+			const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 		});
@@ -921,15 +921,15 @@ describe('Timelines', () => {
 		test.concurrent('リスインしているフォローしているユーザーの visibility: home なノートが含まれる', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
-			const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
-			await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
+			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote = await post(bob, { text: 'hi', visibility: 'home' });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+			const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 		});
@@ -937,15 +937,15 @@ describe('Timelines', () => {
 		test.concurrent('リスインしているフォローしているユーザーの visibility: followers なノートが含まれる', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
-			const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
-			await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
+			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote = await post(bob, { text: 'hi', visibility: 'followers' });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+			const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 			assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi');
@@ -954,14 +954,14 @@ describe('Timelines', () => {
 		test.concurrent('リスインしている自分の visibility: followers なノートが含まれる', async () => {
 			const [alice] = await Promise.all([signup(), signup()]);
 
-			const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
-			await api('/users/lists/push', { listId: list.id, userId: alice.id }, alice);
+			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+			await api('users/lists/push', { listId: list.id, userId: alice.id }, alice);
 			await sleep(1000);
 			const aliceNote = await post(alice, { text: 'hi', visibility: 'followers' });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+			const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
 			assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi');
@@ -970,15 +970,15 @@ describe('Timelines', () => {
 		test.concurrent('リスインしているユーザーのチャンネルノートが含まれない', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			const channel = await api('/channels/create', { name: 'channel' }, bob).then(x => x.body);
-			const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
-			await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+			const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body);
+			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote = await post(bob, { text: 'hi', channelId: channel.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+			const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
@@ -986,15 +986,15 @@ describe('Timelines', () => {
 		test.concurrent('[withFiles: true] リスインしているユーザーのファイル付きノートのみ含まれる', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
-			await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
 			const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png');
 			const bobNote1 = await post(bob, { text: 'hi' });
 			const bobNote2 = await post(bob, { fileIds: [file.id] });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/user-list-timeline', { listId: list.id, withFiles: true }, alice);
+			const res = await api('notes/user-list-timeline', { listId: list.id, withFiles: true }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false);
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -1003,14 +1003,14 @@ describe('Timelines', () => {
 		test.concurrent('リスインしているユーザーの自身宛ての visibility: specified なノートが含まれる', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
-			await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [alice.id] });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+			const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 			assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi');
@@ -1019,15 +1019,15 @@ describe('Timelines', () => {
 		test.concurrent('リスインしているユーザーの自身宛てではない visibility: specified なノートが含まれない', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
-			await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
-			await api('/users/lists/push', { listId: list.id, userId: carol.id }, alice);
+			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
+			await api('users/lists/push', { listId: list.id, userId: carol.id }, alice);
 			await sleep(1000);
 			const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] });
 
 			await waitForPushToTl();
 
-			const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+			const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
@@ -1041,7 +1041,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/users/notes', { userId: bob.id }, alice);
+			const res = await api('users/notes', { userId: bob.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 		});
@@ -1053,7 +1053,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/users/notes', { userId: bob.id }, alice);
+			const res = await api('users/notes', { userId: bob.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
@@ -1061,13 +1061,13 @@ describe('Timelines', () => {
 		test.concurrent('フォローしているユーザーの visibility: followers なノートが含まれる', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			await api('/following/create', { userId: bob.id }, alice);
+			await api('following/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote = await post(bob, { text: 'hi', visibility: 'followers' });
 
 			await waitForPushToTl();
 
-			const res = await api('/users/notes', { userId: bob.id }, alice);
+			const res = await api('users/notes', { userId: bob.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 			assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi');
@@ -1080,7 +1080,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/users/notes', { userId: alice.id }, alice);
+			const res = await api('users/notes', { userId: alice.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
 			assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi');
@@ -1089,12 +1089,12 @@ describe('Timelines', () => {
 		test.concurrent('チャンネル投稿が含まれない', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			const channel = await api('/channels/create', { name: 'channel' }, bob).then(x => x.body);
+			const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body);
 			const bobNote = await post(bob, { text: 'hi', channelId: channel.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/users/notes', { userId: bob.id }, alice);
+			const res = await api('users/notes', { userId: bob.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
@@ -1108,7 +1108,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/users/notes', { userId: bob.id }, alice);
+			const res = await api('users/notes', { userId: bob.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), false);
@@ -1123,7 +1123,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/users/notes', { userId: bob.id, withReplies: true }, alice);
+			const res = await api('users/notes', { userId: bob.id, withReplies: true }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -1138,7 +1138,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/users/notes', { userId: bob.id, withReplies: true }, alice);
+			const res = await api('users/notes', { userId: bob.id, withReplies: true }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), false);
@@ -1153,7 +1153,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/users/notes', { userId: bob.id, withFiles: true }, alice);
+			const res = await api('users/notes', { userId: bob.id, withFiles: true }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false);
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -1162,12 +1162,12 @@ describe('Timelines', () => {
 		test.concurrent('[withChannelNotes: true] チャンネル投稿が含まれる', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			const channel = await api('/channels/create', { name: 'channel' }, bob).then(x => x.body);
+			const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body);
 			const bobNote = await post(bob, { text: 'hi', channelId: channel.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/users/notes', { userId: bob.id, withChannelNotes: true }, alice);
+			const res = await api('users/notes', { userId: bob.id, withChannelNotes: true }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 		});
@@ -1175,12 +1175,12 @@ describe('Timelines', () => {
 		test.concurrent('[withChannelNotes: true] 他人が取得した場合センシティブチャンネル投稿が含まれない', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			const channel = await api('/channels/create', { name: 'channel', isSensitive: true }, bob).then(x => x.body);
+			const channel = await api('channels/create', { name: 'channel', isSensitive: true }, bob).then(x => x.body);
 			const bobNote = await post(bob, { text: 'hi', channelId: channel.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/users/notes', { userId: bob.id, withChannelNotes: true }, alice);
+			const res = await api('users/notes', { userId: bob.id, withChannelNotes: true }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
@@ -1188,12 +1188,12 @@ describe('Timelines', () => {
 		test.concurrent('[withChannelNotes: true] 自分が取得した場合センシティブチャンネル投稿が含まれる', async () => {
 			const [bob] = await Promise.all([signup()]);
 
-			const channel = await api('/channels/create', { name: 'channel', isSensitive: true }, bob).then(x => x.body);
+			const channel = await api('channels/create', { name: 'channel', isSensitive: true }, bob).then(x => x.body);
 			const bobNote = await post(bob, { text: 'hi', channelId: channel.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/users/notes', { userId: bob.id, withChannelNotes: true }, bob);
+			const res = await api('users/notes', { userId: bob.id, withChannelNotes: true }, bob);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 		});
@@ -1201,14 +1201,14 @@ describe('Timelines', () => {
 		test.concurrent('ミュートしているユーザーに関連する投稿が含まれない', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
-			await api('/mute/create', { userId: carol.id }, alice);
+			await api('mute/create', { userId: carol.id }, alice);
 			await sleep(1000);
 			const carolNote = await post(carol, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('/users/notes', { userId: bob.id }, alice);
+			const res = await api('users/notes', { userId: bob.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
@@ -1216,7 +1216,7 @@ describe('Timelines', () => {
 		test.concurrent('ミュートしていても userId に指定したユーザーの投稿が含まれる', async () => {
 			const [alice, bob] = await Promise.all([signup(), signup()]);
 
-			await api('/mute/create', { userId: bob.id }, alice);
+			await api('mute/create', { userId: bob.id }, alice);
 			await sleep(1000);
 			const bobNote1 = await post(bob, { text: 'hi' });
 			const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id });
@@ -1224,7 +1224,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/users/notes', { userId: bob.id }, alice);
+			const res = await api('users/notes', { userId: bob.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -1238,7 +1238,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/users/notes', { userId: alice.id, withReplies: true }, alice);
+			const res = await api('users/notes', { userId: alice.id, withReplies: true }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
 		});
@@ -1250,7 +1250,7 @@ describe('Timelines', () => {
 
 			await waitForPushToTl();
 
-			const res = await api('/users/notes', { userId: bob.id, withReplies: true }, alice);
+			const res = await api('users/notes', { userId: bob.id, withReplies: true }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
 		});
diff --git a/packages/backend/test/e2e/user-notes.ts b/packages/backend/test/e2e/user-notes.ts
index 6897cf08c6..331e053935 100644
--- a/packages/backend/test/e2e/user-notes.ts
+++ b/packages/backend/test/e2e/user-notes.ts
@@ -11,9 +11,9 @@ import type * as misskey from 'misskey-js';
 
 describe('users/notes', () => {
 	let alice: misskey.entities.SignupResponse;
-	let jpgNote: any;
-	let pngNote: any;
-	let jpgPngNote: any;
+	let jpgNote: misskey.entities.Note;
+	let pngNote: misskey.entities.Note;
+	let jpgPngNote: misskey.entities.Note;
 
 	beforeAll(async () => {
 		alice = await signup({ username: 'alice' });
@@ -31,7 +31,7 @@ describe('users/notes', () => {
 	}, 1000 * 60 * 2);
 
 	test('withFiles', async () => {
-		const res = await api('/users/notes', {
+		const res = await api('users/notes', {
 			userId: alice.id,
 			withFiles: true,
 		}, alice);
diff --git a/packages/backend/test/e2e/users.ts b/packages/backend/test/e2e/users.ts
index 3cf2a5dee1..3458e06384 100644
--- a/packages/backend/test/e2e/users.ts
+++ b/packages/backend/test/e2e/users.ts
@@ -8,7 +8,7 @@ process.env.NODE_ENV = 'test';
 import * as assert from 'assert';
 import { inspect } from 'node:util';
 import { DEFAULT_POLICIES } from '@/core/RoleService.js';
-import { api, page, post, role, signup, successfulApiCall, uploadFile } from '../utils.js';
+import { api, post, role, signup, successfulApiCall, uploadFile } from '../utils.js';
 import type * as misskey from 'misskey-js';
 
 describe('ユーザー', () => {
@@ -24,31 +24,12 @@ describe('ユーザー', () => {
 			}, {});
 	};
 
-	// BUG misskey-jsとjson-schemaと実際に返ってくるデータが全部違う
-	type UserLite = misskey.entities.UserLite & {
-		badgeRoles: any[],
-	};
-
-	type UserDetailedNotMe = UserLite &
-	misskey.entities.UserDetailed & {
-		roles: any[],
-	};
-
-	type MeDetailed = UserDetailedNotMe &
-		misskey.entities.MeDetailed & {
-		achievements: object[],
-		loggedInDays: number,
-		policies: object,
-	};
-
-	type User = MeDetailed & { token: string };
-
-	const show = async (id: string, me = root): Promise<MeDetailed | UserDetailedNotMe> => {
-		return successfulApiCall({ endpoint: 'users/show', parameters: { userId: id }, user: me }) as any;
+	const show = async (id: string, me = root): Promise<misskey.entities.UserDetailed> => {
+		return successfulApiCall({ endpoint: 'users/show', parameters: { userId: id }, user: me });
 	};
 
 	// UserLiteのキーが過不足なく入っている?
-	const userLite = (user: User): Partial<UserLite> => {
+	const userLite = (user: misskey.entities.UserLite): Partial<misskey.entities.UserLite> => {
 		return stripUndefined({
 			id: user.id,
 			name: user.name,
@@ -71,7 +52,7 @@ describe('ユーザー', () => {
 	};
 
 	// UserDetailedNotMeのキーが過不足なく入っている?
-	const userDetailedNotMe = (user: User): Partial<UserDetailedNotMe> => {
+	const userDetailedNotMe = (user: misskey.entities.SignupResponse): Partial<misskey.entities.UserDetailedNotMe> => {
 		return stripUndefined({
 			...userLite(user),
 			url: user.url,
@@ -111,7 +92,7 @@ describe('ユーザー', () => {
 	};
 
 	// Relations関連のキーが過不足なく入っている?
-	const userDetailedNotMeWithRelations = (user: User): Partial<UserDetailedNotMe> => {
+	const userDetailedNotMeWithRelations = (user: misskey.entities.SignupResponse): Partial<misskey.entities.UserDetailedNotMe> => {
 		return stripUndefined({
 			...userDetailedNotMe(user),
 			isFollowing: user.isFollowing ?? false,
@@ -128,7 +109,7 @@ describe('ユーザー', () => {
 	};
 
 	// MeDetailedのキーが過不足なく入っている?
-	const meDetailed = (user: User, security = false): Partial<MeDetailed> => {
+	const meDetailed = (user: misskey.entities.SignupResponse, security = false): Partial<misskey.entities.MeDetailed> => {
 		return stripUndefined({
 			...userDetailedNotMe(user),
 			avatarId: user.avatarId,
@@ -159,6 +140,7 @@ describe('ユーザー', () => {
 			mutedWords: user.mutedWords,
 			hardMutedWords: user.hardMutedWords,
 			mutedInstances: user.mutedInstances,
+			// @ts-expect-error 後方互換性
 			mutingNotificationTypes: user.mutingNotificationTypes,
 			notificationRecieveConfig: user.notificationRecieveConfig,
 			emailNotificationTypes: user.emailNotificationTypes,
@@ -173,61 +155,53 @@ describe('ユーザー', () => {
 		});
 	};
 
-	let root: User;
-	let alice: User;
+	let root: misskey.entities.SignupResponse;
+	let alice: misskey.entities.SignupResponse;
 	let aliceNote: misskey.entities.Note;
-	let alicePage: misskey.entities.Page;
-	let aliceList: misskey.entities.UserList;
 
-	let bob: User;
-	let bobNote: misskey.entities.Note;
+	let bob: misskey.entities.SignupResponse;
 
-	let carol: User;
-	let dave: User;
-	let ellen: User;
-	let frank: User;
+	// NOTE: これがないと落ちる(bob の updatedAt が null になってしまうため?)
+	let bobNote: misskey.entities.Note; // eslint-disable-line @typescript-eslint/no-unused-vars
 
-	let usersReplying: User[];
+	let carol: misskey.entities.SignupResponse;
 
-	let userNoNote: User;
-	let userNotExplorable: User;
-	let userLocking: User;
-	let userAdmin: User;
-	let roleAdmin: any;
-	let userModerator: User;
-	let roleModerator: any;
-	let userRolePublic: User;
-	let rolePublic: any;
-	let userRoleBadge: User;
-	let roleBadge: any;
-	let userSilenced: User;
-	let roleSilenced: any;
-	let userSuspended: User;
-	let userDeletedBySelf: User;
-	let userDeletedByAdmin: User;
-	let userFollowingAlice: User;
-	let userFollowedByAlice: User;
-	let userBlockingAlice: User;
-	let userBlockedByAlice: User;
-	let userMutingAlice: User;
-	let userMutedByAlice: User;
-	let userRnMutingAlice: User;
-	let userRnMutedByAlice: User;
-	let userFollowRequesting: User;
-	let userFollowRequested: User;
+	let usersReplying: misskey.entities.SignupResponse[];
+
+	let userNoNote: misskey.entities.SignupResponse;
+	let userNotExplorable: misskey.entities.SignupResponse;
+	let userLocking: misskey.entities.SignupResponse;
+	let userAdmin: misskey.entities.SignupResponse;
+	let roleAdmin: misskey.entities.Role;
+	let userModerator: misskey.entities.SignupResponse;
+	let roleModerator: misskey.entities.Role;
+	let userRolePublic: misskey.entities.SignupResponse;
+	let rolePublic: misskey.entities.Role;
+	let userRoleBadge: misskey.entities.SignupResponse;
+	let roleBadge: misskey.entities.Role;
+	let userSilenced: misskey.entities.SignupResponse;
+	let roleSilenced: misskey.entities.Role;
+	let userSuspended: misskey.entities.SignupResponse;
+	let userDeletedBySelf: misskey.entities.SignupResponse;
+	let userDeletedByAdmin: misskey.entities.SignupResponse;
+	let userFollowingAlice: misskey.entities.SignupResponse;
+	let userFollowedByAlice: misskey.entities.SignupResponse;
+	let userBlockingAlice: misskey.entities.SignupResponse;
+	let userBlockedByAlice: misskey.entities.SignupResponse;
+	let userMutingAlice: misskey.entities.SignupResponse;
+	let userMutedByAlice: misskey.entities.SignupResponse;
+	let userRnMutingAlice: misskey.entities.SignupResponse;
+	let userRnMutedByAlice: misskey.entities.SignupResponse;
+	let userFollowRequesting: misskey.entities.SignupResponse;
+	let userFollowRequested: misskey.entities.SignupResponse;
 
 	beforeAll(async () => {
 		root = await signup({ username: 'root' });
 		alice = await signup({ username: 'alice' });
-		aliceNote = await post(alice, { text: 'test' }) as any;
-		alicePage = await page(alice);
-		aliceList = (await api('users/list/create', { name: 'aliceList' }, alice)).body;
+		aliceNote = await post(alice, { text: 'test' });
 		bob = await signup({ username: 'bob' });
-		bobNote = await post(bob, { text: 'test' }) as any;
+		bobNote = await post(bob, { text: 'test' });
 		carol = await signup({ username: 'carol' });
-		dave = await signup({ username: 'dave' });
-		ellen = await signup({ username: 'ellen' });
-		frank = await signup({ username: 'frank' });
 
 		// @alice -> @replyingへのリプライ。Promise.allで一気に作るとtimeoutしてしまうのでreduceで一つ一つawaitする
 		usersReplying = await [...Array(10)].map((_, i) => i).reduce(async (acc, i) => {
@@ -238,7 +212,7 @@ describe('ユーザー', () => {
 			}
 
 			return (await acc).concat(u);
-		}, Promise.resolve([] as User[]));
+		}, Promise.resolve([] as misskey.entities.SignupResponse[]));
 
 		userNoNote = await signup({ username: 'userNoNote' });
 		userNotExplorable = await signup({ username: 'userNotExplorable' });
@@ -306,7 +280,7 @@ describe('ユーザー', () => {
 	beforeEach(async () => {
 		alice = {
 			...alice,
-			...await successfulApiCall({ endpoint: 'i', parameters: {}, user: alice }) as any,
+			...await successfulApiCall({ endpoint: 'i', parameters: {}, user: alice }),
 		};
 		aliceNote = await successfulApiCall({ endpoint: 'notes/show', parameters: { noteId: aliceNote.id }, user: alice });
 	});
@@ -319,7 +293,7 @@ describe('ユーザー', () => {
 			endpoint: 'signup',
 			parameters: { username: 'zoe', password: 'password' },
 			user: undefined,
-		}) as unknown as User; // BUG MeDetailedに足りないキーがある
+		}) as unknown as misskey.entities.SignupResponse; // BUG MeDetailedに足りないキーがある
 
 		// signupの時はtokenが含まれる特別なMeDetailedが返ってくる
 		assert.match(response.token, /[a-zA-Z0-9]{16}/);
@@ -329,7 +303,7 @@ describe('ユーザー', () => {
 		assert.strictEqual(response.name, null);
 		assert.strictEqual(response.username, 'zoe');
 		assert.strictEqual(response.host, null);
-		assert.match(response.avatarUrl, /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/);
+		response.avatarUrl && assert.match(response.avatarUrl, /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/);
 		assert.strictEqual(response.avatarBlurhash, null);
 		assert.deepStrictEqual(response.avatarDecorations, []);
 		assert.strictEqual(response.isBot, false);
@@ -401,6 +375,7 @@ describe('ユーザー', () => {
 		assert.deepStrictEqual(response.unreadAnnouncements, []);
 		assert.deepStrictEqual(response.mutedWords, []);
 		assert.deepStrictEqual(response.mutedInstances, []);
+		// @ts-expect-error 後方互換のため
 		assert.deepStrictEqual(response.mutingNotificationTypes, []);
 		assert.deepStrictEqual(response.notificationRecieveConfig, {});
 		assert.deepStrictEqual(response.emailNotificationTypes, ['follow', 'receiveFollowRequest']);
@@ -430,66 +405,66 @@ describe('ユーザー', () => {
 	//#region 自分の情報の更新(i/update)
 
 	test.each([
-		{ parameters: (): object => ({ name: null }) },
-		{ parameters: (): object => ({ name: 'x'.repeat(50) }) },
-		{ parameters: (): object => ({ name: 'x' }) },
-		{ parameters: (): object => ({ name: 'My name' }) },
-		{ parameters: (): object => ({ description: null }) },
-		{ parameters: (): object => ({ description: 'x'.repeat(1500) }) },
-		{ parameters: (): object => ({ description: 'x' }) },
-		{ parameters: (): object => ({ description: 'My description' }) },
-		{ parameters: (): object => ({ location: null }) },
-		{ parameters: (): object => ({ location: 'x'.repeat(50) }) },
-		{ parameters: (): object => ({ location: 'x' }) },
-		{ parameters: (): object => ({ location: 'My location' }) },
-		{ parameters: (): object => ({ birthday: '0000-00-00' }) },
-		{ parameters: (): object => ({ birthday: '9999-99-99' }) },
-		{ parameters: (): object => ({ lang: 'en-US' }) },
-		{ parameters: (): object => ({ fields: [] }) },
-		{ parameters: (): object => ({ fields: [{ name: 'x', value: 'x' }] }) },
-		{ parameters: (): object => ({ fields: [{ name: 'x'.repeat(3000), value: 'x'.repeat(3000) }] }) }, // BUG? fieldには制限がない
-		{ parameters: (): object => ({ fields: Array(16).fill({ name: 'x', value: 'y' }) }) },
-		{ parameters: (): object => ({ isLocked: true }) },
-		{ parameters: (): object => ({ isLocked: false }) },
-		{ parameters: (): object => ({ isExplorable: false }) },
-		{ parameters: (): object => ({ isExplorable: true }) },
-		{ parameters: (): object => ({ hideOnlineStatus: true }) },
-		{ parameters: (): object => ({ hideOnlineStatus: false }) },
-		{ parameters: (): object => ({ publicReactions: false }) },
-		{ parameters: (): object => ({ publicReactions: true }) },
-		{ parameters: (): object => ({ autoAcceptFollowed: true }) },
-		{ parameters: (): object => ({ autoAcceptFollowed: false }) },
-		{ parameters: (): object => ({ noCrawle: true }) },
-		{ parameters: (): object => ({ noCrawle: false }) },
-		{ parameters: (): object => ({ preventAiLearning: false }) },
-		{ parameters: (): object => ({ preventAiLearning: true }) },
-		{ parameters: (): object => ({ isBot: true }) },
-		{ parameters: (): object => ({ isBot: false }) },
-		{ parameters: (): object => ({ isCat: true }) },
-		{ parameters: (): object => ({ isCat: false }) },
-		{ parameters: (): object => ({ injectFeaturedNote: true }) },
-		{ parameters: (): object => ({ injectFeaturedNote: false }) },
-		{ parameters: (): object => ({ receiveAnnouncementEmail: true }) },
-		{ parameters: (): object => ({ receiveAnnouncementEmail: false }) },
-		{ parameters: (): object => ({ alwaysMarkNsfw: true }) },
-		{ parameters: (): object => ({ alwaysMarkNsfw: false }) },
-		{ parameters: (): object => ({ autoSensitive: true }) },
-		{ parameters: (): object => ({ autoSensitive: false }) },
-		{ parameters: (): object => ({ followingVisibility: 'private' }) },
-		{ parameters: (): object => ({ followingVisibility: 'followers' }) },
-		{ parameters: (): object => ({ followingVisibility: 'public' }) },
-		{ parameters: (): object => ({ followersVisibility: 'private' }) },
-		{ parameters: (): object => ({ followersVisibility: 'followers' }) },
-		{ parameters: (): object => ({ followersVisibility: 'public' }) },
-		{ parameters: (): object => ({ mutedWords: Array(19).fill(['xxxxx']) }) },
-		{ parameters: (): object => ({ mutedWords: [['x'.repeat(194)]] }) },
-		{ parameters: (): object => ({ mutedWords: [] }) },
-		{ parameters: (): object => ({ mutedInstances: ['xxxx.xxxxx'] }) },
-		{ parameters: (): object => ({ mutedInstances: [] }) },
-		{ parameters: (): object => ({ notificationRecieveConfig: { mention: { type: 'following' } } }) },
-		{ parameters: (): object => ({ notificationRecieveConfig: {} }) },
-		{ parameters: (): object => ({ emailNotificationTypes: ['mention', 'reply', 'quote', 'follow', 'receiveFollowRequest'] }) },
-		{ parameters: (): object => ({ emailNotificationTypes: [] }) },
+		{ parameters: () => ({ name: null }) },
+		{ parameters: () => ({ name: 'x'.repeat(50) }) },
+		{ parameters: () => ({ name: 'x' }) },
+		{ parameters: () => ({ name: 'My name' }) },
+		{ parameters: () => ({ description: null }) },
+		{ parameters: () => ({ description: 'x'.repeat(1500) }) },
+		{ parameters: () => ({ description: 'x' }) },
+		{ parameters: () => ({ description: 'My description' }) },
+		{ parameters: () => ({ location: null }) },
+		{ parameters: () => ({ location: 'x'.repeat(50) }) },
+		{ parameters: () => ({ location: 'x' }) },
+		{ parameters: () => ({ location: 'My location' }) },
+		{ parameters: () => ({ birthday: '0000-00-00' }) },
+		{ parameters: () => ({ birthday: '9999-99-99' }) },
+		{ parameters: () => ({ lang: 'en-US' as const }) },
+		{ parameters: () => ({ fields: [] }) },
+		{ parameters: () => ({ fields: [{ name: 'x', value: 'x' }] }) },
+		{ parameters: () => ({ fields: [{ name: 'x'.repeat(3000), value: 'x'.repeat(3000) }] }) }, // BUG? fieldには制限がない
+		{ parameters: () => ({ fields: Array(16).fill({ name: 'x', value: 'y' }) }) },
+		{ parameters: () => ({ isLocked: true }) },
+		{ parameters: () => ({ isLocked: false }) },
+		{ parameters: () => ({ isExplorable: false }) },
+		{ parameters: () => ({ isExplorable: true }) },
+		{ parameters: () => ({ hideOnlineStatus: true }) },
+		{ parameters: () => ({ hideOnlineStatus: false }) },
+		{ parameters: () => ({ publicReactions: false }) },
+		{ parameters: () => ({ publicReactions: true }) },
+		{ parameters: () => ({ autoAcceptFollowed: true }) },
+		{ parameters: () => ({ autoAcceptFollowed: false }) },
+		{ parameters: () => ({ noCrawle: true }) },
+		{ parameters: () => ({ noCrawle: false }) },
+		{ parameters: () => ({ preventAiLearning: false }) },
+		{ parameters: () => ({ preventAiLearning: true }) },
+		{ parameters: () => ({ isBot: true }) },
+		{ parameters: () => ({ isBot: false }) },
+		{ parameters: () => ({ isCat: true }) },
+		{ parameters: () => ({ isCat: false }) },
+		{ parameters: () => ({ injectFeaturedNote: true }) },
+		{ parameters: () => ({ injectFeaturedNote: false }) },
+		{ parameters: () => ({ receiveAnnouncementEmail: true }) },
+		{ parameters: () => ({ receiveAnnouncementEmail: false }) },
+		{ parameters: () => ({ alwaysMarkNsfw: true }) },
+		{ parameters: () => ({ alwaysMarkNsfw: false }) },
+		{ parameters: () => ({ autoSensitive: true }) },
+		{ parameters: () => ({ autoSensitive: false }) },
+		{ parameters: () => ({ followingVisibility: 'private' as const }) },
+		{ parameters: () => ({ followingVisibility: 'followers' as const }) },
+		{ parameters: () => ({ followingVisibility: 'public' as const }) },
+		{ parameters: () => ({ followersVisibility: 'private' as const }) },
+		{ parameters: () => ({ followersVisibility: 'followers' as const }) },
+		{ parameters: () => ({ followersVisibility: 'public' as const }) },
+		{ parameters: () => ({ mutedWords: Array(19).fill(['xxxxx']) }) },
+		{ parameters: () => ({ mutedWords: [['x'.repeat(194)]] }) },
+		{ parameters: () => ({ mutedWords: [] }) },
+		{ parameters: () => ({ mutedInstances: ['xxxx.xxxxx'] }) },
+		{ parameters: () => ({ mutedInstances: [] }) },
+		{ parameters: () => ({ notificationRecieveConfig: { mention: { type: 'following' } } }) },
+		{ parameters: () => ({ notificationRecieveConfig: {} }) },
+		{ parameters: () => ({ emailNotificationTypes: ['mention', 'reply', 'quote', 'follow', 'receiveFollowRequest'] }) },
+		{ parameters: () => ({ emailNotificationTypes: [] }) },
 	] as const)('を書き換えることができる($#)', async ({ parameters }) => {
 		const response = await successfulApiCall({ endpoint: 'i/update', parameters: parameters(), user: alice });
 		const expected = { ...meDetailed(alice, true), ...parameters() };
@@ -498,13 +473,13 @@ describe('ユーザー', () => {
 
 	test('を書き換えることができる(Avatar)', async () => {
 		const aliceFile = (await uploadFile(alice)).body;
-		const parameters = { avatarId: aliceFile.id };
+		const parameters = { avatarId: aliceFile!.id };
 		const response = await successfulApiCall({ endpoint: 'i/update', parameters: parameters, user: alice });
 		assert.match(response.avatarUrl ?? '.', /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/);
 		assert.match(response.avatarBlurhash ?? '.', /[ -~]{54}/);
 		const expected = {
 			...meDetailed(alice, true),
-			avatarId: aliceFile.id,
+			avatarId: aliceFile!.id,
 			avatarBlurhash: response.avatarBlurhash,
 			avatarUrl: response.avatarUrl,
 		};
@@ -523,13 +498,13 @@ describe('ユーザー', () => {
 
 	test('を書き換えることができる(Banner)', async () => {
 		const aliceFile = (await uploadFile(alice)).body;
-		const parameters = { bannerId: aliceFile.id };
+		const parameters = { bannerId: aliceFile!.id };
 		const response = await successfulApiCall({ endpoint: 'i/update', parameters: parameters, user: alice });
 		assert.match(response.bannerUrl ?? '.', /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/);
 		assert.match(response.bannerBlurhash ?? '.', /[ -~]{54}/);
 		const expected = {
 			...meDetailed(alice, true),
-			bannerId: aliceFile.id,
+			bannerId: aliceFile!.id,
 			bannerBlurhash: response.bannerBlurhash,
 			bannerUrl: response.bannerUrl,
 		};
@@ -579,13 +554,13 @@ describe('ユーザー', () => {
 	//#region ユーザー(users)
 
 	test.each([
-		{ label: 'ID昇順', parameters: { limit: 5 }, selector: (u: UserLite): string => u.id },
-		{ label: 'フォロワー昇順', parameters: { sort: '+follower' }, selector: (u: UserDetailedNotMe): string => String(u.followersCount) },
-		{ label: 'フォロワー降順', parameters: { sort: '-follower' }, selector: (u: UserDetailedNotMe): string => String(u.followersCount) },
-		{ label: '登録日時昇順', parameters: { sort: '+createdAt' }, selector: (u: UserDetailedNotMe): string => u.createdAt },
-		{ label: '登録日時降順', parameters: { sort: '-createdAt' }, selector: (u: UserDetailedNotMe): string => u.createdAt },
-		{ label: '投稿日時昇順', parameters: { sort: '+updatedAt' }, selector: (u: UserDetailedNotMe): string => String(u.updatedAt) },
-		{ label: '投稿日時降順', parameters: { sort: '-updatedAt' }, selector: (u: UserDetailedNotMe): string => String(u.updatedAt) },
+		{ label: 'ID昇順', parameters: { limit: 5 }, selector: (u: misskey.entities.UserLite): string => u.id },
+		{ label: 'フォロワー昇順', parameters: { sort: '+follower' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.followersCount) },
+		{ label: 'フォロワー降順', parameters: { sort: '-follower' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.followersCount) },
+		{ label: '登録日時昇順', parameters: { sort: '+createdAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => u.createdAt },
+		{ label: '登録日時降順', parameters: { sort: '-createdAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => u.createdAt },
+		{ label: '投稿日時昇順', parameters: { sort: '+updatedAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.updatedAt) },
+		{ label: '投稿日時降順', parameters: { sort: '-updatedAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.updatedAt) },
 	] as const)('をリスト形式で取得することができる($label)', async ({ parameters, selector }) => {
 		const response = await successfulApiCall({ endpoint: 'users', parameters, user: alice });
 
@@ -598,15 +573,15 @@ describe('ユーザー', () => {
 		assert.deepStrictEqual(response, expected);
 	});
 	test.each([
-		{ label: '「見つけやすくする」がOFFのユーザーが含まれない', user: (): User => userNotExplorable, excluded: true },
-		{ label: 'ミュートユーザーが含まれない', user: (): User => userMutedByAlice, excluded: true },
-		{ label: 'ブロックされているユーザーが含まれない', user: (): User => userBlockedByAlice, excluded: true },
-		{ label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice, excluded: true },
-		{ label: '承認制ユーザーが含まれる', user: (): User => userLocking },
-		{ label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
-		{ label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true },
-		{ label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
-		{ label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
+		{ label: '「見つけやすくする」がOFFのユーザーが含まれない', user: () => userNotExplorable, excluded: true },
+		{ label: 'ミュートユーザーが含まれない', user: () => userMutedByAlice, excluded: true },
+		{ label: 'ブロックされているユーザーが含まれない', user: () => userBlockedByAlice, excluded: true },
+		{ label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice, excluded: true },
+		{ label: '承認制ユーザーが含まれる', user: () => userLocking },
+		{ label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
+		{ label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true },
+		{ label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
+		{ label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
 	] as const)('をリスト形式で取得することができ、結果に$label', async ({ user, excluded }) => {
 		const parameters = { limit: 100 };
 		const response = await successfulApiCall({ endpoint: 'users', parameters, user: alice });
@@ -620,39 +595,44 @@ describe('ユーザー', () => {
 	//#region ユーザー情報(users/show)
 
 	test.each([
-		{ label: 'ID指定で自分自身を', parameters: (): object => ({ userId: alice.id }), user: (): User => alice, type: meDetailed },
-		{ label: 'ID指定で他人を', parameters: (): object => ({ userId: alice.id }), user: (): User => bob, type: userDetailedNotMeWithRelations },
-		{ label: 'ID指定かつ未認証', parameters: (): object => ({ userId: alice.id }), user: undefined, type: userDetailedNotMe },
-		{ label: '@指定で自分自身を', parameters: (): object => ({ username: alice.username }), user: (): User => alice, type: meDetailed },
-		{ label: '@指定で他人を', parameters: (): object => ({ username: alice.username }), user: (): User => bob, type: userDetailedNotMeWithRelations },
-		{ label: '@指定かつ未認証', parameters: (): object => ({ username: alice.username }), user: undefined, type: userDetailedNotMe },
+		{ label: 'ID指定で自分自身を', parameters: () => ({ userId: alice.id }), user: () => alice, type: meDetailed },
+		{ label: 'ID指定で他人を', parameters: () => ({ userId: alice.id }), user: () => bob, type: userDetailedNotMeWithRelations },
+		{ label: 'ID指定かつ未認証', parameters: () => ({ userId: alice.id }), user: undefined, type: userDetailedNotMe },
+		{ label: '@指定で自分自身を', parameters: () => ({ username: alice.username }), user: () => alice, type: meDetailed },
+		{ label: '@指定で他人を', parameters: () => ({ username: alice.username }), user: () => bob, type: userDetailedNotMeWithRelations },
+		{ label: '@指定かつ未認証', parameters: () => ({ username: alice.username }), user: undefined, type: userDetailedNotMe },
 	] as const)('を取得することができる($label)', async ({ parameters, user, type }) => {
 		const response = await successfulApiCall({ endpoint: 'users/show', parameters: parameters(), user: user?.() });
 		const expected = type(alice);
 		assert.deepStrictEqual(response, expected);
 	});
 	test.each([
-		{ label: 'Administratorになっている', user: (): User => userAdmin, me: (): User => userAdmin, selector: (user: User): unknown => user.isAdmin },
-		{ label: '自分以外から見たときはAdministratorか判定できない', user: (): User => userAdmin, selector: (user: User): unknown => user.isAdmin, expected: (): undefined => undefined },
-		{ label: 'Moderatorになっている', user: (): User => userModerator, me: (): User => userModerator, selector: (user: User): unknown => user.isModerator },
-		{ label: '自分以外から見たときはModeratorか判定できない', user: (): User => userModerator, selector: (user: User): unknown => user.isModerator, expected: (): undefined => undefined },
-		{ label: 'サイレンスになっている', user: (): User => userSilenced, selector: (user: User): unknown => user.isSilenced },
-		//{ label: 'サスペンドになっている', user: (): User => userSuspended, selector: (user: User): unknown => user.isSuspended },
-		{ label: '削除済みになっている', user: (): User => userDeletedBySelf, me: (): User => userDeletedBySelf, selector: (user: User): unknown => user.isDeleted },
-		{ label: '自分以外から見たときは削除済みか判定できない', user: (): User => userDeletedBySelf, selector: (user: User): unknown => user.isDeleted, expected: (): undefined => undefined },
-		{ label: '削除済み(byAdmin)になっている', user: (): User => userDeletedByAdmin, me: (): User => userDeletedByAdmin, selector: (user: User): unknown => user.isDeleted },
-		{ label: '自分以外から見たときは削除済み(byAdmin)か判定できない', user: (): User => userDeletedByAdmin, selector: (user: User): unknown => user.isDeleted, expected: (): undefined => undefined },
-		{ label: 'フォロー中になっている', user: (): User => userFollowedByAlice, selector: (user: User): unknown => user.isFollowing },
-		{ label: 'フォローされている', user: (): User => userFollowingAlice, selector: (user: User): unknown => user.isFollowed },
-		{ label: 'ブロック中になっている', user: (): User => userBlockedByAlice, selector: (user: User): unknown => user.isBlocking },
-		{ label: 'ブロックされている', user: (): User => userBlockingAlice, selector: (user: User): unknown => user.isBlocked },
-		{ label: 'ミュート中になっている', user: (): User => userMutedByAlice, selector: (user: User): unknown => user.isMuted },
-		{ label: 'リノートミュート中になっている', user: (): User => userRnMutedByAlice, selector: (user: User): unknown => user.isRenoteMuted },
-		{ label: 'フォローリクエスト中になっている', user: (): User => userFollowRequested, me: (): User => userFollowRequesting, selector: (user: User): unknown => user.hasPendingFollowRequestFromYou },
-		{ label: 'フォローリクエストされている', user: (): User => userFollowRequesting, me: (): User => userFollowRequested, selector: (user: User): unknown => user.hasPendingFollowRequestToYou },
+		{ label: 'Administratorになっている', user: () => userAdmin, me: () => userAdmin, selector: (user: misskey.entities.MeDetailed) => user.isAdmin },
+		// @ts-expect-error UserDetailedNotMe doesn't include isAdmin
+		{ label: '自分以外から見たときはAdministratorか判定できない', user: () => userAdmin, selector: (user: misskey.entities.UserDetailedNotMe) => user.isAdmin, expected: () => undefined },
+		{ label: 'Moderatorになっている', user: () => userModerator, me: () => userModerator, selector: (user: misskey.entities.MeDetailed) => user.isModerator },
+		// @ts-expect-error UserDetailedNotMe doesn't include isModerator
+		{ label: '自分以外から見たときはModeratorか判定できない', user: () => userModerator, selector: (user: misskey.entities.UserDetailedNotMe) => user.isModerator, expected: () => undefined },
+		{ label: 'サイレンスになっている', user: () => userSilenced, selector: (user: misskey.entities.UserDetailed) => user.isSilenced },
+		// FIXME: 落ちる
+		//{ label: 'サスペンドになっている', user: () => userSuspended, selector: (user: misskey.entities.UserDetailed) => user.isSuspended },
+		{ label: '削除済みになっている', user: () => userDeletedBySelf, me: () => userDeletedBySelf, selector: (user: misskey.entities.MeDetailed) => user.isDeleted },
+		// @ts-expect-error UserDetailedNotMe doesn't include isDeleted
+		{ label: '自分以外から見たときは削除済みか判定できない', user: () => userDeletedBySelf, selector: (user: misskey.entities.UserDetailedNotMe) => user.isDeleted, expected: () => undefined },
+		{ label: '削除済み(byAdmin)になっている', user: () => userDeletedByAdmin, me: () => userDeletedByAdmin, selector: (user: misskey.entities.MeDetailed) => user.isDeleted },
+		// @ts-expect-error UserDetailedNotMe doesn't include isDeleted
+		{ label: '自分以外から見たときは削除済み(byAdmin)か判定できない', user: () => userDeletedByAdmin, selector: (user: misskey.entities.UserDetailedNotMe) => user.isDeleted, expected: () => undefined },
+		{ label: 'フォロー中になっている', user: () => userFollowedByAlice, selector: (user: misskey.entities.UserDetailed) => user.isFollowing },
+		{ label: 'フォローされている', user: () => userFollowingAlice, selector: (user: misskey.entities.UserDetailed) => user.isFollowed },
+		{ label: 'ブロック中になっている', user: () => userBlockedByAlice, selector: (user: misskey.entities.UserDetailed) => user.isBlocking },
+		{ label: 'ブロックされている', user: () => userBlockingAlice, selector: (user: misskey.entities.UserDetailed) => user.isBlocked },
+		{ label: 'ミュート中になっている', user: () => userMutedByAlice, selector: (user: misskey.entities.UserDetailed) => user.isMuted },
+		{ label: 'リノートミュート中になっている', user: () => userRnMutedByAlice, selector: (user: misskey.entities.UserDetailed) => user.isRenoteMuted },
+		{ label: 'フォローリクエスト中になっている', user: () => userFollowRequested, me: () => userFollowRequesting, selector: (user: misskey.entities.UserDetailed) => user.hasPendingFollowRequestFromYou },
+		{ label: 'フォローリクエストされている', user: () => userFollowRequesting, me: () => userFollowRequested, selector: (user: misskey.entities.UserDetailed) => user.hasPendingFollowRequestToYou },
 	] as const)('を取得することができ、$labelこと', async ({ user, me, selector, expected }) => {
 		const response = await successfulApiCall({ endpoint: 'users/show', parameters: { userId: user().id }, user: me?.() ?? alice });
-		assert.strictEqual(selector(response), (expected ?? ((): true => true))());
+		assert.strictEqual(selector(response as any), (expected ?? ((): true => true))());
 	});
 	test('を取得することができ、Publicなロールがセットされていること', async () => {
 		const response = await successfulApiCall({ endpoint: 'users/show', parameters: { userId: userRolePublic.id }, user: alice });
@@ -694,17 +674,18 @@ describe('ユーザー', () => {
 		assert.deepStrictEqual(response, expected);
 	});
 	test.each([
-		{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable },
-		{ label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice },
-		{ label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice },
-		{ label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice },
-		{ label: '承認制ユーザーが含まれる', user: (): User => userLocking },
-		{ label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
-		{ label: 'サスペンドユーザーが(モデレーターが見るときは)含まれる', user: (): User => userSuspended, me: (): User => root },
+		{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable },
+		{ label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice },
+		{ label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice },
+		{ label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice },
+		{ label: '承認制ユーザーが含まれる', user: () => userLocking },
+		{ label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
+		{ label: 'サスペンドユーザーが(モデレーターが見るときは)含まれる', user: () => userSuspended, me: () => root },
 		// BUG サスペンドユーザーを一般ユーザーから見るとrootユーザーが返ってくる
-		//{ label: 'サスペンドユーザーが(一般ユーザーが見るときは)含まれない', user: (): User => userSuspended, me: (): User => bob, excluded: true },
-		{ label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
-		{ label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
+		//{ label: 'サスペンドユーザーが(一般ユーザーが見るときは)含まれない', user: () => userSuspended, me: () => bob, excluded: true },
+		{ label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
+		{ label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
+		// @ts-expect-error excluded は上でコメントアウトされているので
 	] as const)('をID指定のリスト形式で取得することができ、結果に$label', async ({ user, me, excluded }) => {
 		const parameters = { userIds: [user().id] };
 		const response = await successfulApiCall({ endpoint: 'users/show', parameters, user: me?.() ?? alice });
@@ -729,15 +710,15 @@ describe('ユーザー', () => {
 		assert.deepStrictEqual(response, expected);
 	});
 	test.each([
-		{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable },
-		{ label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice },
-		{ label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice },
-		{ label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice },
-		{ label: '承認制ユーザーが含まれる', user: (): User => userLocking },
-		{ label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
-		{ label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true },
-		{ label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
-		{ label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
+		{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable },
+		{ label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice },
+		{ label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice },
+		{ label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice },
+		{ label: '承認制ユーザーが含まれる', user: () => userLocking },
+		{ label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
+		{ label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true },
+		{ label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
+		{ label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
 	] as const)('を検索することができ、結果に$labelが含まれる', async ({ user, excluded }) => {
 		const parameters = { query: user().username, limit: 1 };
 		const response = await successfulApiCall({ endpoint: 'users/search', parameters, user: alice });
@@ -751,30 +732,30 @@ describe('ユーザー', () => {
 	//#region ID指定検索(users/search-by-username-and-host)
 
 	test.each([
-		{ label: '自分', parameters: { username: 'alice' }, user: (): User[] => [alice] },
-		{ label: '自分かつusernameが大文字', parameters: { username: 'ALICE' }, user: (): User[] => [alice] },
-		{ label: 'ローカルのフォロイーでノートなし', parameters: { username: 'userFollowedByAlice' }, user: (): User[] => [userFollowedByAlice] },
-		{ label: 'ローカルでノートなしは検索に載らない', parameters: { username: 'userNoNote' }, user: (): User[] => [] },
-		{ label: 'ローカルの他人1', parameters: { username: 'bob' }, user: (): User[] => [bob] },
-		{ label: 'ローカルの他人2', parameters: { username: 'bob', host: null }, user: (): User[] => [bob] },
-		{ label: 'ローカルの他人3', parameters: { username: 'bob', host: '.' }, user: (): User[] => [bob] },
-		{ label: 'ローカル', parameters: { host: null, limit: 1 }, user: (): User[] => [userFollowedByAlice] },
-		{ label: 'ローカル', parameters: { host: '.', limit: 1 }, user: (): User[] => [userFollowedByAlice] },
+		{ label: '自分', parameters: { username: 'alice' }, user: () => [alice] },
+		{ label: '自分かつusernameが大文字', parameters: { username: 'ALICE' }, user: () => [alice] },
+		{ label: 'ローカルのフォロイーでノートなし', parameters: { username: 'userFollowedByAlice' }, user: () => [userFollowedByAlice] },
+		{ label: 'ローカルでノートなしは検索に載らない', parameters: { username: 'userNoNote' }, user: () => [] },
+		{ label: 'ローカルの他人1', parameters: { username: 'bob' }, user: () => [bob] },
+		{ label: 'ローカルの他人2', parameters: { username: 'bob', host: null }, user: () => [bob] },
+		{ label: 'ローカルの他人3', parameters: { username: 'bob', host: '.' }, user: () => [bob] },
+		{ label: 'ローカル', parameters: { host: null, limit: 1 }, user: () => [userFollowedByAlice] },
+		{ label: 'ローカル', parameters: { host: '.', limit: 1 }, user: () => [userFollowedByAlice] },
 	])('をID&ホスト指定で検索できる($label)', async ({ parameters, user }) => {
 		const response = await successfulApiCall({ endpoint: 'users/search-by-username-and-host', parameters, user: alice });
 		const expected = await Promise.all(user().map(u => show(u.id, alice)));
 		assert.deepStrictEqual(response, expected);
 	});
 	test.each([
-		{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable },
-		{ label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice },
-		{ label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice },
-		{ label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice },
-		{ label: '承認制ユーザーが含まれる', user: (): User => userLocking },
-		{ label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
-		{ label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true },
-		{ label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
-		{ label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
+		{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable },
+		{ label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice },
+		{ label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice },
+		{ label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice },
+		{ label: '承認制ユーザーが含まれる', user: () => userLocking },
+		{ label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
+		{ label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true },
+		{ label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
+		{ label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
 	] as const)('をID&ホスト指定で検索でき、結果に$label', async ({ user, excluded }) => {
 		const parameters = { username: user().username };
 		const response = await successfulApiCall({ endpoint: 'users/search-by-username-and-host', parameters, user: alice });
@@ -796,15 +777,15 @@ describe('ユーザー', () => {
 		assert.deepStrictEqual(response, expected);
 	});
 	test.each([
-		{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable },
-		{ label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice },
-		{ label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice },
-		{ label: 'ブロックしてきているユーザーが含まれない', user: (): User => userBlockingAlice, excluded: true },
-		{ label: '承認制ユーザーが含まれる', user: (): User => userLocking },
-		{ label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
-		//{ label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true },
-		{ label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
-		{ label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
+		{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable },
+		{ label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice },
+		{ label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice },
+		{ label: 'ブロックしてきているユーザーが含まれない', user: () => userBlockingAlice, excluded: true },
+		{ label: '承認制ユーザーが含まれる', user: () => userLocking },
+		{ label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
+		//{ label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true },
+		{ label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
+		{ label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
 	] as const)('がよくリプライをするユーザーのリストを取得でき、結果に$label', async ({ user, excluded }) => {
 		const replyTo = (await successfulApiCall({ endpoint: 'users/notes', parameters: { userId: user().id }, user: undefined }))[0];
 		await post(alice, { text: `@${user().username} test`, replyId: replyTo.id });
@@ -818,12 +799,12 @@ describe('ユーザー', () => {
 	//#region ハッシュタグ(hashtags/users)
 
 	test.each([
-		{ label: 'フォロワー昇順', sort: { sort: '+follower' }, selector: (u: UserDetailedNotMe): string => String(u.followersCount) },
-		{ label: 'フォロワー降順', sort: { sort: '-follower' }, selector: (u: UserDetailedNotMe): string => String(u.followersCount) },
-		{ label: '登録日時昇順', sort: { sort: '+createdAt' }, selector: (u: UserDetailedNotMe): string => u.createdAt },
-		{ label: '登録日時降順', sort: { sort: '-createdAt' }, selector: (u: UserDetailedNotMe): string => u.createdAt },
-		{ label: '投稿日時昇順', sort: { sort: '+updatedAt' }, selector: (u: UserDetailedNotMe): string => String(u.updatedAt) },
-		{ label: '投稿日時降順', sort: { sort: '-updatedAt' }, selector: (u: UserDetailedNotMe): string => String(u.updatedAt) },
+		{ label: 'フォロワー昇順', sort: { sort: '+follower' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.followersCount) },
+		{ label: 'フォロワー降順', sort: { sort: '-follower' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.followersCount) },
+		{ label: '登録日時昇順', sort: { sort: '+createdAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => u.createdAt },
+		{ label: '登録日時降順', sort: { sort: '-createdAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => u.createdAt },
+		{ label: '投稿日時昇順', sort: { sort: '+updatedAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.updatedAt) },
+		{ label: '投稿日時降順', sort: { sort: '-updatedAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.updatedAt) },
 	] as const)('をハッシュタグ指定で取得することができる($label)', async ({ sort, selector }) => {
 		const hashtag = 'test_hashtag';
 		await successfulApiCall({ endpoint: 'i/update', parameters: { description: `#${hashtag}` }, user: alice });
@@ -837,15 +818,15 @@ describe('ユーザー', () => {
 		assert.deepStrictEqual(response, expected);
 	});
 	test.each([
-		{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable },
-		{ label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice },
-		{ label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice },
-		{ label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice },
-		{ label: '承認制ユーザーが含まれる', user: (): User => userLocking },
-		{ label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
-		{ label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true },
-		{ label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
-		{ label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
+		{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable },
+		{ label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice },
+		{ label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice },
+		{ label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice },
+		{ label: '承認制ユーザーが含まれる', user: () => userLocking },
+		{ label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
+		{ label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true },
+		{ label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
+		{ label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
 	] as const)('をハッシュタグ指定で取得することができ、結果に$label', async ({ user, excluded }) => {
 		const hashtag = `user_test${user().username}`;
 		if (user() !== userSuspended) {
diff --git a/packages/backend/test/unit/AnnouncementService.ts b/packages/backend/test/unit/AnnouncementService.ts
index fc35837420..aa082ff2f2 100644
--- a/packages/backend/test/unit/AnnouncementService.ts
+++ b/packages/backend/test/unit/AnnouncementService.ts
@@ -51,7 +51,7 @@ describe('AnnouncementService', () => {
 
 	function createAnnouncement(data: Partial<MiAnnouncement & { createdAt: Date }> = {}) {
 		return announcementsRepository.insert({
-			id: genAidx(data.createdAt ?? new Date()),
+			id: genAidx(data.createdAt?.getTime() ?? Date.now()),
 			updatedAt: null,
 			title: 'Title',
 			text: 'Text',
diff --git a/packages/backend/test/unit/FetchInstanceMetadataService.ts b/packages/backend/test/unit/FetchInstanceMetadataService.ts
index e6e68ccd6d..510b84b680 100644
--- a/packages/backend/test/unit/FetchInstanceMetadataService.ts
+++ b/packages/backend/test/unit/FetchInstanceMetadataService.ts
@@ -19,8 +19,8 @@ import { DI } from '@/di-symbols.js';
 import type { TestingModule } from '@nestjs/testing';
 
 function mockRedis() {
-	const hash = {};
-	const set = jest.fn((key, value) => {
+	const hash = {} as any;
+	const set = jest.fn((key: string, value) => {
 		const ret = hash[key];
 		hash[key] = value;
 		return ret;
@@ -61,7 +61,7 @@ describe('FetchInstanceMetadataService', () => {
 
 		app.enableShutdownHooks();
 
-		fetchInstanceMetadataService = app.get<FetchInstanceMetadataService>(FetchInstanceMetadataService);
+		fetchInstanceMetadataService = app.get<FetchInstanceMetadataService>(FetchInstanceMetadataService) as jest.Mocked<FetchInstanceMetadataService>;
 		federatedInstanceService = app.get<FederatedInstanceService>(FederatedInstanceService) as jest.Mocked<FederatedInstanceService>;
 		redisClient = app.get<Redis>(DI.redis) as jest.Mocked<Redis>;
 		httpRequestService = app.get<HttpRequestService>(HttpRequestService) as jest.Mocked<HttpRequestService>;
@@ -74,11 +74,11 @@ describe('FetchInstanceMetadataService', () => {
 	test('Lock and update', async () => {
 		redisClient.set = mockRedis();
 		const now = Date.now();
-		federatedInstanceService.fetch.mockReturnValue({ infoUpdatedAt: { getTime: () => { return now - 10 * 1000 * 60 * 60 * 24; } } });
+		federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => { return now - 10 * 1000 * 60 * 60 * 24; } } } as any);
 		httpRequestService.getJson.mockImplementation(() => { throw Error(); });
 		const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
 		const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
-		await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' });
+		await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any);
 		expect(tryLockSpy).toHaveBeenCalledTimes(1);
 		expect(unlockSpy).toHaveBeenCalledTimes(1);
 		expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(1);
@@ -88,11 +88,11 @@ describe('FetchInstanceMetadataService', () => {
 	test('Lock and don\'t update', async () => {
 		redisClient.set = mockRedis();
 		const now = Date.now();
-		federatedInstanceService.fetch.mockReturnValue({ infoUpdatedAt: { getTime: () => now } });
+		federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => now } } as any);
 		httpRequestService.getJson.mockImplementation(() => { throw Error(); });
 		const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
 		const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
-		await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' });
+		await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any);
 		expect(tryLockSpy).toHaveBeenCalledTimes(1);
 		expect(unlockSpy).toHaveBeenCalledTimes(1);
 		expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(1);
@@ -101,12 +101,13 @@ describe('FetchInstanceMetadataService', () => {
 
 	test('Do nothing when lock not acquired', async () => {
 		redisClient.set = mockRedis();
-		federatedInstanceService.fetch.mockReturnValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } });
+		const now = Date.now();
+		federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } } as any);
 		httpRequestService.getJson.mockImplementation(() => { throw Error(); });
 		const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
 		const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
 		await fetchInstanceMetadataService.tryLock('example.com');
-		await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' });
+		await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any);
 		expect(tryLockSpy).toHaveBeenCalledTimes(2);
 		expect(unlockSpy).toHaveBeenCalledTimes(0);
 		expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(0);
diff --git a/packages/backend/test/unit/RoleService.ts b/packages/backend/test/unit/RoleService.ts
index fe5ad31597..19d03570e0 100644
--- a/packages/backend/test/unit/RoleService.ts
+++ b/packages/backend/test/unit/RoleService.ts
@@ -228,11 +228,14 @@ describe('RoleService', () => {
 				},
 				target: 'conditional',
 				condFormula: {
+					id: '232a4221-9816-49a6-a967-ae0fac52ec5e',
 					type: 'and',
 					values: [{
+						id: '2a37ef43-2d93-4c4d-87f6-f2fdb7d9b530',
 						type: 'followersMoreThanOrEq',
 						value: 10,
 					}, {
+						id: '1bd67839-b126-4f92-bad0-4e285dab453b',
 						type: 'createdMoreThan',
 						sec: 60 * 60 * 24 * 7,
 					}],
diff --git a/packages/backend/test/utils.ts b/packages/backend/test/utils.ts
index cd5dddd68d..86814fffe0 100644
--- a/packages/backend/test/utils.ts
+++ b/packages/backend/test/utils.ts
@@ -9,11 +9,10 @@ import { basename, isAbsolute } from 'node:path';
 import { randomUUID } from 'node:crypto';
 import { inspect } from 'node:util';
 import WebSocket, { ClientOptions } from 'ws';
-import fetch, { File, RequestInit } from 'node-fetch';
+import fetch, { File, RequestInit, type Headers } from 'node-fetch';
 import { DataSource } from 'typeorm';
 import { JSDOM } from 'jsdom';
 import { DEFAULT_POLICIES } from '@/core/RoleService.js';
-import { Packed } from '@/misc/json-schema.js';
 import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
 import { entities } from '../src/postgres.js';
 import { loadConfig } from '../src/config.js';
@@ -21,7 +20,7 @@ import type * as misskey from 'misskey-js';
 
 export { server as startServer, jobQueue as startJobQueue } from '@/boot/common.js';
 
-interface UserToken {
+export interface UserToken {
 	token: string;
 	bearer?: boolean;
 }
@@ -35,20 +34,15 @@ export const cookie = (me: UserToken): string => {
 	return `token=${me.token};`;
 };
 
-export const api = async (endpoint: string, params: any, me?: UserToken) => {
-	const normalized = endpoint.replace(/^\//, '');
-	return await request(`api/${normalized}`, params, me);
-};
-
-export type ApiRequest = {
-	endpoint: string,
-	parameters: object,
+export type ApiRequest<E extends keyof misskey.Endpoints, P extends misskey.Endpoints[E]['req'] = misskey.Endpoints[E]['req']> = {
+	endpoint: E,
+	parameters: P,
 	user: UserToken | undefined,
 };
 
-export const successfulApiCall = async <T, >(request: ApiRequest, assertion: {
+export const successfulApiCall = async <E extends keyof misskey.Endpoints, P extends misskey.Endpoints[E]['req']>(request: ApiRequest<E, P>, assertion: {
 	status?: number,
-} = {}): Promise<T> => {
+} = {}): Promise<misskey.api.SwitchCaseResponseType<E, P>> => {
 	const { endpoint, parameters, user } = request;
 	const res = await api(endpoint, parameters, user);
 	const status = assertion.status ?? (res.body == null ? 204 : 200);
@@ -56,7 +50,7 @@ export const successfulApiCall = async <T, >(request: ApiRequest, assertion: {
 	return res.body;
 };
 
-export const failedApiCall = async <T, >(request: ApiRequest, assertion: {
+export const failedApiCall = async <T, E extends keyof misskey.Endpoints, P extends misskey.Endpoints[E]['req']>(request: ApiRequest<E, P>, assertion: {
 	status: number,
 	code: string,
 	id: string
@@ -70,7 +64,7 @@ export const failedApiCall = async <T, >(request: ApiRequest, assertion: {
 	return res.body;
 };
 
-const request = async (path: string, params: any, me?: UserToken): Promise<{
+export const api = async <E extends keyof misskey.Endpoints>(path: E, params: misskey.Endpoints[E]['req'], me?: UserToken): Promise<{
 	status: number,
 	headers: Headers,
 	body: any
@@ -86,7 +80,7 @@ const request = async (path: string, params: any, me?: UserToken): Promise<{
 		bodyAuth.i = me.token;
 	}
 
-	const res = await relativeFetch(path, {
+	const res = await relativeFetch(`api/${path}`, {
 		method: 'POST',
 		headers,
 		body: JSON.stringify(Object.assign(bodyAuth, params)),
@@ -141,7 +135,7 @@ export const signup = async (params?: Partial<misskey.Endpoints['signup']['req']
 	return res.body;
 };
 
-export const post = async (user: UserToken, params?: misskey.Endpoints['notes/create']['req']): Promise<misskey.entities.Note> => {
+export const post = async (user: UserToken, params: misskey.Endpoints['notes/create']['req']): Promise<misskey.entities.Note> => {
 	const q = params;
 
 	const res = await api('notes/create', q, user);
@@ -159,8 +153,8 @@ export const createAppToken = async (user: UserToken, permissions: (typeof missk
 };
 
 // 非公開ノートをAPI越しに見たときのノート NoteEntityService.ts
-export const hiddenNote = (note: any): any => {
-	const temp = {
+export const hiddenNote = (note: misskey.entities.Note): misskey.entities.Note => {
+	const temp: misskey.entities.Note = {
 		...note,
 		fileIds: [],
 		files: [],
@@ -173,21 +167,22 @@ export const hiddenNote = (note: any): any => {
 	return temp;
 };
 
-export const react = async (user: UserToken, note: any, reaction: string): Promise<any> => {
+export const react = async (user: UserToken, note: misskey.entities.Note, reaction: string): Promise<void> => {
 	await api('notes/reactions/create', {
 		noteId: note.id,
 		reaction: reaction,
 	}, user);
 };
 
-export const userList = async (user: UserToken, userList: any = {}): Promise<any> => {
+export const userList = async (user: UserToken, userList: Partial<misskey.entities.UserList> = {}): Promise<misskey.entities.UserList> => {
 	const res = await api('users/lists/create', {
 		name: 'test',
+		...userList,
 	}, user);
 	return res.body;
 };
 
-export const page = async (user: UserToken, page: any = {}): Promise<any> => {
+export const page = async (user: UserToken, page: Partial<misskey.entities.Page> = {}): Promise<misskey.entities.Page> => {
 	const res = await api('pages/create', {
 		alignCenter: false,
 		content: [
@@ -198,7 +193,7 @@ export const page = async (user: UserToken, page: any = {}): Promise<any> => {
 			},
 		],
 		eyeCatchingImageId: null,
-		font: 'sans-serif',
+		font: 'sans-serif' as any,
 		hideTitleWhenPinned: false,
 		name: '1678594845072',
 		script: '',
@@ -210,7 +205,7 @@ export const page = async (user: UserToken, page: any = {}): Promise<any> => {
 	return res.body;
 };
 
-export const play = async (user: UserToken, play: any = {}): Promise<any> => {
+export const play = async (user: UserToken, play: Partial<misskey.entities.Flash> = {}): Promise<misskey.entities.Flash> => {
 	const res = await api('flash/create', {
 		permissions: [],
 		script: 'test',
@@ -221,7 +216,7 @@ export const play = async (user: UserToken, play: any = {}): Promise<any> => {
 	return res.body;
 };
 
-export const clip = async (user: UserToken, clip: any = {}): Promise<any> => {
+export const clip = async (user: UserToken, clip: Partial<misskey.entities.Clip> = {}): Promise<misskey.entities.Clip> => {
 	const res = await api('clips/create', {
 		description: null,
 		isPublic: true,
@@ -231,18 +226,18 @@ export const clip = async (user: UserToken, clip: any = {}): Promise<any> => {
 	return res.body;
 };
 
-export const galleryPost = async (user: UserToken, channel: any = {}): Promise<any> => {
+export const galleryPost = async (user: UserToken, galleryPost: Partial<misskey.entities.GalleryPost> = {}): Promise<misskey.entities.GalleryPost> => {
 	const res = await api('gallery/posts/create', {
 		description: null,
 		fileIds: [],
 		isSensitive: false,
 		title: 'test',
-		...channel,
+		...galleryPost,
 	}, user);
 	return res.body;
 };
 
-export const channel = async (user: UserToken, channel: any = {}): Promise<any> => {
+export const channel = async (user: UserToken, channel: Partial<misskey.entities.Channel> = {}): Promise<misskey.entities.Channel> => {
 	const res = await api('channels/create', {
 		bannerId: null,
 		description: null,
@@ -252,7 +247,7 @@ export const channel = async (user: UserToken, channel: any = {}): Promise<any>
 	return res.body;
 };
 
-export const role = async (user: UserToken, role: any = {}, policies: any = {}): Promise<any> => {
+export const role = async (user: UserToken, role: Partial<misskey.entities.Role> = {}, policies: any = {}): Promise<misskey.entities.Role> => {
 	const res = await api('admin/roles/create', {
 		asBadge: false,
 		canEditMembersByModerator: false,
@@ -260,7 +255,7 @@ export const role = async (user: UserToken, role: any = {}, policies: any = {}):
 		condFormula: {
 			id: 'ebef1684-672d-49b6-ad82-1b3ec3784f85',
 			type: 'isRemote',
-		},
+		} as any,
 		description: '',
 		displayOrder: 0,
 		iconUrl: null,
@@ -298,7 +293,7 @@ interface UploadOptions {
 export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadOptions = {}): Promise<{
 	status: number,
 	headers: Headers,
-	body: misskey.Endpoints['drive/files/create']['res'] | null
+	body: misskey.entities.DriveFile | null
 }> => {
 	const absPath = path == null
 		? new URL('resources/Lenna.jpg', import.meta.url)
@@ -335,14 +330,14 @@ export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadO
 	};
 };
 
-export const uploadUrl = async (user: UserToken, url: string): Promise<Packed<'DriveFile'>> => {
+export const uploadUrl = async (user: UserToken, url: string): Promise<misskey.entities.DriveFile> => {
 	const marker = Math.random().toString();
 
 	const catcher = makeStreamCatcher(
 		user,
 		'main',
 		(msg) => msg.type === 'urlUploadFinished' && msg.body.marker === marker,
-		(msg) => msg.body.file as Packed<'DriveFile'>,
+		(msg) => msg.body.file,
 		60 * 1000,
 	);
 

From 983480131bf6ac48b3834d334deb97a6b3f2f4f6 Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Mon, 4 Mar 2024 12:54:13 +0900
Subject: [PATCH 003/191] chore: Automated release (#13075)

* chore: Automated release

* follow
---
 .github/workflows/release-edit-with-push.yml |  40 ++++++
 .github/workflows/release-with-dispatch.yml  | 122 +++++++++++++++++++
 .github/workflows/release-with-ready.yml     |  38 ++++++
 3 files changed, 200 insertions(+)
 create mode 100644 .github/workflows/release-edit-with-push.yml
 create mode 100644 .github/workflows/release-with-dispatch.yml
 create mode 100644 .github/workflows/release-with-ready.yml

diff --git a/.github/workflows/release-edit-with-push.yml b/.github/workflows/release-edit-with-push.yml
new file mode 100644
index 0000000000..944b98eb7c
--- /dev/null
+++ b/.github/workflows/release-edit-with-push.yml
@@ -0,0 +1,40 @@
+name: "Release Manager: sync changelog with PR"
+
+on:
+  push:
+    branches:
+      - release/**
+    paths:
+      - 'CHANGELOG.md'
+
+env:
+  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+permissions:
+  contents: write
+  issues: write
+  pull-requests: write
+
+jobs:
+  edit:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      # headがrelease/かつopenのPRを1つ取得
+      - name: Get PR
+        run: |
+          echo "pr_number=$(gh pr list --limit 1 --head "${{ github.ref_name }}" --json number  --jq '.[] | .number')" >> $GITHUB_OUTPUT
+        id: get_pr
+      - name: Get target version
+        uses: misskey-dev/release-manager-actions/.github/actions/get-target-version@v1
+        id: v
+      # CHANGELOG.mdの内容を取得
+      - name: Get changelog
+        uses: misskey-dev/release-manager-actions/.github/actions/get-changelog@v1
+        with:
+          version: ${{ steps.v.outputs.target_version }}
+        id: changelog
+      # PRのnotesを更新
+      - name: Update PR
+        run: |
+          gh pr edit ${{ steps.get_pr.outputs.pr_number }} --body "${{ steps.changelog.outputs.changelog }}"
diff --git a/.github/workflows/release-with-dispatch.yml b/.github/workflows/release-with-dispatch.yml
new file mode 100644
index 0000000000..1a954739d9
--- /dev/null
+++ b/.github/workflows/release-with-dispatch.yml
@@ -0,0 +1,122 @@
+name: "Release Manager [Dispatch]"
+
+on:
+  workflow_dispatch:
+    inputs:
+      ## Specify the type of the next release.
+      #version_increment_type:
+      #  type: choice
+      #  description: 'VERSION INCREMENT TYPE'
+      #  default: 'patch'
+      #  required: false
+      #  options:
+      #    - 'major'
+      #    - 'minor'
+      #    - 'patch'
+      merge:
+        type: boolean
+        description: 'MERGE RELEASE BRANCH TO MAIN'
+        default: false
+
+env:
+  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+permissions:
+  contents: write
+  issues: write
+  pull-requests: write
+
+jobs:
+  get-pr:
+    runs-on: ubuntu-latest
+    outputs:
+      pr_number: ${{ steps.get_pr.outputs.pr_number }}
+    steps:
+      - uses: actions/checkout@v4
+      # headがrelease/かつopenのPRを1つ取得
+      - name: Get PRs
+        run: |
+          echo "pr_number=$(gh pr list --limit 1 --search "head:release/ is:open" --json number  --jq '.[] | .number')" >> $GITHUB_OUTPUT
+        id: get_pr
+
+  merge:
+    uses: misskey-dev/release-manager-actions/.github/workflows/merge.yml@v1
+    needs: get-pr
+    if: ${{ needs.get-pr.outputs.pr_number != '' && inputs.merge == true }}
+    with:
+      pr_number: ${{ needs.get-pr.outputs.pr_number }}
+      package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
+      # Text to prepend to the changelog
+      # The first line must be `## Unreleased`
+      changes_template: |
+        ## Unreleased
+
+        ### General
+        -
+
+        ### Client
+        -
+
+        ### Server
+        -
+
+      use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
+    secrets:
+      RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
+      RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
+      RULESET_EDIT_APP_ID: ${{ secrets.RULESET_EDIT_APP_ID }}
+      RULESET_EDIT_APP_PRIVATE_KEY: ${{ secrets.RULESET_EDIT_APP_PRIVATE_KEY }}
+
+  create-prerelease:
+    uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v1
+    needs: get-pr
+    if: ${{ needs.get-pr.outputs.pr_number != '' && inputs.merge != true  }}
+    with:
+      pr_number: ${{ needs.get-pr.outputs.pr_number }}
+      package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
+      use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
+    secrets:
+      RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
+      RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
+
+  create-target:
+    uses: misskey-dev/release-manager-actions/.github/workflows/create-target.yml@v1
+    needs: get-pr
+    if: ${{ needs.get-pr.outputs.pr_number == '' }}
+    with:
+      # The script for version increment.
+      # process.env.CURRENT_VERSION: The current version.
+      #
+      # Misskey calender versioning (yyyy.MM.patch) example
+      version_increment_script: |
+        const now = new Date();
+        const year = now.toLocaleDateString('en-US', { year: 'numeric', timeZone: 'Asia/Tokyo' });
+        const month = now.toLocaleDateString('en-US', { month: 'numeric', timeZone: 'Asia/Tokyo' });
+        const [major, minor, _patch] = process.env.CURRENT_VERSION.split('.');
+        const patch = Number(_patch.split('-')[0]);
+        if (Number.isNaN(patch)) {
+          console.error('Invalid patch version', year, month, process.env.CURRENT_VERSION, major, minor, _patch);
+          throw new Error('Invalid patch version');
+        }
+        if (year !== major || month !== minor) {
+          return `${year}.${month}.0`;
+        } else {
+          return `${major}.${minor}.${patch + 1}`;
+        }
+      ##Semver example
+      #version_increment_script: |
+      #  const [major, minor, patch] = process.env.CURRENT_VERSION.split('.');
+      #  if ("${{ inputs.version_increment_type }}" === "major") {
+      #    return `${Number(major) + 1}.0.0`;
+      #  } else if ("${{ inputs.version_increment_type }}" === "minor") {
+      #    return `${major}.${Number(minor) + 1}.0`;
+      #  } else {
+      #    return `${major}.${minor}.${Number(patch) + 1}`;
+      #  }
+      package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
+      use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
+    secrets:
+      RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
+      RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
+      RULESET_EDIT_APP_ID: ${{ secrets.RULESET_EDIT_APP_ID }}
+      RULESET_EDIT_APP_PRIVATE_KEY: ${{ secrets.RULESET_EDIT_APP_PRIVATE_KEY }}
diff --git a/.github/workflows/release-with-ready.yml b/.github/workflows/release-with-ready.yml
new file mode 100644
index 0000000000..b64ed20791
--- /dev/null
+++ b/.github/workflows/release-with-ready.yml
@@ -0,0 +1,38 @@
+name: "Release Manager: release RC when ready for review"
+
+on:
+  pull_request:
+    types: [ready_for_review]
+
+env:
+  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+permissions:
+  contents: write
+  issues: write
+  pull-requests: write
+
+jobs:
+  check:
+    runs-on: ubuntu-latest
+    outputs:
+      ref: ${{ steps.get_pr.outputs.ref }}
+    steps:
+      - uses: actions/checkout@v4
+      # PR情報を取得
+      - name: Get PR
+        run: |
+          pr_json=$(gh pr view ${{ github.event.pull_request.number }} --json isDraft,headRefName)
+          echo "ref=$(echo $pr_json | jq -r '.headRefName')" >> $GITHUB_OUTPUT
+        id: get_pr
+  release:
+    uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v1
+    needs: check
+    if: startsWith(needs.check.outputs.ref, 'release/')
+    with:
+      pr_number: ${{ github.event.pull_request.number }}
+      package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
+      use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
+    secrets:
+      RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
+      RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}

From 9542cb8d6253a93b06a68b9ac3647367f8f7354c Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Mon, 4 Mar 2024 13:48:57 +0900
Subject: [PATCH 004/191] =?UTF-8?q?fix(backend):=20=E3=83=AA=E3=83=A2?=
 =?UTF-8?q?=E3=83=BC=E3=83=88=E3=82=B5=E3=83=BC=E3=83=90=E3=83=BC=E3=81=AE?=
 =?UTF-8?q?=E6=83=85=E5=A0=B1=E3=81=8C=E6=9B=B4=E6=96=B0=E3=81=A7=E3=81=8D?=
 =?UTF-8?q?=E3=81=AA=E3=81=8F=E3=81=AA=E3=81=A3=E3=81=A6=E3=81=84=E3=81=9F?=
 =?UTF-8?q?=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3=20(#13507)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(backend): fetchInstanceMetadataのLockが永遠に解除されない問題を修正

Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com>

* fix test

* fix

* comment

* comment

* improve test

---------

Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com>
---
 .../src/core/FetchInstanceMetadataService.ts  | 28 ++++++++++++++-----
 .../test/unit/FetchInstanceMetadataService.ts | 24 ++++++++++++++--
 2 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/packages/backend/src/core/FetchInstanceMetadataService.ts b/packages/backend/src/core/FetchInstanceMetadataService.ts
index bc270bd28f..8d173855f3 100644
--- a/packages/backend/src/core/FetchInstanceMetadataService.ts
+++ b/packages/backend/src/core/FetchInstanceMetadataService.ts
@@ -51,21 +51,35 @@ export class FetchInstanceMetadataService {
 	}
 
 	@bindThis
-	public async tryLock(host: string): Promise<boolean> {
-		const mutex = await this.redisClient.set(`fetchInstanceMetadata:mutex:${host}`, '1', 'GET');
-		return mutex !== '1';
+	// public for test
+	public async tryLock(host: string): Promise<string | null> {
+		// TODO: マイグレーションなのであとで消す (2024.3.1)
+		this.redisClient.del(`fetchInstanceMetadata:mutex:${host}`);
+
+		return await this.redisClient.set(
+			`fetchInstanceMetadata:mutex:v2:${host}`, '1',
+			'EX', 30, // 30秒したら自動でロック解除 https://github.com/misskey-dev/misskey/issues/13506#issuecomment-1975375395
+			'GET' // 古い値を返す(なかったらnull)
+		);
 	}
 
 	@bindThis
-	public unlock(host: string): Promise<'OK'> {
-		return this.redisClient.set(`fetchInstanceMetadata:mutex:${host}`, '0');
+	// public for test
+	public unlock(host: string): Promise<number> {
+		return this.redisClient.del(`fetchInstanceMetadata:mutex:v2:${host}`);
 	}
 
 	@bindThis
 	public async fetchInstanceMetadata(instance: MiInstance, force = false): Promise<void> {
 		const host = instance.host;
-		// Acquire mutex to ensure no parallel runs
-		if (!await this.tryLock(host)) return;
+
+		// finallyでunlockされてしまうのでtry内でロックチェックをしない
+		// (returnであってもfinallyは実行される)
+		if (!force && await this.tryLock(host) === '1') {
+			// 1が返ってきていたらロックされているという意味なので、何もしない
+			return;
+		}
+
 		try {
 			if (!force) {
 				const _instance = await this.federatedInstanceService.fetch(host);
diff --git a/packages/backend/test/unit/FetchInstanceMetadataService.ts b/packages/backend/test/unit/FetchInstanceMetadataService.ts
index 510b84b680..bf8f3ab0e3 100644
--- a/packages/backend/test/unit/FetchInstanceMetadataService.ts
+++ b/packages/backend/test/unit/FetchInstanceMetadataService.ts
@@ -56,6 +56,7 @@ describe('FetchInstanceMetadataService', () => {
 				} else if (token === DI.redis) {
 					return mockRedis;
 				}
+				return null;
 			})
 			.compile();
 
@@ -78,6 +79,7 @@ describe('FetchInstanceMetadataService', () => {
 		httpRequestService.getJson.mockImplementation(() => { throw Error(); });
 		const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
 		const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
+
 		await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any);
 		expect(tryLockSpy).toHaveBeenCalledTimes(1);
 		expect(unlockSpy).toHaveBeenCalledTimes(1);
@@ -92,6 +94,7 @@ describe('FetchInstanceMetadataService', () => {
 		httpRequestService.getJson.mockImplementation(() => { throw Error(); });
 		const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
 		const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
+
 		await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any);
 		expect(tryLockSpy).toHaveBeenCalledTimes(1);
 		expect(unlockSpy).toHaveBeenCalledTimes(1);
@@ -104,13 +107,30 @@ describe('FetchInstanceMetadataService', () => {
 		const now = Date.now();
 		federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } } as any);
 		httpRequestService.getJson.mockImplementation(() => { throw Error(); });
+		await fetchInstanceMetadataService.tryLock('example.com');
 		const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
 		const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
-		await fetchInstanceMetadataService.tryLock('example.com');
+
 		await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any);
-		expect(tryLockSpy).toHaveBeenCalledTimes(2);
+		expect(tryLockSpy).toHaveBeenCalledTimes(1);
 		expect(unlockSpy).toHaveBeenCalledTimes(0);
 		expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(0);
 		expect(httpRequestService.getJson).toHaveBeenCalledTimes(0);
 	});
+
+	test('Do when lock not acquired but forced', async () => {
+		redisClient.set = mockRedis();
+		const now = Date.now();
+		federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } } as any);
+		httpRequestService.getJson.mockImplementation(() => { throw Error(); });
+		await fetchInstanceMetadataService.tryLock('example.com');
+		const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
+		const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
+
+		await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any, true);
+		expect(tryLockSpy).toHaveBeenCalledTimes(0);
+		expect(unlockSpy).toHaveBeenCalledTimes(1);
+		expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(0);
+		expect(httpRequestService.getJson).toHaveBeenCalled();
+	});
 });

From 96ab1af03b821ac265a1e8ff492c154b80e02759 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 4 Mar 2024 16:09:24 +0900
Subject: [PATCH 005/191] Update CHANGELOG.md

---
 CHANGELOG.md | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index bafee277d2..ca7bf85fd0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,17 @@
 
 -->
 
+## Unreleased
+
+### General
+-
+
+### Client
+- 
+
+### Server
+-
+
 ## 2024.3.1
 
 ### General

From 13f5fafdbc869207141f2a2f1f75f61c3147372d Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Mon, 4 Mar 2024 10:39:43 +0000
Subject: [PATCH 006/191] remove template txt

---
 CHANGELOG.md | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ca7bf85fd0..349e99d133 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,17 +1,3 @@
-<!--
-## 202x.x.x (unreleased)
-
-### General
--
-
-### Client
-- 
-
-### Server
--
-
--->
-
 ## Unreleased
 
 ### General

From 83a5bc0ecd05a352e164bda1f66f48962159c427 Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Tue, 5 Mar 2024 14:26:16 +0900
Subject: [PATCH 007/191] =?UTF-8?q?=20doc:=20Nest=E3=81=A7=E5=BE=AA?=
 =?UTF-8?q?=E7=92=B0=E4=BE=9D=E5=AD=98=E3=81=8C=E3=81=82=E3=82=8B=E5=A0=B4?=
 =?UTF-8?q?=E5=90=88=E3=81=AECONTRIBUTING.md=E3=81=AB=E6=9B=B8=E3=81=8F=20?=
 =?UTF-8?q?=20(#13522)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* doc: Nestモジュールテストの例をCONTRIBUTING.mdに書く

* rm normal test

* forwardRef
---
 CONTRIBUTING.md | 92 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a3263bf6aa..dcb625626d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -316,6 +316,98 @@ export const handlers = [
 
 Don't forget to re-run the `.storybook/generate.js` script after adding, editing, or removing the above files.
 
+## Nest
+
+### Nest Service Circular dependency / Nestでサービスの循環参照でエラーが起きた場合
+
+#### forwardRef
+まずは簡単に`forwardRef`を試してみる
+
+```typescript
+export class FooService {
+	constructor(
+		@Inject(forwardRef(() => BarService))
+		private barService: BarService
+	) {
+	}
+}
+```
+
+#### OnModuleInit
+できなければ`OnModuleInit`を使う
+
+```typescript
+import { Injectable, OnModuleInit } from '@nestjs/common';
+import { ModuleRef } from '@nestjs/core';
+import { BarService } from '@/core/BarService';
+
+@Injectable()
+export class FooService implements OnModuleInit {
+	private barService: BarService // constructorから移動してくる
+
+	constructor(
+		private moduleRef: ModuleRef,
+	) {
+	}
+
+	async onModuleInit() {
+		this.barService = this.moduleRef.get(BarService.name);
+	}
+
+	public async niceMethod() {
+		return await this.barService.incredibleMethod({ hoge: 'fuga' });
+	}
+}
+```
+
+##### Service Unit Test
+テストで`onModuleInit`を呼び出す必要がある
+
+```typescript
+// import ...
+
+describe('test', () => {
+	let app: TestingModule;
+	let fooService: FooService; // for test case
+	let barService: BarService; // for test case
+
+	beforeEach(async () => {
+		app = await Test.createTestingModule({
+			imports: ...,
+			providers: [
+				FooService,
+				{ // mockする (mockは必須ではないかもしれない)
+					provide: BarService,
+					useFactory: () => ({
+						incredibleMethod: jest.fn(),
+					}),
+				},
+				{ // Provideにする
+					provide: BarService.name,
+					useExisting: BarService,
+				},
+			],
+		})
+			.useMocker(...
+			.compile();
+	
+		fooService = app.get<FooService>(FooService);
+		barService = app.get<BarService>(BarService) as jest.Mocked<BarService>;
+
+		// onModuleInitを実行する
+		await fooService.onModuleInit();
+	});
+
+	test('nice', () => {
+		await fooService.niceMethod();
+
+		expect(barService.incredibleMethod).toHaveBeenCalled();
+		expect(barService.incredibleMethod.mock.lastCall![0])
+			.toEqual({ hoge: 'fuga' });
+	});
+})
+```
+
 ## Notes
 
 ### Misskeyのドメイン固有の概念は`Mi`をprefixする

From 45672a70f9f8fd932896468f9bfdc6c511013682 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Tue, 5 Mar 2024 17:27:33 +0900
Subject: [PATCH 008/191] =?UTF-8?q?fix(frontend):=20router=E9=81=B7?=
 =?UTF-8?q?=E7=A7=BB=E6=99=82=E3=81=ABmatchAll=E3=81=AB=E5=85=A5=E3=81=A3?=
 =?UTF-8?q?=E3=81=9F=E5=A0=B4=E5=90=88=E4=B8=80=E5=BA=A6`location.href`?=
 =?UTF-8?q?=E3=82=92=E7=B5=8C=E7=94=B1=E3=81=99=E3=82=8B=E3=82=88=E3=81=86?=
 =?UTF-8?q?=E3=81=AB=20(#13509)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(frontend): router遷移時にmatchAllに入った場合一度`location.href`を経由するように

* Update Changelog

* Update CHANGELOG.md

* remove unnecessary args
---
 CHANGELOG.md                               |  2 +-
 packages/frontend/src/nirax.ts             | 20 ++++++++++++--------
 packages/frontend/vite.config.local-dev.ts |  3 +++
 3 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 349e99d133..0cebaabffd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,7 @@
 -
 
 ### Client
-- 
+- Fix: 一部のページ内リンクが正しく動作しない問題を修正
 
 ### Server
 -
diff --git a/packages/frontend/src/nirax.ts b/packages/frontend/src/nirax.ts
index 616fb104e6..6a8ea09ed6 100644
--- a/packages/frontend/src/nirax.ts
+++ b/packages/frontend/src/nirax.ts
@@ -373,7 +373,7 @@ export class Router extends EventEmitter<RouterEvent> implements IRouter {
 		this.currentRoute.value = res.route;
 		this.currentKey = res.route.globalCacheKey ?? key ?? path;
 
-		if (emitChange) {
+		if (emitChange && res.route.path !== '/:(*)') {
 			this.emit('change', {
 				beforePath,
 				path,
@@ -408,13 +408,17 @@ export class Router extends EventEmitter<RouterEvent> implements IRouter {
 			if (cancel) return;
 		}
 		const res = this.navigate(path, null);
-		this.emit('push', {
-			beforePath,
-			path: res._parsedRoute.fullPath,
-			route: res.route,
-			props: res.props,
-			key: this.currentKey,
-		});
+		if (res.route.path === '/:(*)') {
+			location.href = path;
+		} else {
+			this.emit('push', {
+				beforePath,
+				path: res._parsedRoute.fullPath,
+				route: res.route,
+				props: res.props,
+				key: this.currentKey,
+			});
+		}
 	}
 
 	public replace(path: string, key?: string | null) {
diff --git a/packages/frontend/vite.config.local-dev.ts b/packages/frontend/vite.config.local-dev.ts
index 6d9488797c..460787fd05 100644
--- a/packages/frontend/vite.config.local-dev.ts
+++ b/packages/frontend/vite.config.local-dev.ts
@@ -48,6 +48,9 @@ const devConfig = {
 			},
 			'/url': httpUrl,
 			'/proxy': httpUrl,
+			'/_info_card_': httpUrl,
+			'/bios': httpUrl,
+			'/cli': httpUrl,
 		},
 	},
 	build: {

From 08d618bb8b98199a4670313019d6a85ad4cf155b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Tue, 5 Mar 2024 18:06:57 +0900
Subject: [PATCH 009/191] =?UTF-8?q?enhance(frontend):=20=E8=87=AA=E5=88=86?=
 =?UTF-8?q?=E3=81=AE=E3=83=8E=E3=83=BC=E3=83=88=E3=81=AE=E6=B7=BB=E4=BB=98?=
 =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=8B=E3=82=89=E7=9B=B4?=
 =?UTF-8?q?=E6=8E=A5=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=AE=E8=A9=B3?=
 =?UTF-8?q?=E7=B4=B0=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=AB=E9=A3=9B=E3=81=B9?=
 =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B=20(#1352?=
 =?UTF-8?q?0)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance(frontend): 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるようにする

* 他のファイルタイプにも対応

* Update Changelog

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 CHANGELOG.md                                      |  1 +
 .../src/core/entities/DriveFileEntityService.ts   |  2 +-
 packages/frontend/src/components/MkMediaAudio.vue | 15 ++++++++++++---
 packages/frontend/src/components/MkMediaImage.vue |  9 ++++++++-
 packages/frontend/src/components/MkMediaVideo.vue | 15 ++++++++++++---
 5 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0cebaabffd..1b90094279 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
 -
 
 ### Client
+- Enhance: 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるように
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 
 ### Server
diff --git a/packages/backend/src/core/entities/DriveFileEntityService.ts b/packages/backend/src/core/entities/DriveFileEntityService.ts
index 8affe2b3bf..26bf386cbc 100644
--- a/packages/backend/src/core/entities/DriveFileEntityService.ts
+++ b/packages/backend/src/core/entities/DriveFileEntityService.ts
@@ -248,7 +248,7 @@ export class DriveFileEntityService {
 			folder: opts.detail && file.folderId ? this.driveFolderEntityService.pack(file.folderId, {
 				detail: true,
 			}) : null,
-			userId: opts.withUser ? file.userId : null,
+			userId: file.userId,
 			user: (opts.withUser && file.userId) ? this.userEntityService.pack(file.userId) : null,
 		});
 	}
diff --git a/packages/frontend/src/components/MkMediaAudio.vue b/packages/frontend/src/components/MkMediaAudio.vue
index d42146f941..96c9b9fd66 100644
--- a/packages/frontend/src/components/MkMediaAudio.vue
+++ b/packages/frontend/src/components/MkMediaAudio.vue
@@ -66,7 +66,7 @@ import * as os from '@/os.js';
 import bytes from '@/filters/bytes.js';
 import { hms } from '@/filters/hms.js';
 import MkMediaRange from '@/components/MkMediaRange.vue';
-import { iAmModerator } from '@/account.js';
+import { $i, iAmModerator } from '@/account.js';
 
 const props = defineProps<{
 	audio: Misskey.entities.DriveFile;
@@ -96,8 +96,6 @@ function showMenu(ev: MouseEvent) {
 
 	if (iAmModerator) {
 		menu.push({
-			type: 'divider',
-		}, {
 			text: props.audio.isSensitive ? i18n.ts.unmarkAsSensitive : i18n.ts.markAsSensitive,
 			icon: props.audio.isSensitive ? 'ti ti-eye' : 'ti ti-eye-exclamation',
 			danger: true,
@@ -105,6 +103,17 @@ function showMenu(ev: MouseEvent) {
 		});
 	}
 
+	if ($i?.id === props.audio.userId) {
+		menu.push({
+			type: 'divider',
+		}, {
+			type: 'link' as const,
+			text: i18n.ts._fileViewer.title,
+			icon: 'ti ti-info-circle',
+			to: `/my/drive/file/${props.audio.id}`,
+		});
+	}
+
 	menuShowing.value = true;
 	os.popupMenu(menu, ev.currentTarget ?? ev.target, {
 		align: 'right',
diff --git a/packages/frontend/src/components/MkMediaImage.vue b/packages/frontend/src/components/MkMediaImage.vue
index 4ba2c76133..82f36fe5c4 100644
--- a/packages/frontend/src/components/MkMediaImage.vue
+++ b/packages/frontend/src/components/MkMediaImage.vue
@@ -59,7 +59,7 @@ import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
 import { defaultStore } from '@/store.js';
 import { i18n } from '@/i18n.js';
 import * as os from '@/os.js';
-import { iAmModerator } from '@/account.js';
+import { $i, iAmModerator } from '@/account.js';
 
 const props = withDefaults(defineProps<{
 	image: Misskey.entities.DriveFile;
@@ -114,6 +114,13 @@ function showMenu(ev: MouseEvent) {
 		action: () => {
 			os.apiWithDialog('drive/files/update', { fileId: props.image.id, isSensitive: true });
 		},
+	}] : []), ...($i?.id === props.image.userId ? [{
+		type: 'divider' as const,
+	}, {
+		type: 'link' as const,
+		text: i18n.ts._fileViewer.title,
+		icon: 'ti ti-info-circle',
+		to: `/my/drive/file/${props.image.id}`,
 	}] : [])], ev.currentTarget ?? ev.target);
 }
 
diff --git a/packages/frontend/src/components/MkMediaVideo.vue b/packages/frontend/src/components/MkMediaVideo.vue
index eab4fdfd6b..73c1b6ff9d 100644
--- a/packages/frontend/src/components/MkMediaVideo.vue
+++ b/packages/frontend/src/components/MkMediaVideo.vue
@@ -94,7 +94,7 @@ import * as os from '@/os.js';
 import { isFullscreenNotSupported } from '@/scripts/device-kind.js';
 import hasAudio from '@/scripts/media-has-audio.js';
 import MkMediaRange from '@/components/MkMediaRange.vue';
-import { iAmModerator } from '@/account.js';
+import { $i, iAmModerator } from '@/account.js';
 
 const props = defineProps<{
 	video: Misskey.entities.DriveFile;
@@ -122,8 +122,6 @@ function showMenu(ev: MouseEvent) {
 
 	if (iAmModerator) {
 		menu.push({
-			type: 'divider',
-		}, {
 			text: props.video.isSensitive ? i18n.ts.unmarkAsSensitive : i18n.ts.markAsSensitive,
 			icon: props.video.isSensitive ? 'ti ti-eye' : 'ti ti-eye-exclamation',
 			danger: true,
@@ -131,6 +129,17 @@ function showMenu(ev: MouseEvent) {
 		});
 	}
 
+	if ($i?.id === props.video.userId) {
+		menu.push({
+			type: 'divider',
+		}, {
+			type: 'link' as const,
+			text: i18n.ts._fileViewer.title,
+			icon: 'ti ti-info-circle',
+			to: `/my/drive/file/${props.video.id}`,
+		});
+	}
+
 	menuShowing.value = true;
 	os.popupMenu(menu, ev.currentTarget ?? ev.target, {
 		align: 'right',

From 4457b02db2ca7591afa8683141e4b223170ea367 Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Wed, 6 Mar 2024 08:08:32 +0000
Subject: [PATCH 010/191] =?UTF-8?q?fix(frontend)=3F:=20importAppScript?=
 =?UTF-8?q?=E3=81=AFimport=E3=82=92await=E3=81=99=E3=82=8B=E3=82=88?=
 =?UTF-8?q?=E3=81=86=E3=81=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 packages/backend/src/server/web/boot.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js
index 59441826b0..396536948e 100644
--- a/packages/backend/src/server/web/boot.js
+++ b/packages/backend/src/server/web/boot.js
@@ -86,8 +86,8 @@
 	//#endregion
 
 	//#region Script
-	function importAppScript() {
-		import(`/vite/${CLIENT_ENTRY}`)
+	async function importAppScript() {
+		await import(`/vite/${CLIENT_ENTRY}`)
 			.catch(async e => {
 				console.error(e);
 				renderError('APP_IMPORT', e);

From 00c1e4eb550c68f43ae44ba9f0c8da9887fc2180 Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Wed, 6 Mar 2024 09:40:47 +0000
Subject: [PATCH 011/191] =?UTF-8?q?perf:=20boot.js=E3=81=AE=E8=AA=BF?=
 =?UTF-8?q?=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 packages/backend/src/server/web/boot.js | 525 ++++++++++++++----------
 1 file changed, 300 insertions(+), 225 deletions(-)

diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js
index 396536948e..bc7b800d22 100644
--- a/packages/backend/src/server/web/boot.js
+++ b/packages/backend/src/server/web/boot.js
@@ -7,17 +7,257 @@
  * BOOT LOADER
  * サーバーからレスポンスされるHTMLに埋め込まれるスクリプトで、以下の役割を持ちます。
  * - 翻訳ファイルをフェッチする。
- * - バージョンに基づいて適切なメインスクリプトを読み込む。
+ * - 事前に挿入されたCLIENT_ENTRYを読んで適切なメインスクリプトを読み込む。
  * - キャッシュされたコンパイル済みテーマを適用する。
  * - クライアントの設定値に基づいて対応するHTMLクラス等を設定する。
+ * - もしメインスクリプトの読み込みなどでエラーが発生した場合は、renderErrorでエラーを描画する。
  * テーマをこの段階で設定するのは、メインスクリプトが読み込まれる間もテーマを適用したいためです。
- * 注: webpackは介さないため、このファイルではrequireやimportは使えません。
  */
 
 'use strict';
 
+var misskey_loader = new Set();
+
 // ブロックの中に入れないと、定義した変数がブラウザのグローバルスコープに登録されてしまい邪魔なので
-(async () => {
+function boot() {
+	const defaultSolutions = [
+		'Clear the browser cache / ブラウザのキャッシュをクリアする',
+		'Update your os and browser / ブラウザおよびOSを最新バージョンに更新する',
+		'Disable an adblocker / アドブロッカーを無効にする',
+		'&#40;Tor Browser&#41; Set dom.webaudio.enabled to true / dom.webaudio.enabledをtrueに設定する'
+	];
+
+	const onErrorStyle = `
+	* {
+		font-family: BIZ UDGothic, Roboto, HelveticaNeue, Arial, sans-serif;
+	}
+
+	#misskey_app,
+	#splash {
+		display: none !important;
+	}
+
+	body,
+	html {
+		background-color: #222;
+		color: #dfddcc;
+		justify-content: center;
+		margin: auto;
+		padding: 10px;
+		text-align: center;
+	}
+
+	button {
+		border-radius: 999px;
+		padding: 0px 12px 0px 12px;
+		border: none;
+		cursor: pointer;
+		margin-bottom: 12px;
+	}
+
+	.button-big {
+		background: linear-gradient(90deg, rgb(134, 179, 0), rgb(74, 179, 0));
+		line-height: 50px;
+	}
+
+	.button-big:hover {
+		background: rgb(153, 204, 0);
+	}
+
+	.button-small {
+		background: #444;
+		line-height: 40px;
+	}
+
+	.button-small:hover {
+		background: #555;
+	}
+
+	.button-label-big {
+		color: #222;
+		font-weight: bold;
+		font-size: 1.2em;
+		padding: 12px;
+	}
+
+	.button-label-small {
+		color: rgb(153, 204, 0);
+		font-size: 16px;
+		padding: 12px;
+	}
+
+	a {
+		color: rgb(134, 179, 0);
+		text-decoration: none;
+	}
+
+	p,
+	li {
+		font-size: 16px;
+	}
+
+	.icon-warning {
+		color: #dec340;
+		height: 4rem;
+		padding-top: 2rem;
+	}
+
+	h1 {
+		font-size: 1.5em;
+		margin: 1em;
+	}
+
+	summary {
+		cursor: pointer;
+	}
+
+	code {
+		font-family: Fira, FiraCode, monospace;
+	}
+
+	#errors {
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+	}
+
+	.errorInfo {
+		background: #333;
+		width: 40rem;
+		max-width: 100%;
+		border-radius: 10px;
+		justify-content: center;
+		padding: 1rem;
+		margin-bottom: 1rem;
+		box-sizing: border-box;
+	}
+
+	.errorInfo > pre {
+		text-wrap: auto;
+		text-wrap: balance;
+	}
+	`;
+
+
+	const addStyle = (styleText) => {
+		try {
+			let css = document.createElement('style');
+			css.appendChild(document.createTextNode(styleText));
+			document.head.appendChild(css);
+		} catch (e) {
+			console.error(e);
+		}
+	}
+
+	const renderError = (code, details, solutions = defaultSolutions) => {
+		if (document.readyState === 'loading') {
+			window.addEventListener('DOMContentLoaded', () => {
+				renderError(code, details, solutions);
+			});
+			try {
+				addStyle(onErrorStyle);
+			} catch (e) { }
+			return;
+		}
+
+		let errorsElement = document.getElementById('errors');
+
+		if (!errorsElement) {
+			// エラー描画用のビューになっていない場合は、エラー描画用のビューに切り替える
+			document.body.innerHTML = `
+			<svg class="icon-warning" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-alert-triangle" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+				<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
+				<path d="M12 9v2m0 4v.01"></path>
+				<path d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75"></path>
+			</svg>
+			<h1>Failed to load<br>読み込みに失敗しました</h1>
+			<button class="button-big" onclick="location.reload(true);">
+				<span class="button-label-big">Reload / リロード</span>
+			</button>
+			<p><b>The following actions may solve the problem. / 以下を行うと解決する可能性があります。</b></p>
+			${solutions.map(x => `<p>${x}</p>`).join('')}
+			<details style="color: #86b300;">
+				<summary>Other options / その他のオプション</summary>
+				<a href="/flush">
+					<button class="button-small">
+						<span class="button-label-small">Clear preferences and cache</span>
+					</button>
+				</a>
+				<br>
+				<a href="/cli">
+					<button class="button-small">
+						<span class="button-label-small">Start the simple client</span>
+					</button>
+				</a>
+				<br>
+				<a href="/bios">
+					<button class="button-small">
+						<span class="button-label-small">Start the repair tool</span>
+					</button>
+				</a>
+			</details>
+			<br>
+			<div id="errors"></div>
+			`;
+			errorsElement = document.getElementById('errors');
+		}
+
+		if (typeof details === 'string') {
+			const errorEl = document.createElement('div');
+			errorEl.classList.add('errorInfo');
+
+			const titleCodeElement = document.createElement('code');
+			titleCodeElement.textContent = `ERROR CODE: ${code}`;
+			errorEl.appendChild(titleCodeElement);
+
+			errorEl.appendChild(document.createElement('br'));
+
+			const detailsCodeElement = document.createElement('code');
+			detailsCodeElement.textContent = details;
+			errorEl.appendChild(detailsCodeElement);
+
+			errorsElement.appendChild(errorEl);
+		} else if (details instanceof Error) {
+			const errorEl = document.createElement('details');
+			errorEl.classList.add('errorInfo');
+
+			const summaryElement = document.createElement('summary');
+			const titleCodeElement = document.createElement('code');
+			titleCodeElement.textContent = `ERROR CODE: ${code}`;
+			summaryElement.appendChild(titleCodeElement);
+			errorEl.appendChild(summaryElement);
+
+			const detailsPreElement = document.createElement('pre');
+			const detailsMessageElement = document.createElement('code');
+			detailsMessageElement.textContent = details.message;
+			detailsPreElement.appendChild(detailsMessageElement);
+			detailsPreElement.appendChild(document.createElement('br'));
+			const detailsCodeElement = document.createElement('code');
+			detailsCodeElement.textContent = details.stack;
+			detailsPreElement.appendChild(detailsCodeElement);
+			errorEl.appendChild(detailsPreElement);
+
+			errorsElement.appendChild(errorEl);
+		} else {
+			const errorEl = document.createElement('details');
+			errorEl.classList.add('errorInfo');
+
+			const summaryElement = document.createElement('summary');
+			const titleCodeElement = document.createElement('code');
+			titleCodeElement.textContent = `ERROR CODE: ${code}`;
+			summaryElement.appendChild(titleCodeElement);
+			errorEl.appendChild(summaryElement);
+
+			const detailsCodeElement = document.createElement('code');
+			detailsCodeElement.textContent = JSON.stringify(details);
+			errorEl.appendChild(detailsCodeElement);
+
+			errorsElement.appendChild(errorEl);
+		}
+
+		addStyle(onErrorStyle);
+	}
+
 	window.onerror = (e) => {
 		console.error(e);
 		renderError('SOMETHING_HAPPENED', e);
@@ -30,63 +270,65 @@
 	let forceError = localStorage.getItem('forceError');
 	if (forceError != null) {
 		renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.')
+		renderError('FORCED_ERROR', Error('This error is forced by having forceError in local storage.'));
+		return;
 	}
 
-	//#region Detect language & fetch translations
-	if (!localStorage.hasOwnProperty('locale')) {
-		const supportedLangs = LANGS;
-		let lang = localStorage.getItem('lang');
-		if (lang == null || !supportedLangs.includes(lang)) {
-			if (supportedLangs.includes(navigator.language)) {
-				lang = navigator.language;
-			} else {
-				lang = supportedLangs.find(x => x.split('-')[0] === navigator.language);
+	//#region After DOM loaded
+	async function oncontentload() {
+		const providedMetaEl = document.getElementById('misskey_meta');
+		const meta = providedMetaEl && providedMetaEl.textContent ? JSON.parse(providedMetaEl.textContent) : null;
+		const providedAt = providedMetaEl && providedMetaEl.dataset.generatedAt ? parseInt(providedMetaEl.dataset.generatedAt) : 0;
+		console.log('providedAt', providedAt, 'now', Date.now());
+		if (providedAt < Date.now() - 1000 * 60 * 60 * 24) {
+			// 古いデータがなぜか提供された場合は、エラーを描画する
+			renderError(
+				'META_PROVIDED_AT_TOO_OLD',
+				'This view is too old. Please reload.',
+				[
+					'Reload / リロードする',
+					'Clear the browser cache then reload / ブラウザのキャッシュをクリアしてリロードする',
+					'Disable an adblocker / アドブロッカーを無効にする',
+				]
+			);
+			return;
+		}
 
-				// Fallback
-				if (lang == null) lang = 'en-US';
+		//#region Detect language & fetch translations on first load
+		if (!localStorage.hasOwnProperty('locale')) {
+			const supportedLangs = LANGS;
+			let lang = localStorage.getItem('lang');
+			if (lang == null || !supportedLangs.includes(lang)) {
+				if (supportedLangs.includes(navigator.language)) {
+					lang = navigator.language;
+				} else {
+					lang = supportedLangs.find(x => x.split('-')[0] === navigator.language);
+
+					// Fallback
+					if (lang == null) lang = 'en-US';
+				}
+			}
+
+			const v = meta?.version;
+
+			// for https://github.com/misskey-dev/misskey/issues/10202
+			if (lang == null || lang.toString == null || lang.toString() === 'null') {
+				console.warn('invalid lang value detected!!!', typeof lang, lang);
+				lang = 'en-US';
+			}
+
+			const localRes = await window.fetch(`/assets/locales/${lang}.${v}.json`);
+			if (localRes.status === 200) {
+				localStorage.setItem('lang', lang);
+				localStorage.setItem('locale', await localRes.text());
+				localStorage.setItem('localeVersion', v);
+			} else {
+				renderError('LOCALE_FETCH');
+				return;
 			}
 		}
+		//#endregion
 
-		const metaRes = await window.fetch('/api/meta', {
-			method: 'POST',
-			body: JSON.stringify({}),
-			credentials: 'omit',
-			cache: 'no-cache',
-			headers: {
-				'Content-Type': 'application/json',
-			},
-		});
-		if (metaRes.status !== 200) {
-			renderError('META_FETCH');
-			return;
-		}
-		const meta = await metaRes.json();
-		const v = meta.version;
-		if (v == null) {
-			renderError('META_FETCH_V');
-			return;
-		}
-
-		// for https://github.com/misskey-dev/misskey/issues/10202
-		if (lang == null || lang.toString == null || lang.toString() === 'null') {
-			console.error('invalid lang value detected!!!', typeof lang, lang);
-			lang = 'en-US';
-		}
-
-		const localRes = await window.fetch(`/assets/locales/${lang}.${v}.json`);
-		if (localRes.status === 200) {
-			localStorage.setItem('lang', lang);
-			localStorage.setItem('locale', await localRes.text());
-			localStorage.setItem('localeVersion', v);
-		} else {
-			renderError('LOCALE_FETCH');
-			return;
-		}
-	}
-	//#endregion
-
-	//#region Script
-	async function importAppScript() {
 		await import(`/vite/${CLIENT_ENTRY}`)
 			.catch(async e => {
 				console.error(e);
@@ -94,12 +336,11 @@
 			});
 	}
 
-	// タイミングによっては、この時点でDOMの構築が済んでいる場合とそうでない場合とがある
 	if (document.readyState !== 'loading') {
-		importAppScript();
+		misskey_loader.add(oncontentload());
 	} else {
 		window.addEventListener('DOMContentLoaded', () => {
-			importAppScript();
+			misskey_loader.add(oncontentload());
 		});
 	}
 	//#endregion
@@ -148,172 +389,6 @@
 		style.innerHTML = customCss;
 		document.head.appendChild(style);
 	}
+}
 
-	async function addStyle(styleText) {
-		let css = document.createElement('style');
-		css.appendChild(document.createTextNode(styleText));
-		document.head.appendChild(css);
-	}
-
-	function renderError(code, details) {
-		let errorsElement = document.getElementById('errors');
-
-		if (!errorsElement) {
-			document.body.innerHTML = `
-			<svg class="icon-warning" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-alert-triangle" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
-				<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
-				<path d="M12 9v2m0 4v.01"></path>
-				<path d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75"></path>
-			</svg>
-			<h1>Failed to load<br>読み込みに失敗しました</h1>
-			<button class="button-big" onclick="location.reload(true);">
-				<span class="button-label-big">Reload / リロード</span>
-			</button>
-			<p><b>The following actions may solve the problem. / 以下を行うと解決する可能性があります。</b></p>
-			<p>Clear the browser cache / ブラウザのキャッシュをクリアする</p>
-			<p>Update your os and browser / ブラウザおよびOSを最新バージョンに更新する</p>
-			<p>Disable an adblocker / アドブロッカーを無効にする</p>
-	 		<p>&#40;Tor Browser&#41; Set dom.webaudio.enabled to true / dom.webaudio.enabledをtrueに設定する</p>
-			<details style="color: #86b300;">
-				<summary>Other options / その他のオプション</summary>
-				<a href="/flush">
-					<button class="button-small">
-						<span class="button-label-small">Clear preferences and cache</span>
-					</button>
-				</a>
-				<br>
-				<a href="/cli">
-					<button class="button-small">
-						<span class="button-label-small">Start the simple client</span>
-					</button>
-				</a>
-				<br>
-				<a href="/bios">
-					<button class="button-small">
-						<span class="button-label-small">Start the repair tool</span>
-					</button>
-				</a>
-			</details>
-			<br>
-			<div id="errors"></div>
-			`;
-			errorsElement = document.getElementById('errors');
-		}
-		const detailsElement = document.createElement('details');
-		detailsElement.id = 'errorInfo';
-		detailsElement.innerHTML = `
-		<br>
-		<summary>
-			<code>ERROR CODE: ${code}</code>
-		</summary>
-		<code>${JSON.stringify(details)}</code>`;
-		errorsElement.appendChild(detailsElement);
-		addStyle(`
-		* {
-			font-family: BIZ UDGothic, Roboto, HelveticaNeue, Arial, sans-serif;
-		}
-
-		#misskey_app,
-		#splash {
-			display: none !important;
-		}
-
-		body,
-		html {
-			background-color: #222;
-			color: #dfddcc;
-			justify-content: center;
-			margin: auto;
-			padding: 10px;
-			text-align: center;
-		}
-
-		button {
-			border-radius: 999px;
-			padding: 0px 12px 0px 12px;
-			border: none;
-			cursor: pointer;
-			margin-bottom: 12px;
-		}
-
-		.button-big {
-			background: linear-gradient(90deg, rgb(134, 179, 0), rgb(74, 179, 0));
-			line-height: 50px;
-		}
-
-		.button-big:hover {
-			background: rgb(153, 204, 0);
-		}
-
-		.button-small {
-			background: #444;
-			line-height: 40px;
-		}
-
-		.button-small:hover {
-			background: #555;
-		}
-
-		.button-label-big {
-			color: #222;
-			font-weight: bold;
-			font-size: 1.2em;
-			padding: 12px;
-		}
-
-		.button-label-small {
-			color: rgb(153, 204, 0);
-			font-size: 16px;
-			padding: 12px;
-		}
-
-		a {
-			color: rgb(134, 179, 0);
-			text-decoration: none;
-		}
-
-		p,
-		li {
-			font-size: 16px;
-		}
-
-		.icon-warning {
-			color: #dec340;
-			height: 4rem;
-			padding-top: 2rem;
-		}
-
-		h1 {
-			font-size: 1.5em;
-			margin: 1em;
-		}
-
-		code {
-			font-family: Fira, FiraCode, monospace;
-		}
-
-		#errorInfo {
-			background: #333;
-			margin-bottom: 2rem;
-			padding: 0.5rem 1rem;
-			width: 40rem;
-			border-radius: 10px;
-			justify-content: center;
-			margin: auto;
-		}
-
-		#errorInfo summary {
-			cursor: pointer;
-		}
-
-		#errorInfo summary > * {
-			display: inline;
-		}
-
-		@media screen and (max-width: 500px) {
-			#errorInfo {
-				width: 50%;
-			}
-		`)
-	}
-})();
+boot();

From 62922352b3cddaee9f72261448d862002e55a67c Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Wed, 6 Mar 2024 09:49:01 +0000
Subject: [PATCH 012/191] =?UTF-8?q?Revert=20"perf:=20boot.js=E3=81=AE?=
 =?UTF-8?q?=E8=AA=BF=E6=95=B4"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This reverts commit 00c1e4eb550c68f43ae44ba9f0c8da9887fc2180.
---
 packages/backend/src/server/web/boot.js | 523 ++++++++++--------------
 1 file changed, 224 insertions(+), 299 deletions(-)

diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js
index bc7b800d22..396536948e 100644
--- a/packages/backend/src/server/web/boot.js
+++ b/packages/backend/src/server/web/boot.js
@@ -7,257 +7,17 @@
  * BOOT LOADER
  * サーバーからレスポンスされるHTMLに埋め込まれるスクリプトで、以下の役割を持ちます。
  * - 翻訳ファイルをフェッチする。
- * - 事前に挿入されたCLIENT_ENTRYを読んで適切なメインスクリプトを読み込む。
+ * - バージョンに基づいて適切なメインスクリプトを読み込む。
  * - キャッシュされたコンパイル済みテーマを適用する。
  * - クライアントの設定値に基づいて対応するHTMLクラス等を設定する。
- * - もしメインスクリプトの読み込みなどでエラーが発生した場合は、renderErrorでエラーを描画する。
  * テーマをこの段階で設定するのは、メインスクリプトが読み込まれる間もテーマを適用したいためです。
+ * 注: webpackは介さないため、このファイルではrequireやimportは使えません。
  */
 
 'use strict';
 
-var misskey_loader = new Set();
-
 // ブロックの中に入れないと、定義した変数がブラウザのグローバルスコープに登録されてしまい邪魔なので
-function boot() {
-	const defaultSolutions = [
-		'Clear the browser cache / ブラウザのキャッシュをクリアする',
-		'Update your os and browser / ブラウザおよびOSを最新バージョンに更新する',
-		'Disable an adblocker / アドブロッカーを無効にする',
-		'&#40;Tor Browser&#41; Set dom.webaudio.enabled to true / dom.webaudio.enabledをtrueに設定する'
-	];
-
-	const onErrorStyle = `
-	* {
-		font-family: BIZ UDGothic, Roboto, HelveticaNeue, Arial, sans-serif;
-	}
-
-	#misskey_app,
-	#splash {
-		display: none !important;
-	}
-
-	body,
-	html {
-		background-color: #222;
-		color: #dfddcc;
-		justify-content: center;
-		margin: auto;
-		padding: 10px;
-		text-align: center;
-	}
-
-	button {
-		border-radius: 999px;
-		padding: 0px 12px 0px 12px;
-		border: none;
-		cursor: pointer;
-		margin-bottom: 12px;
-	}
-
-	.button-big {
-		background: linear-gradient(90deg, rgb(134, 179, 0), rgb(74, 179, 0));
-		line-height: 50px;
-	}
-
-	.button-big:hover {
-		background: rgb(153, 204, 0);
-	}
-
-	.button-small {
-		background: #444;
-		line-height: 40px;
-	}
-
-	.button-small:hover {
-		background: #555;
-	}
-
-	.button-label-big {
-		color: #222;
-		font-weight: bold;
-		font-size: 1.2em;
-		padding: 12px;
-	}
-
-	.button-label-small {
-		color: rgb(153, 204, 0);
-		font-size: 16px;
-		padding: 12px;
-	}
-
-	a {
-		color: rgb(134, 179, 0);
-		text-decoration: none;
-	}
-
-	p,
-	li {
-		font-size: 16px;
-	}
-
-	.icon-warning {
-		color: #dec340;
-		height: 4rem;
-		padding-top: 2rem;
-	}
-
-	h1 {
-		font-size: 1.5em;
-		margin: 1em;
-	}
-
-	summary {
-		cursor: pointer;
-	}
-
-	code {
-		font-family: Fira, FiraCode, monospace;
-	}
-
-	#errors {
-		display: flex;
-		flex-direction: column;
-		align-items: center;
-	}
-
-	.errorInfo {
-		background: #333;
-		width: 40rem;
-		max-width: 100%;
-		border-radius: 10px;
-		justify-content: center;
-		padding: 1rem;
-		margin-bottom: 1rem;
-		box-sizing: border-box;
-	}
-
-	.errorInfo > pre {
-		text-wrap: auto;
-		text-wrap: balance;
-	}
-	`;
-
-
-	const addStyle = (styleText) => {
-		try {
-			let css = document.createElement('style');
-			css.appendChild(document.createTextNode(styleText));
-			document.head.appendChild(css);
-		} catch (e) {
-			console.error(e);
-		}
-	}
-
-	const renderError = (code, details, solutions = defaultSolutions) => {
-		if (document.readyState === 'loading') {
-			window.addEventListener('DOMContentLoaded', () => {
-				renderError(code, details, solutions);
-			});
-			try {
-				addStyle(onErrorStyle);
-			} catch (e) { }
-			return;
-		}
-
-		let errorsElement = document.getElementById('errors');
-
-		if (!errorsElement) {
-			// エラー描画用のビューになっていない場合は、エラー描画用のビューに切り替える
-			document.body.innerHTML = `
-			<svg class="icon-warning" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-alert-triangle" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
-				<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
-				<path d="M12 9v2m0 4v.01"></path>
-				<path d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75"></path>
-			</svg>
-			<h1>Failed to load<br>読み込みに失敗しました</h1>
-			<button class="button-big" onclick="location.reload(true);">
-				<span class="button-label-big">Reload / リロード</span>
-			</button>
-			<p><b>The following actions may solve the problem. / 以下を行うと解決する可能性があります。</b></p>
-			${solutions.map(x => `<p>${x}</p>`).join('')}
-			<details style="color: #86b300;">
-				<summary>Other options / その他のオプション</summary>
-				<a href="/flush">
-					<button class="button-small">
-						<span class="button-label-small">Clear preferences and cache</span>
-					</button>
-				</a>
-				<br>
-				<a href="/cli">
-					<button class="button-small">
-						<span class="button-label-small">Start the simple client</span>
-					</button>
-				</a>
-				<br>
-				<a href="/bios">
-					<button class="button-small">
-						<span class="button-label-small">Start the repair tool</span>
-					</button>
-				</a>
-			</details>
-			<br>
-			<div id="errors"></div>
-			`;
-			errorsElement = document.getElementById('errors');
-		}
-
-		if (typeof details === 'string') {
-			const errorEl = document.createElement('div');
-			errorEl.classList.add('errorInfo');
-
-			const titleCodeElement = document.createElement('code');
-			titleCodeElement.textContent = `ERROR CODE: ${code}`;
-			errorEl.appendChild(titleCodeElement);
-
-			errorEl.appendChild(document.createElement('br'));
-
-			const detailsCodeElement = document.createElement('code');
-			detailsCodeElement.textContent = details;
-			errorEl.appendChild(detailsCodeElement);
-
-			errorsElement.appendChild(errorEl);
-		} else if (details instanceof Error) {
-			const errorEl = document.createElement('details');
-			errorEl.classList.add('errorInfo');
-
-			const summaryElement = document.createElement('summary');
-			const titleCodeElement = document.createElement('code');
-			titleCodeElement.textContent = `ERROR CODE: ${code}`;
-			summaryElement.appendChild(titleCodeElement);
-			errorEl.appendChild(summaryElement);
-
-			const detailsPreElement = document.createElement('pre');
-			const detailsMessageElement = document.createElement('code');
-			detailsMessageElement.textContent = details.message;
-			detailsPreElement.appendChild(detailsMessageElement);
-			detailsPreElement.appendChild(document.createElement('br'));
-			const detailsCodeElement = document.createElement('code');
-			detailsCodeElement.textContent = details.stack;
-			detailsPreElement.appendChild(detailsCodeElement);
-			errorEl.appendChild(detailsPreElement);
-
-			errorsElement.appendChild(errorEl);
-		} else {
-			const errorEl = document.createElement('details');
-			errorEl.classList.add('errorInfo');
-
-			const summaryElement = document.createElement('summary');
-			const titleCodeElement = document.createElement('code');
-			titleCodeElement.textContent = `ERROR CODE: ${code}`;
-			summaryElement.appendChild(titleCodeElement);
-			errorEl.appendChild(summaryElement);
-
-			const detailsCodeElement = document.createElement('code');
-			detailsCodeElement.textContent = JSON.stringify(details);
-			errorEl.appendChild(detailsCodeElement);
-
-			errorsElement.appendChild(errorEl);
-		}
-
-		addStyle(onErrorStyle);
-	}
-
+(async () => {
 	window.onerror = (e) => {
 		console.error(e);
 		renderError('SOMETHING_HAPPENED', e);
@@ -270,65 +30,63 @@ function boot() {
 	let forceError = localStorage.getItem('forceError');
 	if (forceError != null) {
 		renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.')
-		renderError('FORCED_ERROR', Error('This error is forced by having forceError in local storage.'));
-		return;
 	}
 
-	//#region After DOM loaded
-	async function oncontentload() {
-		const providedMetaEl = document.getElementById('misskey_meta');
-		const meta = providedMetaEl && providedMetaEl.textContent ? JSON.parse(providedMetaEl.textContent) : null;
-		const providedAt = providedMetaEl && providedMetaEl.dataset.generatedAt ? parseInt(providedMetaEl.dataset.generatedAt) : 0;
-		console.log('providedAt', providedAt, 'now', Date.now());
-		if (providedAt < Date.now() - 1000 * 60 * 60 * 24) {
-			// 古いデータがなぜか提供された場合は、エラーを描画する
-			renderError(
-				'META_PROVIDED_AT_TOO_OLD',
-				'This view is too old. Please reload.',
-				[
-					'Reload / リロードする',
-					'Clear the browser cache then reload / ブラウザのキャッシュをクリアしてリロードする',
-					'Disable an adblocker / アドブロッカーを無効にする',
-				]
-			);
+	//#region Detect language & fetch translations
+	if (!localStorage.hasOwnProperty('locale')) {
+		const supportedLangs = LANGS;
+		let lang = localStorage.getItem('lang');
+		if (lang == null || !supportedLangs.includes(lang)) {
+			if (supportedLangs.includes(navigator.language)) {
+				lang = navigator.language;
+			} else {
+				lang = supportedLangs.find(x => x.split('-')[0] === navigator.language);
+
+				// Fallback
+				if (lang == null) lang = 'en-US';
+			}
+		}
+
+		const metaRes = await window.fetch('/api/meta', {
+			method: 'POST',
+			body: JSON.stringify({}),
+			credentials: 'omit',
+			cache: 'no-cache',
+			headers: {
+				'Content-Type': 'application/json',
+			},
+		});
+		if (metaRes.status !== 200) {
+			renderError('META_FETCH');
+			return;
+		}
+		const meta = await metaRes.json();
+		const v = meta.version;
+		if (v == null) {
+			renderError('META_FETCH_V');
 			return;
 		}
 
-		//#region Detect language & fetch translations on first load
-		if (!localStorage.hasOwnProperty('locale')) {
-			const supportedLangs = LANGS;
-			let lang = localStorage.getItem('lang');
-			if (lang == null || !supportedLangs.includes(lang)) {
-				if (supportedLangs.includes(navigator.language)) {
-					lang = navigator.language;
-				} else {
-					lang = supportedLangs.find(x => x.split('-')[0] === navigator.language);
-
-					// Fallback
-					if (lang == null) lang = 'en-US';
-				}
-			}
-
-			const v = meta?.version;
-
-			// for https://github.com/misskey-dev/misskey/issues/10202
-			if (lang == null || lang.toString == null || lang.toString() === 'null') {
-				console.warn('invalid lang value detected!!!', typeof lang, lang);
-				lang = 'en-US';
-			}
-
-			const localRes = await window.fetch(`/assets/locales/${lang}.${v}.json`);
-			if (localRes.status === 200) {
-				localStorage.setItem('lang', lang);
-				localStorage.setItem('locale', await localRes.text());
-				localStorage.setItem('localeVersion', v);
-			} else {
-				renderError('LOCALE_FETCH');
-				return;
-			}
+		// for https://github.com/misskey-dev/misskey/issues/10202
+		if (lang == null || lang.toString == null || lang.toString() === 'null') {
+			console.error('invalid lang value detected!!!', typeof lang, lang);
+			lang = 'en-US';
 		}
-		//#endregion
 
+		const localRes = await window.fetch(`/assets/locales/${lang}.${v}.json`);
+		if (localRes.status === 200) {
+			localStorage.setItem('lang', lang);
+			localStorage.setItem('locale', await localRes.text());
+			localStorage.setItem('localeVersion', v);
+		} else {
+			renderError('LOCALE_FETCH');
+			return;
+		}
+	}
+	//#endregion
+
+	//#region Script
+	async function importAppScript() {
 		await import(`/vite/${CLIENT_ENTRY}`)
 			.catch(async e => {
 				console.error(e);
@@ -336,11 +94,12 @@ function boot() {
 			});
 	}
 
+	// タイミングによっては、この時点でDOMの構築が済んでいる場合とそうでない場合とがある
 	if (document.readyState !== 'loading') {
-		misskey_loader.add(oncontentload());
+		importAppScript();
 	} else {
 		window.addEventListener('DOMContentLoaded', () => {
-			misskey_loader.add(oncontentload());
+			importAppScript();
 		});
 	}
 	//#endregion
@@ -389,6 +148,172 @@ function boot() {
 		style.innerHTML = customCss;
 		document.head.appendChild(style);
 	}
-}
 
-boot();
+	async function addStyle(styleText) {
+		let css = document.createElement('style');
+		css.appendChild(document.createTextNode(styleText));
+		document.head.appendChild(css);
+	}
+
+	function renderError(code, details) {
+		let errorsElement = document.getElementById('errors');
+
+		if (!errorsElement) {
+			document.body.innerHTML = `
+			<svg class="icon-warning" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-alert-triangle" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+				<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
+				<path d="M12 9v2m0 4v.01"></path>
+				<path d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75"></path>
+			</svg>
+			<h1>Failed to load<br>読み込みに失敗しました</h1>
+			<button class="button-big" onclick="location.reload(true);">
+				<span class="button-label-big">Reload / リロード</span>
+			</button>
+			<p><b>The following actions may solve the problem. / 以下を行うと解決する可能性があります。</b></p>
+			<p>Clear the browser cache / ブラウザのキャッシュをクリアする</p>
+			<p>Update your os and browser / ブラウザおよびOSを最新バージョンに更新する</p>
+			<p>Disable an adblocker / アドブロッカーを無効にする</p>
+	 		<p>&#40;Tor Browser&#41; Set dom.webaudio.enabled to true / dom.webaudio.enabledをtrueに設定する</p>
+			<details style="color: #86b300;">
+				<summary>Other options / その他のオプション</summary>
+				<a href="/flush">
+					<button class="button-small">
+						<span class="button-label-small">Clear preferences and cache</span>
+					</button>
+				</a>
+				<br>
+				<a href="/cli">
+					<button class="button-small">
+						<span class="button-label-small">Start the simple client</span>
+					</button>
+				</a>
+				<br>
+				<a href="/bios">
+					<button class="button-small">
+						<span class="button-label-small">Start the repair tool</span>
+					</button>
+				</a>
+			</details>
+			<br>
+			<div id="errors"></div>
+			`;
+			errorsElement = document.getElementById('errors');
+		}
+		const detailsElement = document.createElement('details');
+		detailsElement.id = 'errorInfo';
+		detailsElement.innerHTML = `
+		<br>
+		<summary>
+			<code>ERROR CODE: ${code}</code>
+		</summary>
+		<code>${JSON.stringify(details)}</code>`;
+		errorsElement.appendChild(detailsElement);
+		addStyle(`
+		* {
+			font-family: BIZ UDGothic, Roboto, HelveticaNeue, Arial, sans-serif;
+		}
+
+		#misskey_app,
+		#splash {
+			display: none !important;
+		}
+
+		body,
+		html {
+			background-color: #222;
+			color: #dfddcc;
+			justify-content: center;
+			margin: auto;
+			padding: 10px;
+			text-align: center;
+		}
+
+		button {
+			border-radius: 999px;
+			padding: 0px 12px 0px 12px;
+			border: none;
+			cursor: pointer;
+			margin-bottom: 12px;
+		}
+
+		.button-big {
+			background: linear-gradient(90deg, rgb(134, 179, 0), rgb(74, 179, 0));
+			line-height: 50px;
+		}
+
+		.button-big:hover {
+			background: rgb(153, 204, 0);
+		}
+
+		.button-small {
+			background: #444;
+			line-height: 40px;
+		}
+
+		.button-small:hover {
+			background: #555;
+		}
+
+		.button-label-big {
+			color: #222;
+			font-weight: bold;
+			font-size: 1.2em;
+			padding: 12px;
+		}
+
+		.button-label-small {
+			color: rgb(153, 204, 0);
+			font-size: 16px;
+			padding: 12px;
+		}
+
+		a {
+			color: rgb(134, 179, 0);
+			text-decoration: none;
+		}
+
+		p,
+		li {
+			font-size: 16px;
+		}
+
+		.icon-warning {
+			color: #dec340;
+			height: 4rem;
+			padding-top: 2rem;
+		}
+
+		h1 {
+			font-size: 1.5em;
+			margin: 1em;
+		}
+
+		code {
+			font-family: Fira, FiraCode, monospace;
+		}
+
+		#errorInfo {
+			background: #333;
+			margin-bottom: 2rem;
+			padding: 0.5rem 1rem;
+			width: 40rem;
+			border-radius: 10px;
+			justify-content: center;
+			margin: auto;
+		}
+
+		#errorInfo summary {
+			cursor: pointer;
+		}
+
+		#errorInfo summary > * {
+			display: inline;
+		}
+
+		@media screen and (max-width: 500px) {
+			#errorInfo {
+				width: 50%;
+			}
+		`)
+	}
+})();

From 7ead98cbe592e6911e4a54550cb7bb507e782d7c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Wed, 6 Mar 2024 21:08:42 +0900
Subject: [PATCH 013/191] =?UTF-8?q?enhance(frontend):=20=E3=83=AA=E3=82=A2?=
 =?UTF-8?q?=E3=82=AF=E3=82=B7=E3=83=A7=E3=83=B3=E3=81=AE=E7=B7=8F=E6=95=B0?=
 =?UTF-8?q?=E3=82=92=E8=A1=A8=E7=A4=BA=E3=81=99=E3=82=8B=E3=82=88=E3=81=86?=
 =?UTF-8?q?=E3=81=AB=20(#13532)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance(frontend): リアクションの総数を表示するように

* Update Changelog

* リアクション選択済の色をaccentに
---
 CHANGELOG.md                                  |  2 ++
 locales/index.d.ts                            |  4 +++
 locales/ja-JP.yml                             |  1 +
 .../src/core/entities/NoteEntityService.ts    |  1 +
 .../backend/src/models/json-schema/note.ts    |  4 +++
 packages/frontend/src/components/MkNote.vue   | 25 ++++++++++-----
 .../src/components/MkNoteDetailed.vue         | 31 ++++++++++++-------
 .../src/components/MkNotification.vue         | 27 ++++++++++------
 .../src/components/MkTutorialDialog.Note.vue  |  1 +
 .../components/MkTutorialDialog.PostNote.vue  |  1 +
 .../components/MkTutorialDialog.Sensitive.vue |  1 +
 .../frontend/src/scripts/use-note-capture.ts  |  2 ++
 packages/frontend/src/style.scss              |  7 +++++
 packages/misskey-js/src/autogen/types.ts      |  1 +
 14 files changed, 79 insertions(+), 29 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1b90094279..7bdfa53e99 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,8 @@
 
 ### Client
 - Enhance: 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるように
+- Enhance: リアクション・いいねの総数を表示するように
+- Enhance: リアクション受け入れが「いいねのみ」の場合はリアクション絵文字一覧を表示しないように
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 
 ### Server
diff --git a/locales/index.d.ts b/locales/index.d.ts
index c1aa163f98..3ac4ff9e74 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -8909,6 +8909,10 @@ export interface Locale extends ILocale {
          * {n}人がリアクションしました
          */
         "reactedBySomeUsers": ParameterizedString<"n">;
+        /**
+         * {n}人がいいねしました
+         */
+        "likedBySomeUsers": ParameterizedString<"n">;
         /**
          * {n}人がリノートしました
          */
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 51380e49c5..177d6a06c9 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -2355,6 +2355,7 @@ _notification:
   sendTestNotification: "テスト通知を送信する"
   notificationWillBeDisplayedLikeThis: "通知はこのように表示されます"
   reactedBySomeUsers: "{n}人がリアクションしました"
+  likedBySomeUsers: "{n}人がいいねしました"
   renotedBySomeUsers: "{n}人がリノートしました"
   followedBySomeUsers: "{n}人にフォローされました"
   flushNotification: "通知の履歴をリセットする"
diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts
index 5b6affc6a5..22d01462e7 100644
--- a/packages/backend/src/core/entities/NoteEntityService.ts
+++ b/packages/backend/src/core/entities/NoteEntityService.ts
@@ -333,6 +333,7 @@ export class NoteEntityService implements OnModuleInit {
 			visibleUserIds: note.visibility === 'specified' ? note.visibleUserIds : undefined,
 			renoteCount: note.renoteCount,
 			repliesCount: note.repliesCount,
+			reactionCount: Object.values(note.reactions).reduce((a, b) => a + b, 0),
 			reactions: this.reactionService.convertLegacyReactions(note.reactions),
 			reactionEmojis: this.customEmojiService.populateEmojis(reactionEmojiNames, host),
 			reactionAndUserPairCache: opts.withReactionAndUserPairCache ? note.reactionAndUserPairCache : undefined,
diff --git a/packages/backend/src/models/json-schema/note.ts b/packages/backend/src/models/json-schema/note.ts
index bb4ccc7ee4..2641161c8b 100644
--- a/packages/backend/src/models/json-schema/note.ts
+++ b/packages/backend/src/models/json-schema/note.ts
@@ -223,6 +223,10 @@ export const packedNoteSchema = {
 				}],
 			},
 		},
+		reactionCount: {
+			type: 'number',
+			optional: false, nullable: false,
+		},
 		renoteCount: {
 			type: 'number',
 			optional: false, nullable: false,
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index 03a283cab3..656ccc7959 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -93,7 +93,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 				</div>
 				<MkA v-if="appearNote.channel && !inChannel" :class="$style.channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA>
 			</div>
-			<MkReactionsViewer :note="appearNote" :maxNumber="16" @mockUpdateMyReaction="emitUpdReaction">
+			<MkReactionsViewer v-if="appearNote.reactionAcceptance !== 'likeOnly'" :note="appearNote" :maxNumber="16" @mockUpdateMyReaction="emitUpdReaction">
 				<template #more>
 					<div :class="$style.reactionOmitted">{{ i18n.ts.more }}</div>
 				</template>
@@ -101,7 +101,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 			<footer :class="$style.footer">
 				<button :class="$style.footerButton" class="_button" @click="reply()">
 					<i class="ti ti-arrow-back-up"></i>
-					<p v-if="appearNote.repliesCount > 0" :class="$style.footerButtonCount">{{ appearNote.repliesCount }}</p>
+					<p v-if="appearNote.repliesCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.repliesCount) }}</p>
 				</button>
 				<button
 					v-if="canRenote"
@@ -111,17 +111,17 @@ SPDX-License-Identifier: AGPL-3.0-only
 					@mousedown="renote()"
 				>
 					<i class="ti ti-repeat"></i>
-					<p v-if="appearNote.renoteCount > 0" :class="$style.footerButtonCount">{{ appearNote.renoteCount }}</p>
+					<p v-if="appearNote.renoteCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.renoteCount) }}</p>
 				</button>
 				<button v-else :class="$style.footerButton" class="_button" disabled>
 					<i class="ti ti-ban"></i>
 				</button>
-				<button v-if="appearNote.myReaction == null" ref="reactButton" :class="$style.footerButton" class="_button" @mousedown="react()">
-					<i v-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
+				<button ref="reactButton" :class="$style.footerButton" class="_button" @click="toggleReact()">
+					<i v-if="appearNote.reactionAcceptance === 'likeOnly' && appearNote.myReaction != null" class="ti ti-heart-filled" style="color: var(--eventReactionHeart);"></i>
+					<i v-else-if="appearNote.myReaction != null" class="ti ti-minus" style="color: var(--accent);"></i>
+					<i v-else-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
 					<i v-else class="ti ti-plus"></i>
-				</button>
-				<button v-if="appearNote.myReaction != null" ref="reactButton" :class="$style.footerButton" class="_button" @click="undoReact(appearNote)">
-					<i class="ti ti-minus"></i>
+					<p v-if="appearNote.reactionCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.reactionCount) }}</p>
 				</button>
 				<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" :class="$style.footerButton" class="_button" @mousedown="clip()">
 					<i class="ti ti-paperclip"></i>
@@ -175,6 +175,7 @@ import { pleaseLogin } from '@/scripts/please-login.js';
 import { focusPrev, focusNext } from '@/scripts/focus.js';
 import { checkWordMute } from '@/scripts/check-word-mute.js';
 import { userPage } from '@/filters/user.js';
+import number from '@/filters/number.js';
 import * as os from '@/os.js';
 import * as sound from '@/scripts/sound.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
@@ -420,6 +421,14 @@ function undoReact(targetNote: Misskey.entities.Note): void {
 	});
 }
 
+function toggleReact() {
+	if (appearNote.value.myReaction == null) {
+		react();
+	} else {
+		undoReact(appearNote.value);
+	}
+}
+
 function onContextmenu(ev: MouseEvent): void {
 	if (props.mock) {
 		return;
diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue
index e3ef14120f..2d2930ee7c 100644
--- a/packages/frontend/src/components/MkNoteDetailed.vue
+++ b/packages/frontend/src/components/MkNoteDetailed.vue
@@ -106,10 +106,10 @@ SPDX-License-Identifier: AGPL-3.0-only
 					<MkTime :time="appearNote.createdAt" mode="detail" colored/>
 				</MkA>
 			</div>
-			<MkReactionsViewer ref="reactionsViewer" :note="appearNote"/>
+			<MkReactionsViewer v-if="appearNote.reactionAcceptance !== 'likeOnly'" ref="reactionsViewer" :note="appearNote"/>
 			<button class="_button" :class="$style.noteFooterButton" @click="reply()">
 				<i class="ti ti-arrow-back-up"></i>
-				<p v-if="appearNote.repliesCount > 0" :class="$style.noteFooterButtonCount">{{ appearNote.repliesCount }}</p>
+				<p v-if="appearNote.repliesCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.repliesCount) }}</p>
 			</button>
 			<button
 				v-if="canRenote"
@@ -119,17 +119,17 @@ SPDX-License-Identifier: AGPL-3.0-only
 				@mousedown="renote()"
 			>
 				<i class="ti ti-repeat"></i>
-				<p v-if="appearNote.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ appearNote.renoteCount }}</p>
+				<p v-if="appearNote.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.renoteCount) }}</p>
 			</button>
 			<button v-else class="_button" :class="$style.noteFooterButton" disabled>
 				<i class="ti ti-ban"></i>
 			</button>
-			<button v-if="appearNote.myReaction == null" ref="reactButton" :class="$style.noteFooterButton" class="_button" @mousedown="react()">
-				<i v-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
+			<button ref="reactButton" :class="$style.noteFooterButton" class="_button" @click="toggleReact()">
+				<i v-if="appearNote.reactionAcceptance === 'likeOnly' && appearNote.myReaction != null" class="ti ti-heart-filled" style="color: var(--eventReactionHeart);"></i>
+				<i v-else-if="appearNote.myReaction != null" class="ti ti-minus" style="color: var(--accent);"></i>
+				<i v-else-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
 				<i v-else class="ti ti-plus"></i>
-			</button>
-			<button v-if="appearNote.myReaction != null" ref="reactButton" class="_button" :class="[$style.noteFooterButton, $style.reacted]" @click="undoReact(appearNote)">
-				<i class="ti ti-minus"></i>
+				<p v-if="appearNote.reactionCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.reactionCount) }}</p>
 			</button>
 			<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" class="_button" :class="$style.noteFooterButton" @mousedown="clip()">
 				<i class="ti ti-paperclip"></i>
@@ -209,6 +209,7 @@ import { pleaseLogin } from '@/scripts/please-login.js';
 import { checkWordMute } from '@/scripts/check-word-mute.js';
 import { userPage } from '@/filters/user.js';
 import { notePage } from '@/filters/note.js';
+import number from '@/filters/number.js';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import * as sound from '@/scripts/sound.js';
@@ -401,14 +402,22 @@ function react(viaKeyboard = false): void {
 	}
 }
 
-function undoReact(note): void {
-	const oldReaction = note.myReaction;
+function undoReact(targetNote: Misskey.entities.Note): void {
+	const oldReaction = targetNote.myReaction;
 	if (!oldReaction) return;
 	misskeyApi('notes/reactions/delete', {
-		noteId: note.id,
+		noteId: targetNote.id,
 	});
 }
 
+function toggleReact() {
+	if (appearNote.value.myReaction == null) {
+		react();
+	} else {
+		undoReact(appearNote.value);
+	}
+}
+
 function onContextmenu(ev: MouseEvent): void {
 	const isLink = (el: HTMLElement): boolean => {
 		if (el.tagName === 'A') return true;
diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue
index 322b9400be..0d3a5c13ba 100644
--- a/packages/frontend/src/components/MkNotification.vue
+++ b/packages/frontend/src/components/MkNotification.vue
@@ -8,6 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 	<div :class="$style.head">
 		<MkAvatar v-if="['pollEnded', 'note'].includes(notification.type) && notification.note" :class="$style.icon" :user="notification.note.user" link preview/>
 		<MkAvatar v-else-if="['roleAssigned', 'achievementEarned'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/>
+		<div v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'" :class="[$style.icon, $style.icon_reactionGroupHeart]"><i class="ti ti-heart" style="line-height: 1;"></i></div>
 		<div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ti ti-plus" style="line-height: 1;"></i></div>
 		<div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ti ti-repeat" style="line-height: 1;"></i></div>
 		<img v-else-if="notification.type === 'test'" :class="$style.icon" :src="infoImageUrl"/>
@@ -57,6 +58,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 			<span v-else-if="notification.type === 'achievementEarned'">{{ i18n.ts._notification.achievementEarned }}</span>
 			<span v-else-if="notification.type === 'test'">{{ i18n.ts._notification.testNotification }}</span>
 			<MkA v-else-if="notification.type === 'follow' || notification.type === 'mention' || notification.type === 'reply' || notification.type === 'renote' || notification.type === 'quote' || notification.type === 'reaction' || notification.type === 'receiveFollowRequest' || notification.type === 'followRequestAccepted'" v-user-preview="notification.user.id" :class="$style.headerName" :to="userPage(notification.user)"><MkUserName :user="notification.user"/></MkA>
+			<span v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'">{{ i18n.tsx._notification.likedBySomeUsers({ n: notification.reactions.length }) }}</span>
 			<span v-else-if="notification.type === 'reaction:grouped'">{{ i18n.tsx._notification.reactedBySomeUsers({ n: notification.reactions.length }) }}</span>
 			<span v-else-if="notification.type === 'renote:grouped'">{{ i18n.tsx._notification.renotedBySomeUsers({ n: notification.users.length }) }}</span>
 			<span v-else-if="notification.type === 'app'">{{ notification.header }}</span>
@@ -201,6 +203,7 @@ const rejectFollowRequest = () => {
 }
 
 .icon_reactionGroup,
+.icon_reactionGroupHeart,
 .icon_renoteGroup {
 	display: grid;
 	align-items: center;
@@ -213,11 +216,15 @@ const rejectFollowRequest = () => {
 }
 
 .icon_reactionGroup {
-	background: #e99a0b;
+	background: var(--eventReaction);
+}
+
+.icon_reactionGroupHeart {
+	background: var(--eventReactionHeart);
 }
 
 .icon_renoteGroup {
-	background: #36d298;
+	background: var(--eventRenote);
 }
 
 .icon_app {
@@ -246,49 +253,49 @@ const rejectFollowRequest = () => {
 
 .t_follow, .t_followRequestAccepted, .t_receiveFollowRequest {
 	padding: 3px;
-	background: #36aed2;
+	background: var(--eventFollow);
 	pointer-events: none;
 }
 
 .t_renote {
 	padding: 3px;
-	background: #36d298;
+	background: var(--eventRenote);
 	pointer-events: none;
 }
 
 .t_quote {
 	padding: 3px;
-	background: #36d298;
+	background: var(--eventRenote);
 	pointer-events: none;
 }
 
 .t_reply {
 	padding: 3px;
-	background: #007aff;
+	background: var(--eventReply);
 	pointer-events: none;
 }
 
 .t_mention {
 	padding: 3px;
-	background: #88a6b7;
+	background: var(--eventOther);
 	pointer-events: none;
 }
 
 .t_pollEnded {
 	padding: 3px;
-	background: #88a6b7;
+	background: var(--eventOther);
 	pointer-events: none;
 }
 
 .t_achievementEarned {
 	padding: 3px;
-	background: #cb9a11;
+	background: var(--eventAchievement);
 	pointer-events: none;
 }
 
 .t_roleAssigned {
 	padding: 3px;
-	background: #88a6b7;
+	background: var(--eventOther);
 	pointer-events: none;
 }
 
diff --git a/packages/frontend/src/components/MkTutorialDialog.Note.vue b/packages/frontend/src/components/MkTutorialDialog.Note.vue
index f03a83293b..2a26d22dc2 100644
--- a/packages/frontend/src/components/MkTutorialDialog.Note.vue
+++ b/packages/frontend/src/components/MkTutorialDialog.Note.vue
@@ -63,6 +63,7 @@ const exampleNote = reactive<Misskey.entities.Note>({
 	reactionAcceptance: null,
 	renoteCount: 0,
 	repliesCount: 1,
+	reactionCount: 0,
 	reactions: {},
 	reactionEmojis: {},
 	fileIds: [],
diff --git a/packages/frontend/src/components/MkTutorialDialog.PostNote.vue b/packages/frontend/src/components/MkTutorialDialog.PostNote.vue
index 2b8c586dac..e1d88b5e5c 100644
--- a/packages/frontend/src/components/MkTutorialDialog.PostNote.vue
+++ b/packages/frontend/src/components/MkTutorialDialog.PostNote.vue
@@ -68,6 +68,7 @@ const exampleCWNote = reactive<Misskey.entities.Note>({
 	reactionAcceptance: null,
 	renoteCount: 0,
 	repliesCount: 1,
+	reactionCount: 0,
 	reactions: {},
 	reactionEmojis: {},
 	fileIds: [],
diff --git a/packages/frontend/src/components/MkTutorialDialog.Sensitive.vue b/packages/frontend/src/components/MkTutorialDialog.Sensitive.vue
index b17ec66461..7ae48dcd15 100644
--- a/packages/frontend/src/components/MkTutorialDialog.Sensitive.vue
+++ b/packages/frontend/src/components/MkTutorialDialog.Sensitive.vue
@@ -58,6 +58,7 @@ const exampleNote = reactive<Misskey.entities.Note>({
 	reactionAcceptance: null,
 	renoteCount: 0,
 	repliesCount: 1,
+	reactionCount: 0,
 	reactions: {},
 	reactionEmojis: {},
 	fileIds: ['0000000002'],
diff --git a/packages/frontend/src/scripts/use-note-capture.ts b/packages/frontend/src/scripts/use-note-capture.ts
index 524ac5d3fe..542d8ab52b 100644
--- a/packages/frontend/src/scripts/use-note-capture.ts
+++ b/packages/frontend/src/scripts/use-note-capture.ts
@@ -35,6 +35,7 @@ export function useNoteCapture(props: {
 				const currentCount = (note.value.reactions || {})[reaction] || 0;
 
 				note.value.reactions[reaction] = currentCount + 1;
+				note.value.reactionCount += 1;
 
 				if ($i && (body.userId === $i.id)) {
 					note.value.myReaction = reaction;
@@ -49,6 +50,7 @@ export function useNoteCapture(props: {
 				const currentCount = (note.value.reactions || {})[reaction] || 0;
 
 				note.value.reactions[reaction] = Math.max(0, currentCount - 1);
+				note.value.reactionCount = Math.max(0, note.value.reactionCount - 1);
 				if (note.value.reactions[reaction] === 0) delete note.value.reactions[reaction];
 
 				if ($i && (body.userId === $i.id)) {
diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss
index 0951a7d98d..187d902733 100644
--- a/packages/frontend/src/style.scss
+++ b/packages/frontend/src/style.scss
@@ -22,6 +22,13 @@
 	}
 
 	//--ad: rgb(255 169 0 / 10%);
+	--eventFollow: #36aed2;
+	--eventRenote: #36d298;
+	--eventReply: #007aff;
+	--eventReactionHeart: #dd2e44;
+	--eventReaction: #e99a0b;
+	--eventAchievement: #cb9a11;
+	--eventOther: #88a6b7;
 }
 
 ::selection {
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index b1e6a194f9..41c3f50135 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -3987,6 +3987,7 @@ export type components = {
       reactions: {
         [key: string]: number;
       };
+      reactionCount: number;
       renoteCount: number;
       repliesCount: number;
       uri?: string;

From 412e9f284dce4167304a57c905f3cd8e9438b128 Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Thu, 7 Mar 2024 09:51:57 +0900
Subject: [PATCH 014/191] test(backend): enable typecheck by workflow (#13526)

---
 packages/backend/package.json                 |  2 +-
 packages/backend/test/e2e/note.ts             |  8 ++++----
 packages/backend/test/e2e/timelines.ts        | 20 ++++++++++++++++++-
 packages/backend/test/global.d.ts             |  7 +++++++
 .../backend/test/prelude/get-api-validator.ts |  4 ++--
 packages/backend/test/tsconfig.json           |  3 ++-
 packages/backend/test/unit/RelayService.ts    |  3 ++-
 7 files changed, 37 insertions(+), 10 deletions(-)
 create mode 100644 packages/backend/test/global.d.ts

diff --git a/packages/backend/package.json b/packages/backend/package.json
index 8680610441..eaad96d5f6 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -19,7 +19,7 @@
 		"watch": "node watch.mjs",
 		"restart": "pnpm build && pnpm start",
 		"dev": "nodemon -w src -e ts,js,mjs,cjs,json --exec \"cross-env NODE_ENV=development pnpm run restart\"",
-		"typecheck": "tsc --noEmit",
+		"typecheck": "tsc --noEmit && tsc -p test --noEmit",
 		"eslint": "eslint --quiet \"src/**/*.ts\"",
 		"lint": "pnpm typecheck && pnpm eslint",
 		"jest": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --config jest.config.unit.cjs",
diff --git a/packages/backend/test/e2e/note.ts b/packages/backend/test/e2e/note.ts
index 973bcbd750..11016f58ae 100644
--- a/packages/backend/test/e2e/note.ts
+++ b/packages/backend/test/e2e/note.ts
@@ -472,7 +472,7 @@ describe('Note', () => {
 						priority: 0,
 						value: true,
 					},
-				},
+				} as any,
 			}, alice);
 
 			assert.strictEqual(res.status, 200);
@@ -784,7 +784,7 @@ describe('Note', () => {
 						priority: 1,
 						value: 0,
 					},
-				},
+				} as any,
 			}, alice);
 
 			assert.strictEqual(res.status, 200);
@@ -838,7 +838,7 @@ describe('Note', () => {
 						priority: 1,
 						value: 0,
 					},
-				},
+				} as any,
 			}, alice);
 
 			assert.strictEqual(res.status, 200);
@@ -894,7 +894,7 @@ describe('Note', () => {
 						priority: 1,
 						value: 1,
 					},
-				},
+				} as any,
 			}, alice);
 
 			assert.strictEqual(res.status, 200);
diff --git a/packages/backend/test/e2e/timelines.ts b/packages/backend/test/e2e/timelines.ts
index d413703ede..5487292afc 100644
--- a/packages/backend/test/e2e/timelines.ts
+++ b/packages/backend/test/e2e/timelines.ts
@@ -890,17 +890,35 @@ describe('Timelines', () => {
 
 			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
 			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
+			await api('users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: false }, alice);
 			await sleep(1000);
 			const aliceNote = await post(alice, { text: 'hi' });
 			const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id });
 
 			await waitForPushToTl();
 
-			const res = await api('notes/user-list-timeline', { listId: list.id, withReplies: false }, alice);
+			const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
 
 			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
 		});
 
+		test.concurrent('withReplies: false でリスインしているフォローしていないユーザーの他人への返信が含まれない', async () => {
+			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
+
+			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
+			await api('users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: false }, alice);
+			await sleep(1000);
+			const carolNote = await post(carol, { text: 'hi' });
+			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
+
+			await waitForPushToTl();
+
+			const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
+
+			assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+		});
+
 		test.concurrent('withReplies: true でリスインしているフォローしていないユーザーの他人への返信が含まれる', async () => {
 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
 
diff --git a/packages/backend/test/global.d.ts b/packages/backend/test/global.d.ts
new file mode 100644
index 0000000000..0363073356
--- /dev/null
+++ b/packages/backend/test/global.d.ts
@@ -0,0 +1,7 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+type FIXME = any;
diff --git a/packages/backend/test/prelude/get-api-validator.ts b/packages/backend/test/prelude/get-api-validator.ts
index b86a7a978d..7aa7a92702 100644
--- a/packages/backend/test/prelude/get-api-validator.ts
+++ b/packages/backend/test/prelude/get-api-validator.ts
@@ -4,10 +4,10 @@
  */
 
 import Ajv from 'ajv';
-import { Schema } from '@/misc/schema';
+import { Schema } from '@/misc/json-schema.js';
 
 export const getValidator = (paramDef: Schema) => {
-	const ajv = new Ajv({
+	const ajv = new Ajv.default({
 		useDefaults: true,
 	});
 	ajv.addFormat('misskey:id', /^[a-zA-Z0-9]+$/);
diff --git a/packages/backend/test/tsconfig.json b/packages/backend/test/tsconfig.json
index 4597ff8780..2b562acda8 100644
--- a/packages/backend/test/tsconfig.json
+++ b/packages/backend/test/tsconfig.json
@@ -5,7 +5,7 @@
 		"noImplicitAny": true,
 		"noImplicitReturns": true,
 		"noUnusedParameters": false,
-		"noUnusedLocals": true,
+		"noUnusedLocals": false,
 		"noFallthroughCasesInSwitch": true,
 		"declaration": false,
 		"sourceMap": true,
@@ -18,6 +18,7 @@
 		"strict": true,
 		"strictNullChecks": true,
 		"strictPropertyInitialization": false,
+		"skipLibCheck": true,
 		"experimentalDecorators": true,
 		"emitDecoratorMetadata": true,
 		"resolveJsonModule": true,
diff --git a/packages/backend/test/unit/RelayService.ts b/packages/backend/test/unit/RelayService.ts
index f2a67dba46..9676abf07b 100644
--- a/packages/backend/test/unit/RelayService.ts
+++ b/packages/backend/test/unit/RelayService.ts
@@ -90,7 +90,8 @@ describe('RelayService', () => {
 
 		expect(queueService.deliver).toHaveBeenCalled();
 		expect(queueService.deliver.mock.lastCall![1]?.type).toBe('Undo');
-		expect(queueService.deliver.mock.lastCall![1]?.object.type).toBe('Follow');
+		expect(typeof queueService.deliver.mock.lastCall![1]?.object).toBe('object');
+		expect((queueService.deliver.mock.lastCall![1]?.object as any).type).toBe('Follow');
 		expect(queueService.deliver.mock.lastCall![2]).toBe('https://example.com');
 		//expect(queueService.deliver.mock.lastCall![0].username).toBe('relay.actor');
 

From c680e35aa0e91ee66794c3d419c282aaea0ef05a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Thu, 7 Mar 2024 16:36:06 +0900
Subject: [PATCH 015/191] =?UTF-8?q?enhance(frontend):=20=E5=BA=83=E5=91=8A?=
 =?UTF-8?q?=E3=81=8C=E5=90=8C=E4=B8=80=E3=83=89=E3=83=A1=E3=82=A4=E3=83=B3?=
 =?UTF-8?q?=E3=81=AE=E5=A0=B4=E5=90=88=E3=81=AFRouter=E3=81=A7=E9=81=B7?=
 =?UTF-8?q?=E7=A7=BB=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=20(#1351?=
 =?UTF-8?q?0)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance(frontend): 広告が同一ドメインの場合はRouterで遷移するように

* Update Changelog

* Update CHANGELOG.md

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 CHANGELOG.md                                  |  1 +
 .../frontend/src/components/global/MkAd.vue   | 21 +++++++++++++++----
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7bdfa53e99..66b41ca771 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@
 
 ### Client
 - Enhance: 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるように
+- Enhance: 広告がMisskeyと同一ドメインの場合はRouterで遷移するように
 - Enhance: リアクション・いいねの総数を表示するように
 - Enhance: リアクション受け入れが「いいねのみ」の場合はリアクション絵文字一覧を表示しないように
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
diff --git a/packages/frontend/src/components/global/MkAd.vue b/packages/frontend/src/components/global/MkAd.vue
index 8f5ed760d5..bdaa8a809f 100644
--- a/packages/frontend/src/components/global/MkAd.vue
+++ b/packages/frontend/src/components/global/MkAd.vue
@@ -14,10 +14,20 @@ SPDX-License-Identifier: AGPL-3.0-only
 			[$style.form_vertical]: chosen.place === 'vertical',
 		}]"
 	>
-		<a :href="chosen.url" target="_blank" :class="$style.link">
+		<component
+			:is="self ? 'MkA' : 'a'"
+			:class="$style.link"
+			v-bind="self ? {
+				to: chosen.url.substring(local.length),
+			} : {
+				href: chosen.url,
+				rel: 'nofollow noopener',
+				target: '_blank',
+			}"
+		>
 			<img :src="chosen.imageUrl" :class="$style.img">
 			<button class="_button" :class="$style.i" @click.prevent.stop="toggleMenu"><i :class="$style.iIcon" class="ti ti-info-circle"></i></button>
-		</a>
+		</component>
 	</div>
 	<div v-else :class="$style.menu">
 		<div :class="$style.menuContainer">
@@ -32,10 +42,10 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { ref } from 'vue';
+import { ref, computed } from 'vue';
 import { i18n } from '@/i18n.js';
 import { instance } from '@/instance.js';
-import { host } from '@/config.js';
+import { url as local, host } from '@/config.js';
 import MkButton from '@/components/MkButton.vue';
 import { defaultStore } from '@/store.js';
 import * as os from '@/os.js';
@@ -96,6 +106,9 @@ const choseAd = (): Ad | null => {
 };
 
 const chosen = ref(choseAd());
+
+const self = computed(() => chosen.value?.url.startsWith(local));
+
 const shouldHide = ref(!defaultStore.state.forceShowAds && $i && $i.policies.canHideAds && (props.specify == null));
 
 function reduceFrequency(): void {

From f4a57404120be713d5fec4fc8e882b09927deca2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Thu, 7 Mar 2024 17:21:57 +0900
Subject: [PATCH 016/191] =?UTF-8?q?fix(frontend):=20=E5=91=A8=E5=B9=B4?=
 =?UTF-8?q?=E3=81=AE=E5=AE=9F=E7=B8=BE=E3=81=8C=E9=96=8F=E5=B9=B4=E3=82=92?=
 =?UTF-8?q?=E8=80=83=E6=85=AE=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?=
 =?UTF-8?q?=20(#13525)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(frontend): 周年の実績が閏年を考慮するように

* まちがえた

* Update Changelog

* 変数の定義回数を減らす
---
 CHANGELOG.md                            |  1 +
 packages/frontend/src/boot/main-boot.ts | 28 ++++++++++++++++++-------
 2 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 66b41ca771..be621e1ebd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@
 - Enhance: リアクション・いいねの総数を表示するように
 - Enhance: リアクション受け入れが「いいねのみ」の場合はリアクション絵文字一覧を表示しないように
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
+- Fix: 周年の実績が閏年を考慮しない問題を修正
 
 ### Server
 -
diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts
index 61f04678bf..8016e8b0e0 100644
--- a/packages/frontend/src/boot/main-boot.ts
+++ b/packages/frontend/src/boot/main-boot.ts
@@ -187,14 +187,26 @@ export async function mainBoot() {
 		if ($i.followersCount >= 500) claimAchievement('followers500');
 		if ($i.followersCount >= 1000) claimAchievement('followers1000');
 
-		if (Date.now() - new Date($i.createdAt).getTime() > 1000 * 60 * 60 * 24 * 365) {
-			claimAchievement('passedSinceAccountCreated1');
-		}
-		if (Date.now() - new Date($i.createdAt).getTime() > 1000 * 60 * 60 * 24 * 365 * 2) {
-			claimAchievement('passedSinceAccountCreated2');
-		}
-		if (Date.now() - new Date($i.createdAt).getTime() > 1000 * 60 * 60 * 24 * 365 * 3) {
+		const createdAt = new Date($i.createdAt);
+		const createdAtThreeYearsLater = new Date($i.createdAt);
+		createdAtThreeYearsLater.setFullYear(createdAtThreeYearsLater.getFullYear() + 3);
+		if (now >= createdAtThreeYearsLater) {
 			claimAchievement('passedSinceAccountCreated3');
+			claimAchievement('passedSinceAccountCreated2');
+			claimAchievement('passedSinceAccountCreated1');
+		} else {
+			const createdAtTwoYearsLater = new Date($i.createdAt);
+			createdAtTwoYearsLater.setFullYear(createdAtTwoYearsLater.getFullYear() + 2);
+			if (now >= createdAtTwoYearsLater) {
+				claimAchievement('passedSinceAccountCreated2');
+				claimAchievement('passedSinceAccountCreated1');
+			} else {
+				const createdAtOneYearLater = new Date($i.createdAt);
+				createdAtOneYearLater.setFullYear(createdAtOneYearLater.getFullYear() + 1);
+				if (now >= createdAtOneYearLater) {
+					claimAchievement('passedSinceAccountCreated1');
+				}
+			}
 		}
 
 		if (claimedAchievements.length >= 30) {
@@ -229,7 +241,7 @@ export async function mainBoot() {
 
 		const latestDonationInfoShownAt = miLocalStorage.getItem('latestDonationInfoShownAt');
 		const neverShowDonationInfo = miLocalStorage.getItem('neverShowDonationInfo');
-		if (neverShowDonationInfo !== 'true' && (new Date($i.createdAt).getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 3))) && !location.pathname.startsWith('/miauth')) {
+		if (neverShowDonationInfo !== 'true' && (createdAt.getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 3))) && !location.pathname.startsWith('/miauth')) {
 			if (latestDonationInfoShownAt == null || (new Date(latestDonationInfoShownAt).getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 30)))) {
 				popup(defineAsyncComponent(() => import('@/components/MkDonation.vue')), {}, {}, 'closed');
 			}

From 27f823e8823225ce33f464c1d12acf7c37834426 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Fri, 8 Mar 2024 18:13:09 +0900
Subject: [PATCH 017/191] =?UTF-8?q?enhance(frontend):=20=E3=83=AA=E3=82=A2?=
 =?UTF-8?q?=E3=82=AF=E3=82=B7=E3=83=A7=E3=83=B3=E3=81=AE=E7=B7=8F=E6=95=B0?=
 =?UTF-8?q?=E3=82=92=E8=A1=A8=E7=A4=BA=E3=81=99=E3=82=8B=E3=81=8B=E8=A8=AD?=
 =?UTF-8?q?=E5=AE=9A=E3=81=A7=E9=81=B8=E3=81=B9=E3=82=8B=E3=82=88=E3=81=86?=
 =?UTF-8?q?=E3=81=AB=20(#13539)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance(frontend): リプライ・リノート・リアクションの総数を表示するか設定で選べるように (MisskeyIO#512)

(cherry picked from commit 3c8475e5ac217f055eab0f6d0aedcbbcb2a2f27c)

* fix: いいねのみの場合は強制的にカウント表示

* make `showReactionsCount` default false

* リアクションだけ

* けしわすれ

* けしわすれ2

---------

Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com>
---
 locales/index.d.ts                                        | 4 ++++
 locales/ja-JP.yml                                         | 1 +
 packages/frontend/src/components/MkNote.vue               | 2 +-
 packages/frontend/src/components/MkNoteDetailed.vue       | 2 +-
 packages/frontend/src/pages/settings/general.vue          | 2 ++
 .../frontend/src/pages/settings/preferences-backups.vue   | 1 +
 packages/frontend/src/store.ts                            | 8 ++++++--
 7 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/locales/index.d.ts b/locales/index.d.ts
index 3ac4ff9e74..53c3159da6 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -1992,6 +1992,10 @@ export interface Locale extends ILocale {
      * ノートのアクションをホバー時のみ表示する
      */
     "showNoteActionsOnlyHover": string;
+    /**
+     * ノートのリアクション数を表示する
+     */
+    "showReactionsCount": string;
     /**
      * 履歴はありません
      */
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 177d6a06c9..64705868b9 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -494,6 +494,7 @@ emojiStyle: "絵文字のスタイル"
 native: "ネイティブ"
 disableDrawer: "メニューをドロワーで表示しない"
 showNoteActionsOnlyHover: "ノートのアクションをホバー時のみ表示する"
+showReactionsCount: "ノートのリアクション数を表示する"
 noHistory: "履歴はありません"
 signinHistory: "ログイン履歴"
 enableAdvancedMfm: "高度なMFMを有効にする"
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index 656ccc7959..5ca0eae012 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -121,7 +121,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 					<i v-else-if="appearNote.myReaction != null" class="ti ti-minus" style="color: var(--accent);"></i>
 					<i v-else-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
 					<i v-else class="ti ti-plus"></i>
-					<p v-if="appearNote.reactionCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.reactionCount) }}</p>
+					<p v-if="(appearNote.reactionAcceptance === 'likeOnly' || defaultStore.state.showReactionsCount) && appearNote.reactionCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.reactionCount) }}</p>
 				</button>
 				<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" :class="$style.footerButton" class="_button" @mousedown="clip()">
 					<i class="ti ti-paperclip"></i>
diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue
index 2d2930ee7c..e271215516 100644
--- a/packages/frontend/src/components/MkNoteDetailed.vue
+++ b/packages/frontend/src/components/MkNoteDetailed.vue
@@ -129,7 +129,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 				<i v-else-if="appearNote.myReaction != null" class="ti ti-minus" style="color: var(--accent);"></i>
 				<i v-else-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
 				<i v-else class="ti ti-plus"></i>
-				<p v-if="appearNote.reactionCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.reactionCount) }}</p>
+				<p v-if="(appearNote.reactionAcceptance === 'likeOnly' || defaultStore.state.showReactionsCount) && appearNote.reactionCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.reactionCount) }}</p>
 			</button>
 			<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" class="_button" :class="$style.noteFooterButton" @mousedown="clip()">
 				<i class="ti ti-paperclip"></i>
diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue
index d13b6884bd..285f874dde 100644
--- a/packages/frontend/src/pages/settings/general.vue
+++ b/packages/frontend/src/pages/settings/general.vue
@@ -56,6 +56,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 				<MkSwitch v-model="advancedMfm">{{ i18n.ts.enableAdvancedMfm }}</MkSwitch>
 				<MkSwitch v-if="advancedMfm" v-model="animatedMfm">{{ i18n.ts.enableAnimatedMfm }}</MkSwitch>
 				<MkSwitch v-if="advancedMfm" v-model="enableQuickAddMfmFunction">{{ i18n.ts.enableQuickAddMfmFunction }}</MkSwitch>
+				<MkSwitch v-model="showReactionsCount">{{ i18n.ts.showReactionsCount }}</MkSwitch>
 				<MkSwitch v-model="showGapBetweenNotesInTimeline">{{ i18n.ts.showGapBetweenNotesInTimeline }}</MkSwitch>
 				<MkSwitch v-model="loadRawImages">{{ i18n.ts.loadRawImages }}</MkSwitch>
 				<MkRadios v-model="reactionsDisplaySize">
@@ -281,6 +282,7 @@ const useBlurEffect = computed(defaultStore.makeGetterSetter('useBlurEffect'));
 const showGapBetweenNotesInTimeline = computed(defaultStore.makeGetterSetter('showGapBetweenNotesInTimeline'));
 const animatedMfm = computed(defaultStore.makeGetterSetter('animatedMfm'));
 const advancedMfm = computed(defaultStore.makeGetterSetter('advancedMfm'));
+const showReactionsCount = computed(defaultStore.makeGetterSetter('showReactionsCount'));
 const enableQuickAddMfmFunction = computed(defaultStore.makeGetterSetter('enableQuickAddMfmFunction'));
 const emojiStyle = computed(defaultStore.makeGetterSetter('emojiStyle'));
 const disableDrawer = computed(defaultStore.makeGetterSetter('disableDrawer'));
diff --git a/packages/frontend/src/pages/settings/preferences-backups.vue b/packages/frontend/src/pages/settings/preferences-backups.vue
index 942de19d82..b6f1043154 100644
--- a/packages/frontend/src/pages/settings/preferences-backups.vue
+++ b/packages/frontend/src/pages/settings/preferences-backups.vue
@@ -70,6 +70,7 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
 	'animation',
 	'animatedMfm',
 	'advancedMfm',
+	'showReactionsCount',
 	'loadRawImages',
 	'imageNewTab',
 	'dataSaver',
diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts
index dfc4169a54..a335ed33bb 100644
--- a/packages/frontend/src/store.ts
+++ b/packages/frontend/src/store.ts
@@ -227,6 +227,10 @@ export const defaultStore = markRaw(new Storage('base', {
 		where: 'device',
 		default: true,
 	},
+	showReactionsCount: {
+		where: 'device',
+		default: false,
+	},
 	enableQuickAddMfmFunction: {
 		where: 'device',
 		default: false,
@@ -431,10 +435,10 @@ export const defaultStore = markRaw(new Storage('base', {
 			sfxVolume: 1,
 		},
 	},
-  hemisphere: {
+	hemisphere: {
 		where: 'device',
 		default: hemisphere as 'N' | 'S',
-  },
+	},
 	enableHorizontalSwipe: {
 		where: 'device',
 		default: true,

From 1b064d7e30899827a59535ffa5fe6c90512a836d Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Sat, 9 Mar 2024 04:10:17 +0000
Subject: [PATCH 018/191] =?UTF-8?q?chore(backend):=20validateNote=E3=81=AE?=
 =?UTF-8?q?=E7=B5=90=E6=9E=9CError=E3=81=AF=E3=81=9D=E3=81=AE=E3=81=BE?=
 =?UTF-8?q?=E3=81=BEthrow=E3=81=99=E3=82=8B=20=E7=90=86=E7=94=B1=E3=81=8C?=
 =?UTF-8?q?=E3=82=8F=E3=81=8B=E3=82=89=E3=81=AA=E3=81=84=E3=81=9F=E3=82=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 packages/backend/src/core/activitypub/models/ApNoteService.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts
index b2fd435f93..4d64b08e15 100644
--- a/packages/backend/src/core/activitypub/models/ApNoteService.ts
+++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts
@@ -129,7 +129,7 @@ export class ApNoteService {
 				value,
 				object,
 			});
-			throw new Error('invalid note');
+			throw err;
 		}
 
 		const note = object as IPost;

From db29680e749fae8ce93f82b527bf8e8597fa0526 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Sat, 9 Mar 2024 15:31:21 +0900
Subject: [PATCH 019/191] chore(dev): remove deprecated vscode plugins

---
 .devcontainer/devcontainer.json | 1 -
 .vscode/extensions.json         | 1 -
 2 files changed, 2 deletions(-)

diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index e409adf644..f8d9905ecd 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -19,7 +19,6 @@
 				"editorconfig.editorconfig",
 				"dbaeumer.vscode-eslint",
 				"Vue.volar",
-				"Vue.vscode-typescript-vue-plugin",
 				"Orta.vscode-jest",
 				"dbaeumer.vscode-eslint",
 				"mrmlnc.vscode-json5"
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index baca8db246..d08109477c 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -3,7 +3,6 @@
 		"editorconfig.editorconfig",
 		"dbaeumer.vscode-eslint",
 		"Vue.volar",
-		"Vue.vscode-typescript-vue-plugin",
 		"Orta.vscode-jest",
 		"dbaeumer.vscode-eslint",
 		"mrmlnc.vscode-json5"

From dbc4fd3e93a7b73be9e0bc3e863cf1d553edd80c Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Sat, 9 Mar 2024 15:40:21 +0900
Subject: [PATCH 020/191] Update about-misskey.vue

---
 packages/frontend/src/pages/about-misskey.vue | 1 +
 1 file changed, 1 insertion(+)

diff --git a/packages/frontend/src/pages/about-misskey.vue b/packages/frontend/src/pages/about-misskey.vue
index 1a49dbf1d5..9aaa2d8fba 100644
--- a/packages/frontend/src/pages/about-misskey.vue
+++ b/packages/frontend/src/pages/about-misskey.vue
@@ -324,6 +324,7 @@ const patrons = [
 	'てば',
 	'たっくん',
 	'SHO SEKIGUCHI',
+	'塩キャベツ',
 ];
 
 const thereIsTreasure = ref($i && !claimedAchievements.includes('foundTreasure'));

From e4eaf1220e0d23b056f3203b3b24d8e3827134b9 Mon Sep 17 00:00:00 2001
From: FineArchs <133759614+FineArchs@users.noreply.github.com>
Date: Sat, 9 Mar 2024 17:55:41 +0900
Subject: [PATCH 021/191] Update example.yml (#13551)

---
 .config/example.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.config/example.yml b/.config/example.yml
index 7fea929374..b0b7f14059 100644
--- a/.config/example.yml
+++ b/.config/example.yml
@@ -38,7 +38,7 @@
 # Option 3: If neither of the above applies to you.
 #           (In this case, the source code should be published
 #           on the Misskey interface.  IT IS NOT ENOUGH TO
-#           DISCLOSE THE SOURCE CODE WEHN A USER REQUESTS IT BY
+#           DISCLOSE THE SOURCE CODE WHEN A USER REQUESTS IT BY
 #           E-MAIL OR OTHER MEANS.  If you are not satisfied
 #           with this, it is recommended that you read the
 #           license again carefully.  Anyway, enabling this

From 6b676a928d3e167c98f2a1854a432adf5c125d65 Mon Sep 17 00:00:00 2001
From: yupix <yupi0982@outlook.jp>
Date: Sun, 10 Mar 2024 17:31:39 +0900
Subject: [PATCH 022/191] =?UTF-8?q?enhance(backend):=20antennas/update?=
 =?UTF-8?q?=E3=81=AE=E5=BF=85=E9=A0=88=E9=A0=85=E7=9B=AE=E3=82=92antennaId?=
 =?UTF-8?q?=E3=81=AE=E3=81=BF=E3=81=AB=20(#13542)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* refactor: antennas/updateの必須項目を最小限に

* fix: userListIdがnullにできない
---
 CHANGELOG.md                                   |  2 +-
 .../server/api/endpoints/antennas/update.ts    | 12 +++++++-----
 packages/misskey-js/src/autogen/types.ts       | 18 +++++++++---------
 3 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index be621e1ebd..8c5f05dbe5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,7 +26,7 @@
 - Fix: カスタム絵文字の画像読み込みに失敗した際はテキストではなくダミー画像を表示 #13487
 
 ### Server
--
+- Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
 
 ## 2024.3.0
 
diff --git a/packages/backend/src/server/api/endpoints/antennas/update.ts b/packages/backend/src/server/api/endpoints/antennas/update.ts
index 459729f61f..76a34924a0 100644
--- a/packages/backend/src/server/api/endpoints/antennas/update.ts
+++ b/packages/backend/src/server/api/endpoints/antennas/update.ts
@@ -67,7 +67,7 @@ export const paramDef = {
 		withFile: { type: 'boolean' },
 		notify: { type: 'boolean' },
 	},
-	required: ['antennaId', 'name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile', 'notify'],
+	required: ['antennaId'],
 } as const;
 
 @Injectable()
@@ -83,8 +83,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 		private globalEventService: GlobalEventService,
 	) {
 		super(meta, paramDef, async (ps, me) => {
-			if (ps.keywords.flat().every(x => x === '') && ps.excludeKeywords.flat().every(x => x === '')) {
-				throw new Error('either keywords or excludeKeywords is required.');
+			if (ps.keywords && ps.excludeKeywords) {
+				if (ps.keywords.flat().every(x => x === '') && ps.excludeKeywords.flat().every(x => x === '')) {
+					throw new Error('either keywords or excludeKeywords is required.');
+				}
 			}
 			// Fetch the antenna
 			const antenna = await this.antennasRepository.findOneBy({
@@ -98,7 +100,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 
 			let userList;
 
-			if (ps.src === 'list' && ps.userListId) {
+			if ((ps.src === 'list' || antenna.src === 'list') && ps.userListId) {
 				userList = await this.userListsRepository.findOneBy({
 					id: ps.userListId,
 					userId: me.id,
@@ -112,7 +114,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 			await this.antennasRepository.update(antenna.id, {
 				name: ps.name,
 				src: ps.src,
-				userListId: userList ? userList.id : null,
+				userListId: ps.userListId !== undefined ? userList ? userList.id : null : undefined,
 				keywords: ps.keywords,
 				excludeKeywords: ps.excludeKeywords,
 				users: ps.users,
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 41c3f50135..be3e86bd78 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -9925,19 +9925,19 @@ export type operations = {
         'application/json': {
           /** Format: misskey:id */
           antennaId: string;
-          name: string;
+          name?: string;
           /** @enum {string} */
-          src: 'home' | 'all' | 'users' | 'list' | 'users_blacklist';
+          src?: 'home' | 'all' | 'users' | 'list' | 'users_blacklist';
           /** Format: misskey:id */
           userListId?: string | null;
-          keywords: string[][];
-          excludeKeywords: string[][];
-          users: string[];
-          caseSensitive: boolean;
+          keywords?: string[][];
+          excludeKeywords?: string[][];
+          users?: string[];
+          caseSensitive?: boolean;
           localOnly?: boolean;
-          withReplies: boolean;
-          withFile: boolean;
-          notify: boolean;
+          withReplies?: boolean;
+          withFile?: boolean;
+          notify?: boolean;
         };
       };
     };

From e23e2f4ae9368754e4eadcd0afaa2bb1f984ba6a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Tue, 12 Mar 2024 12:09:26 +0900
Subject: [PATCH 023/191] Fix Changelog

---
 CHANGELOG.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8c5f05dbe5..9c2a32aa56 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,7 +12,7 @@
 - Fix: 周年の実績が閏年を考慮しない問題を修正
 
 ### Server
--
+- Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
 
 ## 2024.3.1
 
@@ -26,7 +26,7 @@
 - Fix: カスタム絵文字の画像読み込みに失敗した際はテキストではなくダミー画像を表示 #13487
 
 ### Server
-- Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
+-
 
 ## 2024.3.0
 

From b280faa8e72c29036ef65af7fd8949538ab43dbd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Tue, 12 Mar 2024 13:48:14 +0900
Subject: [PATCH 024/191] =?UTF-8?q?enhance(frontend):=20=E5=90=84=E3=82=B5?=
 =?UTF-8?q?=E3=83=BC=E3=83=90=E3=83=BC=E3=81=AFMisskey=E3=82=92=E5=88=A9?=
 =?UTF-8?q?=E7=94=A8=E3=81=97=E3=81=9F=E3=82=B5=E3=83=BC=E3=83=93=E3=82=B9?=
 =?UTF-8?q?=E3=81=A7=E3=81=82=E3=82=8B=E3=81=93=E3=81=A8=E3=82=92=E5=BC=B7?=
 =?UTF-8?q?=E8=AA=BF=20(#13559)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* ロゴ周りを追加

* 調整

---------

Co-authored-by: uboar <10250330+uboar@users.noreply.github.com>
---
 .../frontend/src/pages/welcome.entrance.a.vue | 27 ++++++++++++++-----
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/packages/frontend/src/pages/welcome.entrance.a.vue b/packages/frontend/src/pages/welcome.entrance.a.vue
index 89bb010dd6..6c05aad24f 100644
--- a/packages/frontend/src/pages/welcome.entrance.a.vue
+++ b/packages/frontend/src/pages/welcome.entrance.a.vue
@@ -9,7 +9,10 @@ SPDX-License-Identifier: AGPL-3.0-only
 	<XTimeline class="tl"/>
 	<div class="shape1"></div>
 	<div class="shape2"></div>
-	<img :src="misskeysvg" class="misskey"/>
+	<div class="logo-wrapper">
+		<div class="powered-by">Powered by</div>
+		<img :src="misskeysvg" class="misskey"/>
+	</div>
 	<div class="emojis">
 		<MkEmoji :normal="true" :noStyle="true" emoji="👍"/>
 		<MkEmoji :normal="true" :noStyle="true" emoji="❤"/>
@@ -113,14 +116,24 @@ misskeyApiGet('federation/instances', {
 		opacity: 0.5;
 	}
 
-	> .misskey {
+	> .logo-wrapper {
 		position: fixed;
-		top: 42px;
-		left: 42px;
-		width: 140px;
+		top: 36px;
+		left: 36px;
+		flex: auto;
+		color: #fff;
+		user-select: none;
+		pointer-events: none;
 
-		@media (max-width: 450px) {
-			width: 130px;
+		> .powered-by {
+			margin-bottom: 2px;
+		}
+
+		> .misskey {
+			width: 140px;
+			@media (max-width: 450px) {
+				width: 130px;
+			}
 		}
 	}
 

From 6d9c234cb6d3ddfaa3266255e7c305b329a556b6 Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Tue, 12 Mar 2024 13:50:24 +0900
Subject: [PATCH 025/191] fix: URL preview popup for local URL appears in the
 upper left corner (#13555)

---
 CHANGELOG.md                                      | 1 +
 packages/frontend/src/components/MkLink.vue       | 4 ++--
 packages/frontend/src/components/global/MkA.vue   | 8 ++++++--
 packages/frontend/src/components/global/MkUrl.vue | 2 +-
 4 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9c2a32aa56..83d0a3f7d2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@
 - Enhance: リアクション受け入れが「いいねのみ」の場合はリアクション絵文字一覧を表示しないように
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
+- Fix: ローカルURLのプレビューポップアップが左上に表示される
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
diff --git a/packages/frontend/src/components/MkLink.vue b/packages/frontend/src/components/MkLink.vue
index a5abbeceac..3f7aba2fe4 100644
--- a/packages/frontend/src/components/MkLink.vue
+++ b/packages/frontend/src/components/MkLink.vue
@@ -29,13 +29,13 @@ const self = props.url.startsWith(local);
 const attr = self ? 'to' : 'href';
 const target = self ? null : '_blank';
 
-const el = ref<HTMLElement>();
+const el = ref<HTMLElement | { $el: HTMLElement }>();
 
 useTooltip(el, (showing) => {
 	os.popup(defineAsyncComponent(() => import('@/components/MkUrlPreviewPopup.vue')), {
 		showing,
 		url: props.url,
-		source: el.value,
+		source: el.value instanceof HTMLElement ? el.value : el.value?.$el,
 	}, {}, 'closed');
 });
 </script>
diff --git a/packages/frontend/src/components/global/MkA.vue b/packages/frontend/src/components/global/MkA.vue
index 61d7ac17d9..1ba7cb2022 100644
--- a/packages/frontend/src/components/global/MkA.vue
+++ b/packages/frontend/src/components/global/MkA.vue
@@ -4,13 +4,13 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-<a :href="to" :class="active ? activeClass : null" @click.prevent="nav" @contextmenu.prevent.stop="onContextmenu">
+<a ref="el" :href="to" :class="active ? activeClass : null" @click.prevent="nav" @contextmenu.prevent.stop="onContextmenu">
 	<slot></slot>
 </a>
 </template>
 
 <script lang="ts" setup>
-import { computed } from 'vue';
+import { computed, shallowRef } from 'vue';
 import * as os from '@/os.js';
 import copyToClipboard from '@/scripts/copy-to-clipboard.js';
 import { url } from '@/config.js';
@@ -26,6 +26,10 @@ const props = withDefaults(defineProps<{
 	behavior: null,
 });
 
+const el = shallowRef<HTMLElement>();
+
+defineExpose({ $el: el });
+
 const router = useRouter();
 
 const active = computed(() => {
diff --git a/packages/frontend/src/components/global/MkUrl.vue b/packages/frontend/src/components/global/MkUrl.vue
index 0c3eee63ff..8d29a4da8c 100644
--- a/packages/frontend/src/components/global/MkUrl.vue
+++ b/packages/frontend/src/components/global/MkUrl.vue
@@ -49,7 +49,7 @@ if (props.showUrlPreview) {
 		os.popup(defineAsyncComponent(() => import('@/components/MkUrlPreviewPopup.vue')), {
 			showing,
 			url: props.url,
-			source: el.value,
+			source: el.value instanceof HTMLElement ? el.value : el.value?.$el,
 		}, {}, 'closed');
 	});
 }

From 5c1d86b796d6ab878bc4f9bd2faf4207998e71cf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?=
 <46447427+samunohito@users.noreply.github.com>
Date: Tue, 12 Mar 2024 14:31:34 +0900
Subject: [PATCH 026/191] =?UTF-8?q?refactor(backend):=20UserEntityService.?=
 =?UTF-8?q?packMany()=E3=81=AE=E9=AB=98=E9=80=9F=E5=8C=96=20(#13550)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* refactor(backend): UserEntityService.packMany()の高速化

* 修正
---
 .../src/core/entities/UserEntityService.ts    | 229 +++++++-
 .../server/api/endpoints/users/relation.ts    |   8 +-
 .../test/unit/entities/UserEntityService.ts   | 528 ++++++++++++++++++
 3 files changed, 729 insertions(+), 36 deletions(-)
 create mode 100644 packages/backend/test/unit/entities/UserEntityService.ts

diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts
index 14761357a5..df2b27d709 100644
--- a/packages/backend/src/core/entities/UserEntityService.ts
+++ b/packages/backend/src/core/entities/UserEntityService.ts
@@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
 import * as Redis from 'ioredis';
 import _Ajv from 'ajv';
 import { ModuleRef } from '@nestjs/core';
+import { In } from 'typeorm';
 import { DI } from '@/di-symbols.js';
 import type { Config } from '@/config.js';
 import type { Packed } from '@/misc/json-schema.js';
@@ -14,9 +15,30 @@ import type { Promiseable } from '@/misc/prelude/await-all.js';
 import { awaitAll } from '@/misc/prelude/await-all.js';
 import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const.js';
 import type { MiLocalUser, MiPartialLocalUser, MiPartialRemoteUser, MiRemoteUser, MiUser } from '@/models/User.js';
-import { birthdaySchema, descriptionSchema, localUsernameSchema, locationSchema, nameSchema, passwordSchema } from '@/models/User.js';
-import { MiNotification } from '@/models/Notification.js';
-import type { UsersRepository, UserSecurityKeysRepository, FollowingsRepository, FollowRequestsRepository, BlockingsRepository, MutingsRepository, DriveFilesRepository, NoteUnreadsRepository, UserNotePiningsRepository, UserProfilesRepository, AnnouncementReadsRepository, AnnouncementsRepository, MiUserProfile, RenoteMutingsRepository, UserMemoRepository } from '@/models/_.js';
+import {
+	birthdaySchema,
+	descriptionSchema,
+	localUsernameSchema,
+	locationSchema,
+	nameSchema,
+	passwordSchema,
+} from '@/models/User.js';
+import type {
+	BlockingsRepository,
+	FollowingsRepository,
+	FollowRequestsRepository,
+	MiFollowing,
+	MiUserNotePining,
+	MiUserProfile,
+	MutingsRepository,
+	NoteUnreadsRepository,
+	RenoteMutingsRepository,
+	UserMemoRepository,
+	UserNotePiningsRepository,
+	UserProfilesRepository,
+	UserSecurityKeysRepository,
+	UsersRepository,
+} from '@/models/_.js';
 import { bindThis } from '@/decorators.js';
 import { RoleService } from '@/core/RoleService.js';
 import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
@@ -46,11 +68,23 @@ function isRemoteUser(user: MiUser | { host: MiUser['host'] }): boolean {
 	return !isLocalUser(user);
 }
 
+export type UserRelation = {
+	id: MiUser['id']
+	following: MiFollowing | null,
+	isFollowing: boolean
+	isFollowed: boolean
+	hasPendingFollowRequestFromYou: boolean
+	hasPendingFollowRequestToYou: boolean
+	isBlocking: boolean
+	isBlocked: boolean
+	isMuted: boolean
+	isRenoteMuted: boolean
+}
+
 @Injectable()
 export class UserEntityService implements OnModuleInit {
 	private apPersonService: ApPersonService;
 	private noteEntityService: NoteEntityService;
-	private driveFileEntityService: DriveFileEntityService;
 	private pageEntityService: PageEntityService;
 	private customEmojiService: CustomEmojiService;
 	private announcementService: AnnouncementService;
@@ -89,9 +123,6 @@ export class UserEntityService implements OnModuleInit {
 		@Inject(DI.renoteMutingsRepository)
 		private renoteMutingsRepository: RenoteMutingsRepository,
 
-		@Inject(DI.driveFilesRepository)
-		private driveFilesRepository: DriveFilesRepository,
-
 		@Inject(DI.noteUnreadsRepository)
 		private noteUnreadsRepository: NoteUnreadsRepository,
 
@@ -101,12 +132,6 @@ export class UserEntityService implements OnModuleInit {
 		@Inject(DI.userProfilesRepository)
 		private userProfilesRepository: UserProfilesRepository,
 
-		@Inject(DI.announcementReadsRepository)
-		private announcementReadsRepository: AnnouncementReadsRepository,
-
-		@Inject(DI.announcementsRepository)
-		private announcementsRepository: AnnouncementsRepository,
-
 		@Inject(DI.userMemosRepository)
 		private userMemosRepository: UserMemoRepository,
 	) {
@@ -115,7 +140,6 @@ export class UserEntityService implements OnModuleInit {
 	onModuleInit() {
 		this.apPersonService = this.moduleRef.get('ApPersonService');
 		this.noteEntityService = this.moduleRef.get('NoteEntityService');
-		this.driveFileEntityService = this.moduleRef.get('DriveFileEntityService');
 		this.pageEntityService = this.moduleRef.get('PageEntityService');
 		this.customEmojiService = this.moduleRef.get('CustomEmojiService');
 		this.announcementService = this.moduleRef.get('AnnouncementService');
@@ -138,7 +162,7 @@ export class UserEntityService implements OnModuleInit {
 	public isRemoteUser = isRemoteUser;
 
 	@bindThis
-	public async getRelation(me: MiUser['id'], target: MiUser['id']) {
+	public async getRelation(me: MiUser['id'], target: MiUser['id']): Promise<UserRelation> {
 		const [
 			following,
 			isFollowed,
@@ -211,6 +235,59 @@ export class UserEntityService implements OnModuleInit {
 		};
 	}
 
+	@bindThis
+	public async getRelations(me: MiUser['id'], targets: MiUser['id'][]): Promise<Map<MiUser['id'], UserRelation>> {
+		const [
+			followers,
+			followees,
+			followersRequests,
+			followeesRequests,
+			blockers,
+			blockees,
+			muters,
+			renoteMuters,
+		] = await Promise.all([
+			this.followingsRepository.findBy({ followerId: me })
+				.then(f => new Map(f.map(it => [it.followeeId, it]))),
+			this.followingsRepository.findBy({ followeeId: me })
+				.then(it => it.map(it => it.followerId)),
+			this.followRequestsRepository.findBy({ followerId: me })
+				.then(it => it.map(it => it.followeeId)),
+			this.followRequestsRepository.findBy({ followeeId: me })
+				.then(it => it.map(it => it.followerId)),
+			this.blockingsRepository.findBy({ blockerId: me })
+				.then(it => it.map(it => it.blockeeId)),
+			this.blockingsRepository.findBy({ blockeeId: me })
+				.then(it => it.map(it => it.blockerId)),
+			this.mutingsRepository.findBy({ muterId: me })
+				.then(it => it.map(it => it.muteeId)),
+			this.renoteMutingsRepository.findBy({ muterId: me })
+				.then(it => it.map(it => it.muteeId)),
+		]);
+
+		return new Map(
+			targets.map(target => {
+				const following = followers.get(target) ?? null;
+
+				return [
+					target,
+					{
+						id: target,
+						following: following,
+						isFollowing: following != null,
+						isFollowed: followees.includes(target),
+						hasPendingFollowRequestFromYou: followersRequests.includes(target),
+						hasPendingFollowRequestToYou: followeesRequests.includes(target),
+						isBlocking: blockers.includes(target),
+						isBlocked: blockees.includes(target),
+						isMuted: muters.includes(target),
+						isRenoteMuted: renoteMuters.includes(target),
+					},
+				];
+			}),
+		);
+	}
+
 	@bindThis
 	public async getHasUnreadAntenna(userId: MiUser['id']): Promise<boolean> {
 		/*
@@ -303,6 +380,9 @@ export class UserEntityService implements OnModuleInit {
 			schema?: S,
 			includeSecrets?: boolean,
 			userProfile?: MiUserProfile,
+			userRelations?: Map<MiUser['id'], UserRelation>,
+			userMemos?: Map<MiUser['id'], string | null>,
+			pinNotes?: Map<MiUser['id'], MiUserNotePining[]>,
 		},
 	): Promise<Packed<S>> {
 		const opts = Object.assign({
@@ -317,13 +397,41 @@ export class UserEntityService implements OnModuleInit {
 		const isMe = meId === user.id;
 		const iAmModerator = me ? await this.roleService.isModerator(me as MiUser) : false;
 
-		const relation = meId && !isMe && isDetailed ? await this.getRelation(meId, user.id) : null;
-		const pins = isDetailed ? await this.userNotePiningsRepository.createQueryBuilder('pin')
-			.where('pin.userId = :userId', { userId: user.id })
-			.innerJoinAndSelect('pin.note', 'note')
-			.orderBy('pin.id', 'DESC')
-			.getMany() : [];
-		const profile = isDetailed ? (opts.userProfile ?? await this.userProfilesRepository.findOneByOrFail({ userId: user.id })) : null;
+		const profile = isDetailed
+			? (opts.userProfile ?? await this.userProfilesRepository.findOneByOrFail({ userId: user.id }))
+			: null;
+
+		let relation: UserRelation | null = null;
+		if (meId && !isMe && isDetailed) {
+			if (opts.userRelations) {
+				relation = opts.userRelations.get(user.id) ?? null;
+			} else {
+				relation = await this.getRelation(meId, user.id);
+			}
+		}
+
+		let memo: string | null = null;
+		if (isDetailed && meId) {
+			if (opts.userMemos) {
+				memo = opts.userMemos.get(user.id) ?? null;
+			} else {
+				memo = await this.userMemosRepository.findOneBy({ userId: meId, targetUserId: user.id })
+					.then(row => row?.memo ?? null);
+			}
+		}
+
+		let pins: MiUserNotePining[] = [];
+		if (isDetailed) {
+			if (opts.pinNotes) {
+				pins = opts.pinNotes.get(user.id) ?? [];
+			} else {
+				pins = await this.userNotePiningsRepository.createQueryBuilder('pin')
+					.where('pin.userId = :userId', { userId: user.id })
+					.innerJoinAndSelect('pin.note', 'note')
+					.orderBy('pin.id', 'DESC')
+					.getMany();
+			}
+		}
 
 		const followingCount = profile == null ? null :
 			(profile.followingVisibility === 'public') || isMe ? user.followingCount :
@@ -416,9 +524,7 @@ export class UserEntityService implements OnModuleInit {
 				twoFactorEnabled: profile!.twoFactorEnabled,
 				usePasswordLessLogin: profile!.usePasswordLessLogin,
 				securityKeys: profile!.twoFactorEnabled
-					? this.userSecurityKeysRepository.countBy({
-						userId: user.id,
-					}).then(result => result >= 1)
+					? this.userSecurityKeysRepository.countBy({ userId: user.id }).then(result => result >= 1)
 					: false,
 				roles: this.roleService.getUserRoles(user.id).then(roles => roles.filter(role => role.isPublic).sort((a, b) => b.displayOrder - a.displayOrder).map(role => ({
 					id: role.id,
@@ -430,10 +536,7 @@ export class UserEntityService implements OnModuleInit {
 					isAdministrator: role.isAdministrator,
 					displayOrder: role.displayOrder,
 				}))),
-				memo: meId == null ? null : await this.userMemosRepository.findOneBy({
-					userId: meId,
-					targetUserId: user.id,
-				}).then(row => row?.memo ?? null),
+				memo: memo,
 				moderationNote: iAmModerator ? (profile!.moderationNote ?? '') : undefined,
 			} : {}),
 
@@ -514,7 +617,7 @@ export class UserEntityService implements OnModuleInit {
 		return await awaitAll(packed);
 	}
 
-	public packMany<S extends 'MeDetailed' | 'UserDetailedNotMe' | 'UserDetailed' | 'UserLite' = 'UserLite'>(
+	public async packMany<S extends 'MeDetailed' | 'UserDetailedNotMe' | 'UserDetailed' | 'UserLite' = 'UserLite'>(
 		users: (MiUser['id'] | MiUser)[],
 		me?: { id: MiUser['id'] } | null | undefined,
 		options?: {
@@ -522,6 +625,70 @@ export class UserEntityService implements OnModuleInit {
 			includeSecrets?: boolean,
 		},
 	): Promise<Packed<S>[]> {
-		return Promise.all(users.map(u => this.pack(u, me, options)));
+		// -- IDのみの要素を補完して完全なエンティティ一覧を作る
+
+		const _users = users.filter((user): user is MiUser => typeof user !== 'string');
+		if (_users.length !== users.length) {
+			_users.push(
+				...await this.usersRepository.findBy({
+					id: In(users.filter((user): user is string => typeof user === 'string')),
+				}),
+			);
+		}
+		const _userIds = _users.map(u => u.id);
+
+		// -- 特に前提条件のない値群を取得
+
+		const profilesMap = await this.userProfilesRepository.findBy({ userId: In(_userIds) })
+			.then(profiles => new Map(profiles.map(p => [p.userId, p])));
+
+		// -- 実行者の有無や指定スキーマの種別によって要否が異なる値群を取得
+
+		let userRelations: Map<MiUser['id'], UserRelation> = new Map();
+		let userMemos: Map<MiUser['id'], string | null> = new Map();
+		let pinNotes: Map<MiUser['id'], MiUserNotePining[]> = new Map();
+
+		if (options?.schema !== 'UserLite') {
+			const meId = me ? me.id : null;
+			if (meId) {
+				userMemos = await this.userMemosRepository.findBy({ userId: meId })
+					.then(memos => new Map(memos.map(memo => [memo.targetUserId, memo.memo])));
+
+				if (_userIds.length > 0) {
+					userRelations = await this.getRelations(meId, _userIds);
+					pinNotes = await this.userNotePiningsRepository.createQueryBuilder('pin')
+						.where('pin.userId IN (:...userIds)', { userIds: _userIds })
+						.innerJoinAndSelect('pin.note', 'note')
+						.getMany()
+						.then(pinsNotes => {
+							const map = new Map<MiUser['id'], MiUserNotePining[]>();
+							for (const note of pinsNotes) {
+								const notes = map.get(note.userId) ?? [];
+								notes.push(note);
+								map.set(note.userId, notes);
+							}
+							for (const [, notes] of map.entries()) {
+								// pack側ではDESCで取得しているので、それに合わせて降順に並び替えておく
+								notes.sort((a, b) => b.id.localeCompare(a.id));
+							}
+							return map;
+						});
+				}
+			}
+		}
+
+		return Promise.all(
+			_users.map(u => this.pack(
+				u,
+				me,
+				{
+					...options,
+					userProfile: profilesMap.get(u.id),
+					userRelations: userRelations,
+					userMemos: userMemos,
+					pinNotes: pinNotes,
+				},
+			)),
+		);
 	}
 }
diff --git a/packages/backend/src/server/api/endpoints/users/relation.ts b/packages/backend/src/server/api/endpoints/users/relation.ts
index 6a5b2262fa..1d75437b81 100644
--- a/packages/backend/src/server/api/endpoints/users/relation.ts
+++ b/packages/backend/src/server/api/endpoints/users/relation.ts
@@ -132,11 +132,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 		private userEntityService: UserEntityService,
 	) {
 		super(meta, paramDef, async (ps, me) => {
-			const ids = Array.isArray(ps.userId) ? ps.userId : [ps.userId];
-
-			const relations = await Promise.all(ids.map(id => this.userEntityService.getRelation(me.id, id)));
-
-			return Array.isArray(ps.userId) ? relations : relations[0];
+			return Array.isArray(ps.userId)
+				? await this.userEntityService.getRelations(me.id, ps.userId).then(it => [...it.values()])
+				: await this.userEntityService.getRelation(me.id, ps.userId).then(it => [it]);
 		});
 	}
 }
diff --git a/packages/backend/test/unit/entities/UserEntityService.ts b/packages/backend/test/unit/entities/UserEntityService.ts
new file mode 100644
index 0000000000..ee16d421c4
--- /dev/null
+++ b/packages/backend/test/unit/entities/UserEntityService.ts
@@ -0,0 +1,528 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Test, TestingModule } from '@nestjs/testing';
+import { UserEntityService } from '@/core/entities/UserEntityService.js';
+import { GlobalModule } from '@/GlobalModule.js';
+import { CoreModule } from '@/core/CoreModule.js';
+import type { MiUser } from '@/models/User.js';
+import { secureRndstr } from '@/misc/secure-rndstr.js';
+import { genAidx } from '@/misc/id/aidx.js';
+import {
+	BlockingsRepository,
+	FollowingsRepository, FollowRequestsRepository,
+	MiUserProfile, MutingsRepository, RenoteMutingsRepository,
+	UserMemoRepository,
+	UserProfilesRepository,
+	UsersRepository,
+} from '@/models/_.js';
+import { DI } from '@/di-symbols.js';
+import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
+import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
+import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
+import { PageEntityService } from '@/core/entities/PageEntityService.js';
+import { CustomEmojiService } from '@/core/CustomEmojiService.js';
+import { AnnouncementService } from '@/core/AnnouncementService.js';
+import { RoleService } from '@/core/RoleService.js';
+import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
+import { IdService } from '@/core/IdService.js';
+import { UtilityService } from '@/core/UtilityService.js';
+import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js';
+import { ModerationLogService } from '@/core/ModerationLogService.js';
+import { GlobalEventService } from '@/core/GlobalEventService.js';
+import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
+import { MetaService } from '@/core/MetaService.js';
+import { FetchInstanceMetadataService } from '@/core/FetchInstanceMetadataService.js';
+import { CacheService } from '@/core/CacheService.js';
+import { ApResolverService } from '@/core/activitypub/ApResolverService.js';
+import { ApNoteService } from '@/core/activitypub/models/ApNoteService.js';
+import { ApImageService } from '@/core/activitypub/models/ApImageService.js';
+import { ApMfmService } from '@/core/activitypub/ApMfmService.js';
+import { MfmService } from '@/core/MfmService.js';
+import { HashtagService } from '@/core/HashtagService.js';
+import UsersChart from '@/core/chart/charts/users.js';
+import { ChartLoggerService } from '@/core/chart/ChartLoggerService.js';
+import InstanceChart from '@/core/chart/charts/instance.js';
+import { ApLoggerService } from '@/core/activitypub/ApLoggerService.js';
+import { AccountMoveService } from '@/core/AccountMoveService.js';
+import { ReactionService } from '@/core/ReactionService.js';
+import { NotificationService } from '@/core/NotificationService.js';
+
+process.env.NODE_ENV = 'test';
+
+describe('UserEntityService', () => {
+	describe('pack/packMany', () => {
+		let app: TestingModule;
+		let service: UserEntityService;
+		let usersRepository: UsersRepository;
+		let userProfileRepository: UserProfilesRepository;
+		let userMemosRepository: UserMemoRepository;
+		let followingRepository: FollowingsRepository;
+		let followingRequestRepository: FollowRequestsRepository;
+		let blockingRepository: BlockingsRepository;
+		let mutingRepository: MutingsRepository;
+		let renoteMutingsRepository: RenoteMutingsRepository;
+
+		async function createUser(userData: Partial<MiUser> = {}, profileData: Partial<MiUserProfile> = {}) {
+			const un = secureRndstr(16);
+			const user = await usersRepository
+				.insert({
+					...userData,
+					id: genAidx(Date.now()),
+					username: un,
+					usernameLower: un,
+				})
+				.then(x => usersRepository.findOneByOrFail(x.identifiers[0]));
+
+			await userProfileRepository.insert({
+				...profileData,
+				userId: user.id,
+			});
+
+			return user;
+		}
+
+		async function memo(writer: MiUser, target: MiUser, memo: string) {
+			await userMemosRepository.insert({
+				id: genAidx(Date.now()),
+				userId: writer.id,
+				targetUserId: target.id,
+				memo,
+			});
+		}
+
+		async function follow(follower: MiUser, followee: MiUser) {
+			await followingRepository.insert({
+				id: genAidx(Date.now()),
+				followerId: follower.id,
+				followeeId: followee.id,
+			});
+		}
+
+		async function requestFollow(requester: MiUser, requestee: MiUser) {
+			await followingRequestRepository.insert({
+				id: genAidx(Date.now()),
+				followerId: requester.id,
+				followeeId: requestee.id,
+			});
+		}
+
+		async function block(blocker: MiUser, blockee: MiUser) {
+			await blockingRepository.insert({
+				id: genAidx(Date.now()),
+				blockerId: blocker.id,
+				blockeeId: blockee.id,
+			});
+		}
+
+		async function mute(mutant: MiUser, mutee: MiUser) {
+			await mutingRepository.insert({
+				id: genAidx(Date.now()),
+				muterId: mutant.id,
+				muteeId: mutee.id,
+			});
+		}
+
+		async function muteRenote(mutant: MiUser, mutee: MiUser) {
+			await renoteMutingsRepository.insert({
+				id: genAidx(Date.now()),
+				muterId: mutant.id,
+				muteeId: mutee.id,
+			});
+		}
+
+		function randomIntRange(weight = 10) {
+			return [...Array(Math.floor(Math.random() * weight))].map((it, idx) => idx);
+		}
+
+		beforeAll(async () => {
+			const services = [
+				UserEntityService,
+				ApPersonService,
+				NoteEntityService,
+				PageEntityService,
+				CustomEmojiService,
+				AnnouncementService,
+				RoleService,
+				FederatedInstanceService,
+				IdService,
+				AvatarDecorationService,
+				UtilityService,
+				EmojiEntityService,
+				ModerationLogService,
+				GlobalEventService,
+				DriveFileEntityService,
+				MetaService,
+				FetchInstanceMetadataService,
+				CacheService,
+				ApResolverService,
+				ApNoteService,
+				ApImageService,
+				ApMfmService,
+				MfmService,
+				HashtagService,
+				UsersChart,
+				ChartLoggerService,
+				InstanceChart,
+				ApLoggerService,
+				AccountMoveService,
+				ReactionService,
+				NotificationService,
+			];
+
+			app = await Test.createTestingModule({
+				imports: [GlobalModule, CoreModule],
+				providers: [
+					...services,
+					...services.map(x => ({ provide: x.name, useExisting: x })),
+				],
+			}).compile();
+			await app.init();
+			app.enableShutdownHooks();
+
+			service = app.get<UserEntityService>(UserEntityService);
+			usersRepository = app.get<UsersRepository>(DI.usersRepository);
+			userProfileRepository = app.get<UserProfilesRepository>(DI.userProfilesRepository);
+			userMemosRepository = app.get<UserMemoRepository>(DI.userMemosRepository);
+			followingRepository = app.get<FollowingsRepository>(DI.followingsRepository);
+			followingRequestRepository = app.get<FollowRequestsRepository>(DI.followRequestsRepository);
+			blockingRepository = app.get<BlockingsRepository>(DI.blockingsRepository);
+			mutingRepository = app.get<MutingsRepository>(DI.mutingsRepository);
+			renoteMutingsRepository = app.get<RenoteMutingsRepository>(DI.renoteMutingsRepository);
+		});
+
+		afterAll(async () => {
+			await app.close();
+		});
+
+		test('UserLite', async() => {
+			const me = await createUser();
+			const who = await createUser();
+
+			await memo(me, who, 'memo');
+
+			const actual = await service.pack(who, me, { schema: 'UserLite' }) as any;
+			// no detail
+			expect(actual.memo).toBeUndefined();
+			// no detail and me
+			expect(actual.birthday).toBeUndefined();
+			// no detail and me
+			expect(actual.achievements).toBeUndefined();
+		});
+
+		test('UserDetailedNotMe', async() => {
+			const me = await createUser();
+			const who = await createUser({}, { birthday: '2000-01-01' });
+
+			await memo(me, who, 'memo');
+
+			const actual = await service.pack(who, me, { schema: 'UserDetailedNotMe' }) as any;
+			// is detail
+			expect(actual.memo).toBe('memo');
+			// is detail
+			expect(actual.birthday).toBe('2000-01-01');
+			// no detail and me
+			expect(actual.achievements).toBeUndefined();
+		});
+
+		test('MeDetailed', async() => {
+			const achievements = [{ name: 'achievement', unlockedAt: new Date().getTime() }];
+			const me = await createUser({}, {
+				birthday: '2000-01-01',
+				achievements: achievements,
+			});
+			await memo(me, me, 'memo');
+
+			const actual = await service.pack(me, me, { schema: 'MeDetailed' }) as any;
+			// is detail
+			expect(actual.memo).toBe('memo');
+			// is detail
+			expect(actual.birthday).toBe('2000-01-01');
+			// is detail and me
+			expect(actual.achievements).toEqual(achievements);
+		});
+
+		describe('packManyによるpreloadがある時、preloadが無い時とpackの結果が同じになるか見たい', () => {
+			test('no-preload', async() => {
+				const me = await createUser();
+				// meがフォローしてる人たち
+				const followeeMe = await Promise.all(randomIntRange().map(() => createUser()));
+				for (const who of followeeMe) {
+					await follow(me, who);
+					const actual = await service.pack(who, me, { schema: 'UserDetailed' }) as any;
+					expect(actual.isFollowing).toBe(true);
+					expect(actual.isFollowed).toBe(false);
+					expect(actual.hasPendingFollowRequestFromYou).toBe(false);
+					expect(actual.hasPendingFollowRequestToYou).toBe(false);
+					expect(actual.isBlocking).toBe(false);
+					expect(actual.isBlocked).toBe(false);
+					expect(actual.isMuted).toBe(false);
+					expect(actual.isRenoteMuted).toBe(false);
+				}
+
+				// meをフォローしてる人たち
+				const followerMe = await Promise.all(randomIntRange().map(() => createUser()));
+				for (const who of followerMe) {
+					await follow(who, me);
+					const actual = await service.pack(who, me, { schema: 'UserDetailed' }) as any;
+					expect(actual.isFollowing).toBe(false);
+					expect(actual.isFollowed).toBe(true);
+					expect(actual.hasPendingFollowRequestFromYou).toBe(false);
+					expect(actual.hasPendingFollowRequestToYou).toBe(false);
+					expect(actual.isBlocking).toBe(false);
+					expect(actual.isBlocked).toBe(false);
+					expect(actual.isMuted).toBe(false);
+					expect(actual.isRenoteMuted).toBe(false);
+				}
+
+				// meがフォローリクエストを送った人たち
+				const requestsFromYou = await Promise.all(randomIntRange().map(() => createUser()));
+				for (const who of requestsFromYou) {
+					await requestFollow(me, who);
+					const actual = await service.pack(who, me, { schema: 'UserDetailed' }) as any;
+					expect(actual.isFollowing).toBe(false);
+					expect(actual.isFollowed).toBe(false);
+					expect(actual.hasPendingFollowRequestFromYou).toBe(true);
+					expect(actual.hasPendingFollowRequestToYou).toBe(false);
+					expect(actual.isBlocking).toBe(false);
+					expect(actual.isBlocked).toBe(false);
+					expect(actual.isMuted).toBe(false);
+					expect(actual.isRenoteMuted).toBe(false);
+				}
+
+				// meにフォローリクエストを送った人たち
+				const requestsToYou = await Promise.all(randomIntRange().map(() => createUser()));
+				for (const who of requestsToYou) {
+					await requestFollow(who, me);
+					const actual = await service.pack(who, me, { schema: 'UserDetailed' }) as any;
+					expect(actual.isFollowing).toBe(false);
+					expect(actual.isFollowed).toBe(false);
+					expect(actual.hasPendingFollowRequestFromYou).toBe(false);
+					expect(actual.hasPendingFollowRequestToYou).toBe(true);
+					expect(actual.isBlocking).toBe(false);
+					expect(actual.isBlocked).toBe(false);
+					expect(actual.isMuted).toBe(false);
+					expect(actual.isRenoteMuted).toBe(false);
+				}
+
+				// meがブロックしてる人たち
+				const blockingYou = await Promise.all(randomIntRange().map(() => createUser()));
+				for (const who of blockingYou) {
+					await block(me, who);
+					const actual = await service.pack(who, me, { schema: 'UserDetailed' }) as any;
+					expect(actual.isFollowing).toBe(false);
+					expect(actual.isFollowed).toBe(false);
+					expect(actual.hasPendingFollowRequestFromYou).toBe(false);
+					expect(actual.hasPendingFollowRequestToYou).toBe(false);
+					expect(actual.isBlocking).toBe(true);
+					expect(actual.isBlocked).toBe(false);
+					expect(actual.isMuted).toBe(false);
+					expect(actual.isRenoteMuted).toBe(false);
+				}
+
+				// meをブロックしてる人たち
+				const blockingMe = await Promise.all(randomIntRange().map(() => createUser()));
+				for (const who of blockingMe) {
+					await block(who, me);
+					const actual = await service.pack(who, me, { schema: 'UserDetailed' }) as any;
+					expect(actual.isFollowing).toBe(false);
+					expect(actual.isFollowed).toBe(false);
+					expect(actual.hasPendingFollowRequestFromYou).toBe(false);
+					expect(actual.hasPendingFollowRequestToYou).toBe(false);
+					expect(actual.isBlocking).toBe(false);
+					expect(actual.isBlocked).toBe(true);
+					expect(actual.isMuted).toBe(false);
+					expect(actual.isRenoteMuted).toBe(false);
+				}
+
+				// meがミュートしてる人たち
+				const muters = await Promise.all(randomIntRange().map(() => createUser()));
+				for (const who of muters) {
+					await mute(me, who);
+					const actual = await service.pack(who, me, { schema: 'UserDetailed' }) as any;
+					expect(actual.isFollowing).toBe(false);
+					expect(actual.isFollowed).toBe(false);
+					expect(actual.hasPendingFollowRequestFromYou).toBe(false);
+					expect(actual.hasPendingFollowRequestToYou).toBe(false);
+					expect(actual.isBlocking).toBe(false);
+					expect(actual.isBlocked).toBe(false);
+					expect(actual.isMuted).toBe(true);
+					expect(actual.isRenoteMuted).toBe(false);
+				}
+
+				// meがリノートミュートしてる人たち
+				const renoteMuters = await Promise.all(randomIntRange().map(() => createUser()));
+				for (const who of renoteMuters) {
+					await muteRenote(me, who);
+					const actual = await service.pack(who, me, { schema: 'UserDetailed' }) as any;
+					expect(actual.isFollowing).toBe(false);
+					expect(actual.isFollowed).toBe(false);
+					expect(actual.hasPendingFollowRequestFromYou).toBe(false);
+					expect(actual.hasPendingFollowRequestToYou).toBe(false);
+					expect(actual.isBlocking).toBe(false);
+					expect(actual.isBlocked).toBe(false);
+					expect(actual.isMuted).toBe(false);
+					expect(actual.isRenoteMuted).toBe(true);
+				}
+			});
+
+			test('preload', async() => {
+				const me = await createUser();
+
+				{
+					// meがフォローしてる人たち
+					const followeeMe = await Promise.all(randomIntRange().map(() => createUser()));
+					for (const who of followeeMe) {
+						await follow(me, who);
+					}
+					const actualList = await service.packMany(followeeMe, me, { schema: 'UserDetailed' }) as any;
+					for (const actual of actualList) {
+						expect(actual.isFollowing).toBe(true);
+						expect(actual.isFollowed).toBe(false);
+						expect(actual.hasPendingFollowRequestFromYou).toBe(false);
+						expect(actual.hasPendingFollowRequestToYou).toBe(false);
+						expect(actual.isBlocking).toBe(false);
+						expect(actual.isBlocked).toBe(false);
+						expect(actual.isMuted).toBe(false);
+						expect(actual.isRenoteMuted).toBe(false);
+					}
+				}
+
+				{
+					// meをフォローしてる人たち
+					const followerMe = await Promise.all(randomIntRange().map(() => createUser()));
+					for (const who of followerMe) {
+						await follow(who, me);
+					}
+					const actualList = await service.packMany(followerMe, me, { schema: 'UserDetailed' }) as any;
+					for (const actual of actualList) {
+						expect(actual.isFollowing).toBe(false);
+						expect(actual.isFollowed).toBe(true);
+						expect(actual.hasPendingFollowRequestFromYou).toBe(false);
+						expect(actual.hasPendingFollowRequestToYou).toBe(false);
+						expect(actual.isBlocking).toBe(false);
+						expect(actual.isBlocked).toBe(false);
+						expect(actual.isMuted).toBe(false);
+						expect(actual.isRenoteMuted).toBe(false);
+					}
+				}
+
+				{
+					// meがフォローリクエストを送った人たち
+					const requestsFromYou = await Promise.all(randomIntRange().map(() => createUser()));
+					for (const who of requestsFromYou) {
+						await requestFollow(me, who);
+					}
+					const actualList = await service.packMany(requestsFromYou, me, { schema: 'UserDetailed' }) as any;
+					for (const actual of actualList) {
+						expect(actual.isFollowing).toBe(false);
+						expect(actual.isFollowed).toBe(false);
+						expect(actual.hasPendingFollowRequestFromYou).toBe(true);
+						expect(actual.hasPendingFollowRequestToYou).toBe(false);
+						expect(actual.isBlocking).toBe(false);
+						expect(actual.isBlocked).toBe(false);
+						expect(actual.isMuted).toBe(false);
+						expect(actual.isRenoteMuted).toBe(false);
+					}
+				}
+
+				{
+					// meにフォローリクエストを送った人たち
+					const requestsToYou = await Promise.all(randomIntRange().map(() => createUser()));
+					for (const who of requestsToYou) {
+						await requestFollow(who, me);
+					}
+					const actualList = await service.packMany(requestsToYou, me, { schema: 'UserDetailed' }) as any;
+					for (const actual of actualList) {
+						expect(actual.isFollowing).toBe(false);
+						expect(actual.isFollowed).toBe(false);
+						expect(actual.hasPendingFollowRequestFromYou).toBe(false);
+						expect(actual.hasPendingFollowRequestToYou).toBe(true);
+						expect(actual.isBlocking).toBe(false);
+						expect(actual.isBlocked).toBe(false);
+						expect(actual.isMuted).toBe(false);
+						expect(actual.isRenoteMuted).toBe(false);
+					}
+				}
+
+				{
+					// meがブロックしてる人たち
+					const blockingYou = await Promise.all(randomIntRange().map(() => createUser()));
+					for (const who of blockingYou) {
+						await block(me, who);
+					}
+					const actualList = await service.packMany(blockingYou, me, { schema: 'UserDetailed' }) as any;
+					for (const actual of actualList) {
+						expect(actual.isFollowing).toBe(false);
+						expect(actual.isFollowed).toBe(false);
+						expect(actual.hasPendingFollowRequestFromYou).toBe(false);
+						expect(actual.hasPendingFollowRequestToYou).toBe(false);
+						expect(actual.isBlocking).toBe(true);
+						expect(actual.isBlocked).toBe(false);
+						expect(actual.isMuted).toBe(false);
+						expect(actual.isRenoteMuted).toBe(false);
+					}
+				}
+
+				{
+					// meをブロックしてる人たち
+					const blockingMe = await Promise.all(randomIntRange().map(() => createUser()));
+					for (const who of blockingMe) {
+						await block(who, me);
+					}
+					const actualList = await service.packMany(blockingMe, me, { schema: 'UserDetailed' }) as any;
+					for (const actual of actualList) {
+						expect(actual.isFollowing).toBe(false);
+						expect(actual.isFollowed).toBe(false);
+						expect(actual.hasPendingFollowRequestFromYou).toBe(false);
+						expect(actual.hasPendingFollowRequestToYou).toBe(false);
+						expect(actual.isBlocking).toBe(false);
+						expect(actual.isBlocked).toBe(true);
+						expect(actual.isMuted).toBe(false);
+						expect(actual.isRenoteMuted).toBe(false);
+					}
+				}
+
+				{
+					// meがミュートしてる人たち
+					const muters = await Promise.all(randomIntRange().map(() => createUser()));
+					for (const who of muters) {
+						await mute(me, who);
+					}
+					const actualList = await service.packMany(muters, me, { schema: 'UserDetailed' }) as any;
+					for (const actual of actualList) {
+						expect(actual.isFollowing).toBe(false);
+						expect(actual.isFollowed).toBe(false);
+						expect(actual.hasPendingFollowRequestFromYou).toBe(false);
+						expect(actual.hasPendingFollowRequestToYou).toBe(false);
+						expect(actual.isBlocking).toBe(false);
+						expect(actual.isBlocked).toBe(false);
+						expect(actual.isMuted).toBe(true);
+						expect(actual.isRenoteMuted).toBe(false);
+					}
+				}
+
+				{
+					// meがリノートミュートしてる人たち
+					const renoteMuters = await Promise.all(randomIntRange().map(() => createUser()));
+					for (const who of renoteMuters) {
+						await muteRenote(me, who);
+					}
+					const actualList = await service.packMany(renoteMuters, me, { schema: 'UserDetailed' }) as any;
+					for (const actual of actualList) {
+						expect(actual.isFollowing).toBe(false);
+						expect(actual.isFollowed).toBe(false);
+						expect(actual.hasPendingFollowRequestFromYou).toBe(false);
+						expect(actual.hasPendingFollowRequestToYou).toBe(false);
+						expect(actual.isBlocking).toBe(false);
+						expect(actual.isBlocked).toBe(false);
+						expect(actual.isMuted).toBe(false);
+						expect(actual.isRenoteMuted).toBe(true);
+					}
+				}
+			});
+		});
+	});
+});

From 29f6ba6310e162d6e24c9075ddd6176c155a10e7 Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Wed, 13 Mar 2024 22:37:18 +0900
Subject: [PATCH 027/191] chore: add missing SPDX ID and workflow check
 (#13570)

* chore: add workflow which checks if SPDX ID exists

* chore: add missing SPDX ID in some files

* chore: change trigger condition

* chore: trigger on push

* lint
---
 .github/workflows/check-spdx-license-id.yml   | 75 +++++++++++++++++++
 cypress/e2e/basic.cy.js                       |  5 ++
 cypress/e2e/router.cy.js                      |  5 ++
 cypress/e2e/widgets.cy.js                     |  5 ++
 packages/backend/generate_api_json.js         |  7 +-
 .../1689325027964-UserBlacklistAnntena.js     |  5 ++
 .../1690417561185-fix-renote-muting.js        |  5 ++
 ...417561186-ChangeCacheRemoteFilesDefault.js |  5 ++
 .../backend/migration/1690417561187-Fix.js    |  5 ++
 .../1690569881926-user-2fa-backup-codes.js    |  5 ++
 .../1691649257651-refine-announcement.js      |  5 ++
 .../1691657412740-refine-announcement-2.js    |  5 ++
 .../migration/1695260774117-verified-links.js |  5 ++
 .../1695288787870-following-notify.js         |  5 ++
 .../migration/1695440131671-short-name.js     |  5 ++
 .../1695605508898-mutingNotificationTypes.js  |  5 ++
 .../1695901659683-note-updated-at.js          |  5 ++
 .../1696323464251-user-list-membership.js     |  5 ++
 .../migration/1696331570827-hibernation.js    |  5 ++
 .../backend/migration/1696332072038-clean.js  |  5 ++
 .../migration/1700383825690-hard-mute.js      |  5 ++
 .../src/core/ChannelFollowingService.ts       |  5 ++
 .../backend/src/misc/fastify-hook-handlers.ts |  5 ++
 packages/backend/src/misc/is-pure-renote.ts   |  5 ++
 packages/backend/src/misc/loader.ts           |  5 ++
 packages/backend/src/models/ReversiGame.ts    |  5 ++
 .../backend/src/models/json-schema/signin.ts  |  5 ++
 packages/backend/test/jest.setup.ts           |  5 ++
 packages/backend/test/unit/ApMfmService.ts    |  5 ++
 packages/backend/test/unit/misc/loader.ts     |  5 ++
 .../frontend/.storybook/preview-head.html     |  5 ++
 .../frontend/src/components/global/I18n.vue   |  5 ++
 packages/frontend/src/filters/kmg.ts          |  5 ++
 .../src/scripts/check-reaction-permissions.ts |  5 ++
 packages/frontend/src/scripts/clear-cache.ts  |  5 ++
 .../frontend/src/scripts/code-highlighter.ts  |  5 ++
 .../frontend/src/scripts/media-has-audio.ts   |  5 ++
 packages/frontend/src/type.ts                 |  5 ++
 scripts/changelog-checker/src/checker.ts      |  5 ++
 scripts/changelog-checker/src/index.ts        |  5 ++
 scripts/changelog-checker/src/parser.ts       |  5 ++
 .../changelog-checker/test/checker.test.ts    |  7 +-
 scripts/tarball.mjs                           |  5 ++
 43 files changed, 287 insertions(+), 2 deletions(-)
 create mode 100644 .github/workflows/check-spdx-license-id.yml

diff --git a/.github/workflows/check-spdx-license-id.yml b/.github/workflows/check-spdx-license-id.yml
new file mode 100644
index 0000000000..6cd8bf60d5
--- /dev/null
+++ b/.github/workflows/check-spdx-license-id.yml
@@ -0,0 +1,75 @@
+name: Check SPDX-License-Identifier
+
+on:
+  push:
+    branches:
+      - master
+      - develop
+  pull_request:
+
+jobs:
+  check-spdx-license-id:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v4.1.1
+      - name: Check
+        run: |
+          counter=0
+
+          search() {
+            local directory="$1"
+            find "$directory" -type f \
+              '(' \
+                -name "*.cjs" -and -not -name '*.config.cjs' -o \
+                -name "*.html" -o \
+                -name "*.js" -and -not -name '*.config.js' -o \
+                -name "*.mjs" -and -not -name '*.config.mjs' -o \
+                -name "*.scss" -o \
+                -name "*.ts" -and -not -name '*.config.ts' -o \
+                -name "*.vue" \
+              ')' -and \
+              -not -name '*eslint*'
+          }
+
+          check() {
+            local file="$1"
+            if ! (
+              grep -q "SPDX-FileCopyrightText: syuilo and misskey-project" "$file" ||
+              grep -q "SPDX-License-Identifier: AGPL-3.0-only" "$file"
+            ); then
+              echo "Missing: $file"
+              ((counter++))
+            fi
+          }
+
+          directories=(
+            "cypress/e2e"
+            "packages/backend/migration"
+            "packages/backend/src"
+            "packages/backend/test"
+            "packages/frontend/.storybook"
+            "packages/frontend/@types"
+            "packages/frontend/lib"
+            "packages/frontend/public"
+            "packages/frontend/src"
+            "packages/frontend/test"
+            "packages/misskey-bubble-game/src"
+            "packages/misskey-reversi/src"
+            "packages/sw/src"
+            "scripts"
+          )
+
+          for directory in "${directories[@]}"; do
+            for file in $(search $directory); do
+              check "$file"
+            done
+          done
+
+          if [ $counter -gt 0 ]; then
+            echo "SPDX-License-Identifier is missing in $counter files."
+            exit 1
+          else
+            echo "SPDX-License-Identifier is certainly described in all target files!"
+            exit 0
+          fi
diff --git a/cypress/e2e/basic.cy.js b/cypress/e2e/basic.cy.js
index 604241d13c..d2525e0a7d 100644
--- a/cypress/e2e/basic.cy.js
+++ b/cypress/e2e/basic.cy.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 describe('Before setup instance', () => {
 	beforeEach(() => {
 		cy.resetState();
diff --git a/cypress/e2e/router.cy.js b/cypress/e2e/router.cy.js
index 6de27be5f4..8d8fb3af31 100644
--- a/cypress/e2e/router.cy.js
+++ b/cypress/e2e/router.cy.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 describe('Router transition', () => {
 	describe('Redirect', () => {
 		// サーバの初期化。ルートのテストに関しては各describeごとに1度だけ実行で十分だと思う(使いまわした方が早い)
diff --git a/cypress/e2e/widgets.cy.js b/cypress/e2e/widgets.cy.js
index df6ec8357d..847801a69f 100644
--- a/cypress/e2e/widgets.cy.js
+++ b/cypress/e2e/widgets.cy.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 /* flaky
 describe('After user signed in', () => {
 	beforeEach(() => {
diff --git a/packages/backend/generate_api_json.js b/packages/backend/generate_api_json.js
index 4079b3bb0a..602ced1d75 100644
--- a/packages/backend/generate_api_json.js
+++ b/packages/backend/generate_api_json.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 import { loadConfig } from './built/config.js'
 import { genOpenapiSpec } from './built/server/api/openapi/gen-spec.js'
 import { writeFileSync } from "node:fs";
@@ -5,4 +10,4 @@ import { writeFileSync } from "node:fs";
 const config = loadConfig();
 const spec = genOpenapiSpec(config, true);
 
-writeFileSync('./built/api.json', JSON.stringify(spec), 'utf-8');
\ No newline at end of file
+writeFileSync('./built/api.json', JSON.stringify(spec), 'utf-8');
diff --git a/packages/backend/migration/1689325027964-UserBlacklistAnntena.js b/packages/backend/migration/1689325027964-UserBlacklistAnntena.js
index ce246b20f8..2dc7774493 100644
--- a/packages/backend/migration/1689325027964-UserBlacklistAnntena.js
+++ b/packages/backend/migration/1689325027964-UserBlacklistAnntena.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export class UserBlacklistAnntena1689325027964 {
     name = 'UserBlacklistAnntena1689325027964'
 
diff --git a/packages/backend/migration/1690417561185-fix-renote-muting.js b/packages/backend/migration/1690417561185-fix-renote-muting.js
index 14150b0362..d9604ca26c 100644
--- a/packages/backend/migration/1690417561185-fix-renote-muting.js
+++ b/packages/backend/migration/1690417561185-fix-renote-muting.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export class FixRenoteMuting1690417561185 {
     name = 'FixRenoteMuting1690417561185'
 
diff --git a/packages/backend/migration/1690417561186-ChangeCacheRemoteFilesDefault.js b/packages/backend/migration/1690417561186-ChangeCacheRemoteFilesDefault.js
index 7eda5debe5..9bccdb3bb5 100644
--- a/packages/backend/migration/1690417561186-ChangeCacheRemoteFilesDefault.js
+++ b/packages/backend/migration/1690417561186-ChangeCacheRemoteFilesDefault.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export class ChangeCacheRemoteFilesDefault1690417561186 {
     name = 'ChangeCacheRemoteFilesDefault1690417561186'
 
diff --git a/packages/backend/migration/1690417561187-Fix.js b/packages/backend/migration/1690417561187-Fix.js
index e780e66d7b..7f1d62d68c 100644
--- a/packages/backend/migration/1690417561187-Fix.js
+++ b/packages/backend/migration/1690417561187-Fix.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export class Fix1690417561187 {
     name = 'Fix1690417561187'
 
diff --git a/packages/backend/migration/1690569881926-user-2fa-backup-codes.js b/packages/backend/migration/1690569881926-user-2fa-backup-codes.js
index 2049df8ea2..a3ef8dcf08 100644
--- a/packages/backend/migration/1690569881926-user-2fa-backup-codes.js
+++ b/packages/backend/migration/1690569881926-user-2fa-backup-codes.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export class User2faBackupCodes1690569881926 {
 	name = 'User2faBackupCodes1690569881926'
 
diff --git a/packages/backend/migration/1691649257651-refine-announcement.js b/packages/backend/migration/1691649257651-refine-announcement.js
index d8d63f3103..ac621155d5 100644
--- a/packages/backend/migration/1691649257651-refine-announcement.js
+++ b/packages/backend/migration/1691649257651-refine-announcement.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export class RefineAnnouncement1691649257651 {
     name = 'RefineAnnouncement1691649257651'
 
diff --git a/packages/backend/migration/1691657412740-refine-announcement-2.js b/packages/backend/migration/1691657412740-refine-announcement-2.js
index 8791f99f44..67edf19659 100644
--- a/packages/backend/migration/1691657412740-refine-announcement-2.js
+++ b/packages/backend/migration/1691657412740-refine-announcement-2.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export class RefineAnnouncement21691657412740 {
     name = 'RefineAnnouncement21691657412740'
 
diff --git a/packages/backend/migration/1695260774117-verified-links.js b/packages/backend/migration/1695260774117-verified-links.js
index 18e0571d81..64c8a9ad8f 100644
--- a/packages/backend/migration/1695260774117-verified-links.js
+++ b/packages/backend/migration/1695260774117-verified-links.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export class VerifiedLinks1695260774117 {
     name = 'VerifiedLinks1695260774117'
 
diff --git a/packages/backend/migration/1695288787870-following-notify.js b/packages/backend/migration/1695288787870-following-notify.js
index e7e2194b15..b3f78d5f2a 100644
--- a/packages/backend/migration/1695288787870-following-notify.js
+++ b/packages/backend/migration/1695288787870-following-notify.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export class FollowingNotify1695288787870 {
     name = 'FollowingNotify1695288787870'
 
diff --git a/packages/backend/migration/1695440131671-short-name.js b/packages/backend/migration/1695440131671-short-name.js
index 2c37297fc1..fdc256caf8 100644
--- a/packages/backend/migration/1695440131671-short-name.js
+++ b/packages/backend/migration/1695440131671-short-name.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export class ShortName1695440131671 {
     name = 'ShortName1695440131671'
 
diff --git a/packages/backend/migration/1695605508898-mutingNotificationTypes.js b/packages/backend/migration/1695605508898-mutingNotificationTypes.js
index 8c0e52a2f0..67d4243142 100644
--- a/packages/backend/migration/1695605508898-mutingNotificationTypes.js
+++ b/packages/backend/migration/1695605508898-mutingNotificationTypes.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export class MutingNotificationTypes1695605508898 {
     name = 'MutingNotificationTypes1695605508898'
 
diff --git a/packages/backend/migration/1695901659683-note-updated-at.js b/packages/backend/migration/1695901659683-note-updated-at.js
index d8a151a1f7..e828fb1a6f 100644
--- a/packages/backend/migration/1695901659683-note-updated-at.js
+++ b/packages/backend/migration/1695901659683-note-updated-at.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export class NoteUpdatedAt1695901659683 {
     name = 'NoteUpdatedAt1695901659683'
 
diff --git a/packages/backend/migration/1696323464251-user-list-membership.js b/packages/backend/migration/1696323464251-user-list-membership.js
index 7534040c4c..dc1d438dd7 100644
--- a/packages/backend/migration/1696323464251-user-list-membership.js
+++ b/packages/backend/migration/1696323464251-user-list-membership.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export class UserListMembership1696323464251 {
     name = 'UserListMembership1696323464251'
 
diff --git a/packages/backend/migration/1696331570827-hibernation.js b/packages/backend/migration/1696331570827-hibernation.js
index 119d35913f..1487ece77c 100644
--- a/packages/backend/migration/1696331570827-hibernation.js
+++ b/packages/backend/migration/1696331570827-hibernation.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export class Hibernation1696331570827 {
     name = 'Hibernation1696331570827'
 
diff --git a/packages/backend/migration/1696332072038-clean.js b/packages/backend/migration/1696332072038-clean.js
index 97dba655f4..92a6810d6a 100644
--- a/packages/backend/migration/1696332072038-clean.js
+++ b/packages/backend/migration/1696332072038-clean.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export class Clean1696332072038 {
     name = 'Clean1696332072038'
 
diff --git a/packages/backend/migration/1700383825690-hard-mute.js b/packages/backend/migration/1700383825690-hard-mute.js
index afd3247f5c..92c3ada4a1 100644
--- a/packages/backend/migration/1700383825690-hard-mute.js
+++ b/packages/backend/migration/1700383825690-hard-mute.js
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export class HardMute1700383825690 {
     name = 'HardMute1700383825690'
 
diff --git a/packages/backend/src/core/ChannelFollowingService.ts b/packages/backend/src/core/ChannelFollowingService.ts
index 75843b9773..12251595e2 100644
--- a/packages/backend/src/core/ChannelFollowingService.ts
+++ b/packages/backend/src/core/ChannelFollowingService.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
 import Redis from 'ioredis';
 import { DI } from '@/di-symbols.js';
diff --git a/packages/backend/src/misc/fastify-hook-handlers.ts b/packages/backend/src/misc/fastify-hook-handlers.ts
index 49a48f6a6b..3e1c099e00 100644
--- a/packages/backend/src/misc/fastify-hook-handlers.ts
+++ b/packages/backend/src/misc/fastify-hook-handlers.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 import type { onRequestHookHandler } from 'fastify';
 
 export const handleRequestRedirectToOmitSearch: onRequestHookHandler = (request, reply, done) => {
diff --git a/packages/backend/src/misc/is-pure-renote.ts b/packages/backend/src/misc/is-pure-renote.ts
index 994d981522..f9c2243a06 100644
--- a/packages/backend/src/misc/is-pure-renote.ts
+++ b/packages/backend/src/misc/is-pure-renote.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 import type { MiNote } from '@/models/Note.js';
 
 export function isPureRenote(note: MiNote): note is MiNote & { renoteId: NonNullable<MiNote['renoteId']> } {
diff --git a/packages/backend/src/misc/loader.ts b/packages/backend/src/misc/loader.ts
index 25f7b54d31..7f29b9db10 100644
--- a/packages/backend/src/misc/loader.ts
+++ b/packages/backend/src/misc/loader.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export type FetchFunction<K, V> = (key: K) => Promise<V>;
 
 type ResolveReject<V> = Parameters<ConstructorParameters<typeof Promise<V>>[0]>;
diff --git a/packages/backend/src/models/ReversiGame.ts b/packages/backend/src/models/ReversiGame.ts
index c03335dd63..6b29a0ce8c 100644
--- a/packages/backend/src/models/ReversiGame.ts
+++ b/packages/backend/src/models/ReversiGame.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm';
 import { id } from './util/id.js';
 import { MiUser } from './User.js';
diff --git a/packages/backend/src/models/json-schema/signin.ts b/packages/backend/src/models/json-schema/signin.ts
index d27d2490c5..45732a742b 100644
--- a/packages/backend/src/models/json-schema/signin.ts
+++ b/packages/backend/src/models/json-schema/signin.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export const packedSigninSchema = {
 	type: 'object',
 	properties: {
diff --git a/packages/backend/test/jest.setup.ts b/packages/backend/test/jest.setup.ts
index cf5b9bf24d..861bc6db66 100644
--- a/packages/backend/test/jest.setup.ts
+++ b/packages/backend/test/jest.setup.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 import { initTestDb, sendEnvResetRequest } from './utils.js';
 
 beforeAll(async () => {
diff --git a/packages/backend/test/unit/ApMfmService.ts b/packages/backend/test/unit/ApMfmService.ts
index 2b79041c86..79cb81f5c9 100644
--- a/packages/backend/test/unit/ApMfmService.ts
+++ b/packages/backend/test/unit/ApMfmService.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 import * as assert from 'assert';
 import { Test } from '@nestjs/testing';
 
diff --git a/packages/backend/test/unit/misc/loader.ts b/packages/backend/test/unit/misc/loader.ts
index fa37950951..2cf54e1555 100644
--- a/packages/backend/test/unit/misc/loader.ts
+++ b/packages/backend/test/unit/misc/loader.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 import { DebounceLoader } from '@/misc/loader.js';
 
 class Mock {
diff --git a/packages/frontend/.storybook/preview-head.html b/packages/frontend/.storybook/preview-head.html
index 30f3ebfb64..e50c488243 100644
--- a/packages/frontend/.storybook/preview-head.html
+++ b/packages/frontend/.storybook/preview-head.html
@@ -1,3 +1,8 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
 <link rel="preload" href="https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/about-icon.png?raw=true" as="image" type="image/png" crossorigin="anonymous">
 <link rel="preload" href="https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true" as="image" type="image/jpeg" crossorigin="anonymous">
 <link rel="stylesheet" href="https://unpkg.com/@tabler/icons-webfont@2.44.0/tabler-icons.min.css">
diff --git a/packages/frontend/src/components/global/I18n.vue b/packages/frontend/src/components/global/I18n.vue
index 162aa2bcf8..6b7723e6ac 100644
--- a/packages/frontend/src/components/global/I18n.vue
+++ b/packages/frontend/src/components/global/I18n.vue
@@ -1,3 +1,8 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
 <template>
 <render/>
 </template>
diff --git a/packages/frontend/src/filters/kmg.ts b/packages/frontend/src/filters/kmg.ts
index 4dcb5c5800..9608e420f6 100644
--- a/packages/frontend/src/filters/kmg.ts
+++ b/packages/frontend/src/filters/kmg.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export default (v, fractionDigits = 0) => {
 	if (v == null) return 'N/A';
 	if (v === 0) return '0';
diff --git a/packages/frontend/src/scripts/check-reaction-permissions.ts b/packages/frontend/src/scripts/check-reaction-permissions.ts
index e7b473dd75..8fc857f84f 100644
--- a/packages/frontend/src/scripts/check-reaction-permissions.ts
+++ b/packages/frontend/src/scripts/check-reaction-permissions.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 import * as Misskey from 'misskey-js';
 import { UnicodeEmojiDef } from './emojilist.js';
 
diff --git a/packages/frontend/src/scripts/clear-cache.ts b/packages/frontend/src/scripts/clear-cache.ts
index b20109ec72..71d1232710 100644
--- a/packages/frontend/src/scripts/clear-cache.ts
+++ b/packages/frontend/src/scripts/clear-cache.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 import { unisonReload } from '@/scripts/unison-reload.js';
 import * as os from '@/os.js';
 import { miLocalStorage } from '@/local-storage.js';
diff --git a/packages/frontend/src/scripts/code-highlighter.ts b/packages/frontend/src/scripts/code-highlighter.ts
index 2733897bab..5dd0a3be78 100644
--- a/packages/frontend/src/scripts/code-highlighter.ts
+++ b/packages/frontend/src/scripts/code-highlighter.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 import { bundledThemesInfo } from 'shiki';
 import { getHighlighterCore, loadWasm } from 'shiki/core';
 import darkPlus from 'shiki/themes/dark-plus.mjs';
diff --git a/packages/frontend/src/scripts/media-has-audio.ts b/packages/frontend/src/scripts/media-has-audio.ts
index 3421a38a76..4bf3ee5d97 100644
--- a/packages/frontend/src/scripts/media-has-audio.ts
+++ b/packages/frontend/src/scripts/media-has-audio.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export default async function hasAudio(media: HTMLMediaElement) {
 	const cloned = media.cloneNode() as HTMLMediaElement;
 	cloned.muted = (cloned as typeof cloned & Partial<HTMLVideoElement>).playsInline = true;
diff --git a/packages/frontend/src/type.ts b/packages/frontend/src/type.ts
index 9c0fc2a11e..5ff27158d2 100644
--- a/packages/frontend/src/type.ts
+++ b/packages/frontend/src/type.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 export type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };
 
 export type WithNonNullable<T, K extends keyof T> = T & { [P in K]-?: NonNullable<T[P]> };
diff --git a/scripts/changelog-checker/src/checker.ts b/scripts/changelog-checker/src/checker.ts
index bbd5b2270a..8fd6ff5629 100644
--- a/scripts/changelog-checker/src/checker.ts
+++ b/scripts/changelog-checker/src/checker.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 import { Release } from './parser.js';
 
 export class Result {
diff --git a/scripts/changelog-checker/src/index.ts b/scripts/changelog-checker/src/index.ts
index 8cbeb297d9..0e2c5ce057 100644
--- a/scripts/changelog-checker/src/index.ts
+++ b/scripts/changelog-checker/src/index.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 import * as process from 'process';
 import * as fs from 'fs';
 import { parseChangeLog } from './parser.js';
diff --git a/scripts/changelog-checker/src/parser.ts b/scripts/changelog-checker/src/parser.ts
index d6a9ddeda8..894d60d6af 100644
--- a/scripts/changelog-checker/src/parser.ts
+++ b/scripts/changelog-checker/src/parser.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 import * as fs from 'node:fs';
 import { unified } from 'unified';
 import remarkParse from 'remark-parse';
diff --git a/scripts/changelog-checker/test/checker.test.ts b/scripts/changelog-checker/test/checker.test.ts
index bc73e5622b..9ca8fa85f2 100644
--- a/scripts/changelog-checker/test/checker.test.ts
+++ b/scripts/changelog-checker/test/checker.test.ts
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 import {expect, suite, test} from "vitest";
 import {Release, ReleaseCategory} from "../src/parser";
 import {checkNewRelease, checkNewTopic} from "../src/checker";
@@ -411,4 +416,4 @@ suite('checkNewTopic', () => {
 		console.log(result.message)
 		expect(result.success).toBe(false)
 	})
-})
\ No newline at end of file
+})
diff --git a/scripts/tarball.mjs b/scripts/tarball.mjs
index 936a43d270..b1862ad289 100644
--- a/scripts/tarball.mjs
+++ b/scripts/tarball.mjs
@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
 import { createWriteStream } from 'node:fs';
 import { mkdir } from 'node:fs/promises';
 import { resolve } from 'node:path';

From 88d47ab0245bf5990096e59ced280f62cb7e7a60 Mon Sep 17 00:00:00 2001
From: FineArchs <133759614+FineArchs@users.noreply.github.com>
Date: Wed, 13 Mar 2024 22:38:26 +0900
Subject: [PATCH 028/191] =?UTF-8?q?=E3=83=97=E3=83=A9=E3=82=B0=E3=82=A4?=
 =?UTF-8?q?=E3=83=B3=E3=81=AE=E7=B0=A1=E6=98=93=E7=9A=84=E3=81=AA=E3=83=AD?=
 =?UTF-8?q?=E3=82=B0=E3=82=92=E8=A1=A8=E7=A4=BA=E3=81=99=E3=82=8B=E6=A9=9F?=
 =?UTF-8?q?=E8=83=BD=20(#13564)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* add plugin logging

* change variable name

* Update plugin.ts

* Update CHANGELOG.md
---
 CHANGELOG.md                                  |  2 ++
 locales/ja-JP.yml                             |  1 +
 .../frontend/src/pages/settings/plugin.vue    | 20 ++++++++++++---
 packages/frontend/src/plugin.ts               | 25 +++++++++++++------
 4 files changed, 37 insertions(+), 11 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 83d0a3f7d2..f1e863a8f2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,8 @@
 - Enhance: 広告がMisskeyと同一ドメインの場合はRouterで遷移するように
 - Enhance: リアクション・いいねの総数を表示するように
 - Enhance: リアクション受け入れが「いいねのみ」の場合はリアクション絵文字一覧を表示しないように
+- Enhance: 設定>プラグインのページからプラグインの簡易的なログやエラーを見られるように
+  - 実装の都合により、プラグインは1つエラーを起こした時に即時停止するようになりました
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
 - Fix: ローカルURLのプレビューポップアップが左上に表示される
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 64705868b9..f42fd6587a 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1772,6 +1772,7 @@ _plugin:
   installWarn: "信頼できないプラグインはインストールしないでください。"
   manage: "プラグインの管理"
   viewSource: "ソースを表示"
+  viewLog: "ログを表示"
 
 _preferencesBackups:
   list: "作成したバックアップ"
diff --git a/packages/frontend/src/pages/settings/plugin.vue b/packages/frontend/src/pages/settings/plugin.vue
index 0ab75b95a2..9804454e66 100644
--- a/packages/frontend/src/pages/settings/plugin.vue
+++ b/packages/frontend/src/pages/settings/plugin.vue
@@ -41,13 +41,26 @@ SPDX-License-Identifier: AGPL-3.0-only
 					<MkButton inline danger @click="uninstall(plugin)"><i class="ti ti-trash"></i> {{ i18n.ts.uninstall }}</MkButton>
 				</div>
 
+				<MkFolder>
+					<template #icon><i class="ti ti-terminal-2"></i></template>
+					<template #label>{{ i18n.ts._plugin.viewLog }}</template>
+
+					<div class="_gaps_s">
+						<div class="_buttons">
+							<MkButton inline @click="copy(pluginLogs.get(plugin.id)?.join('\n'))"><i class="ti ti-copy"></i> {{ i18n.ts.copy }}</MkButton>
+						</div>
+
+						<MkCode :code="pluginLogs.get(plugin.id)?.join('\n') ?? ''"/>
+					</div>
+				</MkFolder>
+
 				<MkFolder>
 					<template #icon><i class="ti ti-code"></i></template>
 					<template #label>{{ i18n.ts._plugin.viewSource }}</template>
 
 					<div class="_gaps_s">
 						<div class="_buttons">
-							<MkButton inline @click="copy(plugin)"><i class="ti ti-copy"></i> {{ i18n.ts.copy }}</MkButton>
+							<MkButton inline @click="copy(plugin.src)"><i class="ti ti-copy"></i> {{ i18n.ts.copy }}</MkButton>
 						</div>
 
 						<MkCode :code="plugin.src ?? ''" lang="is"/>
@@ -74,6 +87,7 @@ import { ColdDeviceStorage } from '@/store.js';
 import { unisonReload } from '@/scripts/unison-reload.js';
 import { i18n } from '@/i18n.js';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
+import { pluginLogs } from '@/plugin.js';
 
 const plugins = ref(ColdDeviceStorage.get('plugins'));
 
@@ -87,8 +101,8 @@ async function uninstall(plugin) {
 	});
 }
 
-function copy(plugin) {
-	copyToClipboard(plugin.src ?? '');
+function copy(text) {
+	copyToClipboard(text ?? '');
 	os.success();
 }
 
diff --git a/packages/frontend/src/plugin.ts b/packages/frontend/src/plugin.ts
index 743cadc36a..81233a5a5e 100644
--- a/packages/frontend/src/plugin.ts
+++ b/packages/frontend/src/plugin.ts
@@ -3,6 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
+import { ref } from 'vue';
 import { Interpreter, Parser, utils, values } from '@syuilo/aiscript';
 import { aiScriptReadline, createAiScriptEnv } from '@/scripts/aiscript/api.js';
 import { inputText } from '@/os.js';
@@ -10,6 +11,7 @@ import { Plugin, noteActions, notePostInterruptors, noteViewInterruptors, postFo
 
 const parser = new Parser();
 const pluginContexts = new Map<string, Interpreter>();
+export const pluginLogs = ref(new Map<string, string[]>());
 
 export async function install(plugin: Plugin): Promise<void> {
 	// 後方互換性のため
@@ -22,21 +24,27 @@ export async function install(plugin: Plugin): Promise<void> {
 		in: aiScriptReadline,
 		out: (value): void => {
 			console.log(value);
+			pluginLogs.value.get(plugin.id).push(utils.reprValue(value));
 		},
 		log: (): void => {
 		},
+		err: (err): void => {
+			pluginLogs.value.get(plugin.id).push(`${err}`);
+			throw err; // install時のtry-catchに反応させる
+		},
 	});
 
 	initPlugin({ plugin, aiscript });
 
-	try {
-		await aiscript.exec(parser.parse(plugin.src));
-	} catch (err) {
-		console.error('Plugin install failed:', plugin.name, 'v' + plugin.version);
-		return;
-	}
-
-	console.info('Plugin installed:', plugin.name, 'v' + plugin.version);
+	aiscript.exec(parser.parse(plugin.src)).then(
+		() => {
+			console.info('Plugin installed:', plugin.name, 'v' + plugin.version);
+		},
+		(err) => {
+			console.error('Plugin install failed:', plugin.name, 'v' + plugin.version);
+			throw err;
+		},
+	);
 }
 
 function createPluginEnv(opts: { plugin: Plugin; storageKey: string }): Record<string, values.Value> {
@@ -92,6 +100,7 @@ function createPluginEnv(opts: { plugin: Plugin; storageKey: string }): Record<s
 
 function initPlugin({ plugin, aiscript }): void {
 	pluginContexts.set(plugin.id, aiscript);
+	pluginLogs.value.set(plugin.id, []);
 }
 
 function registerPostFormAction({ pluginId, title, handler }): void {

From 75fa43bc59348c59a6e1a95823b5977bff75d78e Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Thu, 14 Mar 2024 17:39:38 +0900
Subject: [PATCH 029/191] fix(dev): fix duplication in .vscode/extensions.json

---
 .vscode/extensions.json | 1 -
 1 file changed, 1 deletion(-)

diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index d08109477c..3cdf81e339 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -4,7 +4,6 @@
 		"dbaeumer.vscode-eslint",
 		"Vue.volar",
 		"Orta.vscode-jest",
-		"dbaeumer.vscode-eslint",
 		"mrmlnc.vscode-json5"
 	]
 }

From 8604bd98078b3e31d8b53de1f9e54f5dab1f22bd Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Thu, 14 Mar 2024 17:42:30 +0900
Subject: [PATCH 030/191] fix(dev): vscode-jest: Deprecated: Please use
 jest.runMode instead.

---
 .vscode/settings.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.vscode/settings.json b/.vscode/settings.json
index e2a82b1ffe..0ceec23acd 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -7,7 +7,7 @@
 		"*.test.ts": "typescript"
 	},
 	"jest.jestCommandLine": "pnpm run jest",
-	"jest.autoRun": "off",
+	"jest.runMode": "on-demand",
 	"editor.codeActionsOnSave": {
 		"source.fixAll": "explicit"
 	},

From 71d0538647684d67de1b15467f890bd65ffc770d Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Thu, 14 Mar 2024 18:18:32 +0900
Subject: [PATCH 031/191] fix(frontend): update locales/index.d.ts

---
 locales/index.d.ts | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/locales/index.d.ts b/locales/index.d.ts
index 53c3159da6..87065e1d37 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -6805,6 +6805,10 @@ export interface Locale extends ILocale {
          * ソースを表示
          */
         "viewSource": string;
+        /**
+         * ログを表示
+         */
+        "viewLog": string;
     };
     "_preferencesBackups": {
         /**

From 4b1ca9ef619903e9ff1de10101c18569efbe099c Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Fri, 15 Mar 2024 22:02:57 +0900
Subject: [PATCH 032/191] =?UTF-8?q?fix(general):=20`flash/create`=E3=81=A7?=
 =?UTF-8?q?Play=E3=81=AE=E5=85=AC=E9=96=8B=E7=AF=84=E5=9B=B2=E3=82=92?=
 =?UTF-8?q?=E6=8C=87=E5=AE=9A=E3=81=A7=E3=81=8D=E3=81=AA=E3=81=84=E5=95=8F?=
 =?UTF-8?q?=E9=A1=8C=E3=81=AE=E4=BF=AE=E6=AD=A3=E3=81=A8=E7=B7=A8=E9=9B=86?=
 =?UTF-8?q?=E7=94=BB=E9=9D=A2=E3=81=AE=E8=AA=BF=E6=95=B4=20(#13574)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(backend): param `visibility` wasn't included in `flash/create`

* fix(frontend): tweak flash editor ui

* Update CHANGELOG.md
---
 CHANGELOG.md                                       |  2 +-
 locales/index.d.ts                                 |  4 ++++
 locales/ja-JP.yml                                  |  1 +
 .../src/server/api/endpoints/flash/create.ts       |  2 ++
 packages/frontend/src/pages/flash/flash-edit.vue   | 14 ++++++++------
 packages/misskey-js/src/autogen/types.ts           |  5 +++++
 6 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index f1e863a8f2..fa56f1a268 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,7 @@
 ## Unreleased
 
 ### General
--
+- Fix: Play作成時に設定した公開範囲が機能していない問題を修正
 
 ### Client
 - Enhance: 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるように
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 87065e1d37..7f4ec7ecb0 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -8635,6 +8635,10 @@ export interface Locale extends ILocale {
          * 説明
          */
         "summary": string;
+        /**
+         * 非公開に設定するとプロフィールに表示されなくなりますが、URLを知っている人は引き続きアクセスできます。
+         */
+        "visibilityDescription": string;
     };
     "_pages": {
         /**
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index f42fd6587a..8b44ac2121 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -2280,6 +2280,7 @@ _play:
   title: "タイトル"
   script: "スクリプト"
   summary: "説明"
+  visibilityDescription: "非公開に設定するとプロフィールに表示されなくなりますが、URLを知っている人は引き続きアクセスできます。"
 
 _pages:
   newPage: "ページの作成"
diff --git a/packages/backend/src/server/api/endpoints/flash/create.ts b/packages/backend/src/server/api/endpoints/flash/create.ts
index 584d167a29..361496e17e 100644
--- a/packages/backend/src/server/api/endpoints/flash/create.ts
+++ b/packages/backend/src/server/api/endpoints/flash/create.ts
@@ -44,6 +44,7 @@ export const paramDef = {
 		permissions: { type: 'array', items: {
 			type: 'string',
 		} },
+		visibility: { type: 'string', enum: ['public', 'private'], default: 'public' },
 	},
 	required: ['title', 'summary', 'script', 'permissions'],
 } as const;
@@ -66,6 +67,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				summary: ps.summary,
 				script: ps.script,
 				permissions: ps.permissions,
+				visibility: ps.visibility,
 			}).then(x => this.flashsRepository.findOneByOrFail(x.identifiers[0]));
 
 			return await this.flashEntityService.pack(flash);
diff --git a/packages/frontend/src/pages/flash/flash-edit.vue b/packages/frontend/src/pages/flash/flash-edit.vue
index 4418172e62..3625bc1164 100644
--- a/packages/frontend/src/pages/flash/flash-edit.vue
+++ b/packages/frontend/src/pages/flash/flash-edit.vue
@@ -18,16 +18,17 @@ SPDX-License-Identifier: AGPL-3.0-only
 			<MkCodeEditor v-model="script" lang="is">
 				<template #label>{{ i18n.ts._play.script }}</template>
 			</MkCodeEditor>
+			<MkSelect v-model="visibility">
+				<template #label>{{ i18n.ts.visibility }}</template>
+				<template #caption>{{ i18n.ts._play.visibilityDescription }}</template>
+				<option :key="'public'" :value="'public'">{{ i18n.ts.public }}</option>
+				<option :key="'private'" :value="'private'">{{ i18n.ts.private }}</option>
+			</MkSelect>
 			<div class="_buttons">
 				<MkButton primary @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
 				<MkButton @click="show"><i class="ti ti-eye"></i> {{ i18n.ts.show }}</MkButton>
 				<MkButton v-if="flash" danger @click="del"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
 			</div>
-			<MkSelect v-model="visibility">
-				<template #label>{{ i18n.ts.visibility }}</template>
-				<option :key="'public'" :value="'public'">{{ i18n.ts.public }}</option>
-				<option :key="'private'" :value="'private'">{{ i18n.ts.private }}</option>
-			</MkSelect>
 		</div>
 	</MkSpacer>
 </MkStickyContainer>
@@ -367,7 +368,7 @@ const props = defineProps<{
 }>();
 
 const flash = ref<Misskey.entities.Flash | null>(null);
-const visibility = ref<Misskey.entities.FlashUpdateRequest['visibility']>('public');
+const visibility = ref<'private' | 'public'>('public');
 
 if (props.id) {
 	flash.value = await misskeyApi('flash/show', {
@@ -420,6 +421,7 @@ async function save() {
 			summary: summary.value,
 			permissions: permissions.value,
 			script: script.value,
+			visibility: visibility.value,
 		});
 		router.push('/play/' + created.id + '/edit');
 	}
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index be3e86bd78..3c862f690e 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -22686,6 +22686,11 @@ export type operations = {
           summary: string;
           script: string;
           permissions: string[];
+          /**
+           * @default public
+           * @enum {string}
+           */
+          visibility?: 'public' | 'private';
         };
       };
     };

From 7e63ab0f5628bea33e8867d8257779b9ffeb8dd6 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Sun, 17 Mar 2024 10:34:13 +0900
Subject: [PATCH 033/191] refactor(backend): refactor chart engine

---
 packages/backend/src/core/chart/core.ts | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/packages/backend/src/core/chart/core.ts b/packages/backend/src/core/chart/core.ts
index aa0cb9dc2b..f10e30ef10 100644
--- a/packages/backend/src/core/chart/core.ts
+++ b/packages/backend/src/core/chart/core.ts
@@ -459,13 +459,15 @@ export default abstract class Chart<T extends Schema> {
 				}
 			}
 
-			// bake unique count
+			// bake cardinality
 			for (const [k, v] of Object.entries(finalDiffs)) {
 				if (this.schema[k].uniqueIncrement) {
 					const name = COLUMN_PREFIX + k.replaceAll('.', COLUMN_DELIMITER) as keyof Columns<T>;
 					const tempColumnName = UNIQUE_TEMP_COLUMN_PREFIX + k.replaceAll('.', COLUMN_DELIMITER) as keyof TempColumnsForUnique<T>;
-					queryForHour[name] = new Set([...(v as string[]), ...(logHour[tempColumnName] as unknown as string[])]).size;
-					queryForDay[name] = new Set([...(v as string[]), ...(logDay[tempColumnName] as unknown as string[])]).size;
+					const cardinalityOfHour = new Set([...(v as string[]), ...(logHour[tempColumnName] as unknown as string[])]).size;
+					const cardinalityOfDay = new Set([...(v as string[]), ...(logDay[tempColumnName] as unknown as string[])]).size;
+					queryForHour[name] = cardinalityOfHour;
+					queryForDay[name] = cardinalityOfDay;
 				}
 			}
 
@@ -637,7 +639,7 @@ export default abstract class Chart<T extends Schema> {
 		// 要求された範囲にログがひとつもなかったら
 		if (logs.length === 0) {
 			// もっとも新しいログを持ってくる
-			// (すくなくともひとつログが無いと隙間埋めできないため)
+			// (すくなくともひとつログが無いと補間できないため)
 			const recentLog = await repository.findOne({
 				where: group ? {
 					group: group,
@@ -654,7 +656,7 @@ export default abstract class Chart<T extends Schema> {
 		// 要求された範囲の最も古い箇所に位置するログが存在しなかったら
 		} else if (!isTimeSame(new Date(logs.at(-1)!.date * 1000), gt)) {
 			// 要求された範囲の最も古い箇所時点での最も新しいログを持ってきて末尾に追加する
-			// (隙間埋めできないため)
+			// (補間できないため)
 			const outdatedLog = await repository.findOne({
 				where: {
 					date: LessThan(Chart.dateToTimestamp(gt)),
@@ -683,7 +685,7 @@ export default abstract class Chart<T extends Schema> {
 			if (log) {
 				chart.unshift(this.convertRawRecord(log));
 			} else {
-				// 隙間埋め
+				// 補間
 				const latest = logs.find(l => isTimeBefore(new Date(l.date * 1000), current));
 				const data = latest ? this.convertRawRecord(latest) : null;
 				chart.unshift(this.getNewLog(data));

From dcfab918e9885ffd533f12d7d62e06a5072baa5c Mon Sep 17 00:00:00 2001
From: BackRunner <dev@backrunner.top>
Date: Sun, 17 Mar 2024 17:47:29 +0800
Subject: [PATCH 034/191] feat: send heartbeat right after visibility changed
 to 'visible' (#13581)

---
 packages/frontend/src/stream.ts | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/packages/frontend/src/stream.ts b/packages/frontend/src/stream.ts
index 0c5ee06197..0d5bd78b09 100644
--- a/packages/frontend/src/stream.ts
+++ b/packages/frontend/src/stream.ts
@@ -8,7 +8,12 @@ import { markRaw } from 'vue';
 import { $i } from '@/account.js';
 import { wsOrigin } from '@/config.js';
 
+// heart beat interval in ms
+const HEART_BEAT_INTERVAL = 1000 * 60;
+
 let stream: Misskey.Stream | null = null;
+let timeoutHeartBeat: ReturnType<typeof setTimeout> | null = null;
+let lastHeartbeatCall = 0;
 
 export function useStream(): Misskey.Stream {
 	if (stream) return stream;
@@ -17,7 +22,18 @@ export function useStream(): Misskey.Stream {
 		token: $i.token,
 	} : null));
 
-	window.setTimeout(heartbeat, 1000 * 60);
+	if (timeoutHeartBeat) window.clearTimeout(timeoutHeartBeat);
+	timeoutHeartBeat = window.setTimeout(heartbeat, HEART_BEAT_INTERVAL);
+
+	// send heartbeat right now when last send time is over HEART_BEAT_INTERVAL
+	document.addEventListener('visibilitychange', () => {
+		if (
+			!stream
+			|| document.visibilityState !== 'visible'
+			|| Date.now() - lastHeartbeatCall < HEART_BEAT_INTERVAL
+		) return;
+		heartbeat();
+	});
 
 	return stream;
 }
@@ -26,5 +42,7 @@ function heartbeat(): void {
 	if (stream != null && document.visibilityState === 'visible') {
 		stream.heartbeat();
 	}
-	window.setTimeout(heartbeat, 1000 * 60);
+	lastHeartbeatCall = Date.now();
+	if (timeoutHeartBeat) window.clearTimeout(timeoutHeartBeat);
+	timeoutHeartBeat = window.setTimeout(heartbeat, HEART_BEAT_INTERVAL);
 }

From b65203c9f852a29a3a6e7ce81c6761e9ac228bf3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sun, 17 Mar 2024 20:33:33 +0900
Subject: [PATCH 035/191] =?UTF-8?q?fix(frontend):=20WebGL2=E3=82=B3?=
 =?UTF-8?q?=E3=83=B3=E3=83=86=E3=82=AD=E3=82=B9=E3=83=88=E3=81=AE=E5=88=9D?=
 =?UTF-8?q?=E6=9C=9F=E5=8C=96=E3=81=AB=E5=A4=B1=E6=95=97=E3=81=99=E3=82=8B?=
 =?UTF-8?q?=E3=81=A8Misskey=E3=81=8C=E8=B5=B7=E5=8B=95=E3=81=A7=E3=81=8D?=
 =?UTF-8?q?=E3=81=AA=E3=81=8F=E3=81=AA=E3=82=8B=E5=95=8F=E9=A1=8C=E3=82=92?=
 =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20(#13587)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Fixed startup crash with seasonal effects

(cherry picked from commit eba0c2cc61512db22109e2f15604eb65f5b7d2f2)

* Update Changelog

* Update Changelog

---------

Co-authored-by: Leah <kevinlukej@gmail.com>
---
 CHANGELOG.md                                  |  2 +
 packages/frontend/src/boot/main-boot.ts       | 44 ++++++++++---------
 .../frontend/src/scripts/snowfall-effect.ts   |  4 +-
 3 files changed, 29 insertions(+), 21 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index fa56f1a268..cbd190d714 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,8 @@
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
 - Fix: ローカルURLのプレビューポップアップが左上に表示される
+- Fix: WebGL2をサポートしないブラウザで「季節に応じた画面の演出」が有効になっているとき、Misskeyが起動できなくなる問題を修正  
+  (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/459)
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts
index 8016e8b0e0..5cb19f388a 100644
--- a/packages/frontend/src/boot/main-boot.ts
+++ b/packages/frontend/src/boot/main-boot.ts
@@ -75,27 +75,31 @@ export async function mainBoot() {
 			mainRouter.push('/search');
 		},
 	};
-
-	if (defaultStore.state.enableSeasonalScreenEffect) {
-		const month = new Date().getMonth() + 1;
-		if (defaultStore.state.hemisphere === 'S') {
-			// ▼南半球
-			if (month === 7 || month === 8) {
-				const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect;
-				new SnowfallEffect({}).render();
+	try {
+		if (defaultStore.state.enableSeasonalScreenEffect) {
+			const month = new Date().getMonth() + 1;
+			if (defaultStore.state.hemisphere === 'S') {
+				// ▼南半球
+				if (month === 7 || month === 8) {
+					const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect;
+					new SnowfallEffect({}).render();
+				}
+			} else {
+				// ▼北半球
+				if (month === 12 || month === 1) {
+					const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect;
+					new SnowfallEffect({}).render();
+				} else if (month === 3 || month === 4) {
+					const SakuraEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect;
+					new SakuraEffect({
+						sakura: true,
+					}).render();
+				}
 			}
-		} else {
-			// ▼北半球
-			if (month === 12 || month === 1) {
-				const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect;
-				new SnowfallEffect({}).render();
-			} else if (month === 3 || month === 4) {
-				const SakuraEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect;
-				new SakuraEffect({
-					sakura: true,
-				}).render();
-			}
-		}
+		}	
+	} catch (error) {
+		// console.error(error);
+		console.error('Failed to initialise the seasonal screen effect canvas context:', error);
 	}
 
 	if ($i) {
diff --git a/packages/frontend/src/scripts/snowfall-effect.ts b/packages/frontend/src/scripts/snowfall-effect.ts
index 11fcaa0716..d88bdb6660 100644
--- a/packages/frontend/src/scripts/snowfall-effect.ts
+++ b/packages/frontend/src/scripts/snowfall-effect.ts
@@ -155,7 +155,9 @@ export class SnowfallEffect {
 		max: 0.125,
 		easing: 0.0005,
 	};
-
+	/**
+	 * @throws {Error} - Thrown when it fails to get WebGL context for the canvas 
+	 */
 	constructor(options: {
 		sakura?: boolean;
 	}) {

From a38646bd0f732c3f71bf9e8174baa7d66f8eae9f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 18 Mar 2024 14:20:28 +0900
Subject: [PATCH 036/191] =?UTF-8?q?fix(backend):=20=E3=83=95=E3=82=A9?=
 =?UTF-8?q?=E3=83=AD=E3=83=BC=E3=83=AA=E3=82=AF=E3=82=A8=E3=82=B9=E3=83=88?=
 =?UTF-8?q?=E3=82=92=E4=BD=9C=E6=88=90=E3=81=99=E3=82=8B=E9=9A=9B=E3=81=AB?=
 =?UTF-8?q?=E6=97=A2=E5=AD=98=E3=81=AE=E3=82=82=E3=81=AE=E3=81=AF=E5=89=8A?=
 =?UTF-8?q?=E9=99=A4=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=20(#1358?=
 =?UTF-8?q?8)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix: delete old follow request (if exists) before creating new

(cherry picked from commit ea948ccadc7eace1fcace176c9c070b2a9b46f56)

* Update Changelog

* Update Changelog

---------

Co-authored-by: Kaity A <kaity@atikayda.au>
---
 CHANGELOG.md                                      | 2 ++
 packages/backend/src/core/UserFollowingService.ts | 6 ++++++
 2 files changed, 8 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index cbd190d714..09f7bba18b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,8 @@
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
+- Fix: フォローリクエストを作成する際に既存のものは削除するように  
+  (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/440)
 
 ## 2024.3.1
 
diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts
index 0a492c06e4..deeecdeb1f 100644
--- a/packages/backend/src/core/UserFollowingService.ts
+++ b/packages/backend/src/core/UserFollowingService.ts
@@ -511,6 +511,12 @@ export class UserFollowingService implements OnModuleInit {
 		if (blocking) throw new Error('blocking');
 		if (blocked) throw new Error('blocked');
 
+		// Remove old follow requests before creating a new one.
+		await this.followRequestsRepository.delete({
+			followeeId: followee.id,
+			followerId: follower.id,
+		});
+
 		const followRequest = await this.followRequestsRepository.insert({
 			id: this.idService.gen(),
 			followerId: follower.id,

From 067cdf3ce422f46535c3f70be91c3b55e03248ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 18 Mar 2024 18:21:27 +0900
Subject: [PATCH 037/191] =?UTF-8?q?enhance(frontend):=20=E3=83=9A=E3=83=BC?=
 =?UTF-8?q?=E3=82=B8=E3=81=AE=E3=83=87=E3=82=B6=E3=82=A4=E3=83=B3=E3=82=92?=
 =?UTF-8?q?=E8=AA=BF=E6=95=B4=20(#13590)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance(frontend): ページのデザインを調整

* 共有ボタンを直感的な導線に変更

* Update Changelog

* Update packages/frontend/src/components/page/page.image.vue

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 CHANGELOG.md                                  |   1 +
 .../src/components/page/page.image.vue        |  24 +-
 .../src/components/page/page.note.vue         |  13 +-
 .../src/components/page/page.text.vue         |   8 +-
 .../frontend/src/components/page/page.vue     |   2 +-
 .../page-editor/els/page-editor.el.note.vue   |   2 +-
 packages/frontend/src/pages/page.vue          | 410 ++++++++++++------
 7 files changed, 306 insertions(+), 154 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 09f7bba18b..5d74090b35 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@
 - Enhance: リアクション受け入れが「いいねのみ」の場合はリアクション絵文字一覧を表示しないように
 - Enhance: 設定>プラグインのページからプラグインの簡易的なログやエラーを見られるように
   - 実装の都合により、プラグインは1つエラーを起こした時に即時停止するようになりました
+- Enhance: ページのデザインを変更	
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
 - Fix: ローカルURLのプレビューポップアップが左上に表示される
diff --git a/packages/frontend/src/components/page/page.image.vue b/packages/frontend/src/components/page/page.image.vue
index ced02943db..fc1ce9fc7b 100644
--- a/packages/frontend/src/components/page/page.image.vue
+++ b/packages/frontend/src/components/page/page.image.vue
@@ -4,19 +4,15 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-<div>
-	<MediaImage
-		v-if="image"
-		:image="image"
-		:disableImageLink="true"
-	/>
+<div :class="$style.root">
+	<MkMediaList v-if="image" :mediaList="[image]" :class="$style.mediaList"/>
 </div>
 </template>
 
 <script lang="ts" setup>
 import { onMounted, ref } from 'vue';
 import * as Misskey from 'misskey-js';
-import MediaImage from '@/components/MkMediaImage.vue';
+import MkMediaList from '@/components/MkMediaList.vue';
 
 const props = defineProps<{
 	block: Misskey.entities.PageBlock,
@@ -28,5 +24,17 @@ const image = ref<Misskey.entities.DriveFile | null>(null);
 onMounted(() => {
 	image.value = props.page.attachedFiles.find(x => x.id === props.block.fileId) ?? null;
 });
-
 </script>
+
+<style lang="scss" module>
+.root {
+	border: 1px solid var(--divider);
+	border-radius: var(--radius);
+	overflow: hidden;
+}
+.mediaList {
+	// MkMediaList 内の上部マージン 4px
+	margin-top: -4px;
+	height: calc(100% + 4px);
+}
+</style>
diff --git a/packages/frontend/src/components/page/page.note.vue b/packages/frontend/src/components/page/page.note.vue
index 7b56494a6e..b5ba407806 100644
--- a/packages/frontend/src/components/page/page.note.vue
+++ b/packages/frontend/src/components/page/page.note.vue
@@ -4,9 +4,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-<div style="margin: 1em 0;">
-	<MkNote v-if="note && !block.detailed" :key="note.id + ':normal'" v-model:note="note"/>
-	<MkNoteDetailed v-if="note && block.detailed" :key="note.id + ':detail'" v-model:note="note"/>
+<div :class="$style.root">
+	<MkNote v-if="note && !block.detailed" :key="note.id + ':normal'" :note="note"/>
+	<MkNoteDetailed v-if="note && block.detailed" :key="note.id + ':detail'" :note="note"/>
 </div>
 </template>
 
@@ -32,3 +32,10 @@ onMounted(() => {
 		});
 });
 </script>
+
+<style lang="scss" module>
+.root {
+	border: 1px solid var(--divider);
+	border-radius: var(--radius);
+}
+</style>
diff --git a/packages/frontend/src/components/page/page.text.vue b/packages/frontend/src/components/page/page.text.vue
index 81a4c4fa93..61247b381f 100644
--- a/packages/frontend/src/components/page/page.text.vue
+++ b/packages/frontend/src/components/page/page.text.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-<div class="_gaps">
+<div class="_gaps" :class="$style.textRoot">
 	<Mfm :text="block.text ?? ''" :isNote="false"/>
 	<MkUrlPreview v-for="url in urls" :key="url" :url="url"/>
 </div>
@@ -25,3 +25,9 @@ const props = defineProps<{
 
 const urls = props.block.text ? extractUrlFromMfm(mfm.parse(props.block.text)) : [];
 </script>
+
+<style lang="scss" module>
+.textRoot {
+	font-size: 1.1rem;
+}
+</style>
diff --git a/packages/frontend/src/components/page/page.vue b/packages/frontend/src/components/page/page.vue
index 53c70b01f4..a31c5eff28 100644
--- a/packages/frontend/src/components/page/page.vue
+++ b/packages/frontend/src/components/page/page.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-<div :class="{ [$style.center]: page.alignCenter, [$style.serif]: page.font === 'serif' }" class="_gaps_s">
+<div :class="{ [$style.center]: page.alignCenter, [$style.serif]: page.font === 'serif' }" class="_gaps">
 	<XBlock v-for="child in page.content" :key="child.id" :page="page" :block="child" :h="2"/>
 </div>
 </template>
diff --git a/packages/frontend/src/pages/page-editor/els/page-editor.el.note.vue b/packages/frontend/src/pages/page-editor/els/page-editor.el.note.vue
index 194a276f89..0a28386986 100644
--- a/packages/frontend/src/pages/page-editor/els/page-editor.el.note.vue
+++ b/packages/frontend/src/pages/page-editor/els/page-editor.el.note.vue
@@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 <XContainer :draggable="true" @remove="() => $emit('remove')">
 	<template #header><i class="ti ti-note"></i> {{ i18n.ts._pages.blocks.note }}</template>
 
-	<section style="padding: 0 16px 0 16px;">
+	<section style="padding: 16px;" class="_gaps_s">
 		<MkInput v-model="id">
 			<template #label>{{ i18n.ts._pages.blocks._note.id }}</template>
 			<template #caption>{{ i18n.ts._pages.blocks._note.idDescription }}</template>
diff --git a/packages/frontend/src/pages/page.vue b/packages/frontend/src/pages/page.vue
index bece32fc11..ab44533b81 100644
--- a/packages/frontend/src/pages/page.vue
+++ b/packages/frontend/src/pages/page.vue
@@ -6,48 +6,73 @@ SPDX-License-Identifier: AGPL-3.0-only
 <template>
 <MkStickyContainer>
 	<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
-	<MkSpacer :contentMax="700">
-		<Transition :name="defaultStore.state.animation ? 'fade' : ''" mode="out-in">
-			<div v-if="page" :key="page.id" class="xcukqgmh">
-				<div class="main">
-					<!--
-				<div class="header">
-					<h1>{{ page.title }}</h1>
-				</div>
-				-->
-					<div class="banner">
-						<MkMediaImage
-							v-if="page.eyeCatchingImageId"
-							:image="page.eyeCatchingImage"
-							:cover="true"
-							:disableImageLink="true"
-							class="thumbnail"
-						/>
+	<MkSpacer :contentMax="800">
+		<Transition
+			:enterActiveClass="defaultStore.state.animation ? $style.fadeEnterActive : ''"
+			:leaveActiveClass="defaultStore.state.animation ? $style.fadeLeaveActive : ''"
+			:enterFromClass="defaultStore.state.animation ? $style.fadeEnterFrom : ''"
+			:leaveToClass="defaultStore.state.animation ? $style.fadeLeaveTo : ''"
+		>
+			<div v-if="page" :key="page.id" class="_gaps">
+				<div :class="$style.pageMain">
+					<div :class="$style.pageBanner">
+						<div :class="$style.pageBannerBgRoot">
+							<MkImgWithBlurhash
+								v-if="page.eyeCatchingImageId"
+								:class="$style.pageBannerBg"
+								:hash="page.eyeCatchingImage?.blurhash"
+								:cover="true"
+								:forceBlurhash="true"
+							/>
+							<img
+								v-else-if="instance.backgroundImageUrl || instance.bannerUrl"
+								:class="[$style.pageBannerBg, $style.pageBannerBgFallback1]"
+								:src="getStaticImageUrl(instance.backgroundImageUrl ?? instance.bannerUrl!)"
+							/>
+							<div v-else :class="[$style.pageBannerBg, $style.pageBannerBgFallback2]"></div>
+						</div>
+						<div v-if="page.eyeCatchingImageId" :class="$style.pageBannerImage">
+							<MkMediaImage
+								:image="page.eyeCatchingImage!"
+								:cover="true"
+								:disableImageLink="true"
+								:class="$style.thumbnail"
+							/>
+						</div>
+						<div :class="$style.pageBannerTitle" class="_gaps_s">
+							<h1>{{ page.title || page.name }}</h1>
+							<div v-if="page.user" :class="$style.pageBannerTitleUser">
+								<MkAvatar :user="page.user" :class="$style.avatar" indicator link preview/> <MkA :to="`/@${username}`"><MkUserName :user="page.user" :nowrap="false"/></MkA>
+							</div>
+						</div>
 					</div>
-					<div class="content">
+					<div :class="$style.pageContent">
 						<XPage :page="page"/>
 					</div>
-					<div class="actions">
-						<div class="like">
+					<div :class="$style.pageActions">
+						<div>
 							<MkButton v-if="page.isLiked" v-tooltip="i18n.ts._pages.unlike" class="button" asLike primary @click="unlike()"><i class="ti ti-heart-off"></i><span v-if="page.likedCount > 0" class="count">{{ page.likedCount }}</span></MkButton>
 							<MkButton v-else v-tooltip="i18n.ts._pages.like" class="button" asLike @click="like()"><i class="ti ti-heart"></i><span v-if="page.likedCount > 0" class="count">{{ page.likedCount }}</span></MkButton>
 						</div>
-						<div class="other">
-							<button v-tooltip="i18n.ts.shareWithNote" v-click-anime class="_button" @click="shareWithNote"><i class="ti ti-repeat ti-fw"></i></button>
-							<button v-tooltip="i18n.ts.copyLink" v-click-anime class="_button" @click="copyLink"><i class="ti ti-link ti-fw"></i></button>
-							<button v-if="isSupportShare()" v-tooltip="i18n.ts.share" v-click-anime class="_button" @click="share"><i class="ti ti-share ti-fw"></i></button>
+						<div :class="$style.other">
+							<button v-tooltip="i18n.ts.copyLink" class="_button" :class="$style.generalActionButton" @click="copyLink"><i class="ti ti-link ti-fw"></i></button>
+							<button v-tooltip="i18n.ts.share" class="_button" :class="$style.generalActionButton" @click="share"><i class="ti ti-share ti-fw"></i></button>
 						</div>
 					</div>
-					<div class="user">
-						<MkAvatar :user="page.user" class="avatar" link preview/>
-						<div class="name">
-							<MkUserName :user="page.user" style="display: block;"/>
-							<MkAcct :user="page.user"/>
-						</div>
-						<MkFollowButton v-if="!$i || $i.id != page.user.id" :user="page.user" :inline="true" :transparent="false" :full="true" large class="koudoku"/>
+					<div :class="$style.pageUser">
+						<MkAvatar :user="page.user" :class="$style.avatar" link preview/>
+						<MkA :to="`/@${username}`">
+							<MkUserName :user="page.user" :class="$style.name"/>
+							<MkAcct :user="page.user" :class="$style.acct"/>
+						</MkA>
+						<MkFollowButton v-if="!$i || $i.id != page.user.id" :user="page.user!" :inline="true" :transparent="false" :full="true" :class="$style.follow"/>
 					</div>
-					<div class="links">
-						<MkA :to="`/@${username}/pages/${pageName}/view-source`" class="link">{{ i18n.ts._pages.viewSource }}</MkA>
+					<div :class="$style.pageDate">
+						<div><i class="ti ti-clock"></i> {{ i18n.ts.createdAt }}: <MkTime :time="page.createdAt" mode="detail"/></div>
+						<div v-if="page.createdAt != page.updatedAt"><i class="ti ti-clock-edit"></i> {{ i18n.ts.updatedAt }}: <MkTime :time="page.updatedAt" mode="detail"/></div>
+					</div>
+					<div :class="$style.pageLinks">
+						<MkA v-if="!$i || $i.id !== page.userId" :to="`/@${username}/pages/${pageName}/view-source`" class="link">{{ i18n.ts._pages.viewSource }}</MkA>
 						<template v-if="$i && $i.id === page.userId">
 							<MkA :to="`/pages/edit/${page.id}`" class="link">{{ i18n.ts._pages.editThisPage }}</MkA>
 							<button v-if="$i.pinnedPageId === page.id" class="link _textButton" @click="pin(false)">{{ i18n.ts.unpin }}</button>
@@ -55,10 +80,6 @@ SPDX-License-Identifier: AGPL-3.0-only
 						</template>
 					</div>
 				</div>
-				<div class="footer">
-					<div><i class="ti ti-clock"></i> {{ i18n.ts.createdAt }}: <MkTime :time="page.createdAt" mode="detail"/></div>
-					<div v-if="page.createdAt != page.updatedAt"><i class="ti ti-clock"></i> {{ i18n.ts.updatedAt }}: <MkTime :time="page.updatedAt" mode="detail"/></div>
-				</div>
 				<MkAd :prefer="['horizontal', 'horizontal-big']"/>
 				<MkContainer :max-height="300" :foldable="true" class="other">
 					<template #icon><i class="ti ti-clock"></i></template>
@@ -84,6 +105,7 @@ import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { url } from '@/config.js';
 import MkMediaImage from '@/components/MkMediaImage.vue';
+import MkImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
 import MkFollowButton from '@/components/MkFollowButton.vue';
 import MkContainer from '@/components/MkContainer.vue';
 import MkPagination from '@/components/MkPagination.vue';
@@ -94,6 +116,8 @@ import { pageViewInterruptors, defaultStore } from '@/store.js';
 import { deepClone } from '@/scripts/clone.js';
 import { $i } from '@/account.js';
 import { isSupportShare } from '@/scripts/navigator.js';
+import { instance } from '@/instance.js';
+import { getStaticImageUrl } from '@/scripts/media-proxy.js';
 import copyToClipboard from '@/scripts/copy-to-clipboard.js';
 
 const props = defineProps<{
@@ -133,35 +157,63 @@ function fetchPage() {
 	});
 }
 
-function share() {
-	navigator.share({
-		title: page.value.title ?? page.value.name,
-		text: page.value.summary,
-		url: `${url}/@${page.value.user.username}/pages/${page.value.name}`,
-	});
+function share(ev: MouseEvent) {
+	if (!page.value) return;
+
+	os.popupMenu([
+		{
+			text: i18n.ts.shareWithNote,
+			icon: 'ti ti-pencil',
+			action: shareWithNote,
+		},
+		...(isSupportShare() ? [{
+			text: i18n.ts.share,
+			icon: 'ti ti-share',
+			action: shareWithNavigator,
+		}] : []),
+	], ev.currentTarget ?? ev.target);
 }
 
 function copyLink() {
+	if (!page.value) return;
+
 	copyToClipboard(`${url}/@${page.value.user.username}/pages/${page.value.name}`);
 	os.success();
 }
 
 function shareWithNote() {
+	if (!page.value) return;
+
 	os.post({
-		initialText: `${page.value.title || page.value.name} ${url}/@${page.value.user.username}/pages/${page.value.name}`,
+		initialText: `${page.value.title || page.value.name}\n${url}/@${page.value.user.username}/pages/${page.value.name}`,
+		instant: true,
+	});
+}
+
+function shareWithNavigator() {
+	if (!page.value) return;
+
+	navigator.share({
+		title: page.value.title ?? page.value.name,
+		text: page.value.summary ?? undefined,
+		url: `${url}/@${page.value.user.username}/pages/${page.value.name}`,
 	});
 }
 
 function like() {
+	if (!page.value) return;
+
 	os.apiWithDialog('pages/like', {
 		pageId: page.value.id,
 	}).then(() => {
-		page.value.isLiked = true;
-		page.value.likedCount++;
+		page.value!.isLiked = true;
+		page.value!.likedCount++;
 	});
 }
 
 async function unlike() {
+	if (!page.value) return;
+
 	const confirm = await os.confirm({
 		type: 'warning',
 		text: i18n.ts.unlikeConfirm,
@@ -170,12 +222,14 @@ async function unlike() {
 	os.apiWithDialog('pages/unlike', {
 		pageId: page.value.id,
 	}).then(() => {
-		page.value.isLiked = false;
-		page.value.likedCount--;
+		page.value!.isLiked = false;
+		page.value!.likedCount--;
 	});
 }
 
 function pin(pin) {
+	if (!page.value) return;
+
 	os.apiWithDialog('i/update', {
 		pinnedPageId: pin ? page.value.id : null,
 	});
@@ -200,109 +254,185 @@ definePageMetadata(() => ({
 }));
 </script>
 
-<style lang="scss" scoped>
-.fade-enter-active,
-.fade-leave-active {
+<style lang="scss" module>
+.fadeEnterActive,
+.fadeLeaveActive {
 	transition: opacity 0.125s ease;
 }
-.fade-enter-from,
-.fade-leave-to {
+.fadeEnterFrom,
+.fadeLeaveTo {
 	opacity: 0;
 }
 
-.xcukqgmh {
-	> .main {
-		padding: 32px;
+.generalActionButton {
+	height: 2.5rem;
+	width: 2.5rem;
+	text-align: center;
+	border-radius: 99rem;
 
-		> .header {
-			padding: 16px;
-
-			> h1 {
-				margin: 0;
-			}
-		}
-
-		> .banner {
-			> .thumbnail {
-				// TODO: 良い感じのアスペクト比で表示
-				display: block;
-				width: 100%;
-				height: auto;
-				aspect-ratio: 3/1;
-				border-radius: var(--radius);
-				overflow: hidden;
-				object-fit: cover;
-			}
-		}
-
-		> .content {
-			margin-top: 16px;
-			padding: 16px 0 0 0;
-		}
-
-		> .actions {
-			display: flex;
-			align-items: center;
-			margin-top: 16px;
-			padding: 16px 0 0 0;
-			border-top: solid 0.5px var(--divider);
-
-			> .other {
-				margin-left: auto;
-
-				> button {
-					padding: 8px;
-					margin: 0 8px;
-
-					&:hover {
-						color: var(--fgHighlighted);
-					}
-				}
-			}
-		}
-
-		> .user {
-			margin-top: 16px;
-			padding: 16px 0 0 0;
-			border-top: solid 0.5px var(--divider);
-			display: flex;
-			align-items: center;
-
-			> .avatar {
-				width: 52px;
-				height: 52px;
-			}
-
-			> .name {
-				margin: 0 0 0 12px;
-				font-size: 90%;
-			}
-
-			> .koudoku {
-				margin-left: auto;
-			}
-		}
-
-		> .links {
-			margin-top: 16px;
-			padding: 24px 0 0 0;
-			border-top: solid 0.5px var(--divider);
-
-			> .link {
-				margin-right: 0.75em;
-			}
-		}
+	& :global(.ti) {
+		line-height: 2.5rem;
 	}
 
-	> .footer {
-		margin: var(--margin) 0 var(--margin) 0;
-		font-size: 85%;
-		opacity: 0.75;
+	&:hover,
+	&:focus-visible {
+		background-color: var(--accentedBg);
+		color: var(--accent);
+		text-decoration: none;
 	}
 }
-</style>
 
-<style module>
+.pageMain {
+	border-radius: var(--radius);
+	padding: 2rem;
+	background: var(--panel);
+	box-sizing: border-box;
+}
+
+.pageBanner {
+	width: calc(100% + 4rem);
+	margin: -2rem -2rem 1.5rem;
+	border-radius: var(--radius) var(--radius) 0 0;
+	overflow: hidden;
+	position: relative;
+
+	> .pageBannerBgRoot {
+		position: absolute;
+		top: 0;
+		left: 0;
+		width: 100%;
+		height: 100%;
+		overflow: hidden;
+
+		.pageBannerBg {
+			width: 100%;
+			height: 100%;
+			object-fit: cover;
+			opacity: .2;
+			filter: brightness(1.2);
+		}
+
+		.pageBannerBgFallback1 {
+			filter: blur(20px);
+		}
+
+		.pageBannerBgFallback2 {
+			background-color: var(--accentedBg);
+		}
+
+		&::after {
+			content: '';
+			position: absolute;
+			left: 0;
+			bottom: 0;
+			width: 100%;
+			height: 100px;
+			background: linear-gradient(0deg, var(--panel), transparent);
+		}
+	}
+
+	> .pageBannerImage {
+		position: relative;
+		padding-top: 56.25%;
+
+		> .thumbnail {
+			position: absolute;
+			top: 0;
+			left: 0;
+			width: 100%;
+			height: 100%;
+		}
+	}
+
+	> .pageBannerTitle {
+		position: relative;
+		padding: 1.5rem 2rem;
+
+		h1 {
+			font-size: 2rem;
+			font-weight: 700;
+			color: var(--fg);
+			margin: 0;
+		}
+
+		.pageBannerTitleUser {
+			--height: 32px;
+
+			.avatar {
+				height: var(--height);
+				width: var(--height);
+			}
+
+			line-height: var(--height);
+		}
+	}
+}
+
+.pageContent {
+	margin-bottom: 1.5rem;
+}
+
+.pageActions {
+	display: flex;
+	align-items: center;
+
+	border-top: 1px solid var(--divider);
+	padding-top: 1.5rem;
+	margin-bottom: 1.5rem;
+
+	> .other {
+		margin-left: auto;
+		display: flex;
+		gap: var(--marginHalf);
+	}
+}
+
+.pageUser {
+	display: flex;
+	align-items: center;
+
+	border-top: 1px solid var(--divider);
+	padding-top: 1.5rem;
+	margin-bottom: 1.5rem;
+
+	.avatar,
+	.name,
+	.acct {
+		display: block;
+	}
+
+	.avatar {
+		width: 4rem;
+		height: 4rem;
+		margin-right: 1rem;
+	}
+
+	.name {
+		font-size: 110%;
+		font-weight: 700;
+	}
+
+	.acct {
+		font-size: 90%;
+		opacity: 0.7;
+	}
+
+	.follow {
+		margin-left: auto;
+	}
+}
+
+.pageDate {
+	margin-bottom: 1.5rem;
+}
+
+.pageLinks {
+	display: flex;
+	align-items: center;
+	flex-wrap: wrap;
+	gap: var(--marginHalf);
+}
+
 .relatedPagesRoot {
 	padding: var(--margin);
 }

From 0226a670ddb0a38dfd8b8f479885ee5e83cf970f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 18 Mar 2024 18:34:31 +0900
Subject: [PATCH 038/191] =?UTF-8?q?fix(backend):=20=E3=83=A6=E3=83=BC?=
 =?UTF-8?q?=E3=82=B6=E3=83=BC=E3=82=84=E3=83=8E=E3=83=BC=E3=83=88=E3=81=AE?=
 =?UTF-8?q?OGP=E3=81=A7=E3=83=AD=E3=83=BC=E3=82=AB=E3=83=AB=E3=81=A8?=
 =?UTF-8?q?=E3=83=AA=E3=83=A2=E3=83=BC=E3=83=88=E3=83=A6=E3=83=BC=E3=82=B6?=
 =?UTF-8?q?=E3=83=BC=E3=81=AE=E8=A6=8B=E5=88=86=E3=81=91=E3=81=8C=E4=BB=98?=
 =?UTF-8?q?=E3=81=8B=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE?=
 =?UTF-8?q?=E6=AD=A3=20(#13586)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance(OGP): ユーザーやノートのOGPでローカルとリモートユーザーの見分けが付かない問題を修正 (MisskeyIO#528)

(cherry picked from commit 0c3de462d99c47297bebc162581bac6f78f21b49)

* Update Changelog

---------

Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com>
---
 CHANGELOG.md                                   | 1 +
 packages/backend/src/server/web/views/note.pug | 4 ++--
 packages/backend/src/server/web/views/user.pug | 2 +-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5d74090b35..91539a6a9e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@
 - Fix: ローカルURLのプレビューポップアップが左上に表示される
 - Fix: WebGL2をサポートしないブラウザで「季節に応じた画面の演出」が有効になっているとき、Misskeyが起動できなくなる問題を修正  
   (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/459)
+- Fix: ページタイトルでローカルユーザーとリモートユーザーの区別がつかない問題を修正
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
diff --git a/packages/backend/src/server/web/views/note.pug b/packages/backend/src/server/web/views/note.pug
index 9bc652b6a1..fb659ce171 100644
--- a/packages/backend/src/server/web/views/note.pug
+++ b/packages/backend/src/server/web/views/note.pug
@@ -2,7 +2,7 @@ extends ./base
 
 block vars
 	- const user = note.user;
-	- const title = user.name ? `${user.name} (@${user.username})` : `@${user.username}`;
+	- const title = user.name ? `${user.name} (@${user.username}${user.host ? `@${user.host}` : ''})` : `@${user.username}${user.host ? `@${user.host}` : ''}`;
 	- const url = `${config.url}/notes/${note.id}`;
 	- const isRenote = note.renote && note.text == null && note.fileIds.length == 0 && note.poll == null;
 	- const images = (note.files || []).filter(file => file.type.startsWith('image/') && !file.isSensitive)
@@ -28,7 +28,7 @@ block og
 			// FIXME: add embed player for Twitter
 	if images.length
 		meta(property='twitter:card' content='summary_large_image')
-		each image in images	
+		each image in images
 			meta(property='og:image'     content= image.url)
 	else
 		meta(property='twitter:card' content='summary')
diff --git a/packages/backend/src/server/web/views/user.pug b/packages/backend/src/server/web/views/user.pug
index 83d57349a6..2b0a7bab5c 100644
--- a/packages/backend/src/server/web/views/user.pug
+++ b/packages/backend/src/server/web/views/user.pug
@@ -1,7 +1,7 @@
 extends ./base
 
 block vars
-	- const title = user.name ? `${user.name} (@${user.username})` : `@${user.username}`;
+	- const title = user.name ? `${user.name} (@${user.username}${user.host ? `@${user.host}` : ''})` : `@${user.username}${user.host ? `@${user.host}` : ''}`;
 	- const url = `${config.url}/@${(user.host ? `${user.username}@${user.host}` : user.username)}`;
 
 block title

From 5f6863b77e9e955b2e82b9f44a63df4c1eb6e4c8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 18 Mar 2024 19:04:20 +0900
Subject: [PATCH 039/191] Add missing credit (for #13586)

---
 CHANGELOG.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 91539a6a9e..d948127d06 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,7 +16,8 @@
 - Fix: ローカルURLのプレビューポップアップが左上に表示される
 - Fix: WebGL2をサポートしないブラウザで「季節に応じた画面の演出」が有効になっているとき、Misskeyが起動できなくなる問題を修正  
   (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/459)
-- Fix: ページタイトルでローカルユーザーとリモートユーザーの区別がつかない問題を修正
+- Fix: ページタイトルでローカルユーザーとリモートユーザーの区別がつかない問題を修正  
+  (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/528)
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに

From 115d91812e4bc25a56126f23b4ad13b07d451552 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?=
 <46447427+samunohito@users.noreply.github.com>
Date: Wed, 20 Mar 2024 10:30:45 +0900
Subject: [PATCH 040/191] =?UTF-8?q?fix(frontend):=20shiki=E3=81=AE?=
 =?UTF-8?q?=E8=A8=80=E8=AA=9E=E3=83=BB=E3=83=86=E3=83=BC=E3=83=9E=E3=81=AE?=
 =?UTF-8?q?=E5=AE=9A=E7=BE=A9=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=82=92?=
 =?UTF-8?q?CDN(esm.sh)=E3=81=8B=E3=82=89=E5=8F=96=E3=82=8B=E3=82=88?=
 =?UTF-8?q?=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B=20(#13598)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(frontend): shikiの言語・テーマの定義ファイルをCDN(esm.sh)から取るようにする

* fix CHANGELOG.md
---
 CHANGELOG.md                                  |  2 ++
 packages/frontend/package.json                |  2 +-
 .../frontend/src/components/MkCode.core.vue   | 10 +++----
 packages/frontend/src/index.html              |  2 +-
 .../frontend/src/scripts/code-highlighter.ts  | 18 ++++++------
 packages/frontend/src/scripts/theme.ts        |  4 +--
 packages/frontend/src/store.ts                |  1 -
 packages/frontend/vite.config.ts              | 29 +++++++++++++++++++
 pnpm-lock.yaml                                | 20 ++++++++-----
 9 files changed, 61 insertions(+), 27 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d948127d06..18dd07f1c3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,8 @@
   (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/459)
 - Fix: ページタイトルでローカルユーザーとリモートユーザーの区別がつかない問題を修正  
   (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/528)
+- Fix: コードブロックのシンタックスハイライトで使用される定義ファイルをCDNから取得するように #13177
+  - CDNから取得せずMisskey本体にバンドルする場合は`pacakges/frontend/vite.config.ts`を修正してください。
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
diff --git a/packages/frontend/package.json b/packages/frontend/package.json
index 682def8e8d..db7f7b76f6 100644
--- a/packages/frontend/package.json
+++ b/packages/frontend/package.json
@@ -60,7 +60,7 @@
 		"rollup": "4.12.0",
 		"sanitize-html": "2.12.1",
 		"sass": "1.71.1",
-		"shiki": "1.1.7",
+		"shiki": "1.2.0",
 		"strict-event-emitter-types": "2.0.0",
 		"textarea-caret": "3.1.0",
 		"three": "0.162.0",
diff --git a/packages/frontend/src/components/MkCode.core.vue b/packages/frontend/src/components/MkCode.core.vue
index 872517b6aa..c0e7df5dac 100644
--- a/packages/frontend/src/components/MkCode.core.vue
+++ b/packages/frontend/src/components/MkCode.core.vue
@@ -9,9 +9,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { ref, computed, watch } from 'vue';
-import { bundledLanguagesInfo } from 'shiki';
-import type { BuiltinLanguage } from 'shiki';
+import { computed, ref, watch } from 'vue';
+import { bundledLanguagesInfo } from 'shiki/langs';
+import type { BundledLanguage } from 'shiki/langs';
 import { getHighlighter, getTheme } from '@/scripts/code-highlighter.js';
 import { defaultStore } from '@/store.js';
 
@@ -23,7 +23,7 @@ const props = defineProps<{
 
 const highlighter = await getHighlighter();
 const darkMode = defaultStore.reactiveState.darkMode;
-const codeLang = ref<BuiltinLanguage | 'aiscript'>('js');
+const codeLang = ref<BundledLanguage | 'aiscript'>('js');
 
 const [lightThemeName, darkThemeName] = await Promise.all([
 	getTheme('light', true),
@@ -42,7 +42,7 @@ const html = computed(() => highlighter.codeToHtml(props.code, {
 }));
 
 async function fetchLanguage(to: string): Promise<void> {
-	const language = to as BuiltinLanguage;
+	const language = to as BundledLanguage;
 
 	// Check for the loaded languages, and load the language if it's not loaded yet.
 	if (!highlighter.getLoadedLanguages().includes(language)) {
diff --git a/packages/frontend/src/index.html b/packages/frontend/src/index.html
index cd84145f40..08ff0c58dd 100644
--- a/packages/frontend/src/index.html
+++ b/packages/frontend/src/index.html
@@ -18,7 +18,7 @@
 		http-equiv="Content-Security-Policy"
 		content="default-src 'self' https://newassets.hcaptcha.com/ https://challenges.cloudflare.com/ http://localhost:7493/;
 			worker-src 'self';
-			script-src 'self' 'unsafe-eval' https://*.hcaptcha.com https://challenges.cloudflare.com;
+			script-src 'self' 'unsafe-eval' https://*.hcaptcha.com https://challenges.cloudflare.com https://esm.sh;
 			style-src 'self' 'unsafe-inline';
 			img-src 'self' data: blob: www.google.com xn--931a.moe localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000;
 			media-src 'self' localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000;
diff --git a/packages/frontend/src/scripts/code-highlighter.ts b/packages/frontend/src/scripts/code-highlighter.ts
index 5dd0a3be78..e94027d302 100644
--- a/packages/frontend/src/scripts/code-highlighter.ts
+++ b/packages/frontend/src/scripts/code-highlighter.ts
@@ -3,18 +3,19 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { bundledThemesInfo } from 'shiki';
 import { getHighlighterCore, loadWasm } from 'shiki/core';
 import darkPlus from 'shiki/themes/dark-plus.mjs';
+import { bundledThemesInfo } from 'shiki/themes';
+import { bundledLanguagesInfo } from 'shiki/langs';
 import { unique } from './array.js';
 import { deepClone } from './clone.js';
 import { deepMerge } from './merge.js';
-import type { Highlighter, LanguageRegistration, ThemeRegistration, ThemeRegistrationRaw } from 'shiki';
+import type { HighlighterCore, LanguageRegistration, ThemeRegistration, ThemeRegistrationRaw } from 'shiki/core';
 import { ColdDeviceStorage } from '@/store.js';
 import lightTheme from '@/themes/_light.json5';
 import darkTheme from '@/themes/_dark.json5';
 
-let _highlighter: Highlighter | null = null;
+let _highlighter: HighlighterCore | null = null;
 
 export async function getTheme(mode: 'light' | 'dark', getName: true): Promise<string>;
 export async function getTheme(mode: 'light' | 'dark', getName?: false): Promise<ThemeRegistration | ThemeRegistrationRaw>;
@@ -51,16 +52,14 @@ export async function getTheme(mode: 'light' | 'dark', getName = false): Promise
 	return darkPlus;
 }
 
-export async function getHighlighter(): Promise<Highlighter> {
+export async function getHighlighter(): Promise<HighlighterCore> {
 	if (!_highlighter) {
 		return await initHighlighter();
 	}
 	return _highlighter;
 }
 
-export async function initHighlighter() {
-	const aiScriptGrammar = await import('aiscript-vscode/aiscript/syntaxes/aiscript.tmLanguage.json');
-
+async function initHighlighter() {
 	await loadWasm(import('shiki/onig.wasm?init'));
 
 	// テーマの重複を消す
@@ -69,11 +68,12 @@ export async function initHighlighter() {
 		...(await Promise.all([getTheme('light'), getTheme('dark')])),
 	]);
 
+	const jsLangInfo = bundledLanguagesInfo.find(t => t.id === 'javascript');
 	const highlighter = await getHighlighterCore({
 		themes,
 		langs: [
-			import('shiki/langs/javascript.mjs'),
-			aiScriptGrammar.default as unknown as LanguageRegistration,
+			...(jsLangInfo ? [async () => await jsLangInfo.import()] : []),
+			async () => (await import('aiscript-vscode/aiscript/syntaxes/aiscript.tmLanguage.json')).default as unknown as LanguageRegistration,
 		],
 	});
 
diff --git a/packages/frontend/src/scripts/theme.ts b/packages/frontend/src/scripts/theme.ts
index 5f7e88bd9f..c7f8b3d596 100644
--- a/packages/frontend/src/scripts/theme.ts
+++ b/packages/frontend/src/scripts/theme.ts
@@ -6,7 +6,7 @@
 import { ref } from 'vue';
 import tinycolor from 'tinycolor2';
 import { deepClone } from './clone.js';
-import type { BuiltinTheme } from 'shiki';
+import type { BundledTheme } from 'shiki/themes';
 import { globalEvents } from '@/events.js';
 import lightTheme from '@/themes/_light.json5';
 import darkTheme from '@/themes/_dark.json5';
@@ -20,7 +20,7 @@ export type Theme = {
 	base?: 'dark' | 'light';
 	props: Record<string, string>;
 	codeHighlighter?: {
-		base: BuiltinTheme;
+		base: BundledTheme;
 		overrides?: Record<string, any>;
 	} | {
 		base: '_none_';
diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts
index a335ed33bb..7742acc60d 100644
--- a/packages/frontend/src/store.ts
+++ b/packages/frontend/src/store.ts
@@ -7,7 +7,6 @@ import { markRaw, ref } from 'vue';
 import * as Misskey from 'misskey-js';
 import { miLocalStorage } from './local-storage.js';
 import type { SoundType } from '@/scripts/sound.js';
-import type { BuiltinTheme as ShikiBuiltinTheme } from 'shiki';
 import { Storage } from '@/pizzax.js';
 import { hemisphere } from '@/scripts/intl-const.js';
 
diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts
index 35d112f6ec..82eb2af464 100644
--- a/packages/frontend/vite.config.ts
+++ b/packages/frontend/vite.config.ts
@@ -5,11 +5,30 @@ import { type UserConfig, defineConfig } from 'vite';
 
 import locales from '../../locales/index.js';
 import meta from '../../package.json';
+import packageInfo from './package.json' assert { type: 'json' };
 import pluginUnwindCssModuleClassName from './lib/rollup-plugin-unwind-css-module-class-name.js';
 import pluginJson5 from './vite.json5.js';
 
 const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.json', '.json5', '.svg', '.sass', '.scss', '.css', '.vue'];
 
+/**
+ * Misskeyのフロントエンドにバンドルせず、CDNなどから別途読み込むリソースを記述する。
+ * CDNを使わずにバンドルしたい場合、以下の配列から該当要素を削除orコメントアウトすればOK
+ */
+const externalPackages = [
+	// shiki(コードブロックのシンタックスハイライトで使用中)はテーマ・言語の定義の容量が大きいため、それらはCDNから読み込む
+	{
+		name: 'shiki',
+		match: /^shiki\/(?<subPkg>(langs|themes))$/,
+		path(id: string, pattern: RegExp): string {
+			const match = pattern.exec(id)?.groups;
+			return match
+				? `https://esm.sh/shiki@${packageInfo.dependencies.shiki}/${match['subPkg']}`
+				: id;
+		},
+	},
+];
+
 const hash = (str: string, seed = 0): number => {
 	let h1 = 0xdeadbeef ^ seed,
 		h2 = 0x41c6ce57 ^ seed;
@@ -112,6 +131,7 @@ export function getConfig(): UserConfig {
 				input: {
 					app: './src/_boot_.ts',
 				},
+				external: externalPackages.map(p => p.match),
 				output: {
 					manualChunks: {
 						vue: ['vue'],
@@ -119,6 +139,15 @@ export function getConfig(): UserConfig {
 					},
 					chunkFileNames: process.env.NODE_ENV === 'production' ? '[hash:8].js' : '[name]-[hash:8].js',
 					assetFileNames: process.env.NODE_ENV === 'production' ? '[hash:8][extname]' : '[name]-[hash:8][extname]',
+					paths(id) {
+						for (const p of externalPackages) {
+							if (p.match.test(id)) {
+								return p.path(id, p.match);
+							}
+						}
+
+						return id;
+					},
 				},
 			},
 			cssCodeSplit: true,
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 5e29c1162b..2906eef4d8 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -806,8 +806,8 @@ importers:
         specifier: 1.71.1
         version: 1.71.1
       shiki:
-        specifier: 1.1.7
-        version: 1.1.7
+        specifier: 1.2.0
+        version: 1.2.0
       strict-event-emitter-types:
         specifier: 2.0.0
         version: 2.0.0
@@ -5324,8 +5324,8 @@ packages:
       string-argv: 0.3.1
     dev: true
 
-  /@shikijs/core@1.1.7:
-    resolution: {integrity: sha512-gTYLUIuD1UbZp/11qozD3fWpUTuMqPSf3svDMMrL0UmlGU7D9dPw/V1FonwAorCUJBltaaESxq90jrSjQyGixg==}
+  /@shikijs/core@1.2.0:
+    resolution: {integrity: sha512-OlFvx+nyr5C8zpcMBnSGir0YPD6K11uYhouqhNmm1qLiis4GA7SsGtu07r9gKS9omks8RtQqHrJL4S+lqWK01A==}
     dev: false
 
   /@sideway/address@4.1.4:
@@ -6646,7 +6646,7 @@ packages:
       ts-dedent: 2.2.0
       type-fest: 2.19.0
       vue: 3.4.21(typescript@5.3.3)
-      vue-component-type-helpers: 1.8.27
+      vue-component-type-helpers: 2.0.6
     transitivePeerDependencies:
       - encoding
       - supports-color
@@ -17658,10 +17658,10 @@ packages:
     resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
     engines: {node: '>=8'}
 
-  /shiki@1.1.7:
-    resolution: {integrity: sha512-9kUTMjZtcPH3i7vHunA6EraTPpPOITYTdA5uMrvsJRexktqP0s7P3s9HVK80b4pP42FRVe03D7fT3NmJv2yYhw==}
+  /shiki@1.2.0:
+    resolution: {integrity: sha512-xLhiTMOIUXCv5DqJ4I70GgQCtdlzsTqFLZWcMHHG3TAieBUbvEGthdrlPDlX4mL/Wszx9C6rEcxU6kMlg4YlxA==}
     dependencies:
-      '@shikijs/core': 1.1.7
+      '@shikijs/core': 1.2.0
     dev: false
 
   /side-channel@1.0.4:
@@ -19445,6 +19445,10 @@ packages:
     resolution: {integrity: sha512-6bnLkn8O0JJyiFSIF0EfCogzeqNXpnjJ0vW/SZzNHfe6sPx30lTtTXlE5TFs2qhJlAtDFybStVNpL73cPe3OMQ==}
     dev: true
 
+  /vue-component-type-helpers@2.0.6:
+    resolution: {integrity: sha512-qdGXCtoBrwqk1BT6r2+1Wcvl583ZVkuSZ3or7Y1O2w5AvWtlvvxwjGhmz5DdPJS9xqRdDlgTJ/38ehWnEi0tFA==}
+    dev: true
+
   /vue-demi@0.14.7(vue@3.4.21):
     resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
     engines: {node: '>=12'}

From d7bb6c88d3e4878486fb1f4d1655379896a5d976 Mon Sep 17 00:00:00 2001
From: Gianni Ceccarelli <dakkar@thenautilus.net>
Date: Wed, 20 Mar 2024 02:25:49 +0000
Subject: [PATCH 041/191] Cypress typescript (#13591)

* convert Cypress tests to TypeScript

this work was done by @lunaisnotaboy https://github.com/lunaisnotaboy
for their fork https://github.com/cutiekey/cutiekey/pull/7

I just repacked their changes into a minimal set

* fix call to `window` in cypress tests

this error was spotted thanks to the TypeScript compiler:

```
support/commands.ts:33:12 - error TS2559: Type '(win: any) => void'
has no properties in common with type 'Partial<Loggable &
Timeoutable>'.

33  cy.window(win => {
              ~~~~~~~~

Found 1 error in support/commands.ts:33
```

(again, @lunaisnotaboy did the actual work)
---
 cypress/e2e/{basic.cy.js => basic.cy.ts}     |  0
 cypress/e2e/{router.cy.js => router.cy.ts}   |  0
 cypress/e2e/{widgets.cy.js => widgets.cy.ts} |  0
 cypress/support/{commands.js => commands.ts} |  2 +-
 cypress/support/{e2e.js => e2e.ts}           |  0
 cypress/support/index.ts                     | 19 +++++++++++++++++++
 cypress/tsconfig.json                        |  8 ++++++++
 package.json                                 |  1 +
 pnpm-lock.yaml                               |  9 +++++++++
 9 files changed, 38 insertions(+), 1 deletion(-)
 rename cypress/e2e/{basic.cy.js => basic.cy.ts} (100%)
 rename cypress/e2e/{router.cy.js => router.cy.ts} (100%)
 rename cypress/e2e/{widgets.cy.js => widgets.cy.ts} (100%)
 rename cypress/support/{commands.js => commands.ts} (98%)
 rename cypress/support/{e2e.js => e2e.ts} (100%)
 create mode 100644 cypress/support/index.ts
 create mode 100644 cypress/tsconfig.json

diff --git a/cypress/e2e/basic.cy.js b/cypress/e2e/basic.cy.ts
similarity index 100%
rename from cypress/e2e/basic.cy.js
rename to cypress/e2e/basic.cy.ts
diff --git a/cypress/e2e/router.cy.js b/cypress/e2e/router.cy.ts
similarity index 100%
rename from cypress/e2e/router.cy.js
rename to cypress/e2e/router.cy.ts
diff --git a/cypress/e2e/widgets.cy.js b/cypress/e2e/widgets.cy.ts
similarity index 100%
rename from cypress/e2e/widgets.cy.js
rename to cypress/e2e/widgets.cy.ts
diff --git a/cypress/support/commands.js b/cypress/support/commands.ts
similarity index 98%
rename from cypress/support/commands.js
rename to cypress/support/commands.ts
index 91a4d7abe6..c2d92e1663 100644
--- a/cypress/support/commands.js
+++ b/cypress/support/commands.ts
@@ -30,7 +30,7 @@ Cypress.Commands.add('visitHome', () => {
 })
 
 Cypress.Commands.add('resetState', () => {
-	cy.window(win => {
+	cy.window().then(win => {
 		win.indexedDB.deleteDatabase('keyval-store');
 	});
 	cy.request('POST', '/api/reset-db', {}).as('reset');
diff --git a/cypress/support/e2e.js b/cypress/support/e2e.ts
similarity index 100%
rename from cypress/support/e2e.js
rename to cypress/support/e2e.ts
diff --git a/cypress/support/index.ts b/cypress/support/index.ts
new file mode 100644
index 0000000000..c1bed21979
--- /dev/null
+++ b/cypress/support/index.ts
@@ -0,0 +1,19 @@
+declare global {
+	namespace Cypress {
+		interface Chainable {
+			login(username: string, password: string): Chainable<void>;
+
+			registerUser(
+				username: string,
+				password: string,
+				isAdmin?: boolean
+			): Chainable<void>;
+
+			resetState(): Chainable<void>;
+
+			visitHome(): Chainable<void>;
+		}
+	}
+}
+
+export {}
diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json
new file mode 100644
index 0000000000..6fe7f32cc4
--- /dev/null
+++ b/cypress/tsconfig.json
@@ -0,0 +1,8 @@
+{
+	"compilerOptions": {
+		"lib": ["dom", "es5"],
+		"target": "es5",
+		"types": ["cypress", "node"]
+	},
+	"include": ["./**/*.ts"]
+}
diff --git a/package.json b/package.json
index 41b865456d..8f5ab0b124 100644
--- a/package.json
+++ b/package.json
@@ -59,6 +59,7 @@
 		"typescript": "5.3.3"
 	},
 	"devDependencies": {
+		"@types/node": "^20.11.28",
 		"@typescript-eslint/eslint-plugin": "7.1.0",
 		"@typescript-eslint/parser": "7.1.0",
 		"cross-env": "7.0.3",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 2906eef4d8..4c1e228a95 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -44,6 +44,9 @@ importers:
         specifier: 4.4.0
         version: 4.4.0
     devDependencies:
+      '@types/node':
+        specifier: ^20.11.28
+        version: 20.11.28
       '@typescript-eslint/eslint-plugin':
         specifier: 7.1.0
         version: 7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3)
@@ -7650,6 +7653,12 @@ packages:
     dependencies:
       undici-types: 5.26.5
 
+  /@types/node@20.11.28:
+    resolution: {integrity: sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==}
+    dependencies:
+      undici-types: 5.26.5
+    dev: true
+
   /@types/node@20.11.5:
     resolution: {integrity: sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==}
     dependencies:

From ca2df14a8f4e2d0d7eef699b44a2dd9580842a2a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Wed, 20 Mar 2024 13:10:09 +0900
Subject: [PATCH 042/191] =?UTF-8?q?fix(frontend):=20woodenPanel=E3=81=AE?=
 =?UTF-8?q?=E9=85=8D=E8=89=B2=E3=82=92=E4=BF=AE=E6=AD=A3=20(#13561)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(frontend): woodenPanelの配色を修正

* fix
---
 packages/frontend/src/boot/common.ts |  3 +++
 packages/frontend/src/style.scss     | 11 ++++++-----
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/packages/frontend/src/boot/common.ts b/packages/frontend/src/boot/common.ts
index 681beaf00f..d86ae18ffe 100644
--- a/packages/frontend/src/boot/common.ts
+++ b/packages/frontend/src/boot/common.ts
@@ -145,8 +145,11 @@ export async function common(createVue: () => App<Element>) {
 	// NOTE: この処理は必ずクライアント更新チェック処理より後に来ること(テーマ再構築のため)
 	watch(defaultStore.reactiveState.darkMode, (darkMode) => {
 		applyTheme(darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme'));
+		document.documentElement.dataset.colorMode = darkMode ? 'dark' : 'light';
 	}, { immediate: miLocalStorage.getItem('theme') == null });
 
+	document.documentElement.dataset.colorMode = defaultStore.state.darkMode ? 'dark' : 'light';
+
 	const darkTheme = computed(ColdDeviceStorage.makeGetterSetter('darkTheme'));
 	const lightTheme = computed(ColdDeviceStorage.makeGetterSetter('lightTheme'));
 
diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss
index 187d902733..250a2616a7 100644
--- a/packages/frontend/src/style.scss
+++ b/packages/frontend/src/style.scss
@@ -431,12 +431,13 @@ rt {
 	border-radius: 10px;
 
 	--bg: #F1E8DC;
-	--panel: #fff;
 	--fg: #693410;
-	--switchOffBg: rgba(0, 0, 0, 0.1);
-	--switchOffFg: rgb(255, 255, 255);
-	--switchOnBg: var(--accent);
-	--switchOnFg: rgb(255, 255, 255);
+}
+
+html[data-color-mode=dark] ._woodenFrame {
+	--bg: #1d0c02;
+	--fg: #F1E8DC;
+	--panel: #192320;
 }
 
 ._woodenFrameH {

From 7795045b23a95032a15a980ad28cc27ce5423bbe Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Wed, 20 Mar 2024 20:01:56 +0900
Subject: [PATCH 043/191] Update about-misskey.vue

---
 packages/frontend/src/pages/about-misskey.vue | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/packages/frontend/src/pages/about-misskey.vue b/packages/frontend/src/pages/about-misskey.vue
index 9aaa2d8fba..92accd0117 100644
--- a/packages/frontend/src/pages/about-misskey.vue
+++ b/packages/frontend/src/pages/about-misskey.vue
@@ -222,6 +222,15 @@ const patronsWithIcon = [{
 }, {
 	name: '有栖かずみ',
 	icon: 'https://assets.misskey-hub.net/patrons/9240e8e0ba294a8884143e99ac7ed6a0.jpg',
+}, {
+	name: 'イカロ(コアラ)',
+	icon: 'https://assets.misskey-hub.net/patrons/50b9bdc03735412c80807dbdf32cecb6.jpg',
+}, {
+	name: 'ハチノス3号',
+	icon: 'https://assets.misskey-hub.net/patrons/030347a6f8ce4e82bc5184b5aad09a18.jpg',
+}, {
+	name: 'Takeno',
+	icon: 'https://assets.misskey-hub.net/patrons/6fba81536aea48fe94a30909c502dfa1.jpg',
 }];
 
 const patrons = [
@@ -325,6 +334,7 @@ const patrons = [
 	'たっくん',
 	'SHO SEKIGUCHI',
 	'塩キャベツ',
+	'はとぽぷさん',
 ];
 
 const thereIsTreasure = ref($i && !claimedAchievements.includes('foundTreasure'));

From f4838e50b4043f917020dd1cfa7b75da087ff8f2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Thu, 21 Mar 2024 07:51:01 +0900
Subject: [PATCH 044/191] =?UTF-8?q?enhance(antenna):=20Bot=E3=81=AE?=
 =?UTF-8?q?=E6=8A=95=E7=A8=BF=E3=82=92=E9=99=A4=E5=A4=96=E3=81=A7=E3=81=8D?=
 =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=20(#13603)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance(antenna): Botの投稿を除外できるように (MisskeyIO#545)

(cherry picked from commit a95ce067c6cf0a93647e358aabc984bdbe99e952)

* Update Changelog

* remove translations

* spdx

---------

Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com>
---
 CHANGELOG.md                                     |  2 ++
 locales/index.d.ts                               |  4 ++++
 locales/ja-JP.yml                                |  1 +
 .../1710919614510-antenna-exclude-bots.js        | 16 ++++++++++++++++
 packages/backend/src/core/AntennaService.ts      |  6 ++++--
 .../src/core/entities/AntennaEntityService.ts    |  1 +
 packages/backend/src/models/Antenna.ts           |  5 +++++
 .../backend/src/models/json-schema/antenna.ts    |  5 +++++
 .../processors/ExportAntennasProcessorService.ts |  1 +
 .../processors/ImportAntennasProcessorService.ts |  2 ++
 .../src/server/api/endpoints/antennas/create.ts  |  2 ++
 .../src/server/api/endpoints/antennas/update.ts  |  2 ++
 packages/backend/test/e2e/antennas.ts            |  2 ++
 .../frontend/src/pages/my-antennas/create.vue    |  1 +
 .../frontend/src/pages/my-antennas/editor.vue    |  3 +++
 packages/misskey-js/src/autogen/types.ts         |  4 ++++
 16 files changed, 55 insertions(+), 2 deletions(-)
 create mode 100644 packages/backend/migration/1710919614510-antenna-exclude-bots.js

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 18dd07f1c3..0dce1a0496 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,8 @@
 ## Unreleased
 
 ### General
+- Enhance: アンテナでBotによるノートを除外できるように  
+  (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/545)
 - Fix: Play作成時に設定した公開範囲が機能していない問題を修正
 
 ### Client
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 7f4ec7ecb0..afb4adac6c 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -1616,6 +1616,10 @@ export interface Locale extends ILocale {
      * 除外キーワード
      */
     "antennaExcludeKeywords": string;
+    /**
+     * Botアカウントを除外
+     */
+    "antennaExcludeBots": string;
     /**
      * スペースで区切るとAND指定になり、改行で区切るとOR指定になります
      */
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 8b44ac2121..a64c83b10f 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -400,6 +400,7 @@ name: "名前"
 antennaSource: "受信ソース"
 antennaKeywords: "受信キーワード"
 antennaExcludeKeywords: "除外キーワード"
+antennaExcludeBots: "Botアカウントを除外"
 antennaKeywordsDescription: "スペースで区切るとAND指定になり、改行で区切るとOR指定になります"
 notifyAntenna: "新しいノートを通知する"
 withFileAntenna: "ファイルが添付されたノートのみ"
diff --git a/packages/backend/migration/1710919614510-antenna-exclude-bots.js b/packages/backend/migration/1710919614510-antenna-exclude-bots.js
new file mode 100644
index 0000000000..fac84317cc
--- /dev/null
+++ b/packages/backend/migration/1710919614510-antenna-exclude-bots.js
@@ -0,0 +1,16 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class AntennaExcludeBots1710919614510 {
+    name = 'AntennaExcludeBots1710919614510'
+
+    async up(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "antenna" ADD "excludeBots" boolean NOT NULL DEFAULT false`);
+    }
+
+    async down(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "excludeBots"`);
+    }
+}
diff --git a/packages/backend/src/core/AntennaService.ts b/packages/backend/src/core/AntennaService.ts
index 4f956a43ed..793d8974b3 100644
--- a/packages/backend/src/core/AntennaService.ts
+++ b/packages/backend/src/core/AntennaService.ts
@@ -92,7 +92,7 @@ export class AntennaService implements OnApplicationShutdown {
 	}
 
 	@bindThis
-	public async addNoteToAntennas(note: MiNote, noteUser: { id: MiUser['id']; username: string; host: string | null; }): Promise<void> {
+	public async addNoteToAntennas(note: MiNote, noteUser: { id: MiUser['id']; username: string; host: string | null; isBot: boolean; }): Promise<void> {
 		const antennas = await this.getAntennas();
 		const antennasWithMatchResult = await Promise.all(antennas.map(antenna => this.checkHitAntenna(antenna, note, noteUser).then(hit => [antenna, hit] as const)));
 		const matchedAntennas = antennasWithMatchResult.filter(([, hit]) => hit).map(([antenna]) => antenna);
@@ -110,10 +110,12 @@ export class AntennaService implements OnApplicationShutdown {
 	// NOTE: フォローしているユーザーのノート、リストのユーザーのノート、グループのユーザーのノート指定はパフォーマンス上の理由で無効になっている
 
 	@bindThis
-	public async checkHitAntenna(antenna: MiAntenna, note: (MiNote | Packed<'Note'>), noteUser: { id: MiUser['id']; username: string; host: string | null; }): Promise<boolean> {
+	public async checkHitAntenna(antenna: MiAntenna, note: (MiNote | Packed<'Note'>), noteUser: { id: MiUser['id']; username: string; host: string | null; isBot: boolean; }): Promise<boolean> {
 		if (note.visibility === 'specified') return false;
 		if (note.visibility === 'followers') return false;
 
+		if (antenna.excludeBots && noteUser.isBot) return false;
+
 		if (antenna.localOnly && noteUser.host != null) return false;
 
 		if (!antenna.withReplies && note.replyId != null) return false;
diff --git a/packages/backend/src/core/entities/AntennaEntityService.ts b/packages/backend/src/core/entities/AntennaEntityService.ts
index 64d6a3c978..3ec8efa6bf 100644
--- a/packages/backend/src/core/entities/AntennaEntityService.ts
+++ b/packages/backend/src/core/entities/AntennaEntityService.ts
@@ -39,6 +39,7 @@ export class AntennaEntityService {
 			caseSensitive: antenna.caseSensitive,
 			localOnly: antenna.localOnly,
 			notify: antenna.notify,
+			excludeBots: antenna.excludeBots,
 			withReplies: antenna.withReplies,
 			withFile: antenna.withFile,
 			isActive: antenna.isActive,
diff --git a/packages/backend/src/models/Antenna.ts b/packages/backend/src/models/Antenna.ts
index 332a899768..f5e819059e 100644
--- a/packages/backend/src/models/Antenna.ts
+++ b/packages/backend/src/models/Antenna.ts
@@ -72,6 +72,11 @@ export class MiAntenna {
 	})
 	public caseSensitive: boolean;
 
+	@Column('boolean', {
+		default: false,
+	})
+	public excludeBots: boolean;
+
 	@Column('boolean', {
 		default: false,
 	})
diff --git a/packages/backend/src/models/json-schema/antenna.ts b/packages/backend/src/models/json-schema/antenna.ts
index 74622b6193..78cf6d3ba2 100644
--- a/packages/backend/src/models/json-schema/antenna.ts
+++ b/packages/backend/src/models/json-schema/antenna.ts
@@ -76,6 +76,11 @@ export const packedAntennaSchema = {
 			type: 'boolean',
 			optional: false, nullable: false,
 		},
+		excludeBots: {
+			type: 'boolean',
+			optional: false, nullable: false,
+			default: false,
+		},
 		withReplies: {
 			type: 'boolean',
 			optional: false, nullable: false,
diff --git a/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts b/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts
index af48bad417..1d8e90f367 100644
--- a/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts
+++ b/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts
@@ -81,6 +81,7 @@ export class ExportAntennasProcessorService {
 					}) : null,
 					caseSensitive: antenna.caseSensitive,
 					localOnly: antenna.localOnly,
+					excludeBots: antenna.excludeBots,
 					withReplies: antenna.withReplies,
 					withFile: antenna.withFile,
 					notify: antenna.notify,
diff --git a/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts b/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts
index 951b560597..ff1c04de06 100644
--- a/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts
+++ b/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts
@@ -44,6 +44,7 @@ const validate = new Ajv().compile({
 		} },
 		caseSensitive: { type: 'boolean' },
 		localOnly: { type: 'boolean' },
+		excludeBots: { type: 'boolean' },
 		withReplies: { type: 'boolean' },
 		withFile: { type: 'boolean' },
 		notify: { type: 'boolean' },
@@ -88,6 +89,7 @@ export class ImportAntennasProcessorService {
 					users: (antenna.src === 'list' && antenna.userListAccts !== null ? antenna.userListAccts : antenna.users).filter(Boolean),
 					caseSensitive: antenna.caseSensitive,
 					localOnly: antenna.localOnly,
+					excludeBots: antenna.excludeBots,
 					withReplies: antenna.withReplies,
 					withFile: antenna.withFile,
 					notify: antenna.notify,
diff --git a/packages/backend/src/server/api/endpoints/antennas/create.ts b/packages/backend/src/server/api/endpoints/antennas/create.ts
index 191de8f833..57c8eb4958 100644
--- a/packages/backend/src/server/api/endpoints/antennas/create.ts
+++ b/packages/backend/src/server/api/endpoints/antennas/create.ts
@@ -64,6 +64,7 @@ export const paramDef = {
 		} },
 		caseSensitive: { type: 'boolean' },
 		localOnly: { type: 'boolean' },
+		excludeBots: { type: 'boolean' },
 		withReplies: { type: 'boolean' },
 		withFile: { type: 'boolean' },
 		notify: { type: 'boolean' },
@@ -124,6 +125,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				users: ps.users,
 				caseSensitive: ps.caseSensitive,
 				localOnly: ps.localOnly,
+				excludeBots: ps.excludeBots,
 				withReplies: ps.withReplies,
 				withFile: ps.withFile,
 				notify: ps.notify,
diff --git a/packages/backend/src/server/api/endpoints/antennas/update.ts b/packages/backend/src/server/api/endpoints/antennas/update.ts
index 76a34924a0..e6720aacf8 100644
--- a/packages/backend/src/server/api/endpoints/antennas/update.ts
+++ b/packages/backend/src/server/api/endpoints/antennas/update.ts
@@ -63,6 +63,7 @@ export const paramDef = {
 		} },
 		caseSensitive: { type: 'boolean' },
 		localOnly: { type: 'boolean' },
+		excludeBots: { type: 'boolean' },
 		withReplies: { type: 'boolean' },
 		withFile: { type: 'boolean' },
 		notify: { type: 'boolean' },
@@ -120,6 +121,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				users: ps.users,
 				caseSensitive: ps.caseSensitive,
 				localOnly: ps.localOnly,
+				excludeBots: ps.excludeBots,
 				withReplies: ps.withReplies,
 				withFile: ps.withFile,
 				notify: ps.notify,
diff --git a/packages/backend/test/e2e/antennas.ts b/packages/backend/test/e2e/antennas.ts
index 7370b1963c..cf5c7dd130 100644
--- a/packages/backend/test/e2e/antennas.ts
+++ b/packages/backend/test/e2e/antennas.ts
@@ -44,6 +44,7 @@ describe('アンテナ', () => {
 		users: [''],
 		withFile: false,
 		withReplies: false,
+		excludeBots: false,
 	};
 
 	let root: User;
@@ -156,6 +157,7 @@ describe('アンテナ', () => {
 			users: [''],
 			withFile: false,
 			withReplies: false,
+			excludeBots: false,
 			localOnly: false,
 		};
 		assert.deepStrictEqual(response, expected);
diff --git a/packages/frontend/src/pages/my-antennas/create.vue b/packages/frontend/src/pages/my-antennas/create.vue
index 8b3b3cfbfd..2d026d2fa9 100644
--- a/packages/frontend/src/pages/my-antennas/create.vue
+++ b/packages/frontend/src/pages/my-antennas/create.vue
@@ -26,6 +26,7 @@ const draft = ref({
 	users: [],
 	keywords: [],
 	excludeKeywords: [],
+	excludeBots: false,
 	withReplies: false,
 	caseSensitive: false,
 	localOnly: false,
diff --git a/packages/frontend/src/pages/my-antennas/editor.vue b/packages/frontend/src/pages/my-antennas/editor.vue
index c6dcbadd9b..97edbc44ce 100644
--- a/packages/frontend/src/pages/my-antennas/editor.vue
+++ b/packages/frontend/src/pages/my-antennas/editor.vue
@@ -26,6 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 				<template #label>{{ i18n.ts.users }}</template>
 				<template #caption>{{ i18n.ts.antennaUsersDescription }} <button class="_textButton" @click="addUser">{{ i18n.ts.addUser }}</button></template>
 			</MkTextarea>
+			<MkSwitch v-model="excludeBots">{{ i18n.ts.antennaExcludeBots }}</MkSwitch>
 			<MkSwitch v-model="withReplies">{{ i18n.ts.withReplies }}</MkSwitch>
 			<MkTextarea v-model="keywords">
 				<template #label>{{ i18n.ts.antennaKeywords }}</template>
@@ -78,6 +79,7 @@ const keywords = ref<string>(props.antenna.keywords.map(x => x.join(' ')).join('
 const excludeKeywords = ref<string>(props.antenna.excludeKeywords.map(x => x.join(' ')).join('\n'));
 const caseSensitive = ref<boolean>(props.antenna.caseSensitive);
 const localOnly = ref<boolean>(props.antenna.localOnly);
+const excludeBots = ref<boolean>(props.antenna.excludeBots);
 const withReplies = ref<boolean>(props.antenna.withReplies);
 const withFile = ref<boolean>(props.antenna.withFile);
 const notify = ref<boolean>(props.antenna.notify);
@@ -94,6 +96,7 @@ async function saveAntenna() {
 		name: name.value,
 		src: src.value,
 		userListId: userListId.value,
+		excludeBots: excludeBots.value,
 		withReplies: withReplies.value,
 		withFile: withFile.value,
 		notify: notify.value,
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 3c862f690e..636bc62aaa 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -4434,6 +4434,8 @@ export type components = {
       localOnly: boolean;
       notify: boolean;
       /** @default false */
+      excludeBots: boolean;
+      /** @default false */
       withReplies: boolean;
       withFile: boolean;
       isActive: boolean;
@@ -9654,6 +9656,7 @@ export type operations = {
           users: string[];
           caseSensitive: boolean;
           localOnly?: boolean;
+          excludeBots?: boolean;
           withReplies: boolean;
           withFile: boolean;
           notify: boolean;
@@ -9935,6 +9938,7 @@ export type operations = {
           users?: string[];
           caseSensitive?: boolean;
           localOnly?: boolean;
+          excludeBots?: boolean;
           withReplies?: boolean;
           withFile?: boolean;
           notify?: boolean;

From 831c74a25b2db0ba3f6d43a9a1a9072d342b2822 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?=
 <46447427+samunohito@users.noreply.github.com>
Date: Thu, 21 Mar 2024 18:46:42 +0900
Subject: [PATCH 045/191] =?UTF-8?q?fix:=20URL=E3=83=97=E3=83=AC=E3=83=93?=
 =?UTF-8?q?=E3=83=A5=E3=83=BC=E3=81=AE=E5=8B=95=E4=BD=9C=E6=94=B9=E5=96=84?=
 =?UTF-8?q?=EF=BC=8B=E5=8B=95=E4=BD=9C=E8=A8=AD=E5=AE=9A=E3=82=92=E5=8F=AF?=
 =?UTF-8?q?=E8=83=BD=E3=81=AB=E3=81=99=E3=82=8B=20(#13579)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* wip

* support new version

* URLプレビュー無効化時、フロント側も非表示にしてリクエストをしないようにする

* fix lint

* fix lint

* tweak preview request error handles

* fix: CHANGELOG.md

* fix

* fix

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 CHANGELOG.md                                  |  5 ++
 locales/index.d.ts                            | 58 +++++++++++++++
 locales/ja-JP.yml                             | 15 ++++
 .../1710512074000-url-preview-meta.js         | 42 +++++++++++
 packages/backend/package.json                 |  2 +-
 .../src/core/entities/MetaEntityService.ts    |  1 +
 packages/backend/src/models/Meta.ts           | 38 ++++++++--
 .../backend/src/models/json-schema/meta.ts    |  4 +
 .../src/server/api/endpoints/admin/meta.ts    | 34 ++++++++-
 .../server/api/endpoints/admin/update-meta.ts | 41 ++++++++--
 .../src/server/web/UrlPreviewService.ts       | 67 +++++++++++++----
 packages/frontend/src/components/MkLink.vue   | 17 +++--
 packages/frontend/src/components/MkNote.vue   |  7 +-
 .../src/components/MkNoteDetailed.vue         |  5 +-
 .../frontend/src/components/MkUrlPreview.vue  | 12 +--
 .../frontend/src/components/global/MkUrl.vue  |  3 +-
 .../src/components/page/page.text.vue         |  5 +-
 packages/frontend/src/instance.ts             |  2 +
 .../frontend/src/pages/admin/security.vue     | 16 ----
 .../frontend/src/pages/admin/settings.vue     | 74 ++++++++++++++++++-
 packages/misskey-js/src/autogen/types.ts      | 20 ++++-
 pnpm-lock.yaml                                | 18 ++++-
 22 files changed, 420 insertions(+), 66 deletions(-)
 create mode 100644 packages/backend/migration/1710512074000-url-preview-meta.js

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0dce1a0496..188e146cdd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,10 @@
 ## Unreleased
 
+### Note
+- コントロールパネル内にあるサマリープロキシの設定個所がセキュリティから全般へ変更となります。
+
 ### General
+- Enhance: URLプレビューの有効化・無効化を設定できるように #13569
 - Enhance: アンテナでBotによるノートを除外できるように  
   (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/545)
 - Fix: Play作成時に設定した公開範囲が機能していない問題を修正
@@ -25,6 +29,7 @@
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
+- Enhance: misskey-dev/summaly@5.1.0の取り込み(プレビュー生成処理の効率化)
 - Fix: フォローリクエストを作成する際に既存のものは削除するように  
   (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/440)
 
diff --git a/locales/index.d.ts b/locales/index.d.ts
index afb4adac6c..70586d7a87 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -4916,6 +4916,10 @@ export interface Locale extends ILocale {
      * リトライ
      */
     "gameRetry": string;
+    /**
+     * 使用しない場合は空欄にしてください
+     */
+    "notUsePleaseLeaveBlank": string;
     "_bubbleGame": {
         /**
          * 遊び方
@@ -9768,6 +9772,60 @@ export interface Locale extends ILocale {
          */
         "header": string;
     };
+    "_urlPreviewSetting": {
+        /**
+         * URLプレビューの設定
+         */
+        "title": string;
+        /**
+         * URLプレビューを有効にする
+         */
+        "enable": string;
+        /**
+         * プレビュー取得時のタイムアウト(ms)
+         */
+        "timeout": string;
+        /**
+         * プレビュー取得の所要時間がこの値を超えた場合、プレビューは生成されません。
+         */
+        "timeoutDescription": string;
+        /**
+         * Content-Lengthの最大値(byte)
+         */
+        "maximumContentLength": string;
+        /**
+         * Content-Lengthがこの値を超えた場合、プレビューは生成されません。
+         */
+        "maximumContentLengthDescription": string;
+        /**
+         * Content-Lengthが取得できた場合のみプレビューを生成
+         */
+        "requireContentLength": string;
+        /**
+         * 相手サーバがContent-Lengthを返さない場合、プレビューは生成されません。
+         */
+        "requireContentLengthDescription": string;
+        /**
+         * User-Agent
+         */
+        "userAgent": string;
+        /**
+         * プレビュー取得時に使用されるUser-Agentを設定します。空欄の場合、デフォルトのUser-Agentが使用されます。
+         */
+        "userAgentDescription": string;
+        /**
+         * プレビューを生成するプロキシのエンドポイント
+         */
+        "summaryProxy": string;
+        /**
+         * Misskey本体ではなく、サマリープロキシを使用してプレビューを生成します。
+         */
+        "summaryProxyDescription": string;
+        /**
+         * プロキシには下記パラメータがクエリ文字列として連携されます。プロキシ側がこれらをサポートしない場合、設定値は無視されます。
+         */
+        "summaryProxyDescription2": string;
+    };
 }
 declare const locales: {
     [lang: string]: Locale;
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index a64c83b10f..cada6d855f 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1225,6 +1225,7 @@ enableHorizontalSwipe: "スワイプしてタブを切り替える"
 loading: "読み込み中"
 surrender: "やめる"
 gameRetry: "リトライ"
+notUsePleaseLeaveBlank: "使用しない場合は空欄にしてください"
 
 _bubbleGame:
   howToPlay: "遊び方"
@@ -2602,3 +2603,17 @@ _offlineScreen:
   title: "オフライン - サーバーに接続できません"
   header: "サーバーに接続できません"
 
+_urlPreviewSetting:
+  title: "URLプレビューの設定"
+  enable: "URLプレビューを有効にする"
+  timeout: "プレビュー取得時のタイムアウト(ms)"
+  timeoutDescription: "プレビュー取得の所要時間がこの値を超えた場合、プレビューは生成されません。"
+  maximumContentLength: "Content-Lengthの最大値(byte)"
+  maximumContentLengthDescription: "Content-Lengthがこの値を超えた場合、プレビューは生成されません。"
+  requireContentLength: "Content-Lengthが取得できた場合のみプレビューを生成"
+  requireContentLengthDescription: "相手サーバがContent-Lengthを返さない場合、プレビューは生成されません。"
+  userAgent: "User-Agent"
+  userAgentDescription: "プレビュー取得時に使用されるUser-Agentを設定します。空欄の場合、デフォルトのUser-Agentが使用されます。"
+  summaryProxy: "プレビューを生成するプロキシのエンドポイント"
+  summaryProxyDescription: "Misskey本体ではなく、サマリープロキシを使用してプレビューを生成します。"
+  summaryProxyDescription2: "プロキシには下記パラメータがクエリ文字列として連携されます。プロキシ側がこれらをサポートしない場合、設定値は無視されます。"
diff --git a/packages/backend/migration/1710512074000-url-preview-meta.js b/packages/backend/migration/1710512074000-url-preview-meta.js
new file mode 100644
index 0000000000..8af521bbf4
--- /dev/null
+++ b/packages/backend/migration/1710512074000-url-preview-meta.js
@@ -0,0 +1,42 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class UrlPreviewMeta1710512074000 {
+    name = 'UrlPreviewMeta1710512074000'
+
+    async up(queryRunner) {
+        await queryRunner.query(`
+					alter table meta
+						rename column "summalyProxy" to "urlPreviewSummaryProxyUrl";
+					alter table meta
+						add "urlPreviewEnabled" boolean default true not null;
+					alter table meta
+						add "urlPreviewTimeout" integer default 10000 not null;
+					alter table meta
+						add "urlPreviewMaximumContentLength" bigint default 10485760 not null;
+					alter table meta
+						add "urlPreviewRequireContentLength" boolean default false not null;
+					alter table meta
+						add "urlPreviewUserAgent" varchar(1024) default null;
+				`);
+    }
+
+    async down(queryRunner) {
+        await queryRunner.query(`
+					alter table meta
+						rename column "urlPreviewSummaryProxyUrl" to "summalyProxy";
+					alter table meta
+						drop column "urlPreviewEnabled";
+					alter table meta
+						drop column "urlPreviewTimeout";
+					alter table meta
+						drop column "urlPreviewMaximumContentLength";
+					alter table meta
+						drop column "urlPreviewRequireContentLength";
+					alter table meta
+						drop column "urlPreviewUserAgent";
+				`);
+    }
+}
diff --git a/packages/backend/package.json b/packages/backend/package.json
index eaad96d5f6..d64fcc3d2a 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -80,7 +80,7 @@
 		"@fastify/static": "6.12.0",
 		"@fastify/view": "8.2.0",
 		"@misskey-dev/sharp-read-bmp": "1.2.0",
-		"@misskey-dev/summaly": "5.0.3",
+		"@misskey-dev/summaly": "5.1.0",
 		"@nestjs/common": "10.3.3",
 		"@nestjs/core": "10.3.3",
 		"@nestjs/testing": "10.3.3",
diff --git a/packages/backend/src/core/entities/MetaEntityService.ts b/packages/backend/src/core/entities/MetaEntityService.ts
index b50d76288f..9d054ab6a1 100644
--- a/packages/backend/src/core/entities/MetaEntityService.ts
+++ b/packages/backend/src/core/entities/MetaEntityService.ts
@@ -111,6 +111,7 @@ export class MetaEntityService {
 			policies: { ...DEFAULT_POLICIES, ...instance.policies },
 
 			mediaProxy: this.config.mediaProxy,
+			enableUrlPreview: instance.urlPreviewEnabled,
 		};
 
 		return packed;
diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts
index 66f19ce197..04a34bbbb4 100644
--- a/packages/backend/src/models/Meta.ts
+++ b/packages/backend/src/models/Meta.ts
@@ -277,12 +277,6 @@ export class MiMeta {
 	})
 	public enableSensitiveMediaDetectionForVideos: boolean;
 
-	@Column('varchar', {
-		length: 1024,
-		nullable: true,
-	})
-	public summalyProxy: string | null;
-
 	@Column('boolean', {
 		default: false,
 	})
@@ -588,4 +582,36 @@ export class MiMeta {
 		default: 0,
 	})
 	public notesPerOneAd: number;
+
+	@Column('boolean', {
+		default: true,
+	})
+	public urlPreviewEnabled: boolean;
+
+	@Column('integer', {
+		default: 10000,
+	})
+	public urlPreviewTimeout: number;
+
+	@Column('bigint', {
+		default: 1024 * 1024 * 10,
+	})
+	public urlPreviewMaximumContentLength: number;
+
+	@Column('boolean', {
+		default: true,
+	})
+	public urlPreviewRequireContentLength: boolean;
+
+	@Column('varchar', {
+		length: 1024,
+		nullable: true,
+	})
+	public urlPreviewSummaryProxyUrl: string | null;
+
+	@Column('varchar', {
+		length: 1024,
+		nullable: true,
+	})
+	public urlPreviewUserAgent: string | null;
 }
diff --git a/packages/backend/src/models/json-schema/meta.ts b/packages/backend/src/models/json-schema/meta.ts
index 17789f3b46..473339a1ad 100644
--- a/packages/backend/src/models/json-schema/meta.ts
+++ b/packages/backend/src/models/json-schema/meta.ts
@@ -207,6 +207,10 @@ export const packedMetaLiteSchema = {
 			type: 'string',
 			optional: false, nullable: false,
 		},
+		enableUrlPreview: {
+			type: 'boolean',
+			optional: false, nullable: false,
+		},
 		backgroundImageUrl: {
 			type: 'string',
 			optional: false, nullable: true,
diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts
index 88c5907bcc..f4ff573271 100644
--- a/packages/backend/src/server/api/endpoints/admin/meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/meta.ts
@@ -434,6 +434,8 @@ export const meta = {
 			summalyProxy: {
 				type: 'string',
 				optional: false, nullable: true,
+				deprecated: true,
+				description: '[Deprecated] Use "urlPreviewSummaryProxyUrl" instead.',
 			},
 			themeColor: {
 				type: 'string',
@@ -451,6 +453,30 @@ export const meta = {
 				type: 'string',
 				optional: false, nullable: false,
 			},
+			urlPreviewEnabled: {
+				type: 'boolean',
+				optional: false, nullable: false,
+			},
+			urlPreviewTimeout: {
+				type: 'number',
+				optional: false, nullable: false,
+			},
+			urlPreviewMaximumContentLength: {
+				type: 'number',
+				optional: false, nullable: false,
+			},
+			urlPreviewRequireContentLength: {
+				type: 'boolean',
+				optional: false, nullable: false,
+			},
+			urlPreviewUserAgent: {
+				type: 'string',
+				optional: false, nullable: true,
+			},
+			urlPreviewSummaryProxyUrl: {
+				type: 'string',
+				optional: false, nullable: true,
+			},
 		},
 	},
 } as const;
@@ -533,7 +559,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				setSensitiveFlagAutomatically: instance.setSensitiveFlagAutomatically,
 				enableSensitiveMediaDetectionForVideos: instance.enableSensitiveMediaDetectionForVideos,
 				proxyAccountId: instance.proxyAccountId,
-				summalyProxy: instance.summalyProxy,
 				email: instance.email,
 				smtpSecure: instance.smtpSecure,
 				smtpHost: instance.smtpHost,
@@ -577,6 +602,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				perUserHomeTimelineCacheMax: instance.perUserHomeTimelineCacheMax,
 				perUserListTimelineCacheMax: instance.perUserListTimelineCacheMax,
 				notesPerOneAd: instance.notesPerOneAd,
+				summalyProxy: instance.urlPreviewSummaryProxyUrl,
+				urlPreviewEnabled: instance.urlPreviewEnabled,
+				urlPreviewTimeout: instance.urlPreviewTimeout,
+				urlPreviewMaximumContentLength: instance.urlPreviewMaximumContentLength,
+				urlPreviewRequireContentLength: instance.urlPreviewRequireContentLength,
+				urlPreviewUserAgent: instance.urlPreviewUserAgent,
+				urlPreviewSummaryProxyUrl: instance.urlPreviewSummaryProxyUrl,
 			};
 		});
 	}
diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
index bffceef815..2f62d30ada 100644
--- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
@@ -90,7 +90,6 @@ export const paramDef = {
 				type: 'string',
 			},
 		},
-		summalyProxy: { type: 'string', nullable: true },
 		deeplAuthKey: { type: 'string', nullable: true },
 		deeplIsPro: { type: 'boolean' },
 		enableEmail: { type: 'boolean' },
@@ -150,6 +149,16 @@ export const paramDef = {
 				type: 'string',
 			},
 		},
+		summalyProxy: {
+			type: 'string', nullable: true,
+			description: '[Deprecated] Use "urlPreviewSummaryProxyUrl" instead.',
+		},
+		urlPreviewEnabled: { type: 'boolean' },
+		urlPreviewTimeout: { type: 'integer' },
+		urlPreviewMaximumContentLength: { type: 'integer' },
+		urlPreviewRequireContentLength: { type: 'boolean' },
+		urlPreviewUserAgent: { type: 'string', nullable: true },
+		urlPreviewSummaryProxyUrl: { type: 'string', nullable: true },
 	},
 	required: [],
 } as const;
@@ -353,10 +362,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				set.langs = ps.langs.filter(Boolean);
 			}
 
-			if (ps.summalyProxy !== undefined) {
-				set.summalyProxy = ps.summalyProxy;
-			}
-
 			if (ps.enableEmail !== undefined) {
 				set.enableEmail = ps.enableEmail;
 			}
@@ -581,6 +586,32 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				set.bannedEmailDomains = ps.bannedEmailDomains;
 			}
 
+			if (ps.urlPreviewEnabled !== undefined) {
+				set.urlPreviewEnabled = ps.urlPreviewEnabled;
+			}
+
+			if (ps.urlPreviewTimeout !== undefined) {
+				set.urlPreviewTimeout = ps.urlPreviewTimeout;
+			}
+
+			if (ps.urlPreviewMaximumContentLength !== undefined) {
+				set.urlPreviewMaximumContentLength = ps.urlPreviewMaximumContentLength;
+			}
+
+			if (ps.urlPreviewRequireContentLength !== undefined) {
+				set.urlPreviewRequireContentLength = ps.urlPreviewRequireContentLength;
+			}
+
+			if (ps.urlPreviewUserAgent !== undefined) {
+				const value = (ps.urlPreviewUserAgent ?? '').trim();
+				set.urlPreviewUserAgent = value === '' ? null : ps.urlPreviewUserAgent;
+			}
+
+			if (ps.summalyProxy !== undefined || ps.urlPreviewSummaryProxyUrl !== undefined) {
+				const value = ((ps.urlPreviewSummaryProxyUrl ?? ps.summalyProxy) ?? '').trim();
+				set.urlPreviewSummaryProxyUrl = value === '' ? null : value;
+			}
+
 			const before = await this.metaService.fetch(true);
 
 			await this.metaService.update(set);
diff --git a/packages/backend/src/server/web/UrlPreviewService.ts b/packages/backend/src/server/web/UrlPreviewService.ts
index c6a96e94cb..8f8f08a305 100644
--- a/packages/backend/src/server/web/UrlPreviewService.ts
+++ b/packages/backend/src/server/web/UrlPreviewService.ts
@@ -5,6 +5,7 @@
 
 import { Inject, Injectable } from '@nestjs/common';
 import { summaly } from '@misskey-dev/summaly';
+import { SummalyResult } from '@misskey-dev/summaly/built/summary.js';
 import { DI } from '@/di-symbols.js';
 import type { Config } from '@/config.js';
 import { MetaService } from '@/core/MetaService.js';
@@ -14,6 +15,7 @@ import { query } from '@/misc/prelude/url.js';
 import { LoggerService } from '@/core/LoggerService.js';
 import { bindThis } from '@/decorators.js';
 import { ApiError } from '@/server/api/error.js';
+import { MiMeta } from '@/models/Meta.js';
 import type { FastifyRequest, FastifyReply } from 'fastify';
 
 @Injectable()
@@ -62,24 +64,25 @@ export class UrlPreviewService {
 
 		const meta = await this.metaService.fetch();
 
-		this.logger.info(meta.summalyProxy
+		if (!meta.urlPreviewEnabled) {
+			reply.code(403);
+			return {
+				error: new ApiError({
+					message: 'URL preview is disabled',
+					code: 'URL_PREVIEW_DISABLED',
+					id: '58b36e13-d2f5-0323-b0c6-76aa9dabefb8',
+				}),
+			};
+		}
+
+		this.logger.info(meta.urlPreviewSummaryProxyUrl
 			? `(Proxy) Getting preview of ${url}@${lang} ...`
 			: `Getting preview of ${url}@${lang} ...`);
+
 		try {
-			const summary = meta.summalyProxy ?
-				await this.httpRequestService.getJson<ReturnType<typeof summaly>>(`${meta.summalyProxy}?${query({
-					url: url,
-					lang: lang ?? 'ja-JP',
-				})}`)
-				:
-				await summaly(url, {
-					followRedirects: false,
-					lang: lang ?? 'ja-JP',
-					agent: this.config.proxy ? {
-						http: this.httpRequestService.httpAgent,
-						https: this.httpRequestService.httpsAgent,
-					} : undefined,
-				});
+			const summary = meta.urlPreviewSummaryProxyUrl
+				? await this.fetchSummaryFromProxy(url, meta, lang)
+				: await this.fetchSummary(url, meta, lang);
 
 			this.logger.succ(`Got preview of ${url}: ${summary.title}`);
 
@@ -100,6 +103,7 @@ export class UrlPreviewService {
 			return summary;
 		} catch (err) {
 			this.logger.warn(`Failed to get preview of ${url}: ${err}`);
+
 			reply.code(422);
 			reply.header('Cache-Control', 'max-age=86400, immutable');
 			return {
@@ -111,4 +115,37 @@ export class UrlPreviewService {
 			};
 		}
 	}
+
+	private fetchSummary(url: string, meta: MiMeta, lang?: string): Promise<SummalyResult> {
+		const agent = this.config.proxy
+			? {
+				http: this.httpRequestService.httpAgent,
+				https: this.httpRequestService.httpsAgent,
+			}
+			: undefined;
+
+		return summaly(url, {
+			followRedirects: false,
+			lang: lang ?? 'ja-JP',
+			agent: agent,
+			userAgent: meta.urlPreviewUserAgent ?? undefined,
+			operationTimeout: meta.urlPreviewTimeout,
+			contentLengthLimit: meta.urlPreviewMaximumContentLength,
+			contentLengthRequired: meta.urlPreviewRequireContentLength,
+		});
+	}
+
+	private fetchSummaryFromProxy(url: string, meta: MiMeta, lang?: string): Promise<SummalyResult> {
+		const proxy = meta.urlPreviewSummaryProxyUrl!;
+		const queryStr = query({
+			url: url,
+			lang: lang ?? 'ja-JP',
+			userAgent: meta.urlPreviewUserAgent ?? undefined,
+			operationTimeout: meta.urlPreviewTimeout,
+			contentLengthLimit: meta.urlPreviewMaximumContentLength,
+			contentLengthRequired: meta.urlPreviewRequireContentLength,
+		});
+
+		return this.httpRequestService.getJson<SummalyResult>(`${proxy}?${queryStr}`);
+	}
 }
diff --git a/packages/frontend/src/components/MkLink.vue b/packages/frontend/src/components/MkLink.vue
index 3f7aba2fe4..ca875242b4 100644
--- a/packages/frontend/src/components/MkLink.vue
+++ b/packages/frontend/src/components/MkLink.vue
@@ -18,6 +18,7 @@ import { defineAsyncComponent, ref } from 'vue';
 import { url as local } from '@/config.js';
 import { useTooltip } from '@/scripts/use-tooltip.js';
 import * as os from '@/os.js';
+import { isEnabledUrlPreview } from '@/instance.js';
 
 const props = withDefaults(defineProps<{
 	url: string;
@@ -31,13 +32,15 @@ const target = self ? null : '_blank';
 
 const el = ref<HTMLElement | { $el: HTMLElement }>();
 
-useTooltip(el, (showing) => {
-	os.popup(defineAsyncComponent(() => import('@/components/MkUrlPreviewPopup.vue')), {
-		showing,
-		url: props.url,
-		source: el.value instanceof HTMLElement ? el.value : el.value?.$el,
-	}, {}, 'closed');
-});
+if (isEnabledUrlPreview.value) {
+	useTooltip(el, (showing) => {
+		os.popup(defineAsyncComponent(() => import('@/components/MkUrlPreviewPopup.vue')), {
+			showing,
+			url: props.url,
+			source: el.value instanceof HTMLElement ? el.value : el.value?.$el,
+		}, {}, 'closed');
+	});
+}
 </script>
 
 <style lang="scss" module>
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index 5ca0eae012..50741f2cb7 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -82,7 +82,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 						<MkMediaList :mediaList="appearNote.files"/>
 					</div>
 					<MkPoll v-if="appearNote.poll" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/>
-					<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :class="$style.urlPreview"/>
+					<div v-if="isEnabledUrlPreview">
+						<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :class="$style.urlPreview"/>
+					</div>
 					<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
 					<button v-if="isLong && collapsed" :class="$style.collapsed" class="_button" @click="collapsed = false">
 						<span :class="$style.collapsedLabel">{{ i18n.ts.showMore }}</span>
@@ -194,6 +196,7 @@ import { MenuItem } from '@/types/menu.js';
 import MkRippleEffect from '@/components/MkRippleEffect.vue';
 import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
 import { shouldCollapsed } from '@/scripts/collapsed.js';
+import { isEnabledUrlPreview } from '@/instance.js';
 
 const props = withDefaults(defineProps<{
 	note: Misskey.entities.Note;
@@ -268,7 +271,7 @@ const renoteCollapsed = ref(
 	defaultStore.state.collapseRenotes && isRenote && (
 		($i && ($i.id === note.value.userId || $i.id === appearNote.value.userId)) || // `||` must be `||`! See https://github.com/misskey-dev/misskey/issues/13131
 		(appearNote.value.myReaction != null)
-	)
+	),
 );
 
 /* Overload FunctionにLintが対応していないのでコメントアウト
diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue
index e271215516..1b7dcda409 100644
--- a/packages/frontend/src/components/MkNoteDetailed.vue
+++ b/packages/frontend/src/components/MkNoteDetailed.vue
@@ -95,7 +95,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 					<MkMediaList :mediaList="appearNote.files"/>
 				</div>
 				<MkPoll v-if="appearNote.poll" ref="pollViewer" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/>
-				<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" style="margin-top: 6px;"/>
+				<div v-if="isEnabledUrlPreview">
+					<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" style="margin-top: 6px;"/>
+				</div>
 				<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
 			</div>
 			<MkA v-if="appearNote.channel && !inChannel" :class="$style.channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA>
@@ -229,6 +231,7 @@ import MkUserCardMini from '@/components/MkUserCardMini.vue';
 import MkPagination, { type Paging } from '@/components/MkPagination.vue';
 import MkReactionIcon from '@/components/MkReactionIcon.vue';
 import MkButton from '@/components/MkButton.vue';
+import { isEnabledUrlPreview } from '@/instance.js';
 
 const props = defineProps<{
 	note: Misskey.entities.Note;
diff --git a/packages/frontend/src/components/MkUrlPreview.vue b/packages/frontend/src/components/MkUrlPreview.vue
index efc58b7e29..b3dc492616 100644
--- a/packages/frontend/src/components/MkUrlPreview.vue
+++ b/packages/frontend/src/components/MkUrlPreview.vue
@@ -110,7 +110,6 @@ const MOBILE_THRESHOLD = 500;
 const isMobile = ref(deviceKind === 'smartphone' || window.innerWidth <= MOBILE_THRESHOLD);
 
 const self = props.url.startsWith(local);
-const attr = self ? 'to' : 'href';
 const target = self ? null : '_blank';
 const fetching = ref(true);
 const title = ref<string | null>(null);
@@ -152,15 +151,16 @@ requestUrl.hash = '';
 window.fetch(`/url?url=${encodeURIComponent(requestUrl.href)}&lang=${versatileLang}`)
 	.then(res => {
 		if (!res.ok) {
-			fetching.value = false;
-			unknownUrl.value = true;
-			return;
+			if (_DEV_) {
+				console.warn(`[HTTP${res.status}] Failed to fetch url preview`);
+			}
+			return null;
 		}
 
 		return res.json();
 	})
-	.then((info: SummalyResult) => {
-		if (info.url == null) {
+	.then((info: SummalyResult | null) => {
+		if (!info || info.url == null) {
 			fetching.value = false;
 			unknownUrl.value = true;
 			return;
diff --git a/packages/frontend/src/components/global/MkUrl.vue b/packages/frontend/src/components/global/MkUrl.vue
index 8d29a4da8c..d2945a78b9 100644
--- a/packages/frontend/src/components/global/MkUrl.vue
+++ b/packages/frontend/src/components/global/MkUrl.vue
@@ -30,6 +30,7 @@ import { url as local } from '@/config.js';
 import * as os from '@/os.js';
 import { useTooltip } from '@/scripts/use-tooltip.js';
 import { safeURIDecode } from '@/scripts/safe-uri-decode.js';
+import { isEnabledUrlPreview } from '@/instance.js';
 
 const props = withDefaults(defineProps<{
 	url: string;
@@ -44,7 +45,7 @@ const url = new URL(props.url);
 if (!['http:', 'https:'].includes(url.protocol)) throw new Error('invalid url');
 const el = ref();
 
-if (props.showUrlPreview) {
+if (props.showUrlPreview && isEnabledUrlPreview.value) {
 	useTooltip(el, (showing) => {
 		os.popup(defineAsyncComponent(() => import('@/components/MkUrlPreviewPopup.vue')), {
 			showing,
diff --git a/packages/frontend/src/components/page/page.text.vue b/packages/frontend/src/components/page/page.text.vue
index 61247b381f..4e501bd699 100644
--- a/packages/frontend/src/components/page/page.text.vue
+++ b/packages/frontend/src/components/page/page.text.vue
@@ -6,7 +6,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 <template>
 <div class="_gaps" :class="$style.textRoot">
 	<Mfm :text="block.text ?? ''" :isNote="false"/>
-	<MkUrlPreview v-for="url in urls" :key="url" :url="url"/>
+	<div v-if="isEnabledUrlPreview">
+		<MkUrlPreview v-for="url in urls" :key="url" :url="url"/>
+	</div>
 </div>
 </template>
 
@@ -15,6 +17,7 @@ import { defineAsyncComponent } from 'vue';
 import * as mfm from 'mfm-js';
 import * as Misskey from 'misskey-js';
 import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js';
+import { isEnabledUrlPreview } from '@/instance.js';
 
 const MkUrlPreview = defineAsyncComponent(() => import('@/components/MkUrlPreview.vue'));
 
diff --git a/packages/frontend/src/instance.ts b/packages/frontend/src/instance.ts
index 4232cbcd78..22337e7eb9 100644
--- a/packages/frontend/src/instance.ts
+++ b/packages/frontend/src/instance.ts
@@ -36,6 +36,8 @@ export const infoImageUrl = computed(() => instance.infoImageUrl ?? DEFAULT_INFO
 
 export const notFoundImageUrl = computed(() => instance.notFoundImageUrl ?? DEFAULT_NOT_FOUND_IMAGE_URL);
 
+export const isEnabledUrlPreview = computed(() => instance.enableUrlPreview ?? true);
+
 export async function fetchInstance(force = false): Promise<void> {
 	if (!force) {
 		const cachedAt = miLocalStorage.getItem('instanceCachedAt') ? parseInt(miLocalStorage.getItem('instanceCachedAt')!) : 0;
diff --git a/packages/frontend/src/pages/admin/security.vue b/packages/frontend/src/pages/admin/security.vue
index c4745978df..9bccee89a5 100644
--- a/packages/frontend/src/pages/admin/security.vue
+++ b/packages/frontend/src/pages/admin/security.vue
@@ -118,19 +118,6 @@ SPDX-License-Identifier: AGPL-3.0-only
 						</MkSwitch>
 					</div>
 				</MkFolder>
-
-				<MkFolder>
-					<template #label>Summaly Proxy</template>
-
-					<div class="_gaps_m">
-						<MkInput v-model="summalyProxy">
-							<template #prefix><i class="ti ti-link"></i></template>
-							<template #label>Summaly Proxy URL</template>
-						</MkInput>
-
-						<MkButton primary @click="save"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
-					</div>
-				</MkFolder>
 			</div>
 		</FormSuspense>
 	</MkSpacer>
@@ -155,7 +142,6 @@ import { fetchInstance } from '@/instance.js';
 import { i18n } from '@/i18n.js';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
 
-const summalyProxy = ref<string>('');
 const enableHcaptcha = ref<boolean>(false);
 const enableMcaptcha = ref<boolean>(false);
 const enableRecaptcha = ref<boolean>(false);
@@ -175,7 +161,6 @@ const bannedEmailDomains = ref<string>('');
 
 async function init() {
 	const meta = await misskeyApi('admin/meta');
-	summalyProxy.value = meta.summalyProxy;
 	enableHcaptcha.value = meta.enableHcaptcha;
 	enableMcaptcha.value = meta.enableMcaptcha;
 	enableRecaptcha.value = meta.enableRecaptcha;
@@ -201,7 +186,6 @@ async function init() {
 
 function save() {
 	os.apiWithDialog('admin/update-meta', {
-		summalyProxy: summalyProxy.value,
 		sensitiveMediaDetection: sensitiveMediaDetection.value,
 		sensitiveMediaDetectionSensitivity:
 			sensitiveMediaDetectionSensitivity.value === 0 ? 'veryLow' :
diff --git a/packages/frontend/src/pages/admin/settings.vue b/packages/frontend/src/pages/admin/settings.vue
index 9a198ee8a3..6f45c212ec 100644
--- a/packages/frontend/src/pages/admin/settings.vue
+++ b/packages/frontend/src/pages/admin/settings.vue
@@ -143,6 +143,53 @@ SPDX-License-Identifier: AGPL-3.0-only
 							</div>
 						</div>
 					</FormSection>
+
+					<FormSection>
+						<template #label>{{ i18n.ts._urlPreviewSetting.title }}</template>
+
+						<div class="_gaps_m">
+							<MkSwitch v-model="urlPreviewEnabled">
+								<template #label>{{ i18n.ts._urlPreviewSetting.enable }}</template>
+							</MkSwitch>
+
+							<MkSwitch v-model="urlPreviewRequireContentLength">
+								<template #label>{{ i18n.ts._urlPreviewSetting.requireContentLength }}</template>
+								<template #caption>{{ i18n.ts._urlPreviewSetting.requireContentLengthDescription }}</template>
+							</MkSwitch>
+
+							<MkInput v-model="urlPreviewMaximumContentLength" type="number">
+								<template #label>{{ i18n.ts._urlPreviewSetting.maximumContentLength }}</template>
+								<template #caption>{{ i18n.ts._urlPreviewSetting.maximumContentLengthDescription }}</template>
+							</MkInput>
+
+							<MkInput v-model="urlPreviewTimeout" type="number">
+								<template #label>{{ i18n.ts._urlPreviewSetting.timeout }}</template>
+								<template #caption>{{ i18n.ts._urlPreviewSetting.timeoutDescription }}</template>
+							</MkInput>
+
+							<MkInput v-model="urlPreviewUserAgent" type="text">
+								<template #label>{{ i18n.ts._urlPreviewSetting.userAgent }}</template>
+								<template #caption>{{ i18n.ts._urlPreviewSetting.userAgentDescription }}</template>
+							</MkInput>
+
+							<div>
+								<MkInput v-model="urlPreviewSummaryProxyUrl" type="text">
+									<template #label>{{ i18n.ts._urlPreviewSetting.summaryProxy }}</template>
+									<template #caption>[{{ i18n.ts.notUsePleaseLeaveBlank }}] {{ i18n.ts._urlPreviewSetting.summaryProxyDescription }}</template>
+								</MkInput>
+
+								<div :class="$style.subCaption">
+									{{ i18n.ts._urlPreviewSetting.summaryProxyDescription2 }}
+									<ul style="padding-left: 20px; margin: 4px 0">
+										<li>{{ i18n.ts._urlPreviewSetting.timeout }} / key:timeout</li>
+										<li>{{ i18n.ts._urlPreviewSetting.maximumContentLength }} / key:contentLengthLimit</li>
+										<li>{{ i18n.ts._urlPreviewSetting.requireContentLength }} / key:contentLengthRequired</li>
+										<li>{{ i18n.ts._urlPreviewSetting.userAgent }} / key:userAgent</li>
+									</ul>
+								</div>
+							</div>
+						</div>
+					</FormSection>
 				</div>
 			</FormSuspense>
 		</MkSpacer>
@@ -173,6 +220,8 @@ import { fetchInstance, instance } from '@/instance.js';
 import { i18n } from '@/i18n.js';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
 import MkButton from '@/components/MkButton.vue';
+import MkFolder from '@/components/MkFolder.vue';
+import MkSelect from '@/components/MkSelect.vue';
 
 const name = ref<string | null>(null);
 const shortName = ref<string | null>(null);
@@ -194,6 +243,12 @@ const perRemoteUserUserTimelineCacheMax = ref<number>(0);
 const perUserHomeTimelineCacheMax = ref<number>(0);
 const perUserListTimelineCacheMax = ref<number>(0);
 const notesPerOneAd = ref<number>(0);
+const urlPreviewEnabled = ref<boolean>(true);
+const urlPreviewTimeout = ref<number>(10000);
+const urlPreviewMaximumContentLength = ref<number>(1024 * 1024 * 10);
+const urlPreviewRequireContentLength = ref<boolean>(true);
+const urlPreviewUserAgent = ref<string | null>(null);
+const urlPreviewSummaryProxyUrl = ref<string | null>(null);
 
 async function init(): Promise<void> {
 	const meta = await misskeyApi('admin/meta');
@@ -217,9 +272,15 @@ async function init(): Promise<void> {
 	perUserHomeTimelineCacheMax.value = meta.perUserHomeTimelineCacheMax;
 	perUserListTimelineCacheMax.value = meta.perUserListTimelineCacheMax;
 	notesPerOneAd.value = meta.notesPerOneAd;
+	urlPreviewEnabled.value = meta.urlPreviewEnabled;
+	urlPreviewTimeout.value = meta.urlPreviewTimeout;
+	urlPreviewMaximumContentLength.value = meta.urlPreviewMaximumContentLength;
+	urlPreviewRequireContentLength.value = meta.urlPreviewRequireContentLength;
+	urlPreviewUserAgent.value = meta.urlPreviewUserAgent;
+	urlPreviewSummaryProxyUrl.value = meta.urlPreviewSummaryProxyUrl;
 }
 
-async function save(): void {
+async function save() {
 	await os.apiWithDialog('admin/update-meta', {
 		name: name.value,
 		shortName: shortName.value === '' ? null : shortName.value,
@@ -241,6 +302,12 @@ async function save(): void {
 		perUserHomeTimelineCacheMax: perUserHomeTimelineCacheMax.value,
 		perUserListTimelineCacheMax: perUserListTimelineCacheMax.value,
 		notesPerOneAd: notesPerOneAd.value,
+		urlPreviewEnabled: urlPreviewEnabled.value,
+		urlPreviewTimeout: urlPreviewTimeout.value,
+		urlPreviewMaximumContentLength: urlPreviewMaximumContentLength.value,
+		urlPreviewRequireContentLength: urlPreviewRequireContentLength.value,
+		urlPreviewUserAgent: urlPreviewUserAgent.value,
+		urlPreviewSummaryProxyUrl: urlPreviewSummaryProxyUrl.value,
 	});
 
 	fetchInstance(true);
@@ -259,4 +326,9 @@ definePageMetadata(() => ({
 	-webkit-backdrop-filter: var(--blur, blur(15px));
 	backdrop-filter: var(--blur, blur(15px));
 }
+
+.subCaption {
+	font-size: 0.85em;
+	color: var(--fgTransparentWeak);
+}
 </style>
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 636bc62aaa..c6e36d80aa 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -4810,6 +4810,7 @@ export type components = {
       enableServiceWorker: boolean;
       translatorAvailable: boolean;
       mediaProxy: string;
+      enableUrlPreview: boolean;
       backgroundImageUrl: string | null;
       impressumUrl: string | null;
       logoImageUrl: string | null;
@@ -4962,11 +4963,21 @@ export type operations = {
             objectStorageS3ForcePathStyle: boolean;
             privacyPolicyUrl: string | null;
             repositoryUrl: string | null;
+            /**
+             * @deprecated
+             * @description [Deprecated] Use "urlPreviewSummaryProxyUrl" instead.
+             */
             summalyProxy: string | null;
             themeColor: string | null;
             tosUrl: string | null;
             uri: string;
             version: string;
+            urlPreviewEnabled: boolean;
+            urlPreviewTimeout: number;
+            urlPreviewMaximumContentLength: number;
+            urlPreviewRequireContentLength: boolean;
+            urlPreviewUserAgent: string | null;
+            urlPreviewSummaryProxyUrl: string | null;
           };
         };
       };
@@ -8862,7 +8873,6 @@ export type operations = {
           maintainerName?: string | null;
           maintainerEmail?: string | null;
           langs?: string[];
-          summalyProxy?: string | null;
           deeplAuthKey?: string | null;
           deeplIsPro?: boolean;
           enableEmail?: boolean;
@@ -8916,6 +8926,14 @@ export type operations = {
           perUserListTimelineCacheMax?: number;
           notesPerOneAd?: number;
           silencedHosts?: string[] | null;
+          /** @description [Deprecated] Use "urlPreviewSummaryProxyUrl" instead. */
+          summalyProxy?: string | null;
+          urlPreviewEnabled?: boolean;
+          urlPreviewTimeout?: number;
+          urlPreviewMaximumContentLength?: number;
+          urlPreviewRequireContentLength?: boolean;
+          urlPreviewUserAgent?: string | null;
+          urlPreviewSummaryProxyUrl?: string | null;
         };
       };
     };
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4c1e228a95..383b31b1f3 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -117,8 +117,8 @@ importers:
         specifier: 1.2.0
         version: 1.2.0
       '@misskey-dev/summaly':
-        specifier: 5.0.3
-        version: 5.0.3
+        specifier: 5.1.0
+        version: 5.1.0
       '@nestjs/common':
         specifier: 10.3.3
         version: 10.3.3(reflect-metadata@0.2.1)(rxjs@7.8.1)
@@ -4772,6 +4772,20 @@ packages:
       jschardet: 3.0.0
       private-ip: 2.3.3
       trace-redirect: 1.0.6
+    dev: true
+
+  /@misskey-dev/summaly@5.1.0:
+    resolution: {integrity: sha512-WAUrgX3/z4h4aI8Y/WVwmJcJ6Fa1Zf2LJCSS651t9MHoWVGABLsQ2KCXRGmlpk4i+cMDNIwweObUroosE7j8rg==}
+    dependencies:
+      cheerio: 1.0.0-rc.12
+      escape-regexp: 0.0.1
+      got: 12.6.1
+      html-entities: 2.3.2
+      iconv-lite: 0.6.3
+      jschardet: 3.0.0
+      private-ip: 2.3.3
+      trace-redirect: 1.0.6
+    dev: false
 
   /@mole-inc/bin-wrapper@8.0.1:
     resolution: {integrity: sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==}

From 40bb6069ec04bc0461ac407da7d03c6910c23d6d Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Fri, 22 Mar 2024 08:54:34 +0900
Subject: [PATCH 046/191] =?UTF-8?q?fix(frontend):=20URL=E3=83=97=E3=83=AC?=
 =?UTF-8?q?=E3=83=93=E3=83=A5=E3=83=BC=E3=81=AEto/href=E3=81=8C=E3=81=AA?=
 =?UTF-8?q?=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3=20Fix=20?=
 =?UTF-8?q?of=20https://github.com/misskey-dev/misskey/pull/13579/files/9a?=
 =?UTF-8?q?e577871b10f6231acc3451188cd69ede9443ed#diff-cfa02e203bdbd03dbf3?=
 =?UTF-8?q?12a889f009ca7f9ebd8376334ebd74c4961b716b22d93?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 packages/frontend/src/components/MkUrlPreview.vue | 1 +
 1 file changed, 1 insertion(+)

diff --git a/packages/frontend/src/components/MkUrlPreview.vue b/packages/frontend/src/components/MkUrlPreview.vue
index b3dc492616..6954f1f6ff 100644
--- a/packages/frontend/src/components/MkUrlPreview.vue
+++ b/packages/frontend/src/components/MkUrlPreview.vue
@@ -110,6 +110,7 @@ const MOBILE_THRESHOLD = 500;
 const isMobile = ref(deviceKind === 'smartphone' || window.innerWidth <= MOBILE_THRESHOLD);
 
 const self = props.url.startsWith(local);
+const attr = self ? 'to' : 'href';
 const target = self ? null : '_blank';
 const fetching = ref(true);
 const title = ref<string | null>(null);

From c9c6424205f1d05813735a8f9c0e53a1ccc35e0e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Fri, 22 Mar 2024 15:03:21 +0900
Subject: [PATCH 047/191] =?UTF-8?q?enhance(frontend):=20TOTP=E3=81=AE?=
 =?UTF-8?q?=E5=85=A5=E5=8A=9B=E3=83=80=E3=82=A4=E3=82=A2=E3=83=AD=E3=82=B0?=
 =?UTF-8?q?=E3=82=92=E6=94=B9=E8=89=AF=20(#13607)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance(frontend): TOTPの入力ダイアログを改良

* Update Changelog
---
 CHANGELOG.md                                  |  3 ++-
 locales/index.d.ts                            |  8 ++++++
 locales/ja-JP.yml                             |  2 ++
 packages/frontend/src/components/MkInput.vue  |  2 ++
 .../src/components/MkPasswordDialog.vue       | 26 +++++++++++--------
 packages/frontend/src/components/MkSignin.vue | 11 ++++----
 .../src/pages/settings/2fa.qrdialog.vue       |  2 +-
 packages/frontend/src/pages/settings/2fa.vue  |  6 ++++-
 8 files changed, 41 insertions(+), 19 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 188e146cdd..d90b1425c1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,7 +16,8 @@
 - Enhance: リアクション受け入れが「いいねのみ」の場合はリアクション絵文字一覧を表示しないように
 - Enhance: 設定>プラグインのページからプラグインの簡易的なログやエラーを見られるように
   - 実装の都合により、プラグインは1つエラーを起こした時に即時停止するようになりました
-- Enhance: ページのデザインを変更	
+- Enhance: ページのデザインを変更
+- Enhance: 2要素認証(ワンタイムパスワード)の入力欄を改善
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
 - Fix: ローカルURLのプレビューポップアップが左上に表示される
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 70586d7a87..e1250946f3 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -4920,6 +4920,14 @@ export interface Locale extends ILocale {
      * 使用しない場合は空欄にしてください
      */
     "notUsePleaseLeaveBlank": string;
+    /**
+     * ワンタイムパスワードを使う
+     */
+    "useTotp": string;
+    /**
+     * バックアップコードを使う
+     */
+    "useBackupCode": string;
     "_bubbleGame": {
         /**
          * 遊び方
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index cada6d855f..1c4df27d92 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1226,6 +1226,8 @@ loading: "読み込み中"
 surrender: "やめる"
 gameRetry: "リトライ"
 notUsePleaseLeaveBlank: "使用しない場合は空欄にしてください"
+useTotp: "ワンタイムパスワードを使う"
+useBackupCode: "バックアップコードを使う"
 
 _bubbleGame:
   howToPlay: "遊び方"
diff --git a/packages/frontend/src/components/MkInput.vue b/packages/frontend/src/components/MkInput.vue
index d3cddad15b..88ef4635e6 100644
--- a/packages/frontend/src/components/MkInput.vue
+++ b/packages/frontend/src/components/MkInput.vue
@@ -22,6 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 			:autocomplete="autocomplete"
 			:autocapitalize="autocapitalize"
 			:spellcheck="spellcheck"
+			:inputmode="inputmode"
 			:step="step"
 			:list="id"
 			:min="min"
@@ -63,6 +64,7 @@ const props = defineProps<{
 	mfmAutocomplete?: boolean | SuggestionType[],
 	autocapitalize?: string;
 	spellcheck?: boolean;
+	inputmode?: 'none' | 'text' | 'search' | 'email' | 'url' | 'numeric' | 'tel' | 'decimal';
 	step?: any;
 	datalist?: string[];
 	min?: number;
diff --git a/packages/frontend/src/components/MkPasswordDialog.vue b/packages/frontend/src/components/MkPasswordDialog.vue
index c49526d8e2..e749725fea 100644
--- a/packages/frontend/src/components/MkPasswordDialog.vue
+++ b/packages/frontend/src/components/MkPasswordDialog.vue
@@ -19,18 +19,21 @@ SPDX-License-Identifier: AGPL-3.0-only
 			<div style="margin-top: 16px;">{{ i18n.ts.authenticationRequiredToContinue }}</div>
 		</div>
 
-		<div class="_gaps">
-			<MkInput ref="passwordInput" v-model="password" :placeholder="i18n.ts.password" type="password" autocomplete="current-password webauthn" :withPasswordToggle="true">
-				<template #prefix><i class="ti ti-password"></i></template>
-			</MkInput>
+		<form @submit.prevent="done">
+			<div class="_gaps">
+				<MkInput ref="passwordInput" v-model="password" :placeholder="i18n.ts.password" type="password" autocomplete="current-password webauthn" required :withPasswordToggle="true">
+					<template #prefix><i class="ti ti-password"></i></template>
+				</MkInput>
 
-			<MkInput v-if="$i.twoFactorEnabled" v-model="token" type="text" pattern="^([0-9]{6}|[A-Z0-9]{32})$" autocomplete="one-time-code" :spellcheck="false">
-				<template #label>{{ i18n.ts.token }} ({{ i18n.ts['2fa'] }})</template>
-				<template #prefix><i class="ti ti-123"></i></template>
-			</MkInput>
+				<MkInput v-if="$i.twoFactorEnabled" v-model="token" type="text" :pattern="isBackupCode ? '^[A-Z0-9]{32}$' :'^[0-9]{6}$'" autocomplete="one-time-code" required :spellcheck="false" :inputmode="isBackupCode ? undefined : 'numeric'">
+					<template #label>{{ i18n.ts.token }} ({{ i18n.ts['2fa'] }})</template>
+					<template #prefix><i v-if="isBackupCode" class="ti ti-key"></i><i v-else class="ti ti-123"></i></template>
+					<template #caption><button class="_textButton" type="button" @click="isBackupCode = !isBackupCode">{{ isBackupCode ? i18n.ts.useTotp : i18n.ts.useBackupCode }}</button></template>
+				</MkInput>
 
-			<MkButton :disabled="(password ?? '') == '' || ($i.twoFactorEnabled && (token ?? '') == '')" primary rounded style="margin: 0 auto;" @click="done"><i class="ti ti-lock-open"></i> {{ i18n.ts.continue }}</MkButton>
-		</div>
+				<MkButton :disabled="(password ?? '') == '' || ($i.twoFactorEnabled && (token ?? '') == '')" type="submit" primary rounded style="margin: 0 auto;"><i class="ti ti-lock-open"></i> {{ i18n.ts.continue }}</MkButton>
+			</div>
+		</form>
 	</MkSpacer>
 </MkModalWindow>
 </template>
@@ -54,6 +57,7 @@ const emit = defineEmits<{
 const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
 const passwordInput = shallowRef<InstanceType<typeof MkInput>>();
 const password = ref('');
+const isBackupCode = ref(false);
 const token = ref<string | null>(null);
 
 function onClose() {
@@ -61,7 +65,7 @@ function onClose() {
 	if (dialog.value) dialog.value.close();
 }
 
-function done(res) {
+function done() {
 	emit('done', { password: password.value, token: token.value });
 	if (dialog.value) dialog.value.close();
 }
diff --git a/packages/frontend/src/components/MkSignin.vue b/packages/frontend/src/components/MkSignin.vue
index 852af01b5a..970aff825d 100644
--- a/packages/frontend/src/components/MkSignin.vue
+++ b/packages/frontend/src/components/MkSignin.vue
@@ -31,15 +31,15 @@ SPDX-License-Identifier: AGPL-3.0-only
 			<div v-if="user && user.securityKeys" class="or-hr">
 				<p class="or-msg">{{ i18n.ts.or }}</p>
 			</div>
-			<div class="twofa-group totp-group">
-				<p style="margin-bottom:0;">{{ i18n.ts['2fa'] }}</p>
+			<div class="twofa-group totp-group _gaps">
 				<MkInput v-if="user && user.usePasswordLessLogin" v-model="password" type="password" autocomplete="current-password" :withPasswordToggle="true" required>
 					<template #label>{{ i18n.ts.password }}</template>
 					<template #prefix><i class="ti ti-lock"></i></template>
 				</MkInput>
-				<MkInput v-model="token" type="text" pattern="^([0-9]{6}|[A-Z0-9]{32})$" autocomplete="one-time-code" :spellcheck="false" required>
-					<template #label>{{ i18n.ts.token }}</template>
-					<template #prefix><i class="ti ti-123"></i></template>
+				<MkInput v-model="token" type="text" :pattern="isBackupCode ? '^[A-Z0-9]{32}$' :'^[0-9]{6}$'" autocomplete="one-time-code" required :spellcheck="false" :inputmode="isBackupCode ? undefined : 'numeric'">
+					<template #label>{{ i18n.ts.token }} ({{ i18n.ts['2fa'] }})</template>
+					<template #prefix><i v-if="isBackupCode" class="ti ti-key"></i><i v-else class="ti ti-123"></i></template>
+					<template #caption><button class="_textButton" type="button" @click="isBackupCode = !isBackupCode">{{ isBackupCode ? i18n.ts.useTotp : i18n.ts.useBackupCode }}</button></template>
 				</MkInput>
 				<MkButton type="submit" :disabled="signing" large primary rounded style="margin: 0 auto;">{{ signing ? i18n.ts.loggingIn : i18n.ts.login }}</MkButton>
 			</div>
@@ -70,6 +70,7 @@ const password = ref('');
 const token = ref('');
 const host = ref(toUnicode(configHost));
 const totpLogin = ref(false);
+const isBackupCode = ref(false);
 const queryingKey = ref(false);
 const credentialRequest = ref<CredentialRequestOptions | null>(null);
 
diff --git a/packages/frontend/src/pages/settings/2fa.qrdialog.vue b/packages/frontend/src/pages/settings/2fa.qrdialog.vue
index 2608560cc4..2ef664b9a3 100644
--- a/packages/frontend/src/pages/settings/2fa.qrdialog.vue
+++ b/packages/frontend/src/pages/settings/2fa.qrdialog.vue
@@ -52,7 +52,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 					<MkSpacer :marginMin="20" :marginMax="28">
 						<div class="_gaps">
 							<div>{{ i18n.ts._2fa.step3Title }}</div>
-							<MkInput v-model="token" autocomplete="one-time-code"></MkInput>
+							<MkInput v-model="token" autocomplete="one-time-code" inputmode="numeric"></MkInput>
 							<div>{{ i18n.ts._2fa.step3 }}</div>
 						</div>
 						<div class="_buttonsCenter" style="margin-top: 16px;">
diff --git a/packages/frontend/src/pages/settings/2fa.vue b/packages/frontend/src/pages/settings/2fa.vue
index d8c5f848fe..975f23cdd1 100644
--- a/packages/frontend/src/pages/settings/2fa.vue
+++ b/packages/frontend/src/pages/settings/2fa.vue
@@ -80,7 +80,7 @@ import MkSwitch from '@/components/MkSwitch.vue';
 import FormSection from '@/components/form/section.vue';
 import MkFolder from '@/components/MkFolder.vue';
 import * as os from '@/os.js';
-import { signinRequired } from '@/account.js';
+import { signinRequired, updateAccount } from '@/account.js';
 import { i18n } from '@/i18n.js';
 
 const $i = signinRequired();
@@ -116,6 +116,10 @@ async function unregisterTOTP(): Promise<void> {
 	os.apiWithDialog('i/2fa/unregister', {
 		password: auth.result.password,
 		token: auth.result.token,
+	}).then(res => {
+		updateAccount({
+			twoFactorEnabled: false,
+		});
 	}).catch(error => {
 		os.alert({
 			type: 'error',

From 6bd78770de06bd3694127da17ccd051f05057329 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Fri, 22 Mar 2024 18:21:14 +0900
Subject: [PATCH 048/191] =?UTF-8?q?enhance(frontend):=20=E3=83=AA=E3=82=A2?=
 =?UTF-8?q?=E3=82=AF=E3=82=B7=E3=83=A7=E3=83=B3=E5=8F=97=E3=81=91=E5=85=A5?=
 =?UTF-8?q?=E3=82=8C=E3=81=8C=E3=81=84=E3=81=84=E3=81=AD=E3=81=AE=E3=81=BF?=
 =?UTF-8?q?=E3=81=AE=E5=A0=B4=E5=90=88=E3=81=AF=E3=83=9C=E3=82=BF=E3=83=B3?=
 =?UTF-8?q?=E3=83=9B=E3=83=90=E3=83=BC=E3=81=A7=E3=83=84=E3=83=BC=E3=83=AB?=
 =?UTF-8?q?=E3=83=81=E3=83=83=E3=83=97=E3=81=8C=E5=87=BA=E3=82=8B=E3=82=88?=
 =?UTF-8?q?=E3=81=86=E3=81=AB=20(#13613)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 packages/frontend/src/components/MkNote.vue   | 25 ++++++++++++++++++-
 .../src/components/MkNoteDetailed.vue         | 25 ++++++++++++++++++-
 2 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index 50741f2cb7..4add3aa6dd 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -167,6 +167,7 @@ import MkNoteSub from '@/components/MkNoteSub.vue';
 import MkNoteHeader from '@/components/MkNoteHeader.vue';
 import MkNoteSimple from '@/components/MkNoteSimple.vue';
 import MkReactionsViewer from '@/components/MkReactionsViewer.vue';
+import MkReactionsViewerDetails from '@/components/MkReactionsViewer.details.vue';
 import MkMediaList from '@/components/MkMediaList.vue';
 import MkCwButton from '@/components/MkCwButton.vue';
 import MkPoll from '@/components/MkPoll.vue';
@@ -180,7 +181,7 @@ import { userPage } from '@/filters/user.js';
 import number from '@/filters/number.js';
 import * as os from '@/os.js';
 import * as sound from '@/scripts/sound.js';
-import { misskeyApi } from '@/scripts/misskey-api.js';
+import { misskeyApi, misskeyApiGet } from '@/scripts/misskey-api.js';
 import { defaultStore, noteViewInterruptors } from '@/store.js';
 import { reactionPicker } from '@/scripts/reaction-picker.js';
 import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js';
@@ -340,6 +341,28 @@ if (!props.mock) {
 			targetElement: renoteButton.value,
 		}, {}, 'closed');
 	});
+
+	if (appearNote.value.reactionAcceptance === 'likeOnly') {
+		useTooltip(reactButton, async (showing) => {
+			const reactions = await misskeyApiGet('notes/reactions', {
+				noteId: appearNote.value.id,
+				limit: 10,
+				_cacheKey_: appearNote.value.reactionCount,
+			});
+
+			const users = reactions.map(x => x.user);
+
+			if (users.length < 1) return;
+
+			os.popup(MkReactionsViewerDetails, {
+				showing,
+				reaction: '❤️',
+				users,
+				count: appearNote.value.reactionCount,
+				targetElement: reactButton.value!,
+			}, {}, 'closed');
+		});
+	}
 }
 
 function renote(viaKeyboard = false) {
diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue
index 1b7dcda409..ebccd60986 100644
--- a/packages/frontend/src/components/MkNoteDetailed.vue
+++ b/packages/frontend/src/components/MkNoteDetailed.vue
@@ -201,6 +201,7 @@ import * as Misskey from 'misskey-js';
 import MkNoteSub from '@/components/MkNoteSub.vue';
 import MkNoteSimple from '@/components/MkNoteSimple.vue';
 import MkReactionsViewer from '@/components/MkReactionsViewer.vue';
+import MkReactionsViewerDetails from '@/components/MkReactionsViewer.details.vue';
 import MkMediaList from '@/components/MkMediaList.vue';
 import MkCwButton from '@/components/MkCwButton.vue';
 import MkPoll from '@/components/MkPoll.vue';
@@ -213,7 +214,7 @@ import { userPage } from '@/filters/user.js';
 import { notePage } from '@/filters/note.js';
 import number from '@/filters/number.js';
 import * as os from '@/os.js';
-import { misskeyApi } from '@/scripts/misskey-api.js';
+import { misskeyApi, misskeyApiGet } from '@/scripts/misskey-api.js';
 import * as sound from '@/scripts/sound.js';
 import { defaultStore, noteViewInterruptors } from '@/store.js';
 import { reactionPicker } from '@/scripts/reaction-picker.js';
@@ -348,6 +349,28 @@ useTooltip(renoteButton, async (showing) => {
 	}, {}, 'closed');
 });
 
+if (appearNote.value.reactionAcceptance === 'likeOnly') {
+	useTooltip(reactButton, async (showing) => {
+		const reactions = await misskeyApiGet('notes/reactions', {
+			noteId: appearNote.value.id,
+			limit: 10,
+			_cacheKey_: appearNote.value.reactionCount,
+		});
+
+		const users = reactions.map(x => x.user);
+
+		if (users.length < 1) return;
+
+		os.popup(MkReactionsViewerDetails, {
+			showing,
+			reaction: '❤️',
+			users,
+			count: appearNote.value.reactionCount,
+			targetElement: reactButton.value!,
+		}, {}, 'closed');
+	});
+}
+
 function renote(viaKeyboard = false) {
 	pleaseLogin();
 	showMovedDialog();

From 3db26f2b94af6cc981f1305ddd4da20401aa2910 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Sat, 23 Mar 2024 20:43:29 +0900
Subject: [PATCH 049/191] fix(backend): fix openAPI operationId format

---
 packages/backend/src/server/api/openapi/gen-spec.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts
index 7679a9b464..2a14270a24 100644
--- a/packages/backend/src/server/api/openapi/gen-spec.ts
+++ b/packages/backend/src/server/api/openapi/gen-spec.ts
@@ -93,7 +93,7 @@ export function genOpenapiSpec(config: Config, includeSelfRef = false) {
 		const hasBody = (schema.type === 'object' && schema.properties && Object.keys(schema.properties).length >= 1);
 
 		const info = {
-			operationId: endpoint.name,
+			operationId: endpoint.name.replaceAll('/', '___'), // NOTE: スラッシュは使えない
 			summary: endpoint.name,
 			description: desc,
 			externalDocs: {

From 539718f6a86cac21bd47106e206b888135e2a89d Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Sun, 24 Mar 2024 16:46:15 +0900
Subject: [PATCH 050/191] fix(misskey-js): fix ESLint error in generator due to
 `operationId` change (#13619)

---
 packages/misskey-js/generator/src/generator.ts | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/packages/misskey-js/generator/src/generator.ts b/packages/misskey-js/generator/src/generator.ts
index f091e599a9..49dcd4c1ed 100644
--- a/packages/misskey-js/generator/src/generator.ts
+++ b/packages/misskey-js/generator/src/generator.ts
@@ -98,6 +98,8 @@ async function generateEndpoints(
 
 	const entitiesOutputLine: string[] = [];
 
+	entitiesOutputLine.push('/* eslint @typescript-eslint/naming-convention: 0 */');
+
 	entitiesOutputLine.push(`import { operations } from '${toImportPath(typeFileName)}';`);
 	entitiesOutputLine.push('');
 

From a1bc8fa77b0820907399d010f56c2169f6898e8b Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Sun, 24 Mar 2024 16:46:52 +0900
Subject: [PATCH 051/191] test(backend): fix streaming test error when replying
 to followers-only note (#13618)

---
 packages/backend/test/e2e/streaming.ts | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/packages/backend/test/e2e/streaming.ts b/packages/backend/test/e2e/streaming.ts
index edb930617f..26bb68ec6c 100644
--- a/packages/backend/test/e2e/streaming.ts
+++ b/packages/backend/test/e2e/streaming.ts
@@ -158,19 +158,17 @@ describe('Streaming', () => {
 				assert.strictEqual(fired, true);
 			});
 
-			/* なんか失敗する
 			test('フォローしているユーザーの visibility: followers な投稿への返信が流れる', async () => {
-				const note = await api('notes/create', { text: 'foo', visibility: 'followers' }, kyoko);
+				const note = await post(kyoko, { text: 'foo', visibility: 'followers' });
 
 				const fired = await waitFire(
 					ayano, 'homeTimeline',		// ayano:home
-					() => api('notes/create', { text: 'bar', visibility: 'followers', replyId: note.body.id }, kyoko),	// kyoko posts
+					() => api('notes/create', { text: 'bar', visibility: 'followers', replyId: note.id }, kyoko),	// kyoko posts
 					msg => msg.type === 'note' && msg.body.userId === kyoko.id && msg.body.reply.text === 'foo',
 				);
 
 				assert.strictEqual(fired, true);
 			});
-			*/
 
 			test('フォローしているユーザーのフォローしていないユーザーの visibility: followers な投稿への返信が流れない', async () => {
 				const chitoseNote = await post(chitose, { text: 'followers-only post', visibility: 'followers' });

From 8f415d69cd2e459c6a8ac46034d5eb09b91e441f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 25 Mar 2024 12:11:10 +0900
Subject: [PATCH 052/191] =?UTF-8?q?fix(generator):=20API=E3=82=AF=E3=83=A9?=
 =?UTF-8?q?=E3=82=A4=E3=82=A2=E3=83=B3=E3=83=88=E3=81=AE=E3=83=91=E3=82=B9?=
 =?UTF-8?q?=E3=81=ABoperationId=E3=81=8C=E4=BD=BF=E3=82=8F=E3=82=8C?=
 =?UTF-8?q?=E3=82=8B=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3=20(#1362?=
 =?UTF-8?q?2)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 packages/misskey-js/etc/misskey-js.api.md     | 1036 ++++++------
 .../misskey-js/generator/src/generator.ts     |   39 +-
 packages/misskey-js/src/autogen/entities.ts   | 1037 ++++++------
 packages/misskey-js/src/autogen/types.ts      | 1410 ++++++++---------
 4 files changed, 1770 insertions(+), 1752 deletions(-)

diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md
index 2237d278f4..360724d2a9 100644
--- a/packages/misskey-js/etc/misskey-js.api.md
+++ b/packages/misskey-js/etc/misskey-js.api.md
@@ -29,298 +29,298 @@ type Ad = components['schemas']['Ad'];
 // Warning: (ae-forgotten-export) The symbol "operations" needs to be exported by the entry point index.d.ts
 //
 // @public (undocumented)
-type AdminAbuseUserReportsRequest = operations['admin/abuse-user-reports']['requestBody']['content']['application/json'];
+type AdminAbuseUserReportsRequest = operations['admin___abuse-user-reports']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAbuseUserReportsResponse = operations['admin/abuse-user-reports']['responses']['200']['content']['application/json'];
+type AdminAbuseUserReportsResponse = operations['admin___abuse-user-reports']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAccountsCreateRequest = operations['admin/accounts/create']['requestBody']['content']['application/json'];
+type AdminAccountsCreateRequest = operations['admin___accounts___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAccountsCreateResponse = operations['admin/accounts/create']['responses']['200']['content']['application/json'];
+type AdminAccountsCreateResponse = operations['admin___accounts___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAccountsDeleteRequest = operations['admin/accounts/delete']['requestBody']['content']['application/json'];
+type AdminAccountsDeleteRequest = operations['admin___accounts___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAccountsFindByEmailRequest = operations['admin/accounts/find-by-email']['requestBody']['content']['application/json'];
+type AdminAccountsFindByEmailRequest = operations['admin___accounts___find-by-email']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAccountsFindByEmailResponse = operations['admin/accounts/find-by-email']['responses']['200']['content']['application/json'];
+type AdminAccountsFindByEmailResponse = operations['admin___accounts___find-by-email']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAdCreateRequest = operations['admin/ad/create']['requestBody']['content']['application/json'];
+type AdminAdCreateRequest = operations['admin___ad___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAdCreateResponse = operations['admin/ad/create']['responses']['200']['content']['application/json'];
+type AdminAdCreateResponse = operations['admin___ad___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAdDeleteRequest = operations['admin/ad/delete']['requestBody']['content']['application/json'];
+type AdminAdDeleteRequest = operations['admin___ad___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAdListRequest = operations['admin/ad/list']['requestBody']['content']['application/json'];
+type AdminAdListRequest = operations['admin___ad___list']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAdListResponse = operations['admin/ad/list']['responses']['200']['content']['application/json'];
+type AdminAdListResponse = operations['admin___ad___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAdUpdateRequest = operations['admin/ad/update']['requestBody']['content']['application/json'];
+type AdminAdUpdateRequest = operations['admin___ad___update']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAnnouncementsCreateRequest = operations['admin/announcements/create']['requestBody']['content']['application/json'];
+type AdminAnnouncementsCreateRequest = operations['admin___announcements___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAnnouncementsCreateResponse = operations['admin/announcements/create']['responses']['200']['content']['application/json'];
+type AdminAnnouncementsCreateResponse = operations['admin___announcements___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAnnouncementsDeleteRequest = operations['admin/announcements/delete']['requestBody']['content']['application/json'];
+type AdminAnnouncementsDeleteRequest = operations['admin___announcements___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAnnouncementsListRequest = operations['admin/announcements/list']['requestBody']['content']['application/json'];
+type AdminAnnouncementsListRequest = operations['admin___announcements___list']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAnnouncementsListResponse = operations['admin/announcements/list']['responses']['200']['content']['application/json'];
+type AdminAnnouncementsListResponse = operations['admin___announcements___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAnnouncementsUpdateRequest = operations['admin/announcements/update']['requestBody']['content']['application/json'];
+type AdminAnnouncementsUpdateRequest = operations['admin___announcements___update']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAvatarDecorationsCreateRequest = operations['admin/avatar-decorations/create']['requestBody']['content']['application/json'];
+type AdminAvatarDecorationsCreateRequest = operations['admin___avatar-decorations___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAvatarDecorationsDeleteRequest = operations['admin/avatar-decorations/delete']['requestBody']['content']['application/json'];
+type AdminAvatarDecorationsDeleteRequest = operations['admin___avatar-decorations___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAvatarDecorationsListRequest = operations['admin/avatar-decorations/list']['requestBody']['content']['application/json'];
+type AdminAvatarDecorationsListRequest = operations['admin___avatar-decorations___list']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAvatarDecorationsListResponse = operations['admin/avatar-decorations/list']['responses']['200']['content']['application/json'];
+type AdminAvatarDecorationsListResponse = operations['admin___avatar-decorations___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminAvatarDecorationsUpdateRequest = operations['admin/avatar-decorations/update']['requestBody']['content']['application/json'];
+type AdminAvatarDecorationsUpdateRequest = operations['admin___avatar-decorations___update']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminDeleteAccountRequest = operations['admin/delete-account']['requestBody']['content']['application/json'];
+type AdminDeleteAccountRequest = operations['admin___delete-account']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminDeleteAllFilesOfAUserRequest = operations['admin/delete-all-files-of-a-user']['requestBody']['content']['application/json'];
+type AdminDeleteAllFilesOfAUserRequest = operations['admin___delete-all-files-of-a-user']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminDriveFilesRequest = operations['admin/drive/files']['requestBody']['content']['application/json'];
+type AdminDriveFilesRequest = operations['admin___drive___files']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminDriveFilesResponse = operations['admin/drive/files']['responses']['200']['content']['application/json'];
+type AdminDriveFilesResponse = operations['admin___drive___files']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminDriveShowFileRequest = operations['admin/drive/show-file']['requestBody']['content']['application/json'];
+type AdminDriveShowFileRequest = operations['admin___drive___show-file']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminDriveShowFileResponse = operations['admin/drive/show-file']['responses']['200']['content']['application/json'];
+type AdminDriveShowFileResponse = operations['admin___drive___show-file']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminEmojiAddAliasesBulkRequest = operations['admin/emoji/add-aliases-bulk']['requestBody']['content']['application/json'];
+type AdminEmojiAddAliasesBulkRequest = operations['admin___emoji___add-aliases-bulk']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminEmojiAddRequest = operations['admin/emoji/add']['requestBody']['content']['application/json'];
+type AdminEmojiAddRequest = operations['admin___emoji___add']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminEmojiAddResponse = operations['admin/emoji/add']['responses']['200']['content']['application/json'];
+type AdminEmojiAddResponse = operations['admin___emoji___add']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminEmojiCopyRequest = operations['admin/emoji/copy']['requestBody']['content']['application/json'];
+type AdminEmojiCopyRequest = operations['admin___emoji___copy']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminEmojiCopyResponse = operations['admin/emoji/copy']['responses']['200']['content']['application/json'];
+type AdminEmojiCopyResponse = operations['admin___emoji___copy']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminEmojiDeleteBulkRequest = operations['admin/emoji/delete-bulk']['requestBody']['content']['application/json'];
+type AdminEmojiDeleteBulkRequest = operations['admin___emoji___delete-bulk']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminEmojiDeleteRequest = operations['admin/emoji/delete']['requestBody']['content']['application/json'];
+type AdminEmojiDeleteRequest = operations['admin___emoji___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminEmojiImportZipRequest = operations['admin/emoji/import-zip']['requestBody']['content']['application/json'];
+type AdminEmojiImportZipRequest = operations['admin___emoji___import-zip']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminEmojiListRemoteRequest = operations['admin/emoji/list-remote']['requestBody']['content']['application/json'];
+type AdminEmojiListRemoteRequest = operations['admin___emoji___list-remote']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminEmojiListRemoteResponse = operations['admin/emoji/list-remote']['responses']['200']['content']['application/json'];
+type AdminEmojiListRemoteResponse = operations['admin___emoji___list-remote']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminEmojiListRequest = operations['admin/emoji/list']['requestBody']['content']['application/json'];
+type AdminEmojiListRequest = operations['admin___emoji___list']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminEmojiListResponse = operations['admin/emoji/list']['responses']['200']['content']['application/json'];
+type AdminEmojiListResponse = operations['admin___emoji___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminEmojiRemoveAliasesBulkRequest = operations['admin/emoji/remove-aliases-bulk']['requestBody']['content']['application/json'];
+type AdminEmojiRemoveAliasesBulkRequest = operations['admin___emoji___remove-aliases-bulk']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminEmojiSetAliasesBulkRequest = operations['admin/emoji/set-aliases-bulk']['requestBody']['content']['application/json'];
+type AdminEmojiSetAliasesBulkRequest = operations['admin___emoji___set-aliases-bulk']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminEmojiSetCategoryBulkRequest = operations['admin/emoji/set-category-bulk']['requestBody']['content']['application/json'];
+type AdminEmojiSetCategoryBulkRequest = operations['admin___emoji___set-category-bulk']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminEmojiSetLicenseBulkRequest = operations['admin/emoji/set-license-bulk']['requestBody']['content']['application/json'];
+type AdminEmojiSetLicenseBulkRequest = operations['admin___emoji___set-license-bulk']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminEmojiUpdateRequest = operations['admin/emoji/update']['requestBody']['content']['application/json'];
+type AdminEmojiUpdateRequest = operations['admin___emoji___update']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminFederationDeleteAllFilesRequest = operations['admin/federation/delete-all-files']['requestBody']['content']['application/json'];
+type AdminFederationDeleteAllFilesRequest = operations['admin___federation___delete-all-files']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminFederationRefreshRemoteInstanceMetadataRequest = operations['admin/federation/refresh-remote-instance-metadata']['requestBody']['content']['application/json'];
+type AdminFederationRefreshRemoteInstanceMetadataRequest = operations['admin___federation___refresh-remote-instance-metadata']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminFederationRemoveAllFollowingRequest = operations['admin/federation/remove-all-following']['requestBody']['content']['application/json'];
+type AdminFederationRemoveAllFollowingRequest = operations['admin___federation___remove-all-following']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminFederationUpdateInstanceRequest = operations['admin/federation/update-instance']['requestBody']['content']['application/json'];
+type AdminFederationUpdateInstanceRequest = operations['admin___federation___update-instance']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminGetIndexStatsResponse = operations['admin/get-index-stats']['responses']['200']['content']['application/json'];
+type AdminGetIndexStatsResponse = operations['admin___get-index-stats']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminGetTableStatsResponse = operations['admin/get-table-stats']['responses']['200']['content']['application/json'];
+type AdminGetTableStatsResponse = operations['admin___get-table-stats']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminGetUserIpsRequest = operations['admin/get-user-ips']['requestBody']['content']['application/json'];
+type AdminGetUserIpsRequest = operations['admin___get-user-ips']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminGetUserIpsResponse = operations['admin/get-user-ips']['responses']['200']['content']['application/json'];
+type AdminGetUserIpsResponse = operations['admin___get-user-ips']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminInviteCreateRequest = operations['admin/invite/create']['requestBody']['content']['application/json'];
+type AdminInviteCreateRequest = operations['admin___invite___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminInviteCreateResponse = operations['admin/invite/create']['responses']['200']['content']['application/json'];
+type AdminInviteCreateResponse = operations['admin___invite___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminInviteListRequest = operations['admin/invite/list']['requestBody']['content']['application/json'];
+type AdminInviteListRequest = operations['admin___invite___list']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminInviteListResponse = operations['admin/invite/list']['responses']['200']['content']['application/json'];
+type AdminInviteListResponse = operations['admin___invite___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminMetaResponse = operations['admin/meta']['responses']['200']['content']['application/json'];
+type AdminMetaResponse = operations['admin___meta']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminPromoCreateRequest = operations['admin/promo/create']['requestBody']['content']['application/json'];
+type AdminPromoCreateRequest = operations['admin___promo___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminQueueDeliverDelayedResponse = operations['admin/queue/deliver-delayed']['responses']['200']['content']['application/json'];
+type AdminQueueDeliverDelayedResponse = operations['admin___queue___deliver-delayed']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminQueueInboxDelayedResponse = operations['admin/queue/inbox-delayed']['responses']['200']['content']['application/json'];
+type AdminQueueInboxDelayedResponse = operations['admin___queue___inbox-delayed']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminQueuePromoteRequest = operations['admin/queue/promote']['requestBody']['content']['application/json'];
+type AdminQueuePromoteRequest = operations['admin___queue___promote']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminQueueStatsResponse = operations['admin/queue/stats']['responses']['200']['content']['application/json'];
+type AdminQueueStatsResponse = operations['admin___queue___stats']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminRelaysAddRequest = operations['admin/relays/add']['requestBody']['content']['application/json'];
+type AdminRelaysAddRequest = operations['admin___relays___add']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminRelaysAddResponse = operations['admin/relays/add']['responses']['200']['content']['application/json'];
+type AdminRelaysAddResponse = operations['admin___relays___add']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminRelaysListResponse = operations['admin/relays/list']['responses']['200']['content']['application/json'];
+type AdminRelaysListResponse = operations['admin___relays___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminRelaysRemoveRequest = operations['admin/relays/remove']['requestBody']['content']['application/json'];
+type AdminRelaysRemoveRequest = operations['admin___relays___remove']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminResetPasswordRequest = operations['admin/reset-password']['requestBody']['content']['application/json'];
+type AdminResetPasswordRequest = operations['admin___reset-password']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminResetPasswordResponse = operations['admin/reset-password']['responses']['200']['content']['application/json'];
+type AdminResetPasswordResponse = operations['admin___reset-password']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminResolveAbuseUserReportRequest = operations['admin/resolve-abuse-user-report']['requestBody']['content']['application/json'];
+type AdminResolveAbuseUserReportRequest = operations['admin___resolve-abuse-user-report']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminRolesAssignRequest = operations['admin/roles/assign']['requestBody']['content']['application/json'];
+type AdminRolesAssignRequest = operations['admin___roles___assign']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminRolesCreateRequest = operations['admin/roles/create']['requestBody']['content']['application/json'];
+type AdminRolesCreateRequest = operations['admin___roles___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminRolesCreateResponse = operations['admin/roles/create']['responses']['200']['content']['application/json'];
+type AdminRolesCreateResponse = operations['admin___roles___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminRolesDeleteRequest = operations['admin/roles/delete']['requestBody']['content']['application/json'];
+type AdminRolesDeleteRequest = operations['admin___roles___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminRolesListResponse = operations['admin/roles/list']['responses']['200']['content']['application/json'];
+type AdminRolesListResponse = operations['admin___roles___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminRolesShowRequest = operations['admin/roles/show']['requestBody']['content']['application/json'];
+type AdminRolesShowRequest = operations['admin___roles___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminRolesShowResponse = operations['admin/roles/show']['responses']['200']['content']['application/json'];
+type AdminRolesShowResponse = operations['admin___roles___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminRolesUnassignRequest = operations['admin/roles/unassign']['requestBody']['content']['application/json'];
+type AdminRolesUnassignRequest = operations['admin___roles___unassign']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminRolesUpdateDefaultPoliciesRequest = operations['admin/roles/update-default-policies']['requestBody']['content']['application/json'];
+type AdminRolesUpdateDefaultPoliciesRequest = operations['admin___roles___update-default-policies']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminRolesUpdateRequest = operations['admin/roles/update']['requestBody']['content']['application/json'];
+type AdminRolesUpdateRequest = operations['admin___roles___update']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminRolesUsersRequest = operations['admin/roles/users']['requestBody']['content']['application/json'];
+type AdminRolesUsersRequest = operations['admin___roles___users']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminRolesUsersResponse = operations['admin/roles/users']['responses']['200']['content']['application/json'];
+type AdminRolesUsersResponse = operations['admin___roles___users']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminSendEmailRequest = operations['admin/send-email']['requestBody']['content']['application/json'];
+type AdminSendEmailRequest = operations['admin___send-email']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminServerInfoResponse = operations['admin/server-info']['responses']['200']['content']['application/json'];
+type AdminServerInfoResponse = operations['admin___server-info']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminShowModerationLogsRequest = operations['admin/show-moderation-logs']['requestBody']['content']['application/json'];
+type AdminShowModerationLogsRequest = operations['admin___show-moderation-logs']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminShowModerationLogsResponse = operations['admin/show-moderation-logs']['responses']['200']['content']['application/json'];
+type AdminShowModerationLogsResponse = operations['admin___show-moderation-logs']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminShowUserRequest = operations['admin/show-user']['requestBody']['content']['application/json'];
+type AdminShowUserRequest = operations['admin___show-user']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminShowUserResponse = operations['admin/show-user']['responses']['200']['content']['application/json'];
+type AdminShowUserResponse = operations['admin___show-user']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminShowUsersRequest = operations['admin/show-users']['requestBody']['content']['application/json'];
+type AdminShowUsersRequest = operations['admin___show-users']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminShowUsersResponse = operations['admin/show-users']['responses']['200']['content']['application/json'];
+type AdminShowUsersResponse = operations['admin___show-users']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AdminSuspendUserRequest = operations['admin/suspend-user']['requestBody']['content']['application/json'];
+type AdminSuspendUserRequest = operations['admin___suspend-user']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminUnsetUserAvatarRequest = operations['admin/unset-user-avatar']['requestBody']['content']['application/json'];
+type AdminUnsetUserAvatarRequest = operations['admin___unset-user-avatar']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminUnsetUserBannerRequest = operations['admin/unset-user-banner']['requestBody']['content']['application/json'];
+type AdminUnsetUserBannerRequest = operations['admin___unset-user-banner']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminUnsuspendUserRequest = operations['admin/unsuspend-user']['requestBody']['content']['application/json'];
+type AdminUnsuspendUserRequest = operations['admin___unsuspend-user']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminUpdateMetaRequest = operations['admin/update-meta']['requestBody']['content']['application/json'];
+type AdminUpdateMetaRequest = operations['admin___update-meta']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AdminUpdateUserNoteRequest = operations['admin/update-user-note']['requestBody']['content']['application/json'];
+type AdminUpdateUserNoteRequest = operations['admin___update-user-note']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
 type Announcement = components['schemas']['Announcement'];
@@ -340,40 +340,40 @@ type AnnouncementsResponse = operations['announcements']['responses']['200']['co
 type Antenna = components['schemas']['Antenna'];
 
 // @public (undocumented)
-type AntennasCreateRequest = operations['antennas/create']['requestBody']['content']['application/json'];
+type AntennasCreateRequest = operations['antennas___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AntennasCreateResponse = operations['antennas/create']['responses']['200']['content']['application/json'];
+type AntennasCreateResponse = operations['antennas___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AntennasDeleteRequest = operations['antennas/delete']['requestBody']['content']['application/json'];
+type AntennasDeleteRequest = operations['antennas___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AntennasListResponse = operations['antennas/list']['responses']['200']['content']['application/json'];
+type AntennasListResponse = operations['antennas___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AntennasNotesRequest = operations['antennas/notes']['requestBody']['content']['application/json'];
+type AntennasNotesRequest = operations['antennas___notes']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AntennasNotesResponse = operations['antennas/notes']['responses']['200']['content']['application/json'];
+type AntennasNotesResponse = operations['antennas___notes']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AntennasShowRequest = operations['antennas/show']['requestBody']['content']['application/json'];
+type AntennasShowRequest = operations['antennas___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AntennasShowResponse = operations['antennas/show']['responses']['200']['content']['application/json'];
+type AntennasShowResponse = operations['antennas___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AntennasUpdateRequest = operations['antennas/update']['requestBody']['content']['application/json'];
+type AntennasUpdateRequest = operations['antennas___update']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AntennasUpdateResponse = operations['antennas/update']['responses']['200']['content']['application/json'];
+type AntennasUpdateResponse = operations['antennas___update']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ApGetRequest = operations['ap/get']['requestBody']['content']['application/json'];
+type ApGetRequest = operations['ap___get']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ApGetResponse = operations['ap/get']['responses']['200']['content']['application/json'];
+type ApGetResponse = operations['ap___get']['responses']['200']['content']['application/json'];
 
 declare namespace api {
     export {
@@ -414,73 +414,73 @@ type APIError = {
 type App = components['schemas']['App'];
 
 // @public (undocumented)
-type AppCreateRequest = operations['app/create']['requestBody']['content']['application/json'];
+type AppCreateRequest = operations['app___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AppCreateResponse = operations['app/create']['responses']['200']['content']['application/json'];
+type AppCreateResponse = operations['app___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AppShowRequest = operations['app/show']['requestBody']['content']['application/json'];
+type AppShowRequest = operations['app___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AppShowResponse = operations['app/show']['responses']['200']['content']['application/json'];
+type AppShowResponse = operations['app___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ApShowRequest = operations['ap/show']['requestBody']['content']['application/json'];
+type ApShowRequest = operations['ap___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ApShowResponse = operations['ap/show']['responses']['200']['content']['application/json'];
+type ApShowResponse = operations['ap___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AuthAcceptRequest = operations['auth/accept']['requestBody']['content']['application/json'];
+type AuthAcceptRequest = operations['auth___accept']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AuthSessionGenerateRequest = operations['auth/session/generate']['requestBody']['content']['application/json'];
+type AuthSessionGenerateRequest = operations['auth___session___generate']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AuthSessionGenerateResponse = operations['auth/session/generate']['responses']['200']['content']['application/json'];
+type AuthSessionGenerateResponse = operations['auth___session___generate']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AuthSessionShowRequest = operations['auth/session/show']['requestBody']['content']['application/json'];
+type AuthSessionShowRequest = operations['auth___session___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AuthSessionShowResponse = operations['auth/session/show']['responses']['200']['content']['application/json'];
+type AuthSessionShowResponse = operations['auth___session___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type AuthSessionUserkeyRequest = operations['auth/session/userkey']['requestBody']['content']['application/json'];
+type AuthSessionUserkeyRequest = operations['auth___session___userkey']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type AuthSessionUserkeyResponse = operations['auth/session/userkey']['responses']['200']['content']['application/json'];
+type AuthSessionUserkeyResponse = operations['auth___session___userkey']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type Blocking = components['schemas']['Blocking'];
 
 // @public (undocumented)
-type BlockingCreateRequest = operations['blocking/create']['requestBody']['content']['application/json'];
+type BlockingCreateRequest = operations['blocking___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type BlockingCreateResponse = operations['blocking/create']['responses']['200']['content']['application/json'];
+type BlockingCreateResponse = operations['blocking___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type BlockingDeleteRequest = operations['blocking/delete']['requestBody']['content']['application/json'];
+type BlockingDeleteRequest = operations['blocking___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type BlockingDeleteResponse = operations['blocking/delete']['responses']['200']['content']['application/json'];
+type BlockingDeleteResponse = operations['blocking___delete']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type BlockingListRequest = operations['blocking/list']['requestBody']['content']['application/json'];
+type BlockingListRequest = operations['blocking___list']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type BlockingListResponse = operations['blocking/list']['responses']['200']['content']['application/json'];
+type BlockingListResponse = operations['blocking___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type BubbleGameRankingRequest = operations['bubble-game/ranking']['requestBody']['content']['application/json'];
+type BubbleGameRankingRequest = operations['bubble-game___ranking']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type BubbleGameRankingResponse = operations['bubble-game/ranking']['responses']['200']['content']['application/json'];
+type BubbleGameRankingResponse = operations['bubble-game___ranking']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type BubbleGameRegisterRequest = operations['bubble-game/register']['requestBody']['content']['application/json'];
+type BubbleGameRegisterRequest = operations['bubble-game___register']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
 type Channel = components['schemas']['Channel'];
@@ -732,184 +732,184 @@ export type Channels = {
 };
 
 // @public (undocumented)
-type ChannelsCreateRequest = operations['channels/create']['requestBody']['content']['application/json'];
+type ChannelsCreateRequest = operations['channels___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsCreateResponse = operations['channels/create']['responses']['200']['content']['application/json'];
+type ChannelsCreateResponse = operations['channels___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsFavoriteRequest = operations['channels/favorite']['requestBody']['content']['application/json'];
+type ChannelsFavoriteRequest = operations['channels___favorite']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsFeaturedResponse = operations['channels/featured']['responses']['200']['content']['application/json'];
+type ChannelsFeaturedResponse = operations['channels___featured']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsFollowedRequest = operations['channels/followed']['requestBody']['content']['application/json'];
+type ChannelsFollowedRequest = operations['channels___followed']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsFollowedResponse = operations['channels/followed']['responses']['200']['content']['application/json'];
+type ChannelsFollowedResponse = operations['channels___followed']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsFollowRequest = operations['channels/follow']['requestBody']['content']['application/json'];
+type ChannelsFollowRequest = operations['channels___follow']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsMyFavoritesResponse = operations['channels/my-favorites']['responses']['200']['content']['application/json'];
+type ChannelsMyFavoritesResponse = operations['channels___my-favorites']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsOwnedRequest = operations['channels/owned']['requestBody']['content']['application/json'];
+type ChannelsOwnedRequest = operations['channels___owned']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsOwnedResponse = operations['channels/owned']['responses']['200']['content']['application/json'];
+type ChannelsOwnedResponse = operations['channels___owned']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsSearchRequest = operations['channels/search']['requestBody']['content']['application/json'];
+type ChannelsSearchRequest = operations['channels___search']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsSearchResponse = operations['channels/search']['responses']['200']['content']['application/json'];
+type ChannelsSearchResponse = operations['channels___search']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsShowRequest = operations['channels/show']['requestBody']['content']['application/json'];
+type ChannelsShowRequest = operations['channels___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsShowResponse = operations['channels/show']['responses']['200']['content']['application/json'];
+type ChannelsShowResponse = operations['channels___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsTimelineRequest = operations['channels/timeline']['requestBody']['content']['application/json'];
+type ChannelsTimelineRequest = operations['channels___timeline']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsTimelineResponse = operations['channels/timeline']['responses']['200']['content']['application/json'];
+type ChannelsTimelineResponse = operations['channels___timeline']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsUnfavoriteRequest = operations['channels/unfavorite']['requestBody']['content']['application/json'];
+type ChannelsUnfavoriteRequest = operations['channels___unfavorite']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsUnfollowRequest = operations['channels/unfollow']['requestBody']['content']['application/json'];
+type ChannelsUnfollowRequest = operations['channels___unfollow']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsUpdateRequest = operations['channels/update']['requestBody']['content']['application/json'];
+type ChannelsUpdateRequest = operations['channels___update']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChannelsUpdateResponse = operations['channels/update']['responses']['200']['content']['application/json'];
+type ChannelsUpdateResponse = operations['channels___update']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsActiveUsersRequest = operations['charts/active-users']['requestBody']['content']['application/json'];
+type ChartsActiveUsersRequest = operations['charts___active-users']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsActiveUsersResponse = operations['charts/active-users']['responses']['200']['content']['application/json'];
+type ChartsActiveUsersResponse = operations['charts___active-users']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsApRequestRequest = operations['charts/ap-request']['requestBody']['content']['application/json'];
+type ChartsApRequestRequest = operations['charts___ap-request']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsApRequestResponse = operations['charts/ap-request']['responses']['200']['content']['application/json'];
+type ChartsApRequestResponse = operations['charts___ap-request']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsDriveRequest = operations['charts/drive']['requestBody']['content']['application/json'];
+type ChartsDriveRequest = operations['charts___drive']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsDriveResponse = operations['charts/drive']['responses']['200']['content']['application/json'];
+type ChartsDriveResponse = operations['charts___drive']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsFederationRequest = operations['charts/federation']['requestBody']['content']['application/json'];
+type ChartsFederationRequest = operations['charts___federation']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsFederationResponse = operations['charts/federation']['responses']['200']['content']['application/json'];
+type ChartsFederationResponse = operations['charts___federation']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsInstanceRequest = operations['charts/instance']['requestBody']['content']['application/json'];
+type ChartsInstanceRequest = operations['charts___instance']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsInstanceResponse = operations['charts/instance']['responses']['200']['content']['application/json'];
+type ChartsInstanceResponse = operations['charts___instance']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsNotesRequest = operations['charts/notes']['requestBody']['content']['application/json'];
+type ChartsNotesRequest = operations['charts___notes']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsNotesResponse = operations['charts/notes']['responses']['200']['content']['application/json'];
+type ChartsNotesResponse = operations['charts___notes']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsUserDriveRequest = operations['charts/user/drive']['requestBody']['content']['application/json'];
+type ChartsUserDriveRequest = operations['charts___user___drive']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsUserDriveResponse = operations['charts/user/drive']['responses']['200']['content']['application/json'];
+type ChartsUserDriveResponse = operations['charts___user___drive']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsUserFollowingRequest = operations['charts/user/following']['requestBody']['content']['application/json'];
+type ChartsUserFollowingRequest = operations['charts___user___following']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsUserFollowingResponse = operations['charts/user/following']['responses']['200']['content']['application/json'];
+type ChartsUserFollowingResponse = operations['charts___user___following']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsUserNotesRequest = operations['charts/user/notes']['requestBody']['content']['application/json'];
+type ChartsUserNotesRequest = operations['charts___user___notes']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsUserNotesResponse = operations['charts/user/notes']['responses']['200']['content']['application/json'];
+type ChartsUserNotesResponse = operations['charts___user___notes']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsUserPvRequest = operations['charts/user/pv']['requestBody']['content']['application/json'];
+type ChartsUserPvRequest = operations['charts___user___pv']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsUserPvResponse = operations['charts/user/pv']['responses']['200']['content']['application/json'];
+type ChartsUserPvResponse = operations['charts___user___pv']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsUserReactionsRequest = operations['charts/user/reactions']['requestBody']['content']['application/json'];
+type ChartsUserReactionsRequest = operations['charts___user___reactions']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsUserReactionsResponse = operations['charts/user/reactions']['responses']['200']['content']['application/json'];
+type ChartsUserReactionsResponse = operations['charts___user___reactions']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsUsersRequest = operations['charts/users']['requestBody']['content']['application/json'];
+type ChartsUsersRequest = operations['charts___users']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ChartsUsersResponse = operations['charts/users']['responses']['200']['content']['application/json'];
+type ChartsUsersResponse = operations['charts___users']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type Clip = components['schemas']['Clip'];
 
 // @public (undocumented)
-type ClipsAddNoteRequest = operations['clips/add-note']['requestBody']['content']['application/json'];
+type ClipsAddNoteRequest = operations['clips___add-note']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ClipsCreateRequest = operations['clips/create']['requestBody']['content']['application/json'];
+type ClipsCreateRequest = operations['clips___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ClipsCreateResponse = operations['clips/create']['responses']['200']['content']['application/json'];
+type ClipsCreateResponse = operations['clips___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ClipsDeleteRequest = operations['clips/delete']['requestBody']['content']['application/json'];
+type ClipsDeleteRequest = operations['clips___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ClipsFavoriteRequest = operations['clips/favorite']['requestBody']['content']['application/json'];
+type ClipsFavoriteRequest = operations['clips___favorite']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ClipsListResponse = operations['clips/list']['responses']['200']['content']['application/json'];
+type ClipsListResponse = operations['clips___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ClipsMyFavoritesResponse = operations['clips/my-favorites']['responses']['200']['content']['application/json'];
+type ClipsMyFavoritesResponse = operations['clips___my-favorites']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ClipsNotesRequest = operations['clips/notes']['requestBody']['content']['application/json'];
+type ClipsNotesRequest = operations['clips___notes']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ClipsNotesResponse = operations['clips/notes']['responses']['200']['content']['application/json'];
+type ClipsNotesResponse = operations['clips___notes']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ClipsRemoveNoteRequest = operations['clips/remove-note']['requestBody']['content']['application/json'];
+type ClipsRemoveNoteRequest = operations['clips___remove-note']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ClipsShowRequest = operations['clips/show']['requestBody']['content']['application/json'];
+type ClipsShowRequest = operations['clips___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ClipsShowResponse = operations['clips/show']['responses']['200']['content']['application/json'];
+type ClipsShowResponse = operations['clips___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ClipsUnfavoriteRequest = operations['clips/unfavorite']['requestBody']['content']['application/json'];
+type ClipsUnfavoriteRequest = operations['clips___unfavorite']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ClipsUpdateRequest = operations['clips/update']['requestBody']['content']['application/json'];
+type ClipsUpdateRequest = operations['clips___update']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ClipsUpdateResponse = operations['clips/update']['responses']['200']['content']['application/json'];
+type ClipsUpdateResponse = operations['clips___update']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type DateString = string;
@@ -918,109 +918,109 @@ type DateString = string;
 type DriveFile = components['schemas']['DriveFile'];
 
 // @public (undocumented)
-type DriveFilesAttachedNotesRequest = operations['drive/files/attached-notes']['requestBody']['content']['application/json'];
+type DriveFilesAttachedNotesRequest = operations['drive___files___attached-notes']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFilesAttachedNotesResponse = operations['drive/files/attached-notes']['responses']['200']['content']['application/json'];
+type DriveFilesAttachedNotesResponse = operations['drive___files___attached-notes']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFilesCheckExistenceRequest = operations['drive/files/check-existence']['requestBody']['content']['application/json'];
+type DriveFilesCheckExistenceRequest = operations['drive___files___check-existence']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFilesCheckExistenceResponse = operations['drive/files/check-existence']['responses']['200']['content']['application/json'];
+type DriveFilesCheckExistenceResponse = operations['drive___files___check-existence']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFilesCreateRequest = operations['drive/files/create']['requestBody']['content']['multipart/form-data'];
+type DriveFilesCreateRequest = operations['drive___files___create']['requestBody']['content']['multipart/form-data'];
 
 // @public (undocumented)
-type DriveFilesCreateResponse = operations['drive/files/create']['responses']['200']['content']['application/json'];
+type DriveFilesCreateResponse = operations['drive___files___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFilesDeleteRequest = operations['drive/files/delete']['requestBody']['content']['application/json'];
+type DriveFilesDeleteRequest = operations['drive___files___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFilesFindByHashRequest = operations['drive/files/find-by-hash']['requestBody']['content']['application/json'];
+type DriveFilesFindByHashRequest = operations['drive___files___find-by-hash']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFilesFindByHashResponse = operations['drive/files/find-by-hash']['responses']['200']['content']['application/json'];
+type DriveFilesFindByHashResponse = operations['drive___files___find-by-hash']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFilesFindRequest = operations['drive/files/find']['requestBody']['content']['application/json'];
+type DriveFilesFindRequest = operations['drive___files___find']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFilesFindResponse = operations['drive/files/find']['responses']['200']['content']['application/json'];
+type DriveFilesFindResponse = operations['drive___files___find']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFilesRequest = operations['drive/files']['requestBody']['content']['application/json'];
+type DriveFilesRequest = operations['drive___files']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFilesResponse = operations['drive/files']['responses']['200']['content']['application/json'];
+type DriveFilesResponse = operations['drive___files']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFilesShowRequest = operations['drive/files/show']['requestBody']['content']['application/json'];
+type DriveFilesShowRequest = operations['drive___files___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFilesShowResponse = operations['drive/files/show']['responses']['200']['content']['application/json'];
+type DriveFilesShowResponse = operations['drive___files___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFilesUpdateRequest = operations['drive/files/update']['requestBody']['content']['application/json'];
+type DriveFilesUpdateRequest = operations['drive___files___update']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFilesUpdateResponse = operations['drive/files/update']['responses']['200']['content']['application/json'];
+type DriveFilesUpdateResponse = operations['drive___files___update']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFilesUploadFromUrlRequest = operations['drive/files/upload-from-url']['requestBody']['content']['application/json'];
+type DriveFilesUploadFromUrlRequest = operations['drive___files___upload-from-url']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
 type DriveFolder = components['schemas']['DriveFolder'];
 
 // @public (undocumented)
-type DriveFoldersCreateRequest = operations['drive/folders/create']['requestBody']['content']['application/json'];
+type DriveFoldersCreateRequest = operations['drive___folders___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFoldersCreateResponse = operations['drive/folders/create']['responses']['200']['content']['application/json'];
+type DriveFoldersCreateResponse = operations['drive___folders___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFoldersDeleteRequest = operations['drive/folders/delete']['requestBody']['content']['application/json'];
+type DriveFoldersDeleteRequest = operations['drive___folders___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFoldersFindRequest = operations['drive/folders/find']['requestBody']['content']['application/json'];
+type DriveFoldersFindRequest = operations['drive___folders___find']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFoldersFindResponse = operations['drive/folders/find']['responses']['200']['content']['application/json'];
+type DriveFoldersFindResponse = operations['drive___folders___find']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFoldersRequest = operations['drive/folders']['requestBody']['content']['application/json'];
+type DriveFoldersRequest = operations['drive___folders']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFoldersResponse = operations['drive/folders']['responses']['200']['content']['application/json'];
+type DriveFoldersResponse = operations['drive___folders']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFoldersShowRequest = operations['drive/folders/show']['requestBody']['content']['application/json'];
+type DriveFoldersShowRequest = operations['drive___folders___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFoldersShowResponse = operations['drive/folders/show']['responses']['200']['content']['application/json'];
+type DriveFoldersShowResponse = operations['drive___folders___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFoldersUpdateRequest = operations['drive/folders/update']['requestBody']['content']['application/json'];
+type DriveFoldersUpdateRequest = operations['drive___folders___update']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type DriveFoldersUpdateResponse = operations['drive/folders/update']['responses']['200']['content']['application/json'];
+type DriveFoldersUpdateResponse = operations['drive___folders___update']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type DriveResponse = operations['drive']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type DriveStreamRequest = operations['drive/stream']['requestBody']['content']['application/json'];
+type DriveStreamRequest = operations['drive___stream']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type DriveStreamResponse = operations['drive/stream']['responses']['200']['content']['application/json'];
+type DriveStreamResponse = operations['drive___stream']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type EmailAddressAvailableRequest = operations['email-address/available']['requestBody']['content']['application/json'];
+type EmailAddressAvailableRequest = operations['email-address___available']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type EmailAddressAvailableResponse = operations['email-address/available']['responses']['200']['content']['application/json'];
+type EmailAddressAvailableResponse = operations['email-address___available']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type EmojiAdded = {
@@ -1733,46 +1733,46 @@ export { entities }
 type Error_2 = components['schemas']['Error'];
 
 // @public (undocumented)
-type FederationFollowersRequest = operations['federation/followers']['requestBody']['content']['application/json'];
+type FederationFollowersRequest = operations['federation___followers']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FederationFollowersResponse = operations['federation/followers']['responses']['200']['content']['application/json'];
+type FederationFollowersResponse = operations['federation___followers']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type FederationFollowingRequest = operations['federation/following']['requestBody']['content']['application/json'];
+type FederationFollowingRequest = operations['federation___following']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FederationFollowingResponse = operations['federation/following']['responses']['200']['content']['application/json'];
+type FederationFollowingResponse = operations['federation___following']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type FederationInstance = components['schemas']['FederationInstance'];
 
 // @public (undocumented)
-type FederationInstancesRequest = operations['federation/instances']['requestBody']['content']['application/json'];
+type FederationInstancesRequest = operations['federation___instances']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FederationInstancesResponse = operations['federation/instances']['responses']['200']['content']['application/json'];
+type FederationInstancesResponse = operations['federation___instances']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type FederationShowInstanceRequest = operations['federation/show-instance']['requestBody']['content']['application/json'];
+type FederationShowInstanceRequest = operations['federation___show-instance']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FederationShowInstanceResponse = operations['federation/show-instance']['responses']['200']['content']['application/json'];
+type FederationShowInstanceResponse = operations['federation___show-instance']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type FederationStatsRequest = operations['federation/stats']['requestBody']['content']['application/json'];
+type FederationStatsRequest = operations['federation___stats']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FederationStatsResponse = operations['federation/stats']['responses']['200']['content']['application/json'];
+type FederationStatsResponse = operations['federation___stats']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type FederationUpdateRemoteUserRequest = operations['federation/update-remote-user']['requestBody']['content']['application/json'];
+type FederationUpdateRemoteUserRequest = operations['federation___update-remote-user']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FederationUsersRequest = operations['federation/users']['requestBody']['content']['application/json'];
+type FederationUsersRequest = operations['federation___users']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FederationUsersResponse = operations['federation/users']['responses']['200']['content']['application/json'];
+type FederationUsersResponse = operations['federation___users']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type FetchExternalResourcesRequest = operations['fetch-external-resources']['requestBody']['content']['application/json'];
@@ -1804,43 +1804,43 @@ type FetchRssResponse = operations['fetch-rss']['responses']['200']['content']['
 type Flash = components['schemas']['Flash'];
 
 // @public (undocumented)
-type FlashCreateRequest = operations['flash/create']['requestBody']['content']['application/json'];
+type FlashCreateRequest = operations['flash___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FlashCreateResponse = operations['flash/create']['responses']['200']['content']['application/json'];
+type FlashCreateResponse = operations['flash___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type FlashDeleteRequest = operations['flash/delete']['requestBody']['content']['application/json'];
+type FlashDeleteRequest = operations['flash___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FlashFeaturedResponse = operations['flash/featured']['responses']['200']['content']['application/json'];
+type FlashFeaturedResponse = operations['flash___featured']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type FlashLikeRequest = operations['flash/like']['requestBody']['content']['application/json'];
+type FlashLikeRequest = operations['flash___like']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FlashMyLikesRequest = operations['flash/my-likes']['requestBody']['content']['application/json'];
+type FlashMyLikesRequest = operations['flash___my-likes']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FlashMyLikesResponse = operations['flash/my-likes']['responses']['200']['content']['application/json'];
+type FlashMyLikesResponse = operations['flash___my-likes']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type FlashMyRequest = operations['flash/my']['requestBody']['content']['application/json'];
+type FlashMyRequest = operations['flash___my']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FlashMyResponse = operations['flash/my']['responses']['200']['content']['application/json'];
+type FlashMyResponse = operations['flash___my']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type FlashShowRequest = operations['flash/show']['requestBody']['content']['application/json'];
+type FlashShowRequest = operations['flash___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FlashShowResponse = operations['flash/show']['responses']['200']['content']['application/json'];
+type FlashShowResponse = operations['flash___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type FlashUnlikeRequest = operations['flash/unlike']['requestBody']['content']['application/json'];
+type FlashUnlikeRequest = operations['flash___unlike']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FlashUpdateRequest = operations['flash/update']['requestBody']['content']['application/json'];
+type FlashUpdateRequest = operations['flash___update']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
 export const followersVisibilities: readonly ["public", "followers", "private"];
@@ -1849,97 +1849,97 @@ export const followersVisibilities: readonly ["public", "followers", "private"];
 type Following = components['schemas']['Following'];
 
 // @public (undocumented)
-type FollowingCreateRequest = operations['following/create']['requestBody']['content']['application/json'];
+type FollowingCreateRequest = operations['following___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FollowingCreateResponse = operations['following/create']['responses']['200']['content']['application/json'];
+type FollowingCreateResponse = operations['following___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type FollowingDeleteRequest = operations['following/delete']['requestBody']['content']['application/json'];
+type FollowingDeleteRequest = operations['following___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FollowingDeleteResponse = operations['following/delete']['responses']['200']['content']['application/json'];
+type FollowingDeleteResponse = operations['following___delete']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type FollowingInvalidateRequest = operations['following/invalidate']['requestBody']['content']['application/json'];
+type FollowingInvalidateRequest = operations['following___invalidate']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FollowingInvalidateResponse = operations['following/invalidate']['responses']['200']['content']['application/json'];
+type FollowingInvalidateResponse = operations['following___invalidate']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type FollowingRequestsAcceptRequest = operations['following/requests/accept']['requestBody']['content']['application/json'];
+type FollowingRequestsAcceptRequest = operations['following___requests___accept']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FollowingRequestsCancelRequest = operations['following/requests/cancel']['requestBody']['content']['application/json'];
+type FollowingRequestsCancelRequest = operations['following___requests___cancel']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FollowingRequestsCancelResponse = operations['following/requests/cancel']['responses']['200']['content']['application/json'];
+type FollowingRequestsCancelResponse = operations['following___requests___cancel']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type FollowingRequestsListRequest = operations['following/requests/list']['requestBody']['content']['application/json'];
+type FollowingRequestsListRequest = operations['following___requests___list']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FollowingRequestsListResponse = operations['following/requests/list']['responses']['200']['content']['application/json'];
+type FollowingRequestsListResponse = operations['following___requests___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type FollowingRequestsRejectRequest = operations['following/requests/reject']['requestBody']['content']['application/json'];
+type FollowingRequestsRejectRequest = operations['following___requests___reject']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FollowingUpdateAllRequest = operations['following/update-all']['requestBody']['content']['application/json'];
+type FollowingUpdateAllRequest = operations['following___update-all']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FollowingUpdateRequest = operations['following/update']['requestBody']['content']['application/json'];
+type FollowingUpdateRequest = operations['following___update']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type FollowingUpdateResponse = operations['following/update']['responses']['200']['content']['application/json'];
+type FollowingUpdateResponse = operations['following___update']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 export const followingVisibilities: readonly ["public", "followers", "private"];
 
 // @public (undocumented)
-type GalleryFeaturedRequest = operations['gallery/featured']['requestBody']['content']['application/json'];
+type GalleryFeaturedRequest = operations['gallery___featured']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type GalleryFeaturedResponse = operations['gallery/featured']['responses']['200']['content']['application/json'];
+type GalleryFeaturedResponse = operations['gallery___featured']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type GalleryPopularResponse = operations['gallery/popular']['responses']['200']['content']['application/json'];
+type GalleryPopularResponse = operations['gallery___popular']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type GalleryPost = components['schemas']['GalleryPost'];
 
 // @public (undocumented)
-type GalleryPostsCreateRequest = operations['gallery/posts/create']['requestBody']['content']['application/json'];
+type GalleryPostsCreateRequest = operations['gallery___posts___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type GalleryPostsCreateResponse = operations['gallery/posts/create']['responses']['200']['content']['application/json'];
+type GalleryPostsCreateResponse = operations['gallery___posts___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type GalleryPostsDeleteRequest = operations['gallery/posts/delete']['requestBody']['content']['application/json'];
+type GalleryPostsDeleteRequest = operations['gallery___posts___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type GalleryPostsLikeRequest = operations['gallery/posts/like']['requestBody']['content']['application/json'];
+type GalleryPostsLikeRequest = operations['gallery___posts___like']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type GalleryPostsRequest = operations['gallery/posts']['requestBody']['content']['application/json'];
+type GalleryPostsRequest = operations['gallery___posts']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type GalleryPostsResponse = operations['gallery/posts']['responses']['200']['content']['application/json'];
+type GalleryPostsResponse = operations['gallery___posts']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type GalleryPostsShowRequest = operations['gallery/posts/show']['requestBody']['content']['application/json'];
+type GalleryPostsShowRequest = operations['gallery___posts___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type GalleryPostsShowResponse = operations['gallery/posts/show']['responses']['200']['content']['application/json'];
+type GalleryPostsShowResponse = operations['gallery___posts___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type GalleryPostsUnlikeRequest = operations['gallery/posts/unlike']['requestBody']['content']['application/json'];
+type GalleryPostsUnlikeRequest = operations['gallery___posts___unlike']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type GalleryPostsUpdateRequest = operations['gallery/posts/update']['requestBody']['content']['application/json'];
+type GalleryPostsUpdateRequest = operations['gallery___posts___update']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type GalleryPostsUpdateResponse = operations['gallery/posts/update']['responses']['200']['content']['application/json'];
+type GalleryPostsUpdateResponse = operations['gallery___posts___update']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type GetAvatarDecorationsResponse = operations['get-avatar-decorations']['responses']['200']['content']['application/json'];
@@ -1951,280 +1951,280 @@ type GetOnlineUsersCountResponse = operations['get-online-users-count']['respons
 type Hashtag = components['schemas']['Hashtag'];
 
 // @public (undocumented)
-type HashtagsListRequest = operations['hashtags/list']['requestBody']['content']['application/json'];
+type HashtagsListRequest = operations['hashtags___list']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type HashtagsListResponse = operations['hashtags/list']['responses']['200']['content']['application/json'];
+type HashtagsListResponse = operations['hashtags___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type HashtagsSearchRequest = operations['hashtags/search']['requestBody']['content']['application/json'];
+type HashtagsSearchRequest = operations['hashtags___search']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type HashtagsSearchResponse = operations['hashtags/search']['responses']['200']['content']['application/json'];
+type HashtagsSearchResponse = operations['hashtags___search']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type HashtagsShowRequest = operations['hashtags/show']['requestBody']['content']['application/json'];
+type HashtagsShowRequest = operations['hashtags___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type HashtagsShowResponse = operations['hashtags/show']['responses']['200']['content']['application/json'];
+type HashtagsShowResponse = operations['hashtags___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type HashtagsTrendResponse = operations['hashtags/trend']['responses']['200']['content']['application/json'];
+type HashtagsTrendResponse = operations['hashtags___trend']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type HashtagsUsersRequest = operations['hashtags/users']['requestBody']['content']['application/json'];
+type HashtagsUsersRequest = operations['hashtags___users']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type HashtagsUsersResponse = operations['hashtags/users']['responses']['200']['content']['application/json'];
+type HashtagsUsersResponse = operations['hashtags___users']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type I2faDoneRequest = operations['i/2fa/done']['requestBody']['content']['application/json'];
+type I2faDoneRequest = operations['i___2fa___done']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type I2faDoneResponse = operations['i/2fa/done']['responses']['200']['content']['application/json'];
+type I2faDoneResponse = operations['i___2fa___done']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type I2faKeyDoneRequest = operations['i/2fa/key-done']['requestBody']['content']['application/json'];
+type I2faKeyDoneRequest = operations['i___2fa___key-done']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type I2faKeyDoneResponse = operations['i/2fa/key-done']['responses']['200']['content']['application/json'];
+type I2faKeyDoneResponse = operations['i___2fa___key-done']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type I2faPasswordLessRequest = operations['i/2fa/password-less']['requestBody']['content']['application/json'];
+type I2faPasswordLessRequest = operations['i___2fa___password-less']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type I2faRegisterKeyRequest = operations['i/2fa/register-key']['requestBody']['content']['application/json'];
+type I2faRegisterKeyRequest = operations['i___2fa___register-key']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type I2faRegisterKeyResponse = operations['i/2fa/register-key']['responses']['200']['content']['application/json'];
+type I2faRegisterKeyResponse = operations['i___2fa___register-key']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type I2faRegisterRequest = operations['i/2fa/register']['requestBody']['content']['application/json'];
+type I2faRegisterRequest = operations['i___2fa___register']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type I2faRegisterResponse = operations['i/2fa/register']['responses']['200']['content']['application/json'];
+type I2faRegisterResponse = operations['i___2fa___register']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type I2faRemoveKeyRequest = operations['i/2fa/remove-key']['requestBody']['content']['application/json'];
+type I2faRemoveKeyRequest = operations['i___2fa___remove-key']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type I2faUnregisterRequest = operations['i/2fa/unregister']['requestBody']['content']['application/json'];
+type I2faUnregisterRequest = operations['i___2fa___unregister']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type I2faUpdateKeyRequest = operations['i/2fa/update-key']['requestBody']['content']['application/json'];
+type I2faUpdateKeyRequest = operations['i___2fa___update-key']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IAppsRequest = operations['i/apps']['requestBody']['content']['application/json'];
+type IAppsRequest = operations['i___apps']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IAppsResponse = operations['i/apps']['responses']['200']['content']['application/json'];
+type IAppsResponse = operations['i___apps']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IAuthorizedAppsRequest = operations['i/authorized-apps']['requestBody']['content']['application/json'];
+type IAuthorizedAppsRequest = operations['i___authorized-apps']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IAuthorizedAppsResponse = operations['i/authorized-apps']['responses']['200']['content']['application/json'];
+type IAuthorizedAppsResponse = operations['i___authorized-apps']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IChangePasswordRequest = operations['i/change-password']['requestBody']['content']['application/json'];
+type IChangePasswordRequest = operations['i___change-password']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IClaimAchievementRequest = operations['i/claim-achievement']['requestBody']['content']['application/json'];
+type IClaimAchievementRequest = operations['i___claim-achievement']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
 type ID = string;
 
 // @public (undocumented)
-type IDeleteAccountRequest = operations['i/delete-account']['requestBody']['content']['application/json'];
+type IDeleteAccountRequest = operations['i___delete-account']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IExportFollowingRequest = operations['i/export-following']['requestBody']['content']['application/json'];
+type IExportFollowingRequest = operations['i___export-following']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IFavoritesRequest = operations['i/favorites']['requestBody']['content']['application/json'];
+type IFavoritesRequest = operations['i___favorites']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IFavoritesResponse = operations['i/favorites']['responses']['200']['content']['application/json'];
+type IFavoritesResponse = operations['i___favorites']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IGalleryLikesRequest = operations['i/gallery/likes']['requestBody']['content']['application/json'];
+type IGalleryLikesRequest = operations['i___gallery___likes']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IGalleryLikesResponse = operations['i/gallery/likes']['responses']['200']['content']['application/json'];
+type IGalleryLikesResponse = operations['i___gallery___likes']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IGalleryPostsRequest = operations['i/gallery/posts']['requestBody']['content']['application/json'];
+type IGalleryPostsRequest = operations['i___gallery___posts']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IGalleryPostsResponse = operations['i/gallery/posts']['responses']['200']['content']['application/json'];
+type IGalleryPostsResponse = operations['i___gallery___posts']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IImportAntennasRequest = operations['i/import-antennas']['requestBody']['content']['application/json'];
+type IImportAntennasRequest = operations['i___import-antennas']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IImportBlockingRequest = operations['i/import-blocking']['requestBody']['content']['application/json'];
+type IImportBlockingRequest = operations['i___import-blocking']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IImportFollowingRequest = operations['i/import-following']['requestBody']['content']['application/json'];
+type IImportFollowingRequest = operations['i___import-following']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IImportMutingRequest = operations['i/import-muting']['requestBody']['content']['application/json'];
+type IImportMutingRequest = operations['i___import-muting']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IImportUserListsRequest = operations['i/import-user-lists']['requestBody']['content']['application/json'];
+type IImportUserListsRequest = operations['i___import-user-lists']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IMoveRequest = operations['i/move']['requestBody']['content']['application/json'];
+type IMoveRequest = operations['i___move']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IMoveResponse = operations['i/move']['responses']['200']['content']['application/json'];
+type IMoveResponse = operations['i___move']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type INotificationsGroupedRequest = operations['i/notifications-grouped']['requestBody']['content']['application/json'];
+type INotificationsGroupedRequest = operations['i___notifications-grouped']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type INotificationsGroupedResponse = operations['i/notifications-grouped']['responses']['200']['content']['application/json'];
+type INotificationsGroupedResponse = operations['i___notifications-grouped']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type INotificationsRequest = operations['i/notifications']['requestBody']['content']['application/json'];
+type INotificationsRequest = operations['i___notifications']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type INotificationsResponse = operations['i/notifications']['responses']['200']['content']['application/json'];
+type INotificationsResponse = operations['i___notifications']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type InviteCode = components['schemas']['InviteCode'];
 
 // @public (undocumented)
-type InviteCreateResponse = operations['invite/create']['responses']['200']['content']['application/json'];
+type InviteCreateResponse = operations['invite___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type InviteDeleteRequest = operations['invite/delete']['requestBody']['content']['application/json'];
+type InviteDeleteRequest = operations['invite___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type InviteLimitResponse = operations['invite/limit']['responses']['200']['content']['application/json'];
+type InviteLimitResponse = operations['invite___limit']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type InviteListRequest = operations['invite/list']['requestBody']['content']['application/json'];
+type InviteListRequest = operations['invite___list']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type InviteListResponse = operations['invite/list']['responses']['200']['content']['application/json'];
+type InviteListResponse = operations['invite___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IPageLikesRequest = operations['i/page-likes']['requestBody']['content']['application/json'];
+type IPageLikesRequest = operations['i___page-likes']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IPageLikesResponse = operations['i/page-likes']['responses']['200']['content']['application/json'];
+type IPageLikesResponse = operations['i___page-likes']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IPagesRequest = operations['i/pages']['requestBody']['content']['application/json'];
+type IPagesRequest = operations['i___pages']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IPagesResponse = operations['i/pages']['responses']['200']['content']['application/json'];
+type IPagesResponse = operations['i___pages']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IPinRequest = operations['i/pin']['requestBody']['content']['application/json'];
+type IPinRequest = operations['i___pin']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IPinResponse = operations['i/pin']['responses']['200']['content']['application/json'];
+type IPinResponse = operations['i___pin']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IReadAnnouncementRequest = operations['i/read-announcement']['requestBody']['content']['application/json'];
+type IReadAnnouncementRequest = operations['i___read-announcement']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IRegenerateTokenRequest = operations['i/regenerate-token']['requestBody']['content']['application/json'];
+type IRegenerateTokenRequest = operations['i___regenerate-token']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IRegistryGetAllRequest = operations['i/registry/get-all']['requestBody']['content']['application/json'];
+type IRegistryGetAllRequest = operations['i___registry___get-all']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IRegistryGetAllResponse = operations['i/registry/get-all']['responses']['200']['content']['application/json'];
+type IRegistryGetAllResponse = operations['i___registry___get-all']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IRegistryGetDetailRequest = operations['i/registry/get-detail']['requestBody']['content']['application/json'];
+type IRegistryGetDetailRequest = operations['i___registry___get-detail']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IRegistryGetDetailResponse = operations['i/registry/get-detail']['responses']['200']['content']['application/json'];
+type IRegistryGetDetailResponse = operations['i___registry___get-detail']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IRegistryGetRequest = operations['i/registry/get']['requestBody']['content']['application/json'];
+type IRegistryGetRequest = operations['i___registry___get']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IRegistryGetResponse = operations['i/registry/get']['responses']['200']['content']['application/json'];
+type IRegistryGetResponse = operations['i___registry___get']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IRegistryKeysRequest = operations['i/registry/keys']['requestBody']['content']['application/json'];
+type IRegistryKeysRequest = operations['i___registry___keys']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IRegistryKeysResponse = operations['i/registry/keys']['responses']['200']['content']['application/json'];
+type IRegistryKeysResponse = operations['i___registry___keys']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IRegistryKeysWithTypeRequest = operations['i/registry/keys-with-type']['requestBody']['content']['application/json'];
+type IRegistryKeysWithTypeRequest = operations['i___registry___keys-with-type']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IRegistryKeysWithTypeResponse = operations['i/registry/keys-with-type']['responses']['200']['content']['application/json'];
+type IRegistryKeysWithTypeResponse = operations['i___registry___keys-with-type']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IRegistryRemoveRequest = operations['i/registry/remove']['requestBody']['content']['application/json'];
+type IRegistryRemoveRequest = operations['i___registry___remove']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IRegistryScopesWithDomainResponse = operations['i/registry/scopes-with-domain']['responses']['200']['content']['application/json'];
+type IRegistryScopesWithDomainResponse = operations['i___registry___scopes-with-domain']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IRegistrySetRequest = operations['i/registry/set']['requestBody']['content']['application/json'];
+type IRegistrySetRequest = operations['i___registry___set']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
 type IResponse = operations['i']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IRevokeTokenRequest = operations['i/revoke-token']['requestBody']['content']['application/json'];
+type IRevokeTokenRequest = operations['i___revoke-token']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
 function isAPIError(reason: Record<PropertyKey, unknown>): reason is APIError;
 
 // @public (undocumented)
-type ISigninHistoryRequest = operations['i/signin-history']['requestBody']['content']['application/json'];
+type ISigninHistoryRequest = operations['i___signin-history']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ISigninHistoryResponse = operations['i/signin-history']['responses']['200']['content']['application/json'];
+type ISigninHistoryResponse = operations['i___signin-history']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IUnpinRequest = operations['i/unpin']['requestBody']['content']['application/json'];
+type IUnpinRequest = operations['i___unpin']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IUnpinResponse = operations['i/unpin']['responses']['200']['content']['application/json'];
+type IUnpinResponse = operations['i___unpin']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IUpdateEmailRequest = operations['i/update-email']['requestBody']['content']['application/json'];
+type IUpdateEmailRequest = operations['i___update-email']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IUpdateEmailResponse = operations['i/update-email']['responses']['200']['content']['application/json'];
+type IUpdateEmailResponse = operations['i___update-email']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IUpdateRequest = operations['i/update']['requestBody']['content']['application/json'];
+type IUpdateRequest = operations['i___update']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IUpdateResponse = operations['i/update']['responses']['200']['content']['application/json'];
+type IUpdateResponse = operations['i___update']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IWebhooksCreateRequest = operations['i/webhooks/create']['requestBody']['content']['application/json'];
+type IWebhooksCreateRequest = operations['i___webhooks___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IWebhooksCreateResponse = operations['i/webhooks/create']['responses']['200']['content']['application/json'];
+type IWebhooksCreateResponse = operations['i___webhooks___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IWebhooksDeleteRequest = operations['i/webhooks/delete']['requestBody']['content']['application/json'];
+type IWebhooksDeleteRequest = operations['i___webhooks___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IWebhooksListResponse = operations['i/webhooks/list']['responses']['200']['content']['application/json'];
+type IWebhooksListResponse = operations['i___webhooks___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IWebhooksShowRequest = operations['i/webhooks/show']['requestBody']['content']['application/json'];
+type IWebhooksShowRequest = operations['i___webhooks___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type IWebhooksShowResponse = operations['i/webhooks/show']['responses']['200']['content']['application/json'];
+type IWebhooksShowResponse = operations['i___webhooks___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type IWebhooksUpdateRequest = operations['i/webhooks/update']['requestBody']['content']['application/json'];
+type IWebhooksUpdateRequest = operations['i___webhooks___update']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
 type MeDetailed = components['schemas']['MeDetailed'];
@@ -2248,10 +2248,10 @@ type MetaRequest = operations['meta']['requestBody']['content']['application/jso
 type MetaResponse = operations['meta']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type MiauthGenTokenRequest = operations['miauth/gen-token']['requestBody']['content']['application/json'];
+type MiauthGenTokenRequest = operations['miauth___gen-token']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type MiauthGenTokenResponse = operations['miauth/gen-token']['responses']['200']['content']['application/json'];
+type MiauthGenTokenResponse = operations['miauth___gen-token']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type ModerationLog = {
@@ -2379,28 +2379,28 @@ type ModerationLog = {
 export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "updateRemoteInstanceNote", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner"];
 
 // @public (undocumented)
-type MuteCreateRequest = operations['mute/create']['requestBody']['content']['application/json'];
+type MuteCreateRequest = operations['mute___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type MuteDeleteRequest = operations['mute/delete']['requestBody']['content']['application/json'];
+type MuteDeleteRequest = operations['mute___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
 export const mutedNoteReasons: readonly ["word", "manual", "spam", "other"];
 
 // @public (undocumented)
-type MuteListRequest = operations['mute/list']['requestBody']['content']['application/json'];
+type MuteListRequest = operations['mute___list']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type MuteListResponse = operations['mute/list']['responses']['200']['content']['application/json'];
+type MuteListResponse = operations['mute___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type Muting = components['schemas']['Muting'];
 
 // @public (undocumented)
-type MyAppsRequest = operations['my/apps']['requestBody']['content']['application/json'];
+type MyAppsRequest = operations['my___apps']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type MyAppsResponse = operations['my/apps']['responses']['200']['content']['application/json'];
+type MyAppsResponse = operations['my___apps']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type Note = components['schemas']['Note'];
@@ -2412,100 +2412,100 @@ type NoteFavorite = components['schemas']['NoteFavorite'];
 type NoteReaction = components['schemas']['NoteReaction'];
 
 // @public (undocumented)
-type NotesChildrenRequest = operations['notes/children']['requestBody']['content']['application/json'];
+type NotesChildrenRequest = operations['notes___children']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesChildrenResponse = operations['notes/children']['responses']['200']['content']['application/json'];
+type NotesChildrenResponse = operations['notes___children']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesClipsRequest = operations['notes/clips']['requestBody']['content']['application/json'];
+type NotesClipsRequest = operations['notes___clips']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesClipsResponse = operations['notes/clips']['responses']['200']['content']['application/json'];
+type NotesClipsResponse = operations['notes___clips']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesConversationRequest = operations['notes/conversation']['requestBody']['content']['application/json'];
+type NotesConversationRequest = operations['notes___conversation']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesConversationResponse = operations['notes/conversation']['responses']['200']['content']['application/json'];
+type NotesConversationResponse = operations['notes___conversation']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesCreateRequest = operations['notes/create']['requestBody']['content']['application/json'];
+type NotesCreateRequest = operations['notes___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesCreateResponse = operations['notes/create']['responses']['200']['content']['application/json'];
+type NotesCreateResponse = operations['notes___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesDeleteRequest = operations['notes/delete']['requestBody']['content']['application/json'];
+type NotesDeleteRequest = operations['notes___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesFavoritesCreateRequest = operations['notes/favorites/create']['requestBody']['content']['application/json'];
+type NotesFavoritesCreateRequest = operations['notes___favorites___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesFavoritesDeleteRequest = operations['notes/favorites/delete']['requestBody']['content']['application/json'];
+type NotesFavoritesDeleteRequest = operations['notes___favorites___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesFeaturedRequest = operations['notes/featured']['requestBody']['content']['application/json'];
+type NotesFeaturedRequest = operations['notes___featured']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesFeaturedResponse = operations['notes/featured']['responses']['200']['content']['application/json'];
+type NotesFeaturedResponse = operations['notes___featured']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesGlobalTimelineRequest = operations['notes/global-timeline']['requestBody']['content']['application/json'];
+type NotesGlobalTimelineRequest = operations['notes___global-timeline']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesGlobalTimelineResponse = operations['notes/global-timeline']['responses']['200']['content']['application/json'];
+type NotesGlobalTimelineResponse = operations['notes___global-timeline']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesHybridTimelineRequest = operations['notes/hybrid-timeline']['requestBody']['content']['application/json'];
+type NotesHybridTimelineRequest = operations['notes___hybrid-timeline']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesHybridTimelineResponse = operations['notes/hybrid-timeline']['responses']['200']['content']['application/json'];
+type NotesHybridTimelineResponse = operations['notes___hybrid-timeline']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesLocalTimelineRequest = operations['notes/local-timeline']['requestBody']['content']['application/json'];
+type NotesLocalTimelineRequest = operations['notes___local-timeline']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesLocalTimelineResponse = operations['notes/local-timeline']['responses']['200']['content']['application/json'];
+type NotesLocalTimelineResponse = operations['notes___local-timeline']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesMentionsRequest = operations['notes/mentions']['requestBody']['content']['application/json'];
+type NotesMentionsRequest = operations['notes___mentions']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesMentionsResponse = operations['notes/mentions']['responses']['200']['content']['application/json'];
+type NotesMentionsResponse = operations['notes___mentions']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesPollsRecommendationRequest = operations['notes/polls/recommendation']['requestBody']['content']['application/json'];
+type NotesPollsRecommendationRequest = operations['notes___polls___recommendation']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesPollsRecommendationResponse = operations['notes/polls/recommendation']['responses']['200']['content']['application/json'];
+type NotesPollsRecommendationResponse = operations['notes___polls___recommendation']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesPollsVoteRequest = operations['notes/polls/vote']['requestBody']['content']['application/json'];
+type NotesPollsVoteRequest = operations['notes___polls___vote']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesReactionsCreateRequest = operations['notes/reactions/create']['requestBody']['content']['application/json'];
+type NotesReactionsCreateRequest = operations['notes___reactions___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesReactionsDeleteRequest = operations['notes/reactions/delete']['requestBody']['content']['application/json'];
+type NotesReactionsDeleteRequest = operations['notes___reactions___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesReactionsRequest = operations['notes/reactions']['requestBody']['content']['application/json'];
+type NotesReactionsRequest = operations['notes___reactions']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesReactionsResponse = operations['notes/reactions']['responses']['200']['content']['application/json'];
+type NotesReactionsResponse = operations['notes___reactions']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesRenotesRequest = operations['notes/renotes']['requestBody']['content']['application/json'];
+type NotesRenotesRequest = operations['notes___renotes']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesRenotesResponse = operations['notes/renotes']['responses']['200']['content']['application/json'];
+type NotesRenotesResponse = operations['notes___renotes']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesRepliesRequest = operations['notes/replies']['requestBody']['content']['application/json'];
+type NotesRepliesRequest = operations['notes___replies']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesRepliesResponse = operations['notes/replies']['responses']['200']['content']['application/json'];
+type NotesRepliesResponse = operations['notes___replies']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type NotesRequest = operations['notes']['requestBody']['content']['application/json'];
@@ -2514,55 +2514,55 @@ type NotesRequest = operations['notes']['requestBody']['content']['application/j
 type NotesResponse = operations['notes']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesSearchByTagRequest = operations['notes/search-by-tag']['requestBody']['content']['application/json'];
+type NotesSearchByTagRequest = operations['notes___search-by-tag']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesSearchByTagResponse = operations['notes/search-by-tag']['responses']['200']['content']['application/json'];
+type NotesSearchByTagResponse = operations['notes___search-by-tag']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesSearchRequest = operations['notes/search']['requestBody']['content']['application/json'];
+type NotesSearchRequest = operations['notes___search']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesSearchResponse = operations['notes/search']['responses']['200']['content']['application/json'];
+type NotesSearchResponse = operations['notes___search']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesShowRequest = operations['notes/show']['requestBody']['content']['application/json'];
+type NotesShowRequest = operations['notes___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesShowResponse = operations['notes/show']['responses']['200']['content']['application/json'];
+type NotesShowResponse = operations['notes___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesStateRequest = operations['notes/state']['requestBody']['content']['application/json'];
+type NotesStateRequest = operations['notes___state']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesStateResponse = operations['notes/state']['responses']['200']['content']['application/json'];
+type NotesStateResponse = operations['notes___state']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesThreadMutingCreateRequest = operations['notes/thread-muting/create']['requestBody']['content']['application/json'];
+type NotesThreadMutingCreateRequest = operations['notes___thread-muting___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesThreadMutingDeleteRequest = operations['notes/thread-muting/delete']['requestBody']['content']['application/json'];
+type NotesThreadMutingDeleteRequest = operations['notes___thread-muting___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesTimelineRequest = operations['notes/timeline']['requestBody']['content']['application/json'];
+type NotesTimelineRequest = operations['notes___timeline']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesTimelineResponse = operations['notes/timeline']['responses']['200']['content']['application/json'];
+type NotesTimelineResponse = operations['notes___timeline']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesTranslateRequest = operations['notes/translate']['requestBody']['content']['application/json'];
+type NotesTranslateRequest = operations['notes___translate']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesTranslateResponse = operations['notes/translate']['responses']['200']['content']['application/json'];
+type NotesTranslateResponse = operations['notes___translate']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type NotesUnrenoteRequest = operations['notes/unrenote']['requestBody']['content']['application/json'];
+type NotesUnrenoteRequest = operations['notes___unrenote']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesUserListTimelineRequest = operations['notes/user-list-timeline']['requestBody']['content']['application/json'];
+type NotesUserListTimelineRequest = operations['notes___user-list-timeline']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type NotesUserListTimelineResponse = operations['notes/user-list-timeline']['responses']['200']['content']['application/json'];
+type NotesUserListTimelineResponse = operations['notes___user-list-timeline']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 export const noteVisibilities: readonly ["public", "home", "followers", "specified"];
@@ -2571,7 +2571,7 @@ export const noteVisibilities: readonly ["public", "home", "followers", "specifi
 type Notification_2 = components['schemas']['Notification'];
 
 // @public (undocumented)
-type NotificationsCreateRequest = operations['notifications/create']['requestBody']['content']['application/json'];
+type NotificationsCreateRequest = operations['notifications___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
 export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "pollVote", "pollEnded", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app", "roleAssigned", "achievementEarned"];
@@ -2595,31 +2595,31 @@ type PageEvent = {
 type PagePushRequest = operations['page-push']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type PagesCreateRequest = operations['pages/create']['requestBody']['content']['application/json'];
+type PagesCreateRequest = operations['pages___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type PagesCreateResponse = operations['pages/create']['responses']['200']['content']['application/json'];
+type PagesCreateResponse = operations['pages___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type PagesDeleteRequest = operations['pages/delete']['requestBody']['content']['application/json'];
+type PagesDeleteRequest = operations['pages___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type PagesFeaturedResponse = operations['pages/featured']['responses']['200']['content']['application/json'];
+type PagesFeaturedResponse = operations['pages___featured']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type PagesLikeRequest = operations['pages/like']['requestBody']['content']['application/json'];
+type PagesLikeRequest = operations['pages___like']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type PagesShowRequest = operations['pages/show']['requestBody']['content']['application/json'];
+type PagesShowRequest = operations['pages___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type PagesShowResponse = operations['pages/show']['responses']['200']['content']['application/json'];
+type PagesShowResponse = operations['pages___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type PagesUnlikeRequest = operations['pages/unlike']['requestBody']['content']['application/json'];
+type PagesUnlikeRequest = operations['pages___unlike']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type PagesUpdateRequest = operations['pages/update']['requestBody']['content']['application/json'];
+type PagesUpdateRequest = operations['pages___update']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
 function parse(acct: string): Acct;
@@ -2634,7 +2634,7 @@ type PingResponse = operations['ping']['responses']['200']['content']['applicati
 type PinnedUsersResponse = operations['pinned-users']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type PromoReadRequest = operations['promo/read']['requestBody']['content']['application/json'];
+type PromoReadRequest = operations['promo___read']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
 type QueueCount = components['schemas']['QueueCount'];
@@ -2659,16 +2659,16 @@ type QueueStats = {
 type QueueStatsLog = QueueStats[];
 
 // @public (undocumented)
-type RenoteMuteCreateRequest = operations['renote-mute/create']['requestBody']['content']['application/json'];
+type RenoteMuteCreateRequest = operations['renote-mute___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type RenoteMuteDeleteRequest = operations['renote-mute/delete']['requestBody']['content']['application/json'];
+type RenoteMuteDeleteRequest = operations['renote-mute___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type RenoteMuteListRequest = operations['renote-mute/list']['requestBody']['content']['application/json'];
+type RenoteMuteListRequest = operations['renote-mute___list']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type RenoteMuteListResponse = operations['renote-mute/list']['responses']['200']['content']['application/json'];
+type RenoteMuteListResponse = operations['renote-mute___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type RenoteMuting = components['schemas']['RenoteMuting'];
@@ -2683,7 +2683,7 @@ type ResetPasswordRequest = operations['reset-password']['requestBody']['content
 type RetentionResponse = operations['retention']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ReversiCancelMatchRequest = operations['reversi/cancel-match']['requestBody']['content']['application/json'];
+type ReversiCancelMatchRequest = operations['reversi___cancel-match']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
 type ReversiGameDetailed = components['schemas']['ReversiGameDetailed'];
@@ -2692,34 +2692,34 @@ type ReversiGameDetailed = components['schemas']['ReversiGameDetailed'];
 type ReversiGameLite = components['schemas']['ReversiGameLite'];
 
 // @public (undocumented)
-type ReversiGamesRequest = operations['reversi/games']['requestBody']['content']['application/json'];
+type ReversiGamesRequest = operations['reversi___games']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ReversiGamesResponse = operations['reversi/games']['responses']['200']['content']['application/json'];
+type ReversiGamesResponse = operations['reversi___games']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ReversiInvitationsResponse = operations['reversi/invitations']['responses']['200']['content']['application/json'];
+type ReversiInvitationsResponse = operations['reversi___invitations']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ReversiMatchRequest = operations['reversi/match']['requestBody']['content']['application/json'];
+type ReversiMatchRequest = operations['reversi___match']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ReversiMatchResponse = operations['reversi/match']['responses']['200']['content']['application/json'];
+type ReversiMatchResponse = operations['reversi___match']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ReversiShowGameRequest = operations['reversi/show-game']['requestBody']['content']['application/json'];
+type ReversiShowGameRequest = operations['reversi___show-game']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ReversiShowGameResponse = operations['reversi/show-game']['responses']['200']['content']['application/json'];
+type ReversiShowGameResponse = operations['reversi___show-game']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type ReversiSurrenderRequest = operations['reversi/surrender']['requestBody']['content']['application/json'];
+type ReversiSurrenderRequest = operations['reversi___surrender']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ReversiVerifyRequest = operations['reversi/verify']['requestBody']['content']['application/json'];
+type ReversiVerifyRequest = operations['reversi___verify']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type ReversiVerifyResponse = operations['reversi/verify']['responses']['200']['content']['application/json'];
+type ReversiVerifyResponse = operations['reversi___verify']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type Role = components['schemas']['Role'];
@@ -2752,25 +2752,25 @@ type RoleLite = components['schemas']['RoleLite'];
 type RolePolicies = components['schemas']['RolePolicies'];
 
 // @public (undocumented)
-type RolesListResponse = operations['roles/list']['responses']['200']['content']['application/json'];
+type RolesListResponse = operations['roles___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type RolesNotesRequest = operations['roles/notes']['requestBody']['content']['application/json'];
+type RolesNotesRequest = operations['roles___notes']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type RolesNotesResponse = operations['roles/notes']['responses']['200']['content']['application/json'];
+type RolesNotesResponse = operations['roles___notes']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type RolesShowRequest = operations['roles/show']['requestBody']['content']['application/json'];
+type RolesShowRequest = operations['roles___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type RolesShowResponse = operations['roles/show']['responses']['200']['content']['application/json'];
+type RolesShowResponse = operations['roles___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type RolesUsersRequest = operations['roles/users']['requestBody']['content']['application/json'];
+type RolesUsersRequest = operations['roles___users']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type RolesUsersResponse = operations['roles/users']['responses']['200']['content']['application/json'];
+type RolesUsersResponse = operations['roles___users']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type ServerInfoResponse = operations['server-info']['responses']['200']['content']['application/json'];
@@ -2889,25 +2889,25 @@ export class Stream extends EventEmitter<StreamEvents> {
 type SwitchCaseResponseType<E extends keyof Endpoints, P extends Endpoints[E]['req']> = Endpoints[E]['res'] extends SwitchCase ? IsCaseMatched<E, P, 0> extends true ? GetCaseResult<E, P, 0> : IsCaseMatched<E, P, 1> extends true ? GetCaseResult<E, P, 1> : IsCaseMatched<E, P, 2> extends true ? GetCaseResult<E, P, 2> : IsCaseMatched<E, P, 3> extends true ? GetCaseResult<E, P, 3> : IsCaseMatched<E, P, 4> extends true ? GetCaseResult<E, P, 4> : IsCaseMatched<E, P, 5> extends true ? GetCaseResult<E, P, 5> : IsCaseMatched<E, P, 6> extends true ? GetCaseResult<E, P, 6> : IsCaseMatched<E, P, 7> extends true ? GetCaseResult<E, P, 7> : IsCaseMatched<E, P, 8> extends true ? GetCaseResult<E, P, 8> : IsCaseMatched<E, P, 9> extends true ? GetCaseResult<E, P, 9> : Endpoints[E]['res']['$switch']['$default'] : Endpoints[E]['res'];
 
 // @public (undocumented)
-type SwRegisterRequest = operations['sw/register']['requestBody']['content']['application/json'];
+type SwRegisterRequest = operations['sw___register']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type SwRegisterResponse = operations['sw/register']['responses']['200']['content']['application/json'];
+type SwRegisterResponse = operations['sw___register']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type SwShowRegistrationRequest = operations['sw/show-registration']['requestBody']['content']['application/json'];
+type SwShowRegistrationRequest = operations['sw___show-registration']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type SwShowRegistrationResponse = operations['sw/show-registration']['responses']['200']['content']['application/json'];
+type SwShowRegistrationResponse = operations['sw___show-registration']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type SwUnregisterRequest = operations['sw/unregister']['requestBody']['content']['application/json'];
+type SwUnregisterRequest = operations['sw___unregister']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type SwUpdateRegistrationRequest = operations['sw/update-registration']['requestBody']['content']['application/json'];
+type SwUpdateRegistrationRequest = operations['sw___update-registration']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type SwUpdateRegistrationResponse = operations['sw/update-registration']['responses']['200']['content']['application/json'];
+type SwUpdateRegistrationResponse = operations['sw___update-registration']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
 type TestRequest = operations['test']['requestBody']['content']['application/json'];
@@ -2937,145 +2937,145 @@ type UserList = components['schemas']['UserList'];
 type UserLite = components['schemas']['UserLite'];
 
 // @public (undocumented)
-type UsernameAvailableRequest = operations['username/available']['requestBody']['content']['application/json'];
+type UsernameAvailableRequest = operations['username___available']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsernameAvailableResponse = operations['username/available']['responses']['200']['content']['application/json'];
+type UsernameAvailableResponse = operations['username___available']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersAchievementsRequest = operations['users/achievements']['requestBody']['content']['application/json'];
+type UsersAchievementsRequest = operations['users___achievements']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersAchievementsResponse = operations['users/achievements']['responses']['200']['content']['application/json'];
+type UsersAchievementsResponse = operations['users___achievements']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersClipsRequest = operations['users/clips']['requestBody']['content']['application/json'];
+type UsersClipsRequest = operations['users___clips']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersClipsResponse = operations['users/clips']['responses']['200']['content']['application/json'];
+type UsersClipsResponse = operations['users___clips']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersFeaturedNotesRequest = operations['users/featured-notes']['requestBody']['content']['application/json'];
+type UsersFeaturedNotesRequest = operations['users___featured-notes']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersFeaturedNotesResponse = operations['users/featured-notes']['responses']['200']['content']['application/json'];
+type UsersFeaturedNotesResponse = operations['users___featured-notes']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersFlashsRequest = operations['users/flashs']['requestBody']['content']['application/json'];
+type UsersFlashsRequest = operations['users___flashs']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersFlashsResponse = operations['users/flashs']['responses']['200']['content']['application/json'];
+type UsersFlashsResponse = operations['users___flashs']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersFollowersRequest = operations['users/followers']['requestBody']['content']['application/json'];
+type UsersFollowersRequest = operations['users___followers']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersFollowersResponse = operations['users/followers']['responses']['200']['content']['application/json'];
+type UsersFollowersResponse = operations['users___followers']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersFollowingRequest = operations['users/following']['requestBody']['content']['application/json'];
+type UsersFollowingRequest = operations['users___following']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersFollowingResponse = operations['users/following']['responses']['200']['content']['application/json'];
+type UsersFollowingResponse = operations['users___following']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersGalleryPostsRequest = operations['users/gallery/posts']['requestBody']['content']['application/json'];
+type UsersGalleryPostsRequest = operations['users___gallery___posts']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersGalleryPostsResponse = operations['users/gallery/posts']['responses']['200']['content']['application/json'];
+type UsersGalleryPostsResponse = operations['users___gallery___posts']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersGetFrequentlyRepliedUsersRequest = operations['users/get-frequently-replied-users']['requestBody']['content']['application/json'];
+type UsersGetFrequentlyRepliedUsersRequest = operations['users___get-frequently-replied-users']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersGetFrequentlyRepliedUsersResponse = operations['users/get-frequently-replied-users']['responses']['200']['content']['application/json'];
+type UsersGetFrequentlyRepliedUsersResponse = operations['users___get-frequently-replied-users']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsCreateFromPublicRequest = operations['users/lists/create-from-public']['requestBody']['content']['application/json'];
+type UsersListsCreateFromPublicRequest = operations['users___lists___create-from-public']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsCreateFromPublicResponse = operations['users/lists/create-from-public']['responses']['200']['content']['application/json'];
+type UsersListsCreateFromPublicResponse = operations['users___lists___create-from-public']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsCreateRequest = operations['users/lists/create']['requestBody']['content']['application/json'];
+type UsersListsCreateRequest = operations['users___lists___create']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsCreateResponse = operations['users/lists/create']['responses']['200']['content']['application/json'];
+type UsersListsCreateResponse = operations['users___lists___create']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsDeleteRequest = operations['users/lists/delete']['requestBody']['content']['application/json'];
+type UsersListsDeleteRequest = operations['users___lists___delete']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsFavoriteRequest = operations['users/lists/favorite']['requestBody']['content']['application/json'];
+type UsersListsFavoriteRequest = operations['users___lists___favorite']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsGetMembershipsRequest = operations['users/lists/get-memberships']['requestBody']['content']['application/json'];
+type UsersListsGetMembershipsRequest = operations['users___lists___get-memberships']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsGetMembershipsResponse = operations['users/lists/get-memberships']['responses']['200']['content']['application/json'];
+type UsersListsGetMembershipsResponse = operations['users___lists___get-memberships']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsListRequest = operations['users/lists/list']['requestBody']['content']['application/json'];
+type UsersListsListRequest = operations['users___lists___list']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsListResponse = operations['users/lists/list']['responses']['200']['content']['application/json'];
+type UsersListsListResponse = operations['users___lists___list']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsPullRequest = operations['users/lists/pull']['requestBody']['content']['application/json'];
+type UsersListsPullRequest = operations['users___lists___pull']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsPushRequest = operations['users/lists/push']['requestBody']['content']['application/json'];
+type UsersListsPushRequest = operations['users___lists___push']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsShowRequest = operations['users/lists/show']['requestBody']['content']['application/json'];
+type UsersListsShowRequest = operations['users___lists___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsShowResponse = operations['users/lists/show']['responses']['200']['content']['application/json'];
+type UsersListsShowResponse = operations['users___lists___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsUnfavoriteRequest = operations['users/lists/unfavorite']['requestBody']['content']['application/json'];
+type UsersListsUnfavoriteRequest = operations['users___lists___unfavorite']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsUpdateMembershipRequest = operations['users/lists/update-membership']['requestBody']['content']['application/json'];
+type UsersListsUpdateMembershipRequest = operations['users___lists___update-membership']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsUpdateRequest = operations['users/lists/update']['requestBody']['content']['application/json'];
+type UsersListsUpdateRequest = operations['users___lists___update']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersListsUpdateResponse = operations['users/lists/update']['responses']['200']['content']['application/json'];
+type UsersListsUpdateResponse = operations['users___lists___update']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersNotesRequest = operations['users/notes']['requestBody']['content']['application/json'];
+type UsersNotesRequest = operations['users___notes']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersNotesResponse = operations['users/notes']['responses']['200']['content']['application/json'];
+type UsersNotesResponse = operations['users___notes']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersPagesRequest = operations['users/pages']['requestBody']['content']['application/json'];
+type UsersPagesRequest = operations['users___pages']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersPagesResponse = operations['users/pages']['responses']['200']['content']['application/json'];
+type UsersPagesResponse = operations['users___pages']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersReactionsRequest = operations['users/reactions']['requestBody']['content']['application/json'];
+type UsersReactionsRequest = operations['users___reactions']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersReactionsResponse = operations['users/reactions']['responses']['200']['content']['application/json'];
+type UsersReactionsResponse = operations['users___reactions']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersRecommendationRequest = operations['users/recommendation']['requestBody']['content']['application/json'];
+type UsersRecommendationRequest = operations['users___recommendation']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersRecommendationResponse = operations['users/recommendation']['responses']['200']['content']['application/json'];
+type UsersRecommendationResponse = operations['users___recommendation']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersRelationRequest = operations['users/relation']['requestBody']['content']['application/json'];
+type UsersRelationRequest = operations['users___relation']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersRelationResponse = operations['users/relation']['responses']['200']['content']['application/json'];
+type UsersRelationResponse = operations['users___relation']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersReportAbuseRequest = operations['users/report-abuse']['requestBody']['content']['application/json'];
+type UsersReportAbuseRequest = operations['users___report-abuse']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
 type UsersRequest = operations['users']['requestBody']['content']['application/json'];
@@ -3084,25 +3084,25 @@ type UsersRequest = operations['users']['requestBody']['content']['application/j
 type UsersResponse = operations['users']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersSearchByUsernameAndHostRequest = operations['users/search-by-username-and-host']['requestBody']['content']['application/json'];
+type UsersSearchByUsernameAndHostRequest = operations['users___search-by-username-and-host']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersSearchByUsernameAndHostResponse = operations['users/search-by-username-and-host']['responses']['200']['content']['application/json'];
+type UsersSearchByUsernameAndHostResponse = operations['users___search-by-username-and-host']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersSearchRequest = operations['users/search']['requestBody']['content']['application/json'];
+type UsersSearchRequest = operations['users___search']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersSearchResponse = operations['users/search']['responses']['200']['content']['application/json'];
+type UsersSearchResponse = operations['users___search']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersShowRequest = operations['users/show']['requestBody']['content']['application/json'];
+type UsersShowRequest = operations['users___show']['requestBody']['content']['application/json'];
 
 // @public (undocumented)
-type UsersShowResponse = operations['users/show']['responses']['200']['content']['application/json'];
+type UsersShowResponse = operations['users___show']['responses']['200']['content']['application/json'];
 
 // @public (undocumented)
-type UsersUpdateMemoRequest = operations['users/update-memo']['requestBody']['content']['application/json'];
+type UsersUpdateMemoRequest = operations['users___update-memo']['requestBody']['content']['application/json'];
 
 // Warnings were encountered during analysis:
 //
diff --git a/packages/misskey-js/generator/src/generator.ts b/packages/misskey-js/generator/src/generator.ts
index 49dcd4c1ed..78178d7c7e 100644
--- a/packages/misskey-js/generator/src/generator.ts
+++ b/packages/misskey-js/generator/src/generator.ts
@@ -60,13 +60,17 @@ async function generateEndpoints(
 	// misskey-jsはPOST固定で送っているので、こちらも決め打ちする。別メソッドに対応することがあればこちらも直す必要あり
 	const paths = openApiDocs.paths ?? {};
 	const postPathItems = Object.keys(paths)
-		.map(it => paths[it]?.post)
+		.map(it => ({
+			_path_: it.replace(/^\//, ''),
+			...paths[it]?.post,
+		}))
 		.filter(filterUndefined);
 
 	for (const operation of postPathItems) {
+		const path = operation._path_;
 		// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
 		const operationId = operation.operationId!;
-		const endpoint = new Endpoint(operationId);
+		const endpoint = new Endpoint(path);
 		endpoints.push(endpoint);
 
 		if (isRequestBodyObject(operation.requestBody)) {
@@ -76,19 +80,21 @@ async function generateEndpoints(
 				// いまのところ複数のメディアタイプをとるエンドポイントは無いので決め打ちする
 				endpoint.request = new OperationTypeAlias(
 					operationId,
+					path,
 					supportMediaTypes[0],
 					OperationsAliasType.REQUEST,
 				);
 			}
 		}
 
-		if (isResponseObject(operation.responses['200']) && operation.responses['200'].content) {
+		if (operation.responses && isResponseObject(operation.responses['200']) && operation.responses['200'].content) {
 			const resContent = operation.responses['200'].content;
 			const supportMediaTypes = Object.keys(resContent);
 			if (supportMediaTypes.length > 0) {
 				// いまのところ複数のメディアタイプを返すエンドポイントは無いので決め打ちする
 				endpoint.response = new OperationTypeAlias(
 					operationId,
+					path,
 					supportMediaTypes[0],
 					OperationsAliasType.RESPONSE,
 				);
@@ -140,12 +146,19 @@ async function generateApiClientJSDoc(
 	endpointsFileName: string,
 	warningsOutputPath: string,
 ) {
-	const endpoints: { operationId: string; description: string; }[] = [];
+	const endpoints: {
+		operationId: string;
+		path: string;
+		description: string;
+	}[] = [];
 
 	// misskey-jsはPOST固定で送っているので、こちらも決め打ちする。別メソッドに対応することがあればこちらも直す必要あり
 	const paths = openApiDocs.paths ?? {};
 	const postPathItems = Object.keys(paths)
-		.map(it => paths[it]?.post)
+		.map(it => ({
+			_path_: it.replace(/^\//, ''),
+			...paths[it]?.post,
+		}))
 		.filter(filterUndefined);
 
 	for (const operation of postPathItems) {
@@ -155,6 +168,7 @@ async function generateApiClientJSDoc(
 		if (operation.description) {
 			endpoints.push({
 				operationId: operationId,
+				path: operation._path_,
 				description: operation.description,
 			});
 		}
@@ -175,7 +189,7 @@ async function generateApiClientJSDoc(
 			'    /**',
 			`     * ${endpoint.description.split('\n').join('\n     * ')}`,
 			'     */',
-			`    request<E extends '${endpoint.operationId}', P extends Endpoints[E][\'req\']>(`,
+			`    request<E extends '${endpoint.path}', P extends Endpoints[E][\'req\']>(`,
 			'      endpoint: E,',
 			'      params: P,',
 			'      credential?: string | null,',
@@ -234,21 +248,24 @@ interface IOperationTypeAlias {
 
 class OperationTypeAlias implements IOperationTypeAlias {
 	public readonly operationId: string;
+	public readonly path: string;
 	public readonly mediaType: string;
 	public readonly type: OperationsAliasType;
 
 	constructor(
 		operationId: string,
+		path: string,
 		mediaType: string,
 		type: OperationsAliasType,
 	) {
 		this.operationId = operationId;
+		this.path = path;
 		this.mediaType = mediaType;
 		this.type = type;
 	}
 
 	generateName(): string {
-		const nameBase = this.operationId.replace(/\//g, '-');
+		const nameBase = this.path.replace(/\//g, '-');
 		return toPascal(nameBase + this.type);
 	}
 
@@ -281,19 +298,19 @@ const emptyRequest = new EmptyTypeAlias(OperationsAliasType.REQUEST);
 const emptyResponse = new EmptyTypeAlias(OperationsAliasType.RESPONSE);
 
 class Endpoint {
-	public readonly operationId: string;
+	public readonly path: string;
 	public request?: IOperationTypeAlias;
 	public response?: IOperationTypeAlias;
 
-	constructor(operationId: string) {
-		this.operationId = operationId;
+	constructor(path: string) {
+		this.path = path;
 	}
 
 	toLine(): string {
 		const reqName = this.request?.generateName() ?? emptyRequest.generateName();
 		const resName = this.response?.generateName() ?? emptyResponse.generateName();
 
-		return `'${this.operationId}': { req: ${reqName}; res: ${resName} };`;
+		return `'${this.path}': { req: ${reqName}; res: ${resName} };`;
 	}
 }
 
diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts
index a936931e99..60bf6659c0 100644
--- a/packages/misskey-js/src/autogen/entities.ts
+++ b/packages/misskey-js/src/autogen/entities.ts
@@ -1,555 +1,556 @@
+/* eslint @typescript-eslint/naming-convention: 0 */
 import { operations } from './types.js';
 
 export type EmptyRequest = Record<string, unknown> | undefined;
 export type EmptyResponse = Record<string, unknown> | undefined;
 
-export type AdminMetaResponse = operations['admin/meta']['responses']['200']['content']['application/json'];
-export type AdminAbuseUserReportsRequest = operations['admin/abuse-user-reports']['requestBody']['content']['application/json'];
-export type AdminAbuseUserReportsResponse = operations['admin/abuse-user-reports']['responses']['200']['content']['application/json'];
-export type AdminAccountsCreateRequest = operations['admin/accounts/create']['requestBody']['content']['application/json'];
-export type AdminAccountsCreateResponse = operations['admin/accounts/create']['responses']['200']['content']['application/json'];
-export type AdminAccountsDeleteRequest = operations['admin/accounts/delete']['requestBody']['content']['application/json'];
-export type AdminAccountsFindByEmailRequest = operations['admin/accounts/find-by-email']['requestBody']['content']['application/json'];
-export type AdminAccountsFindByEmailResponse = operations['admin/accounts/find-by-email']['responses']['200']['content']['application/json'];
-export type AdminAdCreateRequest = operations['admin/ad/create']['requestBody']['content']['application/json'];
-export type AdminAdCreateResponse = operations['admin/ad/create']['responses']['200']['content']['application/json'];
-export type AdminAdDeleteRequest = operations['admin/ad/delete']['requestBody']['content']['application/json'];
-export type AdminAdListRequest = operations['admin/ad/list']['requestBody']['content']['application/json'];
-export type AdminAdListResponse = operations['admin/ad/list']['responses']['200']['content']['application/json'];
-export type AdminAdUpdateRequest = operations['admin/ad/update']['requestBody']['content']['application/json'];
-export type AdminAnnouncementsCreateRequest = operations['admin/announcements/create']['requestBody']['content']['application/json'];
-export type AdminAnnouncementsCreateResponse = operations['admin/announcements/create']['responses']['200']['content']['application/json'];
-export type AdminAnnouncementsDeleteRequest = operations['admin/announcements/delete']['requestBody']['content']['application/json'];
-export type AdminAnnouncementsListRequest = operations['admin/announcements/list']['requestBody']['content']['application/json'];
-export type AdminAnnouncementsListResponse = operations['admin/announcements/list']['responses']['200']['content']['application/json'];
-export type AdminAnnouncementsUpdateRequest = operations['admin/announcements/update']['requestBody']['content']['application/json'];
-export type AdminAvatarDecorationsCreateRequest = operations['admin/avatar-decorations/create']['requestBody']['content']['application/json'];
-export type AdminAvatarDecorationsDeleteRequest = operations['admin/avatar-decorations/delete']['requestBody']['content']['application/json'];
-export type AdminAvatarDecorationsListRequest = operations['admin/avatar-decorations/list']['requestBody']['content']['application/json'];
-export type AdminAvatarDecorationsListResponse = operations['admin/avatar-decorations/list']['responses']['200']['content']['application/json'];
-export type AdminAvatarDecorationsUpdateRequest = operations['admin/avatar-decorations/update']['requestBody']['content']['application/json'];
-export type AdminDeleteAllFilesOfAUserRequest = operations['admin/delete-all-files-of-a-user']['requestBody']['content']['application/json'];
-export type AdminUnsetUserAvatarRequest = operations['admin/unset-user-avatar']['requestBody']['content']['application/json'];
-export type AdminUnsetUserBannerRequest = operations['admin/unset-user-banner']['requestBody']['content']['application/json'];
-export type AdminDriveFilesRequest = operations['admin/drive/files']['requestBody']['content']['application/json'];
-export type AdminDriveFilesResponse = operations['admin/drive/files']['responses']['200']['content']['application/json'];
-export type AdminDriveShowFileRequest = operations['admin/drive/show-file']['requestBody']['content']['application/json'];
-export type AdminDriveShowFileResponse = operations['admin/drive/show-file']['responses']['200']['content']['application/json'];
-export type AdminEmojiAddAliasesBulkRequest = operations['admin/emoji/add-aliases-bulk']['requestBody']['content']['application/json'];
-export type AdminEmojiAddRequest = operations['admin/emoji/add']['requestBody']['content']['application/json'];
-export type AdminEmojiAddResponse = operations['admin/emoji/add']['responses']['200']['content']['application/json'];
-export type AdminEmojiCopyRequest = operations['admin/emoji/copy']['requestBody']['content']['application/json'];
-export type AdminEmojiCopyResponse = operations['admin/emoji/copy']['responses']['200']['content']['application/json'];
-export type AdminEmojiDeleteBulkRequest = operations['admin/emoji/delete-bulk']['requestBody']['content']['application/json'];
-export type AdminEmojiDeleteRequest = operations['admin/emoji/delete']['requestBody']['content']['application/json'];
-export type AdminEmojiImportZipRequest = operations['admin/emoji/import-zip']['requestBody']['content']['application/json'];
-export type AdminEmojiListRemoteRequest = operations['admin/emoji/list-remote']['requestBody']['content']['application/json'];
-export type AdminEmojiListRemoteResponse = operations['admin/emoji/list-remote']['responses']['200']['content']['application/json'];
-export type AdminEmojiListRequest = operations['admin/emoji/list']['requestBody']['content']['application/json'];
-export type AdminEmojiListResponse = operations['admin/emoji/list']['responses']['200']['content']['application/json'];
-export type AdminEmojiRemoveAliasesBulkRequest = operations['admin/emoji/remove-aliases-bulk']['requestBody']['content']['application/json'];
-export type AdminEmojiSetAliasesBulkRequest = operations['admin/emoji/set-aliases-bulk']['requestBody']['content']['application/json'];
-export type AdminEmojiSetCategoryBulkRequest = operations['admin/emoji/set-category-bulk']['requestBody']['content']['application/json'];
-export type AdminEmojiSetLicenseBulkRequest = operations['admin/emoji/set-license-bulk']['requestBody']['content']['application/json'];
-export type AdminEmojiUpdateRequest = operations['admin/emoji/update']['requestBody']['content']['application/json'];
-export type AdminFederationDeleteAllFilesRequest = operations['admin/federation/delete-all-files']['requestBody']['content']['application/json'];
-export type AdminFederationRefreshRemoteInstanceMetadataRequest = operations['admin/federation/refresh-remote-instance-metadata']['requestBody']['content']['application/json'];
-export type AdminFederationRemoveAllFollowingRequest = operations['admin/federation/remove-all-following']['requestBody']['content']['application/json'];
-export type AdminFederationUpdateInstanceRequest = operations['admin/federation/update-instance']['requestBody']['content']['application/json'];
-export type AdminGetIndexStatsResponse = operations['admin/get-index-stats']['responses']['200']['content']['application/json'];
-export type AdminGetTableStatsResponse = operations['admin/get-table-stats']['responses']['200']['content']['application/json'];
-export type AdminGetUserIpsRequest = operations['admin/get-user-ips']['requestBody']['content']['application/json'];
-export type AdminGetUserIpsResponse = operations['admin/get-user-ips']['responses']['200']['content']['application/json'];
-export type AdminInviteCreateRequest = operations['admin/invite/create']['requestBody']['content']['application/json'];
-export type AdminInviteCreateResponse = operations['admin/invite/create']['responses']['200']['content']['application/json'];
-export type AdminInviteListRequest = operations['admin/invite/list']['requestBody']['content']['application/json'];
-export type AdminInviteListResponse = operations['admin/invite/list']['responses']['200']['content']['application/json'];
-export type AdminPromoCreateRequest = operations['admin/promo/create']['requestBody']['content']['application/json'];
-export type AdminQueueDeliverDelayedResponse = operations['admin/queue/deliver-delayed']['responses']['200']['content']['application/json'];
-export type AdminQueueInboxDelayedResponse = operations['admin/queue/inbox-delayed']['responses']['200']['content']['application/json'];
-export type AdminQueuePromoteRequest = operations['admin/queue/promote']['requestBody']['content']['application/json'];
-export type AdminQueueStatsResponse = operations['admin/queue/stats']['responses']['200']['content']['application/json'];
-export type AdminRelaysAddRequest = operations['admin/relays/add']['requestBody']['content']['application/json'];
-export type AdminRelaysAddResponse = operations['admin/relays/add']['responses']['200']['content']['application/json'];
-export type AdminRelaysListResponse = operations['admin/relays/list']['responses']['200']['content']['application/json'];
-export type AdminRelaysRemoveRequest = operations['admin/relays/remove']['requestBody']['content']['application/json'];
-export type AdminResetPasswordRequest = operations['admin/reset-password']['requestBody']['content']['application/json'];
-export type AdminResetPasswordResponse = operations['admin/reset-password']['responses']['200']['content']['application/json'];
-export type AdminResolveAbuseUserReportRequest = operations['admin/resolve-abuse-user-report']['requestBody']['content']['application/json'];
-export type AdminSendEmailRequest = operations['admin/send-email']['requestBody']['content']['application/json'];
-export type AdminServerInfoResponse = operations['admin/server-info']['responses']['200']['content']['application/json'];
-export type AdminShowModerationLogsRequest = operations['admin/show-moderation-logs']['requestBody']['content']['application/json'];
-export type AdminShowModerationLogsResponse = operations['admin/show-moderation-logs']['responses']['200']['content']['application/json'];
-export type AdminShowUserRequest = operations['admin/show-user']['requestBody']['content']['application/json'];
-export type AdminShowUserResponse = operations['admin/show-user']['responses']['200']['content']['application/json'];
-export type AdminShowUsersRequest = operations['admin/show-users']['requestBody']['content']['application/json'];
-export type AdminShowUsersResponse = operations['admin/show-users']['responses']['200']['content']['application/json'];
-export type AdminSuspendUserRequest = operations['admin/suspend-user']['requestBody']['content']['application/json'];
-export type AdminUnsuspendUserRequest = operations['admin/unsuspend-user']['requestBody']['content']['application/json'];
-export type AdminUpdateMetaRequest = operations['admin/update-meta']['requestBody']['content']['application/json'];
-export type AdminDeleteAccountRequest = operations['admin/delete-account']['requestBody']['content']['application/json'];
-export type AdminUpdateUserNoteRequest = operations['admin/update-user-note']['requestBody']['content']['application/json'];
-export type AdminRolesCreateRequest = operations['admin/roles/create']['requestBody']['content']['application/json'];
-export type AdminRolesCreateResponse = operations['admin/roles/create']['responses']['200']['content']['application/json'];
-export type AdminRolesDeleteRequest = operations['admin/roles/delete']['requestBody']['content']['application/json'];
-export type AdminRolesListResponse = operations['admin/roles/list']['responses']['200']['content']['application/json'];
-export type AdminRolesShowRequest = operations['admin/roles/show']['requestBody']['content']['application/json'];
-export type AdminRolesShowResponse = operations['admin/roles/show']['responses']['200']['content']['application/json'];
-export type AdminRolesUpdateRequest = operations['admin/roles/update']['requestBody']['content']['application/json'];
-export type AdminRolesAssignRequest = operations['admin/roles/assign']['requestBody']['content']['application/json'];
-export type AdminRolesUnassignRequest = operations['admin/roles/unassign']['requestBody']['content']['application/json'];
-export type AdminRolesUpdateDefaultPoliciesRequest = operations['admin/roles/update-default-policies']['requestBody']['content']['application/json'];
-export type AdminRolesUsersRequest = operations['admin/roles/users']['requestBody']['content']['application/json'];
-export type AdminRolesUsersResponse = operations['admin/roles/users']['responses']['200']['content']['application/json'];
+export type AdminMetaResponse = operations['admin___meta']['responses']['200']['content']['application/json'];
+export type AdminAbuseUserReportsRequest = operations['admin___abuse-user-reports']['requestBody']['content']['application/json'];
+export type AdminAbuseUserReportsResponse = operations['admin___abuse-user-reports']['responses']['200']['content']['application/json'];
+export type AdminAccountsCreateRequest = operations['admin___accounts___create']['requestBody']['content']['application/json'];
+export type AdminAccountsCreateResponse = operations['admin___accounts___create']['responses']['200']['content']['application/json'];
+export type AdminAccountsDeleteRequest = operations['admin___accounts___delete']['requestBody']['content']['application/json'];
+export type AdminAccountsFindByEmailRequest = operations['admin___accounts___find-by-email']['requestBody']['content']['application/json'];
+export type AdminAccountsFindByEmailResponse = operations['admin___accounts___find-by-email']['responses']['200']['content']['application/json'];
+export type AdminAdCreateRequest = operations['admin___ad___create']['requestBody']['content']['application/json'];
+export type AdminAdCreateResponse = operations['admin___ad___create']['responses']['200']['content']['application/json'];
+export type AdminAdDeleteRequest = operations['admin___ad___delete']['requestBody']['content']['application/json'];
+export type AdminAdListRequest = operations['admin___ad___list']['requestBody']['content']['application/json'];
+export type AdminAdListResponse = operations['admin___ad___list']['responses']['200']['content']['application/json'];
+export type AdminAdUpdateRequest = operations['admin___ad___update']['requestBody']['content']['application/json'];
+export type AdminAnnouncementsCreateRequest = operations['admin___announcements___create']['requestBody']['content']['application/json'];
+export type AdminAnnouncementsCreateResponse = operations['admin___announcements___create']['responses']['200']['content']['application/json'];
+export type AdminAnnouncementsDeleteRequest = operations['admin___announcements___delete']['requestBody']['content']['application/json'];
+export type AdminAnnouncementsListRequest = operations['admin___announcements___list']['requestBody']['content']['application/json'];
+export type AdminAnnouncementsListResponse = operations['admin___announcements___list']['responses']['200']['content']['application/json'];
+export type AdminAnnouncementsUpdateRequest = operations['admin___announcements___update']['requestBody']['content']['application/json'];
+export type AdminAvatarDecorationsCreateRequest = operations['admin___avatar-decorations___create']['requestBody']['content']['application/json'];
+export type AdminAvatarDecorationsDeleteRequest = operations['admin___avatar-decorations___delete']['requestBody']['content']['application/json'];
+export type AdminAvatarDecorationsListRequest = operations['admin___avatar-decorations___list']['requestBody']['content']['application/json'];
+export type AdminAvatarDecorationsListResponse = operations['admin___avatar-decorations___list']['responses']['200']['content']['application/json'];
+export type AdminAvatarDecorationsUpdateRequest = operations['admin___avatar-decorations___update']['requestBody']['content']['application/json'];
+export type AdminDeleteAllFilesOfAUserRequest = operations['admin___delete-all-files-of-a-user']['requestBody']['content']['application/json'];
+export type AdminUnsetUserAvatarRequest = operations['admin___unset-user-avatar']['requestBody']['content']['application/json'];
+export type AdminUnsetUserBannerRequest = operations['admin___unset-user-banner']['requestBody']['content']['application/json'];
+export type AdminDriveFilesRequest = operations['admin___drive___files']['requestBody']['content']['application/json'];
+export type AdminDriveFilesResponse = operations['admin___drive___files']['responses']['200']['content']['application/json'];
+export type AdminDriveShowFileRequest = operations['admin___drive___show-file']['requestBody']['content']['application/json'];
+export type AdminDriveShowFileResponse = operations['admin___drive___show-file']['responses']['200']['content']['application/json'];
+export type AdminEmojiAddAliasesBulkRequest = operations['admin___emoji___add-aliases-bulk']['requestBody']['content']['application/json'];
+export type AdminEmojiAddRequest = operations['admin___emoji___add']['requestBody']['content']['application/json'];
+export type AdminEmojiAddResponse = operations['admin___emoji___add']['responses']['200']['content']['application/json'];
+export type AdminEmojiCopyRequest = operations['admin___emoji___copy']['requestBody']['content']['application/json'];
+export type AdminEmojiCopyResponse = operations['admin___emoji___copy']['responses']['200']['content']['application/json'];
+export type AdminEmojiDeleteBulkRequest = operations['admin___emoji___delete-bulk']['requestBody']['content']['application/json'];
+export type AdminEmojiDeleteRequest = operations['admin___emoji___delete']['requestBody']['content']['application/json'];
+export type AdminEmojiImportZipRequest = operations['admin___emoji___import-zip']['requestBody']['content']['application/json'];
+export type AdminEmojiListRemoteRequest = operations['admin___emoji___list-remote']['requestBody']['content']['application/json'];
+export type AdminEmojiListRemoteResponse = operations['admin___emoji___list-remote']['responses']['200']['content']['application/json'];
+export type AdminEmojiListRequest = operations['admin___emoji___list']['requestBody']['content']['application/json'];
+export type AdminEmojiListResponse = operations['admin___emoji___list']['responses']['200']['content']['application/json'];
+export type AdminEmojiRemoveAliasesBulkRequest = operations['admin___emoji___remove-aliases-bulk']['requestBody']['content']['application/json'];
+export type AdminEmojiSetAliasesBulkRequest = operations['admin___emoji___set-aliases-bulk']['requestBody']['content']['application/json'];
+export type AdminEmojiSetCategoryBulkRequest = operations['admin___emoji___set-category-bulk']['requestBody']['content']['application/json'];
+export type AdminEmojiSetLicenseBulkRequest = operations['admin___emoji___set-license-bulk']['requestBody']['content']['application/json'];
+export type AdminEmojiUpdateRequest = operations['admin___emoji___update']['requestBody']['content']['application/json'];
+export type AdminFederationDeleteAllFilesRequest = operations['admin___federation___delete-all-files']['requestBody']['content']['application/json'];
+export type AdminFederationRefreshRemoteInstanceMetadataRequest = operations['admin___federation___refresh-remote-instance-metadata']['requestBody']['content']['application/json'];
+export type AdminFederationRemoveAllFollowingRequest = operations['admin___federation___remove-all-following']['requestBody']['content']['application/json'];
+export type AdminFederationUpdateInstanceRequest = operations['admin___federation___update-instance']['requestBody']['content']['application/json'];
+export type AdminGetIndexStatsResponse = operations['admin___get-index-stats']['responses']['200']['content']['application/json'];
+export type AdminGetTableStatsResponse = operations['admin___get-table-stats']['responses']['200']['content']['application/json'];
+export type AdminGetUserIpsRequest = operations['admin___get-user-ips']['requestBody']['content']['application/json'];
+export type AdminGetUserIpsResponse = operations['admin___get-user-ips']['responses']['200']['content']['application/json'];
+export type AdminInviteCreateRequest = operations['admin___invite___create']['requestBody']['content']['application/json'];
+export type AdminInviteCreateResponse = operations['admin___invite___create']['responses']['200']['content']['application/json'];
+export type AdminInviteListRequest = operations['admin___invite___list']['requestBody']['content']['application/json'];
+export type AdminInviteListResponse = operations['admin___invite___list']['responses']['200']['content']['application/json'];
+export type AdminPromoCreateRequest = operations['admin___promo___create']['requestBody']['content']['application/json'];
+export type AdminQueueDeliverDelayedResponse = operations['admin___queue___deliver-delayed']['responses']['200']['content']['application/json'];
+export type AdminQueueInboxDelayedResponse = operations['admin___queue___inbox-delayed']['responses']['200']['content']['application/json'];
+export type AdminQueuePromoteRequest = operations['admin___queue___promote']['requestBody']['content']['application/json'];
+export type AdminQueueStatsResponse = operations['admin___queue___stats']['responses']['200']['content']['application/json'];
+export type AdminRelaysAddRequest = operations['admin___relays___add']['requestBody']['content']['application/json'];
+export type AdminRelaysAddResponse = operations['admin___relays___add']['responses']['200']['content']['application/json'];
+export type AdminRelaysListResponse = operations['admin___relays___list']['responses']['200']['content']['application/json'];
+export type AdminRelaysRemoveRequest = operations['admin___relays___remove']['requestBody']['content']['application/json'];
+export type AdminResetPasswordRequest = operations['admin___reset-password']['requestBody']['content']['application/json'];
+export type AdminResetPasswordResponse = operations['admin___reset-password']['responses']['200']['content']['application/json'];
+export type AdminResolveAbuseUserReportRequest = operations['admin___resolve-abuse-user-report']['requestBody']['content']['application/json'];
+export type AdminSendEmailRequest = operations['admin___send-email']['requestBody']['content']['application/json'];
+export type AdminServerInfoResponse = operations['admin___server-info']['responses']['200']['content']['application/json'];
+export type AdminShowModerationLogsRequest = operations['admin___show-moderation-logs']['requestBody']['content']['application/json'];
+export type AdminShowModerationLogsResponse = operations['admin___show-moderation-logs']['responses']['200']['content']['application/json'];
+export type AdminShowUserRequest = operations['admin___show-user']['requestBody']['content']['application/json'];
+export type AdminShowUserResponse = operations['admin___show-user']['responses']['200']['content']['application/json'];
+export type AdminShowUsersRequest = operations['admin___show-users']['requestBody']['content']['application/json'];
+export type AdminShowUsersResponse = operations['admin___show-users']['responses']['200']['content']['application/json'];
+export type AdminSuspendUserRequest = operations['admin___suspend-user']['requestBody']['content']['application/json'];
+export type AdminUnsuspendUserRequest = operations['admin___unsuspend-user']['requestBody']['content']['application/json'];
+export type AdminUpdateMetaRequest = operations['admin___update-meta']['requestBody']['content']['application/json'];
+export type AdminDeleteAccountRequest = operations['admin___delete-account']['requestBody']['content']['application/json'];
+export type AdminUpdateUserNoteRequest = operations['admin___update-user-note']['requestBody']['content']['application/json'];
+export type AdminRolesCreateRequest = operations['admin___roles___create']['requestBody']['content']['application/json'];
+export type AdminRolesCreateResponse = operations['admin___roles___create']['responses']['200']['content']['application/json'];
+export type AdminRolesDeleteRequest = operations['admin___roles___delete']['requestBody']['content']['application/json'];
+export type AdminRolesListResponse = operations['admin___roles___list']['responses']['200']['content']['application/json'];
+export type AdminRolesShowRequest = operations['admin___roles___show']['requestBody']['content']['application/json'];
+export type AdminRolesShowResponse = operations['admin___roles___show']['responses']['200']['content']['application/json'];
+export type AdminRolesUpdateRequest = operations['admin___roles___update']['requestBody']['content']['application/json'];
+export type AdminRolesAssignRequest = operations['admin___roles___assign']['requestBody']['content']['application/json'];
+export type AdminRolesUnassignRequest = operations['admin___roles___unassign']['requestBody']['content']['application/json'];
+export type AdminRolesUpdateDefaultPoliciesRequest = operations['admin___roles___update-default-policies']['requestBody']['content']['application/json'];
+export type AdminRolesUsersRequest = operations['admin___roles___users']['requestBody']['content']['application/json'];
+export type AdminRolesUsersResponse = operations['admin___roles___users']['responses']['200']['content']['application/json'];
 export type AnnouncementsRequest = operations['announcements']['requestBody']['content']['application/json'];
 export type AnnouncementsResponse = operations['announcements']['responses']['200']['content']['application/json'];
-export type AntennasCreateRequest = operations['antennas/create']['requestBody']['content']['application/json'];
-export type AntennasCreateResponse = operations['antennas/create']['responses']['200']['content']['application/json'];
-export type AntennasDeleteRequest = operations['antennas/delete']['requestBody']['content']['application/json'];
-export type AntennasListResponse = operations['antennas/list']['responses']['200']['content']['application/json'];
-export type AntennasNotesRequest = operations['antennas/notes']['requestBody']['content']['application/json'];
-export type AntennasNotesResponse = operations['antennas/notes']['responses']['200']['content']['application/json'];
-export type AntennasShowRequest = operations['antennas/show']['requestBody']['content']['application/json'];
-export type AntennasShowResponse = operations['antennas/show']['responses']['200']['content']['application/json'];
-export type AntennasUpdateRequest = operations['antennas/update']['requestBody']['content']['application/json'];
-export type AntennasUpdateResponse = operations['antennas/update']['responses']['200']['content']['application/json'];
-export type ApGetRequest = operations['ap/get']['requestBody']['content']['application/json'];
-export type ApGetResponse = operations['ap/get']['responses']['200']['content']['application/json'];
-export type ApShowRequest = operations['ap/show']['requestBody']['content']['application/json'];
-export type ApShowResponse = operations['ap/show']['responses']['200']['content']['application/json'];
-export type AppCreateRequest = operations['app/create']['requestBody']['content']['application/json'];
-export type AppCreateResponse = operations['app/create']['responses']['200']['content']['application/json'];
-export type AppShowRequest = operations['app/show']['requestBody']['content']['application/json'];
-export type AppShowResponse = operations['app/show']['responses']['200']['content']['application/json'];
-export type AuthAcceptRequest = operations['auth/accept']['requestBody']['content']['application/json'];
-export type AuthSessionGenerateRequest = operations['auth/session/generate']['requestBody']['content']['application/json'];
-export type AuthSessionGenerateResponse = operations['auth/session/generate']['responses']['200']['content']['application/json'];
-export type AuthSessionShowRequest = operations['auth/session/show']['requestBody']['content']['application/json'];
-export type AuthSessionShowResponse = operations['auth/session/show']['responses']['200']['content']['application/json'];
-export type AuthSessionUserkeyRequest = operations['auth/session/userkey']['requestBody']['content']['application/json'];
-export type AuthSessionUserkeyResponse = operations['auth/session/userkey']['responses']['200']['content']['application/json'];
-export type BlockingCreateRequest = operations['blocking/create']['requestBody']['content']['application/json'];
-export type BlockingCreateResponse = operations['blocking/create']['responses']['200']['content']['application/json'];
-export type BlockingDeleteRequest = operations['blocking/delete']['requestBody']['content']['application/json'];
-export type BlockingDeleteResponse = operations['blocking/delete']['responses']['200']['content']['application/json'];
-export type BlockingListRequest = operations['blocking/list']['requestBody']['content']['application/json'];
-export type BlockingListResponse = operations['blocking/list']['responses']['200']['content']['application/json'];
-export type ChannelsCreateRequest = operations['channels/create']['requestBody']['content']['application/json'];
-export type ChannelsCreateResponse = operations['channels/create']['responses']['200']['content']['application/json'];
-export type ChannelsFeaturedResponse = operations['channels/featured']['responses']['200']['content']['application/json'];
-export type ChannelsFollowRequest = operations['channels/follow']['requestBody']['content']['application/json'];
-export type ChannelsFollowedRequest = operations['channels/followed']['requestBody']['content']['application/json'];
-export type ChannelsFollowedResponse = operations['channels/followed']['responses']['200']['content']['application/json'];
-export type ChannelsOwnedRequest = operations['channels/owned']['requestBody']['content']['application/json'];
-export type ChannelsOwnedResponse = operations['channels/owned']['responses']['200']['content']['application/json'];
-export type ChannelsShowRequest = operations['channels/show']['requestBody']['content']['application/json'];
-export type ChannelsShowResponse = operations['channels/show']['responses']['200']['content']['application/json'];
-export type ChannelsTimelineRequest = operations['channels/timeline']['requestBody']['content']['application/json'];
-export type ChannelsTimelineResponse = operations['channels/timeline']['responses']['200']['content']['application/json'];
-export type ChannelsUnfollowRequest = operations['channels/unfollow']['requestBody']['content']['application/json'];
-export type ChannelsUpdateRequest = operations['channels/update']['requestBody']['content']['application/json'];
-export type ChannelsUpdateResponse = operations['channels/update']['responses']['200']['content']['application/json'];
-export type ChannelsFavoriteRequest = operations['channels/favorite']['requestBody']['content']['application/json'];
-export type ChannelsUnfavoriteRequest = operations['channels/unfavorite']['requestBody']['content']['application/json'];
-export type ChannelsMyFavoritesResponse = operations['channels/my-favorites']['responses']['200']['content']['application/json'];
-export type ChannelsSearchRequest = operations['channels/search']['requestBody']['content']['application/json'];
-export type ChannelsSearchResponse = operations['channels/search']['responses']['200']['content']['application/json'];
-export type ChartsActiveUsersRequest = operations['charts/active-users']['requestBody']['content']['application/json'];
-export type ChartsActiveUsersResponse = operations['charts/active-users']['responses']['200']['content']['application/json'];
-export type ChartsApRequestRequest = operations['charts/ap-request']['requestBody']['content']['application/json'];
-export type ChartsApRequestResponse = operations['charts/ap-request']['responses']['200']['content']['application/json'];
-export type ChartsDriveRequest = operations['charts/drive']['requestBody']['content']['application/json'];
-export type ChartsDriveResponse = operations['charts/drive']['responses']['200']['content']['application/json'];
-export type ChartsFederationRequest = operations['charts/federation']['requestBody']['content']['application/json'];
-export type ChartsFederationResponse = operations['charts/federation']['responses']['200']['content']['application/json'];
-export type ChartsInstanceRequest = operations['charts/instance']['requestBody']['content']['application/json'];
-export type ChartsInstanceResponse = operations['charts/instance']['responses']['200']['content']['application/json'];
-export type ChartsNotesRequest = operations['charts/notes']['requestBody']['content']['application/json'];
-export type ChartsNotesResponse = operations['charts/notes']['responses']['200']['content']['application/json'];
-export type ChartsUserDriveRequest = operations['charts/user/drive']['requestBody']['content']['application/json'];
-export type ChartsUserDriveResponse = operations['charts/user/drive']['responses']['200']['content']['application/json'];
-export type ChartsUserFollowingRequest = operations['charts/user/following']['requestBody']['content']['application/json'];
-export type ChartsUserFollowingResponse = operations['charts/user/following']['responses']['200']['content']['application/json'];
-export type ChartsUserNotesRequest = operations['charts/user/notes']['requestBody']['content']['application/json'];
-export type ChartsUserNotesResponse = operations['charts/user/notes']['responses']['200']['content']['application/json'];
-export type ChartsUserPvRequest = operations['charts/user/pv']['requestBody']['content']['application/json'];
-export type ChartsUserPvResponse = operations['charts/user/pv']['responses']['200']['content']['application/json'];
-export type ChartsUserReactionsRequest = operations['charts/user/reactions']['requestBody']['content']['application/json'];
-export type ChartsUserReactionsResponse = operations['charts/user/reactions']['responses']['200']['content']['application/json'];
-export type ChartsUsersRequest = operations['charts/users']['requestBody']['content']['application/json'];
-export type ChartsUsersResponse = operations['charts/users']['responses']['200']['content']['application/json'];
-export type ClipsAddNoteRequest = operations['clips/add-note']['requestBody']['content']['application/json'];
-export type ClipsRemoveNoteRequest = operations['clips/remove-note']['requestBody']['content']['application/json'];
-export type ClipsCreateRequest = operations['clips/create']['requestBody']['content']['application/json'];
-export type ClipsCreateResponse = operations['clips/create']['responses']['200']['content']['application/json'];
-export type ClipsDeleteRequest = operations['clips/delete']['requestBody']['content']['application/json'];
-export type ClipsListResponse = operations['clips/list']['responses']['200']['content']['application/json'];
-export type ClipsNotesRequest = operations['clips/notes']['requestBody']['content']['application/json'];
-export type ClipsNotesResponse = operations['clips/notes']['responses']['200']['content']['application/json'];
-export type ClipsShowRequest = operations['clips/show']['requestBody']['content']['application/json'];
-export type ClipsShowResponse = operations['clips/show']['responses']['200']['content']['application/json'];
-export type ClipsUpdateRequest = operations['clips/update']['requestBody']['content']['application/json'];
-export type ClipsUpdateResponse = operations['clips/update']['responses']['200']['content']['application/json'];
-export type ClipsFavoriteRequest = operations['clips/favorite']['requestBody']['content']['application/json'];
-export type ClipsUnfavoriteRequest = operations['clips/unfavorite']['requestBody']['content']['application/json'];
-export type ClipsMyFavoritesResponse = operations['clips/my-favorites']['responses']['200']['content']['application/json'];
+export type AntennasCreateRequest = operations['antennas___create']['requestBody']['content']['application/json'];
+export type AntennasCreateResponse = operations['antennas___create']['responses']['200']['content']['application/json'];
+export type AntennasDeleteRequest = operations['antennas___delete']['requestBody']['content']['application/json'];
+export type AntennasListResponse = operations['antennas___list']['responses']['200']['content']['application/json'];
+export type AntennasNotesRequest = operations['antennas___notes']['requestBody']['content']['application/json'];
+export type AntennasNotesResponse = operations['antennas___notes']['responses']['200']['content']['application/json'];
+export type AntennasShowRequest = operations['antennas___show']['requestBody']['content']['application/json'];
+export type AntennasShowResponse = operations['antennas___show']['responses']['200']['content']['application/json'];
+export type AntennasUpdateRequest = operations['antennas___update']['requestBody']['content']['application/json'];
+export type AntennasUpdateResponse = operations['antennas___update']['responses']['200']['content']['application/json'];
+export type ApGetRequest = operations['ap___get']['requestBody']['content']['application/json'];
+export type ApGetResponse = operations['ap___get']['responses']['200']['content']['application/json'];
+export type ApShowRequest = operations['ap___show']['requestBody']['content']['application/json'];
+export type ApShowResponse = operations['ap___show']['responses']['200']['content']['application/json'];
+export type AppCreateRequest = operations['app___create']['requestBody']['content']['application/json'];
+export type AppCreateResponse = operations['app___create']['responses']['200']['content']['application/json'];
+export type AppShowRequest = operations['app___show']['requestBody']['content']['application/json'];
+export type AppShowResponse = operations['app___show']['responses']['200']['content']['application/json'];
+export type AuthAcceptRequest = operations['auth___accept']['requestBody']['content']['application/json'];
+export type AuthSessionGenerateRequest = operations['auth___session___generate']['requestBody']['content']['application/json'];
+export type AuthSessionGenerateResponse = operations['auth___session___generate']['responses']['200']['content']['application/json'];
+export type AuthSessionShowRequest = operations['auth___session___show']['requestBody']['content']['application/json'];
+export type AuthSessionShowResponse = operations['auth___session___show']['responses']['200']['content']['application/json'];
+export type AuthSessionUserkeyRequest = operations['auth___session___userkey']['requestBody']['content']['application/json'];
+export type AuthSessionUserkeyResponse = operations['auth___session___userkey']['responses']['200']['content']['application/json'];
+export type BlockingCreateRequest = operations['blocking___create']['requestBody']['content']['application/json'];
+export type BlockingCreateResponse = operations['blocking___create']['responses']['200']['content']['application/json'];
+export type BlockingDeleteRequest = operations['blocking___delete']['requestBody']['content']['application/json'];
+export type BlockingDeleteResponse = operations['blocking___delete']['responses']['200']['content']['application/json'];
+export type BlockingListRequest = operations['blocking___list']['requestBody']['content']['application/json'];
+export type BlockingListResponse = operations['blocking___list']['responses']['200']['content']['application/json'];
+export type ChannelsCreateRequest = operations['channels___create']['requestBody']['content']['application/json'];
+export type ChannelsCreateResponse = operations['channels___create']['responses']['200']['content']['application/json'];
+export type ChannelsFeaturedResponse = operations['channels___featured']['responses']['200']['content']['application/json'];
+export type ChannelsFollowRequest = operations['channels___follow']['requestBody']['content']['application/json'];
+export type ChannelsFollowedRequest = operations['channels___followed']['requestBody']['content']['application/json'];
+export type ChannelsFollowedResponse = operations['channels___followed']['responses']['200']['content']['application/json'];
+export type ChannelsOwnedRequest = operations['channels___owned']['requestBody']['content']['application/json'];
+export type ChannelsOwnedResponse = operations['channels___owned']['responses']['200']['content']['application/json'];
+export type ChannelsShowRequest = operations['channels___show']['requestBody']['content']['application/json'];
+export type ChannelsShowResponse = operations['channels___show']['responses']['200']['content']['application/json'];
+export type ChannelsTimelineRequest = operations['channels___timeline']['requestBody']['content']['application/json'];
+export type ChannelsTimelineResponse = operations['channels___timeline']['responses']['200']['content']['application/json'];
+export type ChannelsUnfollowRequest = operations['channels___unfollow']['requestBody']['content']['application/json'];
+export type ChannelsUpdateRequest = operations['channels___update']['requestBody']['content']['application/json'];
+export type ChannelsUpdateResponse = operations['channels___update']['responses']['200']['content']['application/json'];
+export type ChannelsFavoriteRequest = operations['channels___favorite']['requestBody']['content']['application/json'];
+export type ChannelsUnfavoriteRequest = operations['channels___unfavorite']['requestBody']['content']['application/json'];
+export type ChannelsMyFavoritesResponse = operations['channels___my-favorites']['responses']['200']['content']['application/json'];
+export type ChannelsSearchRequest = operations['channels___search']['requestBody']['content']['application/json'];
+export type ChannelsSearchResponse = operations['channels___search']['responses']['200']['content']['application/json'];
+export type ChartsActiveUsersRequest = operations['charts___active-users']['requestBody']['content']['application/json'];
+export type ChartsActiveUsersResponse = operations['charts___active-users']['responses']['200']['content']['application/json'];
+export type ChartsApRequestRequest = operations['charts___ap-request']['requestBody']['content']['application/json'];
+export type ChartsApRequestResponse = operations['charts___ap-request']['responses']['200']['content']['application/json'];
+export type ChartsDriveRequest = operations['charts___drive']['requestBody']['content']['application/json'];
+export type ChartsDriveResponse = operations['charts___drive']['responses']['200']['content']['application/json'];
+export type ChartsFederationRequest = operations['charts___federation']['requestBody']['content']['application/json'];
+export type ChartsFederationResponse = operations['charts___federation']['responses']['200']['content']['application/json'];
+export type ChartsInstanceRequest = operations['charts___instance']['requestBody']['content']['application/json'];
+export type ChartsInstanceResponse = operations['charts___instance']['responses']['200']['content']['application/json'];
+export type ChartsNotesRequest = operations['charts___notes']['requestBody']['content']['application/json'];
+export type ChartsNotesResponse = operations['charts___notes']['responses']['200']['content']['application/json'];
+export type ChartsUserDriveRequest = operations['charts___user___drive']['requestBody']['content']['application/json'];
+export type ChartsUserDriveResponse = operations['charts___user___drive']['responses']['200']['content']['application/json'];
+export type ChartsUserFollowingRequest = operations['charts___user___following']['requestBody']['content']['application/json'];
+export type ChartsUserFollowingResponse = operations['charts___user___following']['responses']['200']['content']['application/json'];
+export type ChartsUserNotesRequest = operations['charts___user___notes']['requestBody']['content']['application/json'];
+export type ChartsUserNotesResponse = operations['charts___user___notes']['responses']['200']['content']['application/json'];
+export type ChartsUserPvRequest = operations['charts___user___pv']['requestBody']['content']['application/json'];
+export type ChartsUserPvResponse = operations['charts___user___pv']['responses']['200']['content']['application/json'];
+export type ChartsUserReactionsRequest = operations['charts___user___reactions']['requestBody']['content']['application/json'];
+export type ChartsUserReactionsResponse = operations['charts___user___reactions']['responses']['200']['content']['application/json'];
+export type ChartsUsersRequest = operations['charts___users']['requestBody']['content']['application/json'];
+export type ChartsUsersResponse = operations['charts___users']['responses']['200']['content']['application/json'];
+export type ClipsAddNoteRequest = operations['clips___add-note']['requestBody']['content']['application/json'];
+export type ClipsRemoveNoteRequest = operations['clips___remove-note']['requestBody']['content']['application/json'];
+export type ClipsCreateRequest = operations['clips___create']['requestBody']['content']['application/json'];
+export type ClipsCreateResponse = operations['clips___create']['responses']['200']['content']['application/json'];
+export type ClipsDeleteRequest = operations['clips___delete']['requestBody']['content']['application/json'];
+export type ClipsListResponse = operations['clips___list']['responses']['200']['content']['application/json'];
+export type ClipsNotesRequest = operations['clips___notes']['requestBody']['content']['application/json'];
+export type ClipsNotesResponse = operations['clips___notes']['responses']['200']['content']['application/json'];
+export type ClipsShowRequest = operations['clips___show']['requestBody']['content']['application/json'];
+export type ClipsShowResponse = operations['clips___show']['responses']['200']['content']['application/json'];
+export type ClipsUpdateRequest = operations['clips___update']['requestBody']['content']['application/json'];
+export type ClipsUpdateResponse = operations['clips___update']['responses']['200']['content']['application/json'];
+export type ClipsFavoriteRequest = operations['clips___favorite']['requestBody']['content']['application/json'];
+export type ClipsUnfavoriteRequest = operations['clips___unfavorite']['requestBody']['content']['application/json'];
+export type ClipsMyFavoritesResponse = operations['clips___my-favorites']['responses']['200']['content']['application/json'];
 export type DriveResponse = operations['drive']['responses']['200']['content']['application/json'];
-export type DriveFilesRequest = operations['drive/files']['requestBody']['content']['application/json'];
-export type DriveFilesResponse = operations['drive/files']['responses']['200']['content']['application/json'];
-export type DriveFilesAttachedNotesRequest = operations['drive/files/attached-notes']['requestBody']['content']['application/json'];
-export type DriveFilesAttachedNotesResponse = operations['drive/files/attached-notes']['responses']['200']['content']['application/json'];
-export type DriveFilesCheckExistenceRequest = operations['drive/files/check-existence']['requestBody']['content']['application/json'];
-export type DriveFilesCheckExistenceResponse = operations['drive/files/check-existence']['responses']['200']['content']['application/json'];
-export type DriveFilesCreateRequest = operations['drive/files/create']['requestBody']['content']['multipart/form-data'];
-export type DriveFilesCreateResponse = operations['drive/files/create']['responses']['200']['content']['application/json'];
-export type DriveFilesDeleteRequest = operations['drive/files/delete']['requestBody']['content']['application/json'];
-export type DriveFilesFindByHashRequest = operations['drive/files/find-by-hash']['requestBody']['content']['application/json'];
-export type DriveFilesFindByHashResponse = operations['drive/files/find-by-hash']['responses']['200']['content']['application/json'];
-export type DriveFilesFindRequest = operations['drive/files/find']['requestBody']['content']['application/json'];
-export type DriveFilesFindResponse = operations['drive/files/find']['responses']['200']['content']['application/json'];
-export type DriveFilesShowRequest = operations['drive/files/show']['requestBody']['content']['application/json'];
-export type DriveFilesShowResponse = operations['drive/files/show']['responses']['200']['content']['application/json'];
-export type DriveFilesUpdateRequest = operations['drive/files/update']['requestBody']['content']['application/json'];
-export type DriveFilesUpdateResponse = operations['drive/files/update']['responses']['200']['content']['application/json'];
-export type DriveFilesUploadFromUrlRequest = operations['drive/files/upload-from-url']['requestBody']['content']['application/json'];
-export type DriveFoldersRequest = operations['drive/folders']['requestBody']['content']['application/json'];
-export type DriveFoldersResponse = operations['drive/folders']['responses']['200']['content']['application/json'];
-export type DriveFoldersCreateRequest = operations['drive/folders/create']['requestBody']['content']['application/json'];
-export type DriveFoldersCreateResponse = operations['drive/folders/create']['responses']['200']['content']['application/json'];
-export type DriveFoldersDeleteRequest = operations['drive/folders/delete']['requestBody']['content']['application/json'];
-export type DriveFoldersFindRequest = operations['drive/folders/find']['requestBody']['content']['application/json'];
-export type DriveFoldersFindResponse = operations['drive/folders/find']['responses']['200']['content']['application/json'];
-export type DriveFoldersShowRequest = operations['drive/folders/show']['requestBody']['content']['application/json'];
-export type DriveFoldersShowResponse = operations['drive/folders/show']['responses']['200']['content']['application/json'];
-export type DriveFoldersUpdateRequest = operations['drive/folders/update']['requestBody']['content']['application/json'];
-export type DriveFoldersUpdateResponse = operations['drive/folders/update']['responses']['200']['content']['application/json'];
-export type DriveStreamRequest = operations['drive/stream']['requestBody']['content']['application/json'];
-export type DriveStreamResponse = operations['drive/stream']['responses']['200']['content']['application/json'];
-export type EmailAddressAvailableRequest = operations['email-address/available']['requestBody']['content']['application/json'];
-export type EmailAddressAvailableResponse = operations['email-address/available']['responses']['200']['content']['application/json'];
+export type DriveFilesRequest = operations['drive___files']['requestBody']['content']['application/json'];
+export type DriveFilesResponse = operations['drive___files']['responses']['200']['content']['application/json'];
+export type DriveFilesAttachedNotesRequest = operations['drive___files___attached-notes']['requestBody']['content']['application/json'];
+export type DriveFilesAttachedNotesResponse = operations['drive___files___attached-notes']['responses']['200']['content']['application/json'];
+export type DriveFilesCheckExistenceRequest = operations['drive___files___check-existence']['requestBody']['content']['application/json'];
+export type DriveFilesCheckExistenceResponse = operations['drive___files___check-existence']['responses']['200']['content']['application/json'];
+export type DriveFilesCreateRequest = operations['drive___files___create']['requestBody']['content']['multipart/form-data'];
+export type DriveFilesCreateResponse = operations['drive___files___create']['responses']['200']['content']['application/json'];
+export type DriveFilesDeleteRequest = operations['drive___files___delete']['requestBody']['content']['application/json'];
+export type DriveFilesFindByHashRequest = operations['drive___files___find-by-hash']['requestBody']['content']['application/json'];
+export type DriveFilesFindByHashResponse = operations['drive___files___find-by-hash']['responses']['200']['content']['application/json'];
+export type DriveFilesFindRequest = operations['drive___files___find']['requestBody']['content']['application/json'];
+export type DriveFilesFindResponse = operations['drive___files___find']['responses']['200']['content']['application/json'];
+export type DriveFilesShowRequest = operations['drive___files___show']['requestBody']['content']['application/json'];
+export type DriveFilesShowResponse = operations['drive___files___show']['responses']['200']['content']['application/json'];
+export type DriveFilesUpdateRequest = operations['drive___files___update']['requestBody']['content']['application/json'];
+export type DriveFilesUpdateResponse = operations['drive___files___update']['responses']['200']['content']['application/json'];
+export type DriveFilesUploadFromUrlRequest = operations['drive___files___upload-from-url']['requestBody']['content']['application/json'];
+export type DriveFoldersRequest = operations['drive___folders']['requestBody']['content']['application/json'];
+export type DriveFoldersResponse = operations['drive___folders']['responses']['200']['content']['application/json'];
+export type DriveFoldersCreateRequest = operations['drive___folders___create']['requestBody']['content']['application/json'];
+export type DriveFoldersCreateResponse = operations['drive___folders___create']['responses']['200']['content']['application/json'];
+export type DriveFoldersDeleteRequest = operations['drive___folders___delete']['requestBody']['content']['application/json'];
+export type DriveFoldersFindRequest = operations['drive___folders___find']['requestBody']['content']['application/json'];
+export type DriveFoldersFindResponse = operations['drive___folders___find']['responses']['200']['content']['application/json'];
+export type DriveFoldersShowRequest = operations['drive___folders___show']['requestBody']['content']['application/json'];
+export type DriveFoldersShowResponse = operations['drive___folders___show']['responses']['200']['content']['application/json'];
+export type DriveFoldersUpdateRequest = operations['drive___folders___update']['requestBody']['content']['application/json'];
+export type DriveFoldersUpdateResponse = operations['drive___folders___update']['responses']['200']['content']['application/json'];
+export type DriveStreamRequest = operations['drive___stream']['requestBody']['content']['application/json'];
+export type DriveStreamResponse = operations['drive___stream']['responses']['200']['content']['application/json'];
+export type EmailAddressAvailableRequest = operations['email-address___available']['requestBody']['content']['application/json'];
+export type EmailAddressAvailableResponse = operations['email-address___available']['responses']['200']['content']['application/json'];
 export type EndpointRequest = operations['endpoint']['requestBody']['content']['application/json'];
 export type EndpointResponse = operations['endpoint']['responses']['200']['content']['application/json'];
 export type EndpointsResponse = operations['endpoints']['responses']['200']['content']['application/json'];
-export type FederationFollowersRequest = operations['federation/followers']['requestBody']['content']['application/json'];
-export type FederationFollowersResponse = operations['federation/followers']['responses']['200']['content']['application/json'];
-export type FederationFollowingRequest = operations['federation/following']['requestBody']['content']['application/json'];
-export type FederationFollowingResponse = operations['federation/following']['responses']['200']['content']['application/json'];
-export type FederationInstancesRequest = operations['federation/instances']['requestBody']['content']['application/json'];
-export type FederationInstancesResponse = operations['federation/instances']['responses']['200']['content']['application/json'];
-export type FederationShowInstanceRequest = operations['federation/show-instance']['requestBody']['content']['application/json'];
-export type FederationShowInstanceResponse = operations['federation/show-instance']['responses']['200']['content']['application/json'];
-export type FederationUpdateRemoteUserRequest = operations['federation/update-remote-user']['requestBody']['content']['application/json'];
-export type FederationUsersRequest = operations['federation/users']['requestBody']['content']['application/json'];
-export type FederationUsersResponse = operations['federation/users']['responses']['200']['content']['application/json'];
-export type FederationStatsRequest = operations['federation/stats']['requestBody']['content']['application/json'];
-export type FederationStatsResponse = operations['federation/stats']['responses']['200']['content']['application/json'];
-export type FollowingCreateRequest = operations['following/create']['requestBody']['content']['application/json'];
-export type FollowingCreateResponse = operations['following/create']['responses']['200']['content']['application/json'];
-export type FollowingDeleteRequest = operations['following/delete']['requestBody']['content']['application/json'];
-export type FollowingDeleteResponse = operations['following/delete']['responses']['200']['content']['application/json'];
-export type FollowingUpdateRequest = operations['following/update']['requestBody']['content']['application/json'];
-export type FollowingUpdateResponse = operations['following/update']['responses']['200']['content']['application/json'];
-export type FollowingUpdateAllRequest = operations['following/update-all']['requestBody']['content']['application/json'];
-export type FollowingInvalidateRequest = operations['following/invalidate']['requestBody']['content']['application/json'];
-export type FollowingInvalidateResponse = operations['following/invalidate']['responses']['200']['content']['application/json'];
-export type FollowingRequestsAcceptRequest = operations['following/requests/accept']['requestBody']['content']['application/json'];
-export type FollowingRequestsCancelRequest = operations['following/requests/cancel']['requestBody']['content']['application/json'];
-export type FollowingRequestsCancelResponse = operations['following/requests/cancel']['responses']['200']['content']['application/json'];
-export type FollowingRequestsListRequest = operations['following/requests/list']['requestBody']['content']['application/json'];
-export type FollowingRequestsListResponse = operations['following/requests/list']['responses']['200']['content']['application/json'];
-export type FollowingRequestsRejectRequest = operations['following/requests/reject']['requestBody']['content']['application/json'];
-export type GalleryFeaturedRequest = operations['gallery/featured']['requestBody']['content']['application/json'];
-export type GalleryFeaturedResponse = operations['gallery/featured']['responses']['200']['content']['application/json'];
-export type GalleryPopularResponse = operations['gallery/popular']['responses']['200']['content']['application/json'];
-export type GalleryPostsRequest = operations['gallery/posts']['requestBody']['content']['application/json'];
-export type GalleryPostsResponse = operations['gallery/posts']['responses']['200']['content']['application/json'];
-export type GalleryPostsCreateRequest = operations['gallery/posts/create']['requestBody']['content']['application/json'];
-export type GalleryPostsCreateResponse = operations['gallery/posts/create']['responses']['200']['content']['application/json'];
-export type GalleryPostsDeleteRequest = operations['gallery/posts/delete']['requestBody']['content']['application/json'];
-export type GalleryPostsLikeRequest = operations['gallery/posts/like']['requestBody']['content']['application/json'];
-export type GalleryPostsShowRequest = operations['gallery/posts/show']['requestBody']['content']['application/json'];
-export type GalleryPostsShowResponse = operations['gallery/posts/show']['responses']['200']['content']['application/json'];
-export type GalleryPostsUnlikeRequest = operations['gallery/posts/unlike']['requestBody']['content']['application/json'];
-export type GalleryPostsUpdateRequest = operations['gallery/posts/update']['requestBody']['content']['application/json'];
-export type GalleryPostsUpdateResponse = operations['gallery/posts/update']['responses']['200']['content']['application/json'];
+export type FederationFollowersRequest = operations['federation___followers']['requestBody']['content']['application/json'];
+export type FederationFollowersResponse = operations['federation___followers']['responses']['200']['content']['application/json'];
+export type FederationFollowingRequest = operations['federation___following']['requestBody']['content']['application/json'];
+export type FederationFollowingResponse = operations['federation___following']['responses']['200']['content']['application/json'];
+export type FederationInstancesRequest = operations['federation___instances']['requestBody']['content']['application/json'];
+export type FederationInstancesResponse = operations['federation___instances']['responses']['200']['content']['application/json'];
+export type FederationShowInstanceRequest = operations['federation___show-instance']['requestBody']['content']['application/json'];
+export type FederationShowInstanceResponse = operations['federation___show-instance']['responses']['200']['content']['application/json'];
+export type FederationUpdateRemoteUserRequest = operations['federation___update-remote-user']['requestBody']['content']['application/json'];
+export type FederationUsersRequest = operations['federation___users']['requestBody']['content']['application/json'];
+export type FederationUsersResponse = operations['federation___users']['responses']['200']['content']['application/json'];
+export type FederationStatsRequest = operations['federation___stats']['requestBody']['content']['application/json'];
+export type FederationStatsResponse = operations['federation___stats']['responses']['200']['content']['application/json'];
+export type FollowingCreateRequest = operations['following___create']['requestBody']['content']['application/json'];
+export type FollowingCreateResponse = operations['following___create']['responses']['200']['content']['application/json'];
+export type FollowingDeleteRequest = operations['following___delete']['requestBody']['content']['application/json'];
+export type FollowingDeleteResponse = operations['following___delete']['responses']['200']['content']['application/json'];
+export type FollowingUpdateRequest = operations['following___update']['requestBody']['content']['application/json'];
+export type FollowingUpdateResponse = operations['following___update']['responses']['200']['content']['application/json'];
+export type FollowingUpdateAllRequest = operations['following___update-all']['requestBody']['content']['application/json'];
+export type FollowingInvalidateRequest = operations['following___invalidate']['requestBody']['content']['application/json'];
+export type FollowingInvalidateResponse = operations['following___invalidate']['responses']['200']['content']['application/json'];
+export type FollowingRequestsAcceptRequest = operations['following___requests___accept']['requestBody']['content']['application/json'];
+export type FollowingRequestsCancelRequest = operations['following___requests___cancel']['requestBody']['content']['application/json'];
+export type FollowingRequestsCancelResponse = operations['following___requests___cancel']['responses']['200']['content']['application/json'];
+export type FollowingRequestsListRequest = operations['following___requests___list']['requestBody']['content']['application/json'];
+export type FollowingRequestsListResponse = operations['following___requests___list']['responses']['200']['content']['application/json'];
+export type FollowingRequestsRejectRequest = operations['following___requests___reject']['requestBody']['content']['application/json'];
+export type GalleryFeaturedRequest = operations['gallery___featured']['requestBody']['content']['application/json'];
+export type GalleryFeaturedResponse = operations['gallery___featured']['responses']['200']['content']['application/json'];
+export type GalleryPopularResponse = operations['gallery___popular']['responses']['200']['content']['application/json'];
+export type GalleryPostsRequest = operations['gallery___posts']['requestBody']['content']['application/json'];
+export type GalleryPostsResponse = operations['gallery___posts']['responses']['200']['content']['application/json'];
+export type GalleryPostsCreateRequest = operations['gallery___posts___create']['requestBody']['content']['application/json'];
+export type GalleryPostsCreateResponse = operations['gallery___posts___create']['responses']['200']['content']['application/json'];
+export type GalleryPostsDeleteRequest = operations['gallery___posts___delete']['requestBody']['content']['application/json'];
+export type GalleryPostsLikeRequest = operations['gallery___posts___like']['requestBody']['content']['application/json'];
+export type GalleryPostsShowRequest = operations['gallery___posts___show']['requestBody']['content']['application/json'];
+export type GalleryPostsShowResponse = operations['gallery___posts___show']['responses']['200']['content']['application/json'];
+export type GalleryPostsUnlikeRequest = operations['gallery___posts___unlike']['requestBody']['content']['application/json'];
+export type GalleryPostsUpdateRequest = operations['gallery___posts___update']['requestBody']['content']['application/json'];
+export type GalleryPostsUpdateResponse = operations['gallery___posts___update']['responses']['200']['content']['application/json'];
 export type GetOnlineUsersCountResponse = operations['get-online-users-count']['responses']['200']['content']['application/json'];
 export type GetAvatarDecorationsResponse = operations['get-avatar-decorations']['responses']['200']['content']['application/json'];
-export type HashtagsListRequest = operations['hashtags/list']['requestBody']['content']['application/json'];
-export type HashtagsListResponse = operations['hashtags/list']['responses']['200']['content']['application/json'];
-export type HashtagsSearchRequest = operations['hashtags/search']['requestBody']['content']['application/json'];
-export type HashtagsSearchResponse = operations['hashtags/search']['responses']['200']['content']['application/json'];
-export type HashtagsShowRequest = operations['hashtags/show']['requestBody']['content']['application/json'];
-export type HashtagsShowResponse = operations['hashtags/show']['responses']['200']['content']['application/json'];
-export type HashtagsTrendResponse = operations['hashtags/trend']['responses']['200']['content']['application/json'];
-export type HashtagsUsersRequest = operations['hashtags/users']['requestBody']['content']['application/json'];
-export type HashtagsUsersResponse = operations['hashtags/users']['responses']['200']['content']['application/json'];
+export type HashtagsListRequest = operations['hashtags___list']['requestBody']['content']['application/json'];
+export type HashtagsListResponse = operations['hashtags___list']['responses']['200']['content']['application/json'];
+export type HashtagsSearchRequest = operations['hashtags___search']['requestBody']['content']['application/json'];
+export type HashtagsSearchResponse = operations['hashtags___search']['responses']['200']['content']['application/json'];
+export type HashtagsShowRequest = operations['hashtags___show']['requestBody']['content']['application/json'];
+export type HashtagsShowResponse = operations['hashtags___show']['responses']['200']['content']['application/json'];
+export type HashtagsTrendResponse = operations['hashtags___trend']['responses']['200']['content']['application/json'];
+export type HashtagsUsersRequest = operations['hashtags___users']['requestBody']['content']['application/json'];
+export type HashtagsUsersResponse = operations['hashtags___users']['responses']['200']['content']['application/json'];
 export type IResponse = operations['i']['responses']['200']['content']['application/json'];
-export type I2faDoneRequest = operations['i/2fa/done']['requestBody']['content']['application/json'];
-export type I2faDoneResponse = operations['i/2fa/done']['responses']['200']['content']['application/json'];
-export type I2faKeyDoneRequest = operations['i/2fa/key-done']['requestBody']['content']['application/json'];
-export type I2faKeyDoneResponse = operations['i/2fa/key-done']['responses']['200']['content']['application/json'];
-export type I2faPasswordLessRequest = operations['i/2fa/password-less']['requestBody']['content']['application/json'];
-export type I2faRegisterKeyRequest = operations['i/2fa/register-key']['requestBody']['content']['application/json'];
-export type I2faRegisterKeyResponse = operations['i/2fa/register-key']['responses']['200']['content']['application/json'];
-export type I2faRegisterRequest = operations['i/2fa/register']['requestBody']['content']['application/json'];
-export type I2faRegisterResponse = operations['i/2fa/register']['responses']['200']['content']['application/json'];
-export type I2faUpdateKeyRequest = operations['i/2fa/update-key']['requestBody']['content']['application/json'];
-export type I2faRemoveKeyRequest = operations['i/2fa/remove-key']['requestBody']['content']['application/json'];
-export type I2faUnregisterRequest = operations['i/2fa/unregister']['requestBody']['content']['application/json'];
-export type IAppsRequest = operations['i/apps']['requestBody']['content']['application/json'];
-export type IAppsResponse = operations['i/apps']['responses']['200']['content']['application/json'];
-export type IAuthorizedAppsRequest = operations['i/authorized-apps']['requestBody']['content']['application/json'];
-export type IAuthorizedAppsResponse = operations['i/authorized-apps']['responses']['200']['content']['application/json'];
-export type IClaimAchievementRequest = operations['i/claim-achievement']['requestBody']['content']['application/json'];
-export type IChangePasswordRequest = operations['i/change-password']['requestBody']['content']['application/json'];
-export type IDeleteAccountRequest = operations['i/delete-account']['requestBody']['content']['application/json'];
-export type IExportFollowingRequest = operations['i/export-following']['requestBody']['content']['application/json'];
-export type IFavoritesRequest = operations['i/favorites']['requestBody']['content']['application/json'];
-export type IFavoritesResponse = operations['i/favorites']['responses']['200']['content']['application/json'];
-export type IGalleryLikesRequest = operations['i/gallery/likes']['requestBody']['content']['application/json'];
-export type IGalleryLikesResponse = operations['i/gallery/likes']['responses']['200']['content']['application/json'];
-export type IGalleryPostsRequest = operations['i/gallery/posts']['requestBody']['content']['application/json'];
-export type IGalleryPostsResponse = operations['i/gallery/posts']['responses']['200']['content']['application/json'];
-export type IImportBlockingRequest = operations['i/import-blocking']['requestBody']['content']['application/json'];
-export type IImportFollowingRequest = operations['i/import-following']['requestBody']['content']['application/json'];
-export type IImportMutingRequest = operations['i/import-muting']['requestBody']['content']['application/json'];
-export type IImportUserListsRequest = operations['i/import-user-lists']['requestBody']['content']['application/json'];
-export type IImportAntennasRequest = operations['i/import-antennas']['requestBody']['content']['application/json'];
-export type INotificationsRequest = operations['i/notifications']['requestBody']['content']['application/json'];
-export type INotificationsResponse = operations['i/notifications']['responses']['200']['content']['application/json'];
-export type INotificationsGroupedRequest = operations['i/notifications-grouped']['requestBody']['content']['application/json'];
-export type INotificationsGroupedResponse = operations['i/notifications-grouped']['responses']['200']['content']['application/json'];
-export type IPageLikesRequest = operations['i/page-likes']['requestBody']['content']['application/json'];
-export type IPageLikesResponse = operations['i/page-likes']['responses']['200']['content']['application/json'];
-export type IPagesRequest = operations['i/pages']['requestBody']['content']['application/json'];
-export type IPagesResponse = operations['i/pages']['responses']['200']['content']['application/json'];
-export type IPinRequest = operations['i/pin']['requestBody']['content']['application/json'];
-export type IPinResponse = operations['i/pin']['responses']['200']['content']['application/json'];
-export type IReadAnnouncementRequest = operations['i/read-announcement']['requestBody']['content']['application/json'];
-export type IRegenerateTokenRequest = operations['i/regenerate-token']['requestBody']['content']['application/json'];
-export type IRegistryGetAllRequest = operations['i/registry/get-all']['requestBody']['content']['application/json'];
-export type IRegistryGetAllResponse = operations['i/registry/get-all']['responses']['200']['content']['application/json'];
-export type IRegistryGetDetailRequest = operations['i/registry/get-detail']['requestBody']['content']['application/json'];
-export type IRegistryGetDetailResponse = operations['i/registry/get-detail']['responses']['200']['content']['application/json'];
-export type IRegistryGetRequest = operations['i/registry/get']['requestBody']['content']['application/json'];
-export type IRegistryGetResponse = operations['i/registry/get']['responses']['200']['content']['application/json'];
-export type IRegistryKeysWithTypeRequest = operations['i/registry/keys-with-type']['requestBody']['content']['application/json'];
-export type IRegistryKeysWithTypeResponse = operations['i/registry/keys-with-type']['responses']['200']['content']['application/json'];
-export type IRegistryKeysRequest = operations['i/registry/keys']['requestBody']['content']['application/json'];
-export type IRegistryKeysResponse = operations['i/registry/keys']['responses']['200']['content']['application/json'];
-export type IRegistryRemoveRequest = operations['i/registry/remove']['requestBody']['content']['application/json'];
-export type IRegistryScopesWithDomainResponse = operations['i/registry/scopes-with-domain']['responses']['200']['content']['application/json'];
-export type IRegistrySetRequest = operations['i/registry/set']['requestBody']['content']['application/json'];
-export type IRevokeTokenRequest = operations['i/revoke-token']['requestBody']['content']['application/json'];
-export type ISigninHistoryRequest = operations['i/signin-history']['requestBody']['content']['application/json'];
-export type ISigninHistoryResponse = operations['i/signin-history']['responses']['200']['content']['application/json'];
-export type IUnpinRequest = operations['i/unpin']['requestBody']['content']['application/json'];
-export type IUnpinResponse = operations['i/unpin']['responses']['200']['content']['application/json'];
-export type IUpdateEmailRequest = operations['i/update-email']['requestBody']['content']['application/json'];
-export type IUpdateEmailResponse = operations['i/update-email']['responses']['200']['content']['application/json'];
-export type IUpdateRequest = operations['i/update']['requestBody']['content']['application/json'];
-export type IUpdateResponse = operations['i/update']['responses']['200']['content']['application/json'];
-export type IMoveRequest = operations['i/move']['requestBody']['content']['application/json'];
-export type IMoveResponse = operations['i/move']['responses']['200']['content']['application/json'];
-export type IWebhooksCreateRequest = operations['i/webhooks/create']['requestBody']['content']['application/json'];
-export type IWebhooksCreateResponse = operations['i/webhooks/create']['responses']['200']['content']['application/json'];
-export type IWebhooksListResponse = operations['i/webhooks/list']['responses']['200']['content']['application/json'];
-export type IWebhooksShowRequest = operations['i/webhooks/show']['requestBody']['content']['application/json'];
-export type IWebhooksShowResponse = operations['i/webhooks/show']['responses']['200']['content']['application/json'];
-export type IWebhooksUpdateRequest = operations['i/webhooks/update']['requestBody']['content']['application/json'];
-export type IWebhooksDeleteRequest = operations['i/webhooks/delete']['requestBody']['content']['application/json'];
-export type InviteCreateResponse = operations['invite/create']['responses']['200']['content']['application/json'];
-export type InviteDeleteRequest = operations['invite/delete']['requestBody']['content']['application/json'];
-export type InviteListRequest = operations['invite/list']['requestBody']['content']['application/json'];
-export type InviteListResponse = operations['invite/list']['responses']['200']['content']['application/json'];
-export type InviteLimitResponse = operations['invite/limit']['responses']['200']['content']['application/json'];
+export type I2faDoneRequest = operations['i___2fa___done']['requestBody']['content']['application/json'];
+export type I2faDoneResponse = operations['i___2fa___done']['responses']['200']['content']['application/json'];
+export type I2faKeyDoneRequest = operations['i___2fa___key-done']['requestBody']['content']['application/json'];
+export type I2faKeyDoneResponse = operations['i___2fa___key-done']['responses']['200']['content']['application/json'];
+export type I2faPasswordLessRequest = operations['i___2fa___password-less']['requestBody']['content']['application/json'];
+export type I2faRegisterKeyRequest = operations['i___2fa___register-key']['requestBody']['content']['application/json'];
+export type I2faRegisterKeyResponse = operations['i___2fa___register-key']['responses']['200']['content']['application/json'];
+export type I2faRegisterRequest = operations['i___2fa___register']['requestBody']['content']['application/json'];
+export type I2faRegisterResponse = operations['i___2fa___register']['responses']['200']['content']['application/json'];
+export type I2faUpdateKeyRequest = operations['i___2fa___update-key']['requestBody']['content']['application/json'];
+export type I2faRemoveKeyRequest = operations['i___2fa___remove-key']['requestBody']['content']['application/json'];
+export type I2faUnregisterRequest = operations['i___2fa___unregister']['requestBody']['content']['application/json'];
+export type IAppsRequest = operations['i___apps']['requestBody']['content']['application/json'];
+export type IAppsResponse = operations['i___apps']['responses']['200']['content']['application/json'];
+export type IAuthorizedAppsRequest = operations['i___authorized-apps']['requestBody']['content']['application/json'];
+export type IAuthorizedAppsResponse = operations['i___authorized-apps']['responses']['200']['content']['application/json'];
+export type IClaimAchievementRequest = operations['i___claim-achievement']['requestBody']['content']['application/json'];
+export type IChangePasswordRequest = operations['i___change-password']['requestBody']['content']['application/json'];
+export type IDeleteAccountRequest = operations['i___delete-account']['requestBody']['content']['application/json'];
+export type IExportFollowingRequest = operations['i___export-following']['requestBody']['content']['application/json'];
+export type IFavoritesRequest = operations['i___favorites']['requestBody']['content']['application/json'];
+export type IFavoritesResponse = operations['i___favorites']['responses']['200']['content']['application/json'];
+export type IGalleryLikesRequest = operations['i___gallery___likes']['requestBody']['content']['application/json'];
+export type IGalleryLikesResponse = operations['i___gallery___likes']['responses']['200']['content']['application/json'];
+export type IGalleryPostsRequest = operations['i___gallery___posts']['requestBody']['content']['application/json'];
+export type IGalleryPostsResponse = operations['i___gallery___posts']['responses']['200']['content']['application/json'];
+export type IImportBlockingRequest = operations['i___import-blocking']['requestBody']['content']['application/json'];
+export type IImportFollowingRequest = operations['i___import-following']['requestBody']['content']['application/json'];
+export type IImportMutingRequest = operations['i___import-muting']['requestBody']['content']['application/json'];
+export type IImportUserListsRequest = operations['i___import-user-lists']['requestBody']['content']['application/json'];
+export type IImportAntennasRequest = operations['i___import-antennas']['requestBody']['content']['application/json'];
+export type INotificationsRequest = operations['i___notifications']['requestBody']['content']['application/json'];
+export type INotificationsResponse = operations['i___notifications']['responses']['200']['content']['application/json'];
+export type INotificationsGroupedRequest = operations['i___notifications-grouped']['requestBody']['content']['application/json'];
+export type INotificationsGroupedResponse = operations['i___notifications-grouped']['responses']['200']['content']['application/json'];
+export type IPageLikesRequest = operations['i___page-likes']['requestBody']['content']['application/json'];
+export type IPageLikesResponse = operations['i___page-likes']['responses']['200']['content']['application/json'];
+export type IPagesRequest = operations['i___pages']['requestBody']['content']['application/json'];
+export type IPagesResponse = operations['i___pages']['responses']['200']['content']['application/json'];
+export type IPinRequest = operations['i___pin']['requestBody']['content']['application/json'];
+export type IPinResponse = operations['i___pin']['responses']['200']['content']['application/json'];
+export type IReadAnnouncementRequest = operations['i___read-announcement']['requestBody']['content']['application/json'];
+export type IRegenerateTokenRequest = operations['i___regenerate-token']['requestBody']['content']['application/json'];
+export type IRegistryGetAllRequest = operations['i___registry___get-all']['requestBody']['content']['application/json'];
+export type IRegistryGetAllResponse = operations['i___registry___get-all']['responses']['200']['content']['application/json'];
+export type IRegistryGetDetailRequest = operations['i___registry___get-detail']['requestBody']['content']['application/json'];
+export type IRegistryGetDetailResponse = operations['i___registry___get-detail']['responses']['200']['content']['application/json'];
+export type IRegistryGetRequest = operations['i___registry___get']['requestBody']['content']['application/json'];
+export type IRegistryGetResponse = operations['i___registry___get']['responses']['200']['content']['application/json'];
+export type IRegistryKeysWithTypeRequest = operations['i___registry___keys-with-type']['requestBody']['content']['application/json'];
+export type IRegistryKeysWithTypeResponse = operations['i___registry___keys-with-type']['responses']['200']['content']['application/json'];
+export type IRegistryKeysRequest = operations['i___registry___keys']['requestBody']['content']['application/json'];
+export type IRegistryKeysResponse = operations['i___registry___keys']['responses']['200']['content']['application/json'];
+export type IRegistryRemoveRequest = operations['i___registry___remove']['requestBody']['content']['application/json'];
+export type IRegistryScopesWithDomainResponse = operations['i___registry___scopes-with-domain']['responses']['200']['content']['application/json'];
+export type IRegistrySetRequest = operations['i___registry___set']['requestBody']['content']['application/json'];
+export type IRevokeTokenRequest = operations['i___revoke-token']['requestBody']['content']['application/json'];
+export type ISigninHistoryRequest = operations['i___signin-history']['requestBody']['content']['application/json'];
+export type ISigninHistoryResponse = operations['i___signin-history']['responses']['200']['content']['application/json'];
+export type IUnpinRequest = operations['i___unpin']['requestBody']['content']['application/json'];
+export type IUnpinResponse = operations['i___unpin']['responses']['200']['content']['application/json'];
+export type IUpdateEmailRequest = operations['i___update-email']['requestBody']['content']['application/json'];
+export type IUpdateEmailResponse = operations['i___update-email']['responses']['200']['content']['application/json'];
+export type IUpdateRequest = operations['i___update']['requestBody']['content']['application/json'];
+export type IUpdateResponse = operations['i___update']['responses']['200']['content']['application/json'];
+export type IMoveRequest = operations['i___move']['requestBody']['content']['application/json'];
+export type IMoveResponse = operations['i___move']['responses']['200']['content']['application/json'];
+export type IWebhooksCreateRequest = operations['i___webhooks___create']['requestBody']['content']['application/json'];
+export type IWebhooksCreateResponse = operations['i___webhooks___create']['responses']['200']['content']['application/json'];
+export type IWebhooksListResponse = operations['i___webhooks___list']['responses']['200']['content']['application/json'];
+export type IWebhooksShowRequest = operations['i___webhooks___show']['requestBody']['content']['application/json'];
+export type IWebhooksShowResponse = operations['i___webhooks___show']['responses']['200']['content']['application/json'];
+export type IWebhooksUpdateRequest = operations['i___webhooks___update']['requestBody']['content']['application/json'];
+export type IWebhooksDeleteRequest = operations['i___webhooks___delete']['requestBody']['content']['application/json'];
+export type InviteCreateResponse = operations['invite___create']['responses']['200']['content']['application/json'];
+export type InviteDeleteRequest = operations['invite___delete']['requestBody']['content']['application/json'];
+export type InviteListRequest = operations['invite___list']['requestBody']['content']['application/json'];
+export type InviteListResponse = operations['invite___list']['responses']['200']['content']['application/json'];
+export type InviteLimitResponse = operations['invite___limit']['responses']['200']['content']['application/json'];
 export type MetaRequest = operations['meta']['requestBody']['content']['application/json'];
 export type MetaResponse = operations['meta']['responses']['200']['content']['application/json'];
 export type EmojisResponse = operations['emojis']['responses']['200']['content']['application/json'];
 export type EmojiRequest = operations['emoji']['requestBody']['content']['application/json'];
 export type EmojiResponse = operations['emoji']['responses']['200']['content']['application/json'];
-export type MiauthGenTokenRequest = operations['miauth/gen-token']['requestBody']['content']['application/json'];
-export type MiauthGenTokenResponse = operations['miauth/gen-token']['responses']['200']['content']['application/json'];
-export type MuteCreateRequest = operations['mute/create']['requestBody']['content']['application/json'];
-export type MuteDeleteRequest = operations['mute/delete']['requestBody']['content']['application/json'];
-export type MuteListRequest = operations['mute/list']['requestBody']['content']['application/json'];
-export type MuteListResponse = operations['mute/list']['responses']['200']['content']['application/json'];
-export type RenoteMuteCreateRequest = operations['renote-mute/create']['requestBody']['content']['application/json'];
-export type RenoteMuteDeleteRequest = operations['renote-mute/delete']['requestBody']['content']['application/json'];
-export type RenoteMuteListRequest = operations['renote-mute/list']['requestBody']['content']['application/json'];
-export type RenoteMuteListResponse = operations['renote-mute/list']['responses']['200']['content']['application/json'];
-export type MyAppsRequest = operations['my/apps']['requestBody']['content']['application/json'];
-export type MyAppsResponse = operations['my/apps']['responses']['200']['content']['application/json'];
+export type MiauthGenTokenRequest = operations['miauth___gen-token']['requestBody']['content']['application/json'];
+export type MiauthGenTokenResponse = operations['miauth___gen-token']['responses']['200']['content']['application/json'];
+export type MuteCreateRequest = operations['mute___create']['requestBody']['content']['application/json'];
+export type MuteDeleteRequest = operations['mute___delete']['requestBody']['content']['application/json'];
+export type MuteListRequest = operations['mute___list']['requestBody']['content']['application/json'];
+export type MuteListResponse = operations['mute___list']['responses']['200']['content']['application/json'];
+export type RenoteMuteCreateRequest = operations['renote-mute___create']['requestBody']['content']['application/json'];
+export type RenoteMuteDeleteRequest = operations['renote-mute___delete']['requestBody']['content']['application/json'];
+export type RenoteMuteListRequest = operations['renote-mute___list']['requestBody']['content']['application/json'];
+export type RenoteMuteListResponse = operations['renote-mute___list']['responses']['200']['content']['application/json'];
+export type MyAppsRequest = operations['my___apps']['requestBody']['content']['application/json'];
+export type MyAppsResponse = operations['my___apps']['responses']['200']['content']['application/json'];
 export type NotesRequest = operations['notes']['requestBody']['content']['application/json'];
 export type NotesResponse = operations['notes']['responses']['200']['content']['application/json'];
-export type NotesChildrenRequest = operations['notes/children']['requestBody']['content']['application/json'];
-export type NotesChildrenResponse = operations['notes/children']['responses']['200']['content']['application/json'];
-export type NotesClipsRequest = operations['notes/clips']['requestBody']['content']['application/json'];
-export type NotesClipsResponse = operations['notes/clips']['responses']['200']['content']['application/json'];
-export type NotesConversationRequest = operations['notes/conversation']['requestBody']['content']['application/json'];
-export type NotesConversationResponse = operations['notes/conversation']['responses']['200']['content']['application/json'];
-export type NotesCreateRequest = operations['notes/create']['requestBody']['content']['application/json'];
-export type NotesCreateResponse = operations['notes/create']['responses']['200']['content']['application/json'];
-export type NotesDeleteRequest = operations['notes/delete']['requestBody']['content']['application/json'];
-export type NotesFavoritesCreateRequest = operations['notes/favorites/create']['requestBody']['content']['application/json'];
-export type NotesFavoritesDeleteRequest = operations['notes/favorites/delete']['requestBody']['content']['application/json'];
-export type NotesFeaturedRequest = operations['notes/featured']['requestBody']['content']['application/json'];
-export type NotesFeaturedResponse = operations['notes/featured']['responses']['200']['content']['application/json'];
-export type NotesGlobalTimelineRequest = operations['notes/global-timeline']['requestBody']['content']['application/json'];
-export type NotesGlobalTimelineResponse = operations['notes/global-timeline']['responses']['200']['content']['application/json'];
-export type NotesHybridTimelineRequest = operations['notes/hybrid-timeline']['requestBody']['content']['application/json'];
-export type NotesHybridTimelineResponse = operations['notes/hybrid-timeline']['responses']['200']['content']['application/json'];
-export type NotesLocalTimelineRequest = operations['notes/local-timeline']['requestBody']['content']['application/json'];
-export type NotesLocalTimelineResponse = operations['notes/local-timeline']['responses']['200']['content']['application/json'];
-export type NotesMentionsRequest = operations['notes/mentions']['requestBody']['content']['application/json'];
-export type NotesMentionsResponse = operations['notes/mentions']['responses']['200']['content']['application/json'];
-export type NotesPollsRecommendationRequest = operations['notes/polls/recommendation']['requestBody']['content']['application/json'];
-export type NotesPollsRecommendationResponse = operations['notes/polls/recommendation']['responses']['200']['content']['application/json'];
-export type NotesPollsVoteRequest = operations['notes/polls/vote']['requestBody']['content']['application/json'];
-export type NotesReactionsRequest = operations['notes/reactions']['requestBody']['content']['application/json'];
-export type NotesReactionsResponse = operations['notes/reactions']['responses']['200']['content']['application/json'];
-export type NotesReactionsCreateRequest = operations['notes/reactions/create']['requestBody']['content']['application/json'];
-export type NotesReactionsDeleteRequest = operations['notes/reactions/delete']['requestBody']['content']['application/json'];
-export type NotesRenotesRequest = operations['notes/renotes']['requestBody']['content']['application/json'];
-export type NotesRenotesResponse = operations['notes/renotes']['responses']['200']['content']['application/json'];
-export type NotesRepliesRequest = operations['notes/replies']['requestBody']['content']['application/json'];
-export type NotesRepliesResponse = operations['notes/replies']['responses']['200']['content']['application/json'];
-export type NotesSearchByTagRequest = operations['notes/search-by-tag']['requestBody']['content']['application/json'];
-export type NotesSearchByTagResponse = operations['notes/search-by-tag']['responses']['200']['content']['application/json'];
-export type NotesSearchRequest = operations['notes/search']['requestBody']['content']['application/json'];
-export type NotesSearchResponse = operations['notes/search']['responses']['200']['content']['application/json'];
-export type NotesShowRequest = operations['notes/show']['requestBody']['content']['application/json'];
-export type NotesShowResponse = operations['notes/show']['responses']['200']['content']['application/json'];
-export type NotesStateRequest = operations['notes/state']['requestBody']['content']['application/json'];
-export type NotesStateResponse = operations['notes/state']['responses']['200']['content']['application/json'];
-export type NotesThreadMutingCreateRequest = operations['notes/thread-muting/create']['requestBody']['content']['application/json'];
-export type NotesThreadMutingDeleteRequest = operations['notes/thread-muting/delete']['requestBody']['content']['application/json'];
-export type NotesTimelineRequest = operations['notes/timeline']['requestBody']['content']['application/json'];
-export type NotesTimelineResponse = operations['notes/timeline']['responses']['200']['content']['application/json'];
-export type NotesTranslateRequest = operations['notes/translate']['requestBody']['content']['application/json'];
-export type NotesTranslateResponse = operations['notes/translate']['responses']['200']['content']['application/json'];
-export type NotesUnrenoteRequest = operations['notes/unrenote']['requestBody']['content']['application/json'];
-export type NotesUserListTimelineRequest = operations['notes/user-list-timeline']['requestBody']['content']['application/json'];
-export type NotesUserListTimelineResponse = operations['notes/user-list-timeline']['responses']['200']['content']['application/json'];
-export type NotificationsCreateRequest = operations['notifications/create']['requestBody']['content']['application/json'];
+export type NotesChildrenRequest = operations['notes___children']['requestBody']['content']['application/json'];
+export type NotesChildrenResponse = operations['notes___children']['responses']['200']['content']['application/json'];
+export type NotesClipsRequest = operations['notes___clips']['requestBody']['content']['application/json'];
+export type NotesClipsResponse = operations['notes___clips']['responses']['200']['content']['application/json'];
+export type NotesConversationRequest = operations['notes___conversation']['requestBody']['content']['application/json'];
+export type NotesConversationResponse = operations['notes___conversation']['responses']['200']['content']['application/json'];
+export type NotesCreateRequest = operations['notes___create']['requestBody']['content']['application/json'];
+export type NotesCreateResponse = operations['notes___create']['responses']['200']['content']['application/json'];
+export type NotesDeleteRequest = operations['notes___delete']['requestBody']['content']['application/json'];
+export type NotesFavoritesCreateRequest = operations['notes___favorites___create']['requestBody']['content']['application/json'];
+export type NotesFavoritesDeleteRequest = operations['notes___favorites___delete']['requestBody']['content']['application/json'];
+export type NotesFeaturedRequest = operations['notes___featured']['requestBody']['content']['application/json'];
+export type NotesFeaturedResponse = operations['notes___featured']['responses']['200']['content']['application/json'];
+export type NotesGlobalTimelineRequest = operations['notes___global-timeline']['requestBody']['content']['application/json'];
+export type NotesGlobalTimelineResponse = operations['notes___global-timeline']['responses']['200']['content']['application/json'];
+export type NotesHybridTimelineRequest = operations['notes___hybrid-timeline']['requestBody']['content']['application/json'];
+export type NotesHybridTimelineResponse = operations['notes___hybrid-timeline']['responses']['200']['content']['application/json'];
+export type NotesLocalTimelineRequest = operations['notes___local-timeline']['requestBody']['content']['application/json'];
+export type NotesLocalTimelineResponse = operations['notes___local-timeline']['responses']['200']['content']['application/json'];
+export type NotesMentionsRequest = operations['notes___mentions']['requestBody']['content']['application/json'];
+export type NotesMentionsResponse = operations['notes___mentions']['responses']['200']['content']['application/json'];
+export type NotesPollsRecommendationRequest = operations['notes___polls___recommendation']['requestBody']['content']['application/json'];
+export type NotesPollsRecommendationResponse = operations['notes___polls___recommendation']['responses']['200']['content']['application/json'];
+export type NotesPollsVoteRequest = operations['notes___polls___vote']['requestBody']['content']['application/json'];
+export type NotesReactionsRequest = operations['notes___reactions']['requestBody']['content']['application/json'];
+export type NotesReactionsResponse = operations['notes___reactions']['responses']['200']['content']['application/json'];
+export type NotesReactionsCreateRequest = operations['notes___reactions___create']['requestBody']['content']['application/json'];
+export type NotesReactionsDeleteRequest = operations['notes___reactions___delete']['requestBody']['content']['application/json'];
+export type NotesRenotesRequest = operations['notes___renotes']['requestBody']['content']['application/json'];
+export type NotesRenotesResponse = operations['notes___renotes']['responses']['200']['content']['application/json'];
+export type NotesRepliesRequest = operations['notes___replies']['requestBody']['content']['application/json'];
+export type NotesRepliesResponse = operations['notes___replies']['responses']['200']['content']['application/json'];
+export type NotesSearchByTagRequest = operations['notes___search-by-tag']['requestBody']['content']['application/json'];
+export type NotesSearchByTagResponse = operations['notes___search-by-tag']['responses']['200']['content']['application/json'];
+export type NotesSearchRequest = operations['notes___search']['requestBody']['content']['application/json'];
+export type NotesSearchResponse = operations['notes___search']['responses']['200']['content']['application/json'];
+export type NotesShowRequest = operations['notes___show']['requestBody']['content']['application/json'];
+export type NotesShowResponse = operations['notes___show']['responses']['200']['content']['application/json'];
+export type NotesStateRequest = operations['notes___state']['requestBody']['content']['application/json'];
+export type NotesStateResponse = operations['notes___state']['responses']['200']['content']['application/json'];
+export type NotesThreadMutingCreateRequest = operations['notes___thread-muting___create']['requestBody']['content']['application/json'];
+export type NotesThreadMutingDeleteRequest = operations['notes___thread-muting___delete']['requestBody']['content']['application/json'];
+export type NotesTimelineRequest = operations['notes___timeline']['requestBody']['content']['application/json'];
+export type NotesTimelineResponse = operations['notes___timeline']['responses']['200']['content']['application/json'];
+export type NotesTranslateRequest = operations['notes___translate']['requestBody']['content']['application/json'];
+export type NotesTranslateResponse = operations['notes___translate']['responses']['200']['content']['application/json'];
+export type NotesUnrenoteRequest = operations['notes___unrenote']['requestBody']['content']['application/json'];
+export type NotesUserListTimelineRequest = operations['notes___user-list-timeline']['requestBody']['content']['application/json'];
+export type NotesUserListTimelineResponse = operations['notes___user-list-timeline']['responses']['200']['content']['application/json'];
+export type NotificationsCreateRequest = operations['notifications___create']['requestBody']['content']['application/json'];
 export type PagePushRequest = operations['page-push']['requestBody']['content']['application/json'];
-export type PagesCreateRequest = operations['pages/create']['requestBody']['content']['application/json'];
-export type PagesCreateResponse = operations['pages/create']['responses']['200']['content']['application/json'];
-export type PagesDeleteRequest = operations['pages/delete']['requestBody']['content']['application/json'];
-export type PagesFeaturedResponse = operations['pages/featured']['responses']['200']['content']['application/json'];
-export type PagesLikeRequest = operations['pages/like']['requestBody']['content']['application/json'];
-export type PagesShowRequest = operations['pages/show']['requestBody']['content']['application/json'];
-export type PagesShowResponse = operations['pages/show']['responses']['200']['content']['application/json'];
-export type PagesUnlikeRequest = operations['pages/unlike']['requestBody']['content']['application/json'];
-export type PagesUpdateRequest = operations['pages/update']['requestBody']['content']['application/json'];
-export type FlashCreateRequest = operations['flash/create']['requestBody']['content']['application/json'];
-export type FlashCreateResponse = operations['flash/create']['responses']['200']['content']['application/json'];
-export type FlashDeleteRequest = operations['flash/delete']['requestBody']['content']['application/json'];
-export type FlashFeaturedResponse = operations['flash/featured']['responses']['200']['content']['application/json'];
-export type FlashLikeRequest = operations['flash/like']['requestBody']['content']['application/json'];
-export type FlashShowRequest = operations['flash/show']['requestBody']['content']['application/json'];
-export type FlashShowResponse = operations['flash/show']['responses']['200']['content']['application/json'];
-export type FlashUnlikeRequest = operations['flash/unlike']['requestBody']['content']['application/json'];
-export type FlashUpdateRequest = operations['flash/update']['requestBody']['content']['application/json'];
-export type FlashMyRequest = operations['flash/my']['requestBody']['content']['application/json'];
-export type FlashMyResponse = operations['flash/my']['responses']['200']['content']['application/json'];
-export type FlashMyLikesRequest = operations['flash/my-likes']['requestBody']['content']['application/json'];
-export type FlashMyLikesResponse = operations['flash/my-likes']['responses']['200']['content']['application/json'];
+export type PagesCreateRequest = operations['pages___create']['requestBody']['content']['application/json'];
+export type PagesCreateResponse = operations['pages___create']['responses']['200']['content']['application/json'];
+export type PagesDeleteRequest = operations['pages___delete']['requestBody']['content']['application/json'];
+export type PagesFeaturedResponse = operations['pages___featured']['responses']['200']['content']['application/json'];
+export type PagesLikeRequest = operations['pages___like']['requestBody']['content']['application/json'];
+export type PagesShowRequest = operations['pages___show']['requestBody']['content']['application/json'];
+export type PagesShowResponse = operations['pages___show']['responses']['200']['content']['application/json'];
+export type PagesUnlikeRequest = operations['pages___unlike']['requestBody']['content']['application/json'];
+export type PagesUpdateRequest = operations['pages___update']['requestBody']['content']['application/json'];
+export type FlashCreateRequest = operations['flash___create']['requestBody']['content']['application/json'];
+export type FlashCreateResponse = operations['flash___create']['responses']['200']['content']['application/json'];
+export type FlashDeleteRequest = operations['flash___delete']['requestBody']['content']['application/json'];
+export type FlashFeaturedResponse = operations['flash___featured']['responses']['200']['content']['application/json'];
+export type FlashLikeRequest = operations['flash___like']['requestBody']['content']['application/json'];
+export type FlashShowRequest = operations['flash___show']['requestBody']['content']['application/json'];
+export type FlashShowResponse = operations['flash___show']['responses']['200']['content']['application/json'];
+export type FlashUnlikeRequest = operations['flash___unlike']['requestBody']['content']['application/json'];
+export type FlashUpdateRequest = operations['flash___update']['requestBody']['content']['application/json'];
+export type FlashMyRequest = operations['flash___my']['requestBody']['content']['application/json'];
+export type FlashMyResponse = operations['flash___my']['responses']['200']['content']['application/json'];
+export type FlashMyLikesRequest = operations['flash___my-likes']['requestBody']['content']['application/json'];
+export type FlashMyLikesResponse = operations['flash___my-likes']['responses']['200']['content']['application/json'];
 export type PingResponse = operations['ping']['responses']['200']['content']['application/json'];
 export type PinnedUsersResponse = operations['pinned-users']['responses']['200']['content']['application/json'];
-export type PromoReadRequest = operations['promo/read']['requestBody']['content']['application/json'];
-export type RolesListResponse = operations['roles/list']['responses']['200']['content']['application/json'];
-export type RolesShowRequest = operations['roles/show']['requestBody']['content']['application/json'];
-export type RolesShowResponse = operations['roles/show']['responses']['200']['content']['application/json'];
-export type RolesUsersRequest = operations['roles/users']['requestBody']['content']['application/json'];
-export type RolesUsersResponse = operations['roles/users']['responses']['200']['content']['application/json'];
-export type RolesNotesRequest = operations['roles/notes']['requestBody']['content']['application/json'];
-export type RolesNotesResponse = operations['roles/notes']['responses']['200']['content']['application/json'];
+export type PromoReadRequest = operations['promo___read']['requestBody']['content']['application/json'];
+export type RolesListResponse = operations['roles___list']['responses']['200']['content']['application/json'];
+export type RolesShowRequest = operations['roles___show']['requestBody']['content']['application/json'];
+export type RolesShowResponse = operations['roles___show']['responses']['200']['content']['application/json'];
+export type RolesUsersRequest = operations['roles___users']['requestBody']['content']['application/json'];
+export type RolesUsersResponse = operations['roles___users']['responses']['200']['content']['application/json'];
+export type RolesNotesRequest = operations['roles___notes']['requestBody']['content']['application/json'];
+export type RolesNotesResponse = operations['roles___notes']['responses']['200']['content']['application/json'];
 export type RequestResetPasswordRequest = operations['request-reset-password']['requestBody']['content']['application/json'];
 export type ResetPasswordRequest = operations['reset-password']['requestBody']['content']['application/json'];
 export type ServerInfoResponse = operations['server-info']['responses']['200']['content']['application/json'];
 export type StatsResponse = operations['stats']['responses']['200']['content']['application/json'];
-export type SwShowRegistrationRequest = operations['sw/show-registration']['requestBody']['content']['application/json'];
-export type SwShowRegistrationResponse = operations['sw/show-registration']['responses']['200']['content']['application/json'];
-export type SwUpdateRegistrationRequest = operations['sw/update-registration']['requestBody']['content']['application/json'];
-export type SwUpdateRegistrationResponse = operations['sw/update-registration']['responses']['200']['content']['application/json'];
-export type SwRegisterRequest = operations['sw/register']['requestBody']['content']['application/json'];
-export type SwRegisterResponse = operations['sw/register']['responses']['200']['content']['application/json'];
-export type SwUnregisterRequest = operations['sw/unregister']['requestBody']['content']['application/json'];
+export type SwShowRegistrationRequest = operations['sw___show-registration']['requestBody']['content']['application/json'];
+export type SwShowRegistrationResponse = operations['sw___show-registration']['responses']['200']['content']['application/json'];
+export type SwUpdateRegistrationRequest = operations['sw___update-registration']['requestBody']['content']['application/json'];
+export type SwUpdateRegistrationResponse = operations['sw___update-registration']['responses']['200']['content']['application/json'];
+export type SwRegisterRequest = operations['sw___register']['requestBody']['content']['application/json'];
+export type SwRegisterResponse = operations['sw___register']['responses']['200']['content']['application/json'];
+export type SwUnregisterRequest = operations['sw___unregister']['requestBody']['content']['application/json'];
 export type TestRequest = operations['test']['requestBody']['content']['application/json'];
 export type TestResponse = operations['test']['responses']['200']['content']['application/json'];
-export type UsernameAvailableRequest = operations['username/available']['requestBody']['content']['application/json'];
-export type UsernameAvailableResponse = operations['username/available']['responses']['200']['content']['application/json'];
+export type UsernameAvailableRequest = operations['username___available']['requestBody']['content']['application/json'];
+export type UsernameAvailableResponse = operations['username___available']['responses']['200']['content']['application/json'];
 export type UsersRequest = operations['users']['requestBody']['content']['application/json'];
 export type UsersResponse = operations['users']['responses']['200']['content']['application/json'];
-export type UsersClipsRequest = operations['users/clips']['requestBody']['content']['application/json'];
-export type UsersClipsResponse = operations['users/clips']['responses']['200']['content']['application/json'];
-export type UsersFollowersRequest = operations['users/followers']['requestBody']['content']['application/json'];
-export type UsersFollowersResponse = operations['users/followers']['responses']['200']['content']['application/json'];
-export type UsersFollowingRequest = operations['users/following']['requestBody']['content']['application/json'];
-export type UsersFollowingResponse = operations['users/following']['responses']['200']['content']['application/json'];
-export type UsersGalleryPostsRequest = operations['users/gallery/posts']['requestBody']['content']['application/json'];
-export type UsersGalleryPostsResponse = operations['users/gallery/posts']['responses']['200']['content']['application/json'];
-export type UsersGetFrequentlyRepliedUsersRequest = operations['users/get-frequently-replied-users']['requestBody']['content']['application/json'];
-export type UsersGetFrequentlyRepliedUsersResponse = operations['users/get-frequently-replied-users']['responses']['200']['content']['application/json'];
-export type UsersFeaturedNotesRequest = operations['users/featured-notes']['requestBody']['content']['application/json'];
-export type UsersFeaturedNotesResponse = operations['users/featured-notes']['responses']['200']['content']['application/json'];
-export type UsersListsCreateRequest = operations['users/lists/create']['requestBody']['content']['application/json'];
-export type UsersListsCreateResponse = operations['users/lists/create']['responses']['200']['content']['application/json'];
-export type UsersListsDeleteRequest = operations['users/lists/delete']['requestBody']['content']['application/json'];
-export type UsersListsListRequest = operations['users/lists/list']['requestBody']['content']['application/json'];
-export type UsersListsListResponse = operations['users/lists/list']['responses']['200']['content']['application/json'];
-export type UsersListsPullRequest = operations['users/lists/pull']['requestBody']['content']['application/json'];
-export type UsersListsPushRequest = operations['users/lists/push']['requestBody']['content']['application/json'];
-export type UsersListsShowRequest = operations['users/lists/show']['requestBody']['content']['application/json'];
-export type UsersListsShowResponse = operations['users/lists/show']['responses']['200']['content']['application/json'];
-export type UsersListsFavoriteRequest = operations['users/lists/favorite']['requestBody']['content']['application/json'];
-export type UsersListsUnfavoriteRequest = operations['users/lists/unfavorite']['requestBody']['content']['application/json'];
-export type UsersListsUpdateRequest = operations['users/lists/update']['requestBody']['content']['application/json'];
-export type UsersListsUpdateResponse = operations['users/lists/update']['responses']['200']['content']['application/json'];
-export type UsersListsCreateFromPublicRequest = operations['users/lists/create-from-public']['requestBody']['content']['application/json'];
-export type UsersListsCreateFromPublicResponse = operations['users/lists/create-from-public']['responses']['200']['content']['application/json'];
-export type UsersListsUpdateMembershipRequest = operations['users/lists/update-membership']['requestBody']['content']['application/json'];
-export type UsersListsGetMembershipsRequest = operations['users/lists/get-memberships']['requestBody']['content']['application/json'];
-export type UsersListsGetMembershipsResponse = operations['users/lists/get-memberships']['responses']['200']['content']['application/json'];
-export type UsersNotesRequest = operations['users/notes']['requestBody']['content']['application/json'];
-export type UsersNotesResponse = operations['users/notes']['responses']['200']['content']['application/json'];
-export type UsersPagesRequest = operations['users/pages']['requestBody']['content']['application/json'];
-export type UsersPagesResponse = operations['users/pages']['responses']['200']['content']['application/json'];
-export type UsersFlashsRequest = operations['users/flashs']['requestBody']['content']['application/json'];
-export type UsersFlashsResponse = operations['users/flashs']['responses']['200']['content']['application/json'];
-export type UsersReactionsRequest = operations['users/reactions']['requestBody']['content']['application/json'];
-export type UsersReactionsResponse = operations['users/reactions']['responses']['200']['content']['application/json'];
-export type UsersRecommendationRequest = operations['users/recommendation']['requestBody']['content']['application/json'];
-export type UsersRecommendationResponse = operations['users/recommendation']['responses']['200']['content']['application/json'];
-export type UsersRelationRequest = operations['users/relation']['requestBody']['content']['application/json'];
-export type UsersRelationResponse = operations['users/relation']['responses']['200']['content']['application/json'];
-export type UsersReportAbuseRequest = operations['users/report-abuse']['requestBody']['content']['application/json'];
-export type UsersSearchByUsernameAndHostRequest = operations['users/search-by-username-and-host']['requestBody']['content']['application/json'];
-export type UsersSearchByUsernameAndHostResponse = operations['users/search-by-username-and-host']['responses']['200']['content']['application/json'];
-export type UsersSearchRequest = operations['users/search']['requestBody']['content']['application/json'];
-export type UsersSearchResponse = operations['users/search']['responses']['200']['content']['application/json'];
-export type UsersShowRequest = operations['users/show']['requestBody']['content']['application/json'];
-export type UsersShowResponse = operations['users/show']['responses']['200']['content']['application/json'];
-export type UsersAchievementsRequest = operations['users/achievements']['requestBody']['content']['application/json'];
-export type UsersAchievementsResponse = operations['users/achievements']['responses']['200']['content']['application/json'];
-export type UsersUpdateMemoRequest = operations['users/update-memo']['requestBody']['content']['application/json'];
+export type UsersClipsRequest = operations['users___clips']['requestBody']['content']['application/json'];
+export type UsersClipsResponse = operations['users___clips']['responses']['200']['content']['application/json'];
+export type UsersFollowersRequest = operations['users___followers']['requestBody']['content']['application/json'];
+export type UsersFollowersResponse = operations['users___followers']['responses']['200']['content']['application/json'];
+export type UsersFollowingRequest = operations['users___following']['requestBody']['content']['application/json'];
+export type UsersFollowingResponse = operations['users___following']['responses']['200']['content']['application/json'];
+export type UsersGalleryPostsRequest = operations['users___gallery___posts']['requestBody']['content']['application/json'];
+export type UsersGalleryPostsResponse = operations['users___gallery___posts']['responses']['200']['content']['application/json'];
+export type UsersGetFrequentlyRepliedUsersRequest = operations['users___get-frequently-replied-users']['requestBody']['content']['application/json'];
+export type UsersGetFrequentlyRepliedUsersResponse = operations['users___get-frequently-replied-users']['responses']['200']['content']['application/json'];
+export type UsersFeaturedNotesRequest = operations['users___featured-notes']['requestBody']['content']['application/json'];
+export type UsersFeaturedNotesResponse = operations['users___featured-notes']['responses']['200']['content']['application/json'];
+export type UsersListsCreateRequest = operations['users___lists___create']['requestBody']['content']['application/json'];
+export type UsersListsCreateResponse = operations['users___lists___create']['responses']['200']['content']['application/json'];
+export type UsersListsDeleteRequest = operations['users___lists___delete']['requestBody']['content']['application/json'];
+export type UsersListsListRequest = operations['users___lists___list']['requestBody']['content']['application/json'];
+export type UsersListsListResponse = operations['users___lists___list']['responses']['200']['content']['application/json'];
+export type UsersListsPullRequest = operations['users___lists___pull']['requestBody']['content']['application/json'];
+export type UsersListsPushRequest = operations['users___lists___push']['requestBody']['content']['application/json'];
+export type UsersListsShowRequest = operations['users___lists___show']['requestBody']['content']['application/json'];
+export type UsersListsShowResponse = operations['users___lists___show']['responses']['200']['content']['application/json'];
+export type UsersListsFavoriteRequest = operations['users___lists___favorite']['requestBody']['content']['application/json'];
+export type UsersListsUnfavoriteRequest = operations['users___lists___unfavorite']['requestBody']['content']['application/json'];
+export type UsersListsUpdateRequest = operations['users___lists___update']['requestBody']['content']['application/json'];
+export type UsersListsUpdateResponse = operations['users___lists___update']['responses']['200']['content']['application/json'];
+export type UsersListsCreateFromPublicRequest = operations['users___lists___create-from-public']['requestBody']['content']['application/json'];
+export type UsersListsCreateFromPublicResponse = operations['users___lists___create-from-public']['responses']['200']['content']['application/json'];
+export type UsersListsUpdateMembershipRequest = operations['users___lists___update-membership']['requestBody']['content']['application/json'];
+export type UsersListsGetMembershipsRequest = operations['users___lists___get-memberships']['requestBody']['content']['application/json'];
+export type UsersListsGetMembershipsResponse = operations['users___lists___get-memberships']['responses']['200']['content']['application/json'];
+export type UsersNotesRequest = operations['users___notes']['requestBody']['content']['application/json'];
+export type UsersNotesResponse = operations['users___notes']['responses']['200']['content']['application/json'];
+export type UsersPagesRequest = operations['users___pages']['requestBody']['content']['application/json'];
+export type UsersPagesResponse = operations['users___pages']['responses']['200']['content']['application/json'];
+export type UsersFlashsRequest = operations['users___flashs']['requestBody']['content']['application/json'];
+export type UsersFlashsResponse = operations['users___flashs']['responses']['200']['content']['application/json'];
+export type UsersReactionsRequest = operations['users___reactions']['requestBody']['content']['application/json'];
+export type UsersReactionsResponse = operations['users___reactions']['responses']['200']['content']['application/json'];
+export type UsersRecommendationRequest = operations['users___recommendation']['requestBody']['content']['application/json'];
+export type UsersRecommendationResponse = operations['users___recommendation']['responses']['200']['content']['application/json'];
+export type UsersRelationRequest = operations['users___relation']['requestBody']['content']['application/json'];
+export type UsersRelationResponse = operations['users___relation']['responses']['200']['content']['application/json'];
+export type UsersReportAbuseRequest = operations['users___report-abuse']['requestBody']['content']['application/json'];
+export type UsersSearchByUsernameAndHostRequest = operations['users___search-by-username-and-host']['requestBody']['content']['application/json'];
+export type UsersSearchByUsernameAndHostResponse = operations['users___search-by-username-and-host']['responses']['200']['content']['application/json'];
+export type UsersSearchRequest = operations['users___search']['requestBody']['content']['application/json'];
+export type UsersSearchResponse = operations['users___search']['responses']['200']['content']['application/json'];
+export type UsersShowRequest = operations['users___show']['requestBody']['content']['application/json'];
+export type UsersShowResponse = operations['users___show']['responses']['200']['content']['application/json'];
+export type UsersAchievementsRequest = operations['users___achievements']['requestBody']['content']['application/json'];
+export type UsersAchievementsResponse = operations['users___achievements']['responses']['200']['content']['application/json'];
+export type UsersUpdateMemoRequest = operations['users___update-memo']['requestBody']['content']['application/json'];
 export type FetchRssRequest = operations['fetch-rss']['requestBody']['content']['application/json'];
 export type FetchRssResponse = operations['fetch-rss']['responses']['200']['content']['application/json'];
 export type FetchExternalResourcesRequest = operations['fetch-external-resources']['requestBody']['content']['application/json'];
 export type FetchExternalResourcesResponse = operations['fetch-external-resources']['responses']['200']['content']['application/json'];
 export type RetentionResponse = operations['retention']['responses']['200']['content']['application/json'];
-export type BubbleGameRegisterRequest = operations['bubble-game/register']['requestBody']['content']['application/json'];
-export type BubbleGameRankingRequest = operations['bubble-game/ranking']['requestBody']['content']['application/json'];
-export type BubbleGameRankingResponse = operations['bubble-game/ranking']['responses']['200']['content']['application/json'];
-export type ReversiCancelMatchRequest = operations['reversi/cancel-match']['requestBody']['content']['application/json'];
-export type ReversiGamesRequest = operations['reversi/games']['requestBody']['content']['application/json'];
-export type ReversiGamesResponse = operations['reversi/games']['responses']['200']['content']['application/json'];
-export type ReversiMatchRequest = operations['reversi/match']['requestBody']['content']['application/json'];
-export type ReversiMatchResponse = operations['reversi/match']['responses']['200']['content']['application/json'];
-export type ReversiInvitationsResponse = operations['reversi/invitations']['responses']['200']['content']['application/json'];
-export type ReversiShowGameRequest = operations['reversi/show-game']['requestBody']['content']['application/json'];
-export type ReversiShowGameResponse = operations['reversi/show-game']['responses']['200']['content']['application/json'];
-export type ReversiSurrenderRequest = operations['reversi/surrender']['requestBody']['content']['application/json'];
-export type ReversiVerifyRequest = operations['reversi/verify']['requestBody']['content']['application/json'];
-export type ReversiVerifyResponse = operations['reversi/verify']['responses']['200']['content']['application/json'];
+export type BubbleGameRegisterRequest = operations['bubble-game___register']['requestBody']['content']['application/json'];
+export type BubbleGameRankingRequest = operations['bubble-game___ranking']['requestBody']['content']['application/json'];
+export type BubbleGameRankingResponse = operations['bubble-game___ranking']['responses']['200']['content']['application/json'];
+export type ReversiCancelMatchRequest = operations['reversi___cancel-match']['requestBody']['content']['application/json'];
+export type ReversiGamesRequest = operations['reversi___games']['requestBody']['content']['application/json'];
+export type ReversiGamesResponse = operations['reversi___games']['responses']['200']['content']['application/json'];
+export type ReversiMatchRequest = operations['reversi___match']['requestBody']['content']['application/json'];
+export type ReversiMatchResponse = operations['reversi___match']['responses']['200']['content']['application/json'];
+export type ReversiInvitationsResponse = operations['reversi___invitations']['responses']['200']['content']['application/json'];
+export type ReversiShowGameRequest = operations['reversi___show-game']['requestBody']['content']['application/json'];
+export type ReversiShowGameResponse = operations['reversi___show-game']['responses']['200']['content']['application/json'];
+export type ReversiSurrenderRequest = operations['reversi___surrender']['requestBody']['content']['application/json'];
+export type ReversiVerifyRequest = operations['reversi___verify']['requestBody']['content']['application/json'];
+export type ReversiVerifyResponse = operations['reversi___verify']['responses']['200']['content']['application/json'];
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index c6e36d80aa..4b2ad16b0f 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -19,7 +19,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:meta*
      */
-    post: operations['admin/meta'];
+    post: operations['admin___meta'];
   };
   '/admin/abuse-user-reports': {
     /**
@@ -28,7 +28,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-user-reports*
      */
-    post: operations['admin/abuse-user-reports'];
+    post: operations['admin___abuse-user-reports'];
   };
   '/admin/accounts/create': {
     /**
@@ -37,7 +37,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['admin/accounts/create'];
+    post: operations['admin___accounts___create'];
   };
   '/admin/accounts/delete': {
     /**
@@ -46,7 +46,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:account*
      */
-    post: operations['admin/accounts/delete'];
+    post: operations['admin___accounts___delete'];
   };
   '/admin/accounts/find-by-email': {
     /**
@@ -55,7 +55,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:account*
      */
-    post: operations['admin/accounts/find-by-email'];
+    post: operations['admin___accounts___find-by-email'];
   };
   '/admin/ad/create': {
     /**
@@ -64,7 +64,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:ad*
      */
-    post: operations['admin/ad/create'];
+    post: operations['admin___ad___create'];
   };
   '/admin/ad/delete': {
     /**
@@ -73,7 +73,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:ad*
      */
-    post: operations['admin/ad/delete'];
+    post: operations['admin___ad___delete'];
   };
   '/admin/ad/list': {
     /**
@@ -82,7 +82,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:ad*
      */
-    post: operations['admin/ad/list'];
+    post: operations['admin___ad___list'];
   };
   '/admin/ad/update': {
     /**
@@ -91,7 +91,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:ad*
      */
-    post: operations['admin/ad/update'];
+    post: operations['admin___ad___update'];
   };
   '/admin/announcements/create': {
     /**
@@ -100,7 +100,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:announcements*
      */
-    post: operations['admin/announcements/create'];
+    post: operations['admin___announcements___create'];
   };
   '/admin/announcements/delete': {
     /**
@@ -109,7 +109,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:announcements*
      */
-    post: operations['admin/announcements/delete'];
+    post: operations['admin___announcements___delete'];
   };
   '/admin/announcements/list': {
     /**
@@ -118,7 +118,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:announcements*
      */
-    post: operations['admin/announcements/list'];
+    post: operations['admin___announcements___list'];
   };
   '/admin/announcements/update': {
     /**
@@ -127,7 +127,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:announcements*
      */
-    post: operations['admin/announcements/update'];
+    post: operations['admin___announcements___update'];
   };
   '/admin/avatar-decorations/create': {
     /**
@@ -136,7 +136,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations*
      */
-    post: operations['admin/avatar-decorations/create'];
+    post: operations['admin___avatar-decorations___create'];
   };
   '/admin/avatar-decorations/delete': {
     /**
@@ -145,7 +145,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations*
      */
-    post: operations['admin/avatar-decorations/delete'];
+    post: operations['admin___avatar-decorations___delete'];
   };
   '/admin/avatar-decorations/list': {
     /**
@@ -154,7 +154,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:avatar-decorations*
      */
-    post: operations['admin/avatar-decorations/list'];
+    post: operations['admin___avatar-decorations___list'];
   };
   '/admin/avatar-decorations/update': {
     /**
@@ -163,7 +163,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations*
      */
-    post: operations['admin/avatar-decorations/update'];
+    post: operations['admin___avatar-decorations___update'];
   };
   '/admin/delete-all-files-of-a-user': {
     /**
@@ -172,7 +172,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:delete-all-files-of-a-user*
      */
-    post: operations['admin/delete-all-files-of-a-user'];
+    post: operations['admin___delete-all-files-of-a-user'];
   };
   '/admin/unset-user-avatar': {
     /**
@@ -181,7 +181,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:unset-user-avatar*
      */
-    post: operations['admin/unset-user-avatar'];
+    post: operations['admin___unset-user-avatar'];
   };
   '/admin/unset-user-banner': {
     /**
@@ -190,7 +190,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:unset-user-banner*
      */
-    post: operations['admin/unset-user-banner'];
+    post: operations['admin___unset-user-banner'];
   };
   '/admin/drive/clean-remote-files': {
     /**
@@ -199,7 +199,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:drive*
      */
-    post: operations['admin/drive/clean-remote-files'];
+    post: operations['admin___drive___clean-remote-files'];
   };
   '/admin/drive/cleanup': {
     /**
@@ -208,7 +208,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:drive*
      */
-    post: operations['admin/drive/cleanup'];
+    post: operations['admin___drive___cleanup'];
   };
   '/admin/drive/files': {
     /**
@@ -217,7 +217,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:drive*
      */
-    post: operations['admin/drive/files'];
+    post: operations['admin___drive___files'];
   };
   '/admin/drive/show-file': {
     /**
@@ -226,7 +226,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:drive*
      */
-    post: operations['admin/drive/show-file'];
+    post: operations['admin___drive___show-file'];
   };
   '/admin/emoji/add-aliases-bulk': {
     /**
@@ -235,7 +235,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
      */
-    post: operations['admin/emoji/add-aliases-bulk'];
+    post: operations['admin___emoji___add-aliases-bulk'];
   };
   '/admin/emoji/add': {
     /**
@@ -244,7 +244,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
      */
-    post: operations['admin/emoji/add'];
+    post: operations['admin___emoji___add'];
   };
   '/admin/emoji/copy': {
     /**
@@ -253,7 +253,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
      */
-    post: operations['admin/emoji/copy'];
+    post: operations['admin___emoji___copy'];
   };
   '/admin/emoji/delete-bulk': {
     /**
@@ -262,7 +262,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
      */
-    post: operations['admin/emoji/delete-bulk'];
+    post: operations['admin___emoji___delete-bulk'];
   };
   '/admin/emoji/delete': {
     /**
@@ -271,7 +271,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
      */
-    post: operations['admin/emoji/delete'];
+    post: operations['admin___emoji___delete'];
   };
   '/admin/emoji/import-zip': {
     /**
@@ -281,7 +281,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['admin/emoji/import-zip'];
+    post: operations['admin___emoji___import-zip'];
   };
   '/admin/emoji/list-remote': {
     /**
@@ -290,7 +290,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:emoji*
      */
-    post: operations['admin/emoji/list-remote'];
+    post: operations['admin___emoji___list-remote'];
   };
   '/admin/emoji/list': {
     /**
@@ -299,7 +299,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:emoji*
      */
-    post: operations['admin/emoji/list'];
+    post: operations['admin___emoji___list'];
   };
   '/admin/emoji/remove-aliases-bulk': {
     /**
@@ -308,7 +308,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
      */
-    post: operations['admin/emoji/remove-aliases-bulk'];
+    post: operations['admin___emoji___remove-aliases-bulk'];
   };
   '/admin/emoji/set-aliases-bulk': {
     /**
@@ -317,7 +317,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
      */
-    post: operations['admin/emoji/set-aliases-bulk'];
+    post: operations['admin___emoji___set-aliases-bulk'];
   };
   '/admin/emoji/set-category-bulk': {
     /**
@@ -326,7 +326,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
      */
-    post: operations['admin/emoji/set-category-bulk'];
+    post: operations['admin___emoji___set-category-bulk'];
   };
   '/admin/emoji/set-license-bulk': {
     /**
@@ -335,7 +335,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
      */
-    post: operations['admin/emoji/set-license-bulk'];
+    post: operations['admin___emoji___set-license-bulk'];
   };
   '/admin/emoji/update': {
     /**
@@ -344,7 +344,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
      */
-    post: operations['admin/emoji/update'];
+    post: operations['admin___emoji___update'];
   };
   '/admin/federation/delete-all-files': {
     /**
@@ -353,7 +353,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:federation*
      */
-    post: operations['admin/federation/delete-all-files'];
+    post: operations['admin___federation___delete-all-files'];
   };
   '/admin/federation/refresh-remote-instance-metadata': {
     /**
@@ -362,7 +362,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:federation*
      */
-    post: operations['admin/federation/refresh-remote-instance-metadata'];
+    post: operations['admin___federation___refresh-remote-instance-metadata'];
   };
   '/admin/federation/remove-all-following': {
     /**
@@ -371,7 +371,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:federation*
      */
-    post: operations['admin/federation/remove-all-following'];
+    post: operations['admin___federation___remove-all-following'];
   };
   '/admin/federation/update-instance': {
     /**
@@ -380,7 +380,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:federation*
      */
-    post: operations['admin/federation/update-instance'];
+    post: operations['admin___federation___update-instance'];
   };
   '/admin/get-index-stats': {
     /**
@@ -389,7 +389,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:index-stats*
      */
-    post: operations['admin/get-index-stats'];
+    post: operations['admin___get-index-stats'];
   };
   '/admin/get-table-stats': {
     /**
@@ -398,7 +398,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:table-stats*
      */
-    post: operations['admin/get-table-stats'];
+    post: operations['admin___get-table-stats'];
   };
   '/admin/get-user-ips': {
     /**
@@ -407,7 +407,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:user-ips*
      */
-    post: operations['admin/get-user-ips'];
+    post: operations['admin___get-user-ips'];
   };
   '/admin/invite/create': {
     /**
@@ -416,7 +416,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:invite-codes*
      */
-    post: operations['admin/invite/create'];
+    post: operations['admin___invite___create'];
   };
   '/admin/invite/list': {
     /**
@@ -425,7 +425,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:invite-codes*
      */
-    post: operations['admin/invite/list'];
+    post: operations['admin___invite___list'];
   };
   '/admin/promo/create': {
     /**
@@ -434,7 +434,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:promo*
      */
-    post: operations['admin/promo/create'];
+    post: operations['admin___promo___create'];
   };
   '/admin/queue/clear': {
     /**
@@ -443,7 +443,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:queue*
      */
-    post: operations['admin/queue/clear'];
+    post: operations['admin___queue___clear'];
   };
   '/admin/queue/deliver-delayed': {
     /**
@@ -452,7 +452,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:queue*
      */
-    post: operations['admin/queue/deliver-delayed'];
+    post: operations['admin___queue___deliver-delayed'];
   };
   '/admin/queue/inbox-delayed': {
     /**
@@ -461,7 +461,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:queue*
      */
-    post: operations['admin/queue/inbox-delayed'];
+    post: operations['admin___queue___inbox-delayed'];
   };
   '/admin/queue/promote': {
     /**
@@ -470,7 +470,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:queue*
      */
-    post: operations['admin/queue/promote'];
+    post: operations['admin___queue___promote'];
   };
   '/admin/queue/stats': {
     /**
@@ -479,7 +479,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:emoji*
      */
-    post: operations['admin/queue/stats'];
+    post: operations['admin___queue___stats'];
   };
   '/admin/relays/add': {
     /**
@@ -488,7 +488,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:relays*
      */
-    post: operations['admin/relays/add'];
+    post: operations['admin___relays___add'];
   };
   '/admin/relays/list': {
     /**
@@ -497,7 +497,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:relays*
      */
-    post: operations['admin/relays/list'];
+    post: operations['admin___relays___list'];
   };
   '/admin/relays/remove': {
     /**
@@ -506,7 +506,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:relays*
      */
-    post: operations['admin/relays/remove'];
+    post: operations['admin___relays___remove'];
   };
   '/admin/reset-password': {
     /**
@@ -515,7 +515,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:reset-password*
      */
-    post: operations['admin/reset-password'];
+    post: operations['admin___reset-password'];
   };
   '/admin/resolve-abuse-user-report': {
     /**
@@ -524,7 +524,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:resolve-abuse-user-report*
      */
-    post: operations['admin/resolve-abuse-user-report'];
+    post: operations['admin___resolve-abuse-user-report'];
   };
   '/admin/send-email': {
     /**
@@ -533,7 +533,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:send-email*
      */
-    post: operations['admin/send-email'];
+    post: operations['admin___send-email'];
   };
   '/admin/server-info': {
     /**
@@ -542,7 +542,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:server-info*
      */
-    post: operations['admin/server-info'];
+    post: operations['admin___server-info'];
   };
   '/admin/show-moderation-logs': {
     /**
@@ -551,7 +551,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:show-moderation-log*
      */
-    post: operations['admin/show-moderation-logs'];
+    post: operations['admin___show-moderation-logs'];
   };
   '/admin/show-user': {
     /**
@@ -560,7 +560,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:show-user*
      */
-    post: operations['admin/show-user'];
+    post: operations['admin___show-user'];
   };
   '/admin/show-users': {
     /**
@@ -569,7 +569,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:show-users*
      */
-    post: operations['admin/show-users'];
+    post: operations['admin___show-users'];
   };
   '/admin/suspend-user': {
     /**
@@ -578,7 +578,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:suspend-user*
      */
-    post: operations['admin/suspend-user'];
+    post: operations['admin___suspend-user'];
   };
   '/admin/unsuspend-user': {
     /**
@@ -587,7 +587,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:unsuspend-user*
      */
-    post: operations['admin/unsuspend-user'];
+    post: operations['admin___unsuspend-user'];
   };
   '/admin/update-meta': {
     /**
@@ -596,7 +596,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:meta*
      */
-    post: operations['admin/update-meta'];
+    post: operations['admin___update-meta'];
   };
   '/admin/delete-account': {
     /**
@@ -605,7 +605,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:delete-account*
      */
-    post: operations['admin/delete-account'];
+    post: operations['admin___delete-account'];
   };
   '/admin/update-user-note': {
     /**
@@ -614,7 +614,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:user-note*
      */
-    post: operations['admin/update-user-note'];
+    post: operations['admin___update-user-note'];
   };
   '/admin/roles/create': {
     /**
@@ -623,7 +623,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:roles*
      */
-    post: operations['admin/roles/create'];
+    post: operations['admin___roles___create'];
   };
   '/admin/roles/delete': {
     /**
@@ -632,7 +632,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:roles*
      */
-    post: operations['admin/roles/delete'];
+    post: operations['admin___roles___delete'];
   };
   '/admin/roles/list': {
     /**
@@ -641,7 +641,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:roles*
      */
-    post: operations['admin/roles/list'];
+    post: operations['admin___roles___list'];
   };
   '/admin/roles/show': {
     /**
@@ -650,7 +650,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:admin:roles*
      */
-    post: operations['admin/roles/show'];
+    post: operations['admin___roles___show'];
   };
   '/admin/roles/update': {
     /**
@@ -659,7 +659,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:roles*
      */
-    post: operations['admin/roles/update'];
+    post: operations['admin___roles___update'];
   };
   '/admin/roles/assign': {
     /**
@@ -668,7 +668,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:roles*
      */
-    post: operations['admin/roles/assign'];
+    post: operations['admin___roles___assign'];
   };
   '/admin/roles/unassign': {
     /**
@@ -677,7 +677,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:roles*
      */
-    post: operations['admin/roles/unassign'];
+    post: operations['admin___roles___unassign'];
   };
   '/admin/roles/update-default-policies': {
     /**
@@ -686,7 +686,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:admin:roles*
      */
-    post: operations['admin/roles/update-default-policies'];
+    post: operations['admin___roles___update-default-policies'];
   };
   '/admin/roles/users': {
     /**
@@ -695,7 +695,7 @@ export type paths = {
      *
      * **Credential required**: *No* / **Permission**: *read:admin:roles*
      */
-    post: operations['admin/roles/users'];
+    post: operations['admin___roles___users'];
   };
   '/announcements': {
     /**
@@ -713,7 +713,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['antennas/create'];
+    post: operations['antennas___create'];
   };
   '/antennas/delete': {
     /**
@@ -722,7 +722,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['antennas/delete'];
+    post: operations['antennas___delete'];
   };
   '/antennas/list': {
     /**
@@ -731,7 +731,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['antennas/list'];
+    post: operations['antennas___list'];
   };
   '/antennas/notes': {
     /**
@@ -740,7 +740,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['antennas/notes'];
+    post: operations['antennas___notes'];
   };
   '/antennas/show': {
     /**
@@ -749,7 +749,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['antennas/show'];
+    post: operations['antennas___show'];
   };
   '/antennas/update': {
     /**
@@ -758,7 +758,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['antennas/update'];
+    post: operations['antennas___update'];
   };
   '/ap/get': {
     /**
@@ -767,7 +767,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:federation*
      */
-    post: operations['ap/get'];
+    post: operations['ap___get'];
   };
   '/ap/show': {
     /**
@@ -776,7 +776,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['ap/show'];
+    post: operations['ap___show'];
   };
   '/app/create': {
     /**
@@ -785,7 +785,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['app/create'];
+    post: operations['app___create'];
   };
   '/app/show': {
     /**
@@ -794,7 +794,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['app/show'];
+    post: operations['app___show'];
   };
   '/auth/accept': {
     /**
@@ -804,7 +804,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['auth/accept'];
+    post: operations['auth___accept'];
   };
   '/auth/session/generate': {
     /**
@@ -813,7 +813,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['auth/session/generate'];
+    post: operations['auth___session___generate'];
   };
   '/auth/session/show': {
     /**
@@ -822,7 +822,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['auth/session/show'];
+    post: operations['auth___session___show'];
   };
   '/auth/session/userkey': {
     /**
@@ -831,7 +831,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['auth/session/userkey'];
+    post: operations['auth___session___userkey'];
   };
   '/blocking/create': {
     /**
@@ -840,7 +840,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:blocks*
      */
-    post: operations['blocking/create'];
+    post: operations['blocking___create'];
   };
   '/blocking/delete': {
     /**
@@ -849,7 +849,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:blocks*
      */
-    post: operations['blocking/delete'];
+    post: operations['blocking___delete'];
   };
   '/blocking/list': {
     /**
@@ -858,7 +858,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:blocks*
      */
-    post: operations['blocking/list'];
+    post: operations['blocking___list'];
   };
   '/channels/create': {
     /**
@@ -867,7 +867,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:channels*
      */
-    post: operations['channels/create'];
+    post: operations['channels___create'];
   };
   '/channels/featured': {
     /**
@@ -876,7 +876,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['channels/featured'];
+    post: operations['channels___featured'];
   };
   '/channels/follow': {
     /**
@@ -885,7 +885,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:channels*
      */
-    post: operations['channels/follow'];
+    post: operations['channels___follow'];
   };
   '/channels/followed': {
     /**
@@ -894,7 +894,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:channels*
      */
-    post: operations['channels/followed'];
+    post: operations['channels___followed'];
   };
   '/channels/owned': {
     /**
@@ -903,7 +903,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:channels*
      */
-    post: operations['channels/owned'];
+    post: operations['channels___owned'];
   };
   '/channels/show': {
     /**
@@ -912,7 +912,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['channels/show'];
+    post: operations['channels___show'];
   };
   '/channels/timeline': {
     /**
@@ -921,7 +921,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['channels/timeline'];
+    post: operations['channels___timeline'];
   };
   '/channels/unfollow': {
     /**
@@ -930,7 +930,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:channels*
      */
-    post: operations['channels/unfollow'];
+    post: operations['channels___unfollow'];
   };
   '/channels/update': {
     /**
@@ -939,7 +939,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:channels*
      */
-    post: operations['channels/update'];
+    post: operations['channels___update'];
   };
   '/channels/favorite': {
     /**
@@ -948,7 +948,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:channels*
      */
-    post: operations['channels/favorite'];
+    post: operations['channels___favorite'];
   };
   '/channels/unfavorite': {
     /**
@@ -957,7 +957,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:channels*
      */
-    post: operations['channels/unfavorite'];
+    post: operations['channels___unfavorite'];
   };
   '/channels/my-favorites': {
     /**
@@ -966,7 +966,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:channels*
      */
-    post: operations['channels/my-favorites'];
+    post: operations['channels___my-favorites'];
   };
   '/channels/search': {
     /**
@@ -975,7 +975,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['channels/search'];
+    post: operations['channels___search'];
   };
   '/charts/active-users': {
     /**
@@ -984,14 +984,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['charts/active-users'];
+    get: operations['charts___active-users'];
     /**
      * charts/active-users
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['charts/active-users'];
+    post: operations['charts___active-users'];
   };
   '/charts/ap-request': {
     /**
@@ -1000,14 +1000,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['charts/ap-request'];
+    get: operations['charts___ap-request'];
     /**
      * charts/ap-request
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['charts/ap-request'];
+    post: operations['charts___ap-request'];
   };
   '/charts/drive': {
     /**
@@ -1016,14 +1016,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['charts/drive'];
+    get: operations['charts___drive'];
     /**
      * charts/drive
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['charts/drive'];
+    post: operations['charts___drive'];
   };
   '/charts/federation': {
     /**
@@ -1032,14 +1032,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['charts/federation'];
+    get: operations['charts___federation'];
     /**
      * charts/federation
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['charts/federation'];
+    post: operations['charts___federation'];
   };
   '/charts/instance': {
     /**
@@ -1048,14 +1048,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['charts/instance'];
+    get: operations['charts___instance'];
     /**
      * charts/instance
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['charts/instance'];
+    post: operations['charts___instance'];
   };
   '/charts/notes': {
     /**
@@ -1064,14 +1064,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['charts/notes'];
+    get: operations['charts___notes'];
     /**
      * charts/notes
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['charts/notes'];
+    post: operations['charts___notes'];
   };
   '/charts/user/drive': {
     /**
@@ -1080,14 +1080,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['charts/user/drive'];
+    get: operations['charts___user___drive'];
     /**
      * charts/user/drive
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['charts/user/drive'];
+    post: operations['charts___user___drive'];
   };
   '/charts/user/following': {
     /**
@@ -1096,14 +1096,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['charts/user/following'];
+    get: operations['charts___user___following'];
     /**
      * charts/user/following
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['charts/user/following'];
+    post: operations['charts___user___following'];
   };
   '/charts/user/notes': {
     /**
@@ -1112,14 +1112,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['charts/user/notes'];
+    get: operations['charts___user___notes'];
     /**
      * charts/user/notes
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['charts/user/notes'];
+    post: operations['charts___user___notes'];
   };
   '/charts/user/pv': {
     /**
@@ -1128,14 +1128,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['charts/user/pv'];
+    get: operations['charts___user___pv'];
     /**
      * charts/user/pv
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['charts/user/pv'];
+    post: operations['charts___user___pv'];
   };
   '/charts/user/reactions': {
     /**
@@ -1144,14 +1144,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['charts/user/reactions'];
+    get: operations['charts___user___reactions'];
     /**
      * charts/user/reactions
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['charts/user/reactions'];
+    post: operations['charts___user___reactions'];
   };
   '/charts/users': {
     /**
@@ -1160,14 +1160,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['charts/users'];
+    get: operations['charts___users'];
     /**
      * charts/users
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['charts/users'];
+    post: operations['charts___users'];
   };
   '/clips/add-note': {
     /**
@@ -1176,7 +1176,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['clips/add-note'];
+    post: operations['clips___add-note'];
   };
   '/clips/remove-note': {
     /**
@@ -1185,7 +1185,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['clips/remove-note'];
+    post: operations['clips___remove-note'];
   };
   '/clips/create': {
     /**
@@ -1194,7 +1194,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['clips/create'];
+    post: operations['clips___create'];
   };
   '/clips/delete': {
     /**
@@ -1203,7 +1203,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['clips/delete'];
+    post: operations['clips___delete'];
   };
   '/clips/list': {
     /**
@@ -1212,7 +1212,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['clips/list'];
+    post: operations['clips___list'];
   };
   '/clips/notes': {
     /**
@@ -1221,7 +1221,7 @@ export type paths = {
      *
      * **Credential required**: *No* / **Permission**: *read:account*
      */
-    post: operations['clips/notes'];
+    post: operations['clips___notes'];
   };
   '/clips/show': {
     /**
@@ -1230,7 +1230,7 @@ export type paths = {
      *
      * **Credential required**: *No* / **Permission**: *read:account*
      */
-    post: operations['clips/show'];
+    post: operations['clips___show'];
   };
   '/clips/update': {
     /**
@@ -1239,7 +1239,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['clips/update'];
+    post: operations['clips___update'];
   };
   '/clips/favorite': {
     /**
@@ -1248,7 +1248,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:clip-favorite*
      */
-    post: operations['clips/favorite'];
+    post: operations['clips___favorite'];
   };
   '/clips/unfavorite': {
     /**
@@ -1257,7 +1257,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:clip-favorite*
      */
-    post: operations['clips/unfavorite'];
+    post: operations['clips___unfavorite'];
   };
   '/clips/my-favorites': {
     /**
@@ -1266,7 +1266,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:clip-favorite*
      */
-    post: operations['clips/my-favorites'];
+    post: operations['clips___my-favorites'];
   };
   '/drive': {
     /**
@@ -1284,7 +1284,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:drive*
      */
-    post: operations['drive/files'];
+    post: operations['drive___files'];
   };
   '/drive/files/attached-notes': {
     /**
@@ -1293,7 +1293,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:drive*
      */
-    post: operations['drive/files/attached-notes'];
+    post: operations['drive___files___attached-notes'];
   };
   '/drive/files/check-existence': {
     /**
@@ -1302,7 +1302,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:drive*
      */
-    post: operations['drive/files/check-existence'];
+    post: operations['drive___files___check-existence'];
   };
   '/drive/files/create': {
     /**
@@ -1311,7 +1311,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:drive*
      */
-    post: operations['drive/files/create'];
+    post: operations['drive___files___create'];
   };
   '/drive/files/delete': {
     /**
@@ -1320,7 +1320,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:drive*
      */
-    post: operations['drive/files/delete'];
+    post: operations['drive___files___delete'];
   };
   '/drive/files/find-by-hash': {
     /**
@@ -1329,7 +1329,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:drive*
      */
-    post: operations['drive/files/find-by-hash'];
+    post: operations['drive___files___find-by-hash'];
   };
   '/drive/files/find': {
     /**
@@ -1338,7 +1338,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:drive*
      */
-    post: operations['drive/files/find'];
+    post: operations['drive___files___find'];
   };
   '/drive/files/show': {
     /**
@@ -1347,7 +1347,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:drive*
      */
-    post: operations['drive/files/show'];
+    post: operations['drive___files___show'];
   };
   '/drive/files/update': {
     /**
@@ -1356,7 +1356,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:drive*
      */
-    post: operations['drive/files/update'];
+    post: operations['drive___files___update'];
   };
   '/drive/files/upload-from-url': {
     /**
@@ -1365,7 +1365,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:drive*
      */
-    post: operations['drive/files/upload-from-url'];
+    post: operations['drive___files___upload-from-url'];
   };
   '/drive/folders': {
     /**
@@ -1374,7 +1374,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:drive*
      */
-    post: operations['drive/folders'];
+    post: operations['drive___folders'];
   };
   '/drive/folders/create': {
     /**
@@ -1383,7 +1383,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:drive*
      */
-    post: operations['drive/folders/create'];
+    post: operations['drive___folders___create'];
   };
   '/drive/folders/delete': {
     /**
@@ -1392,7 +1392,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:drive*
      */
-    post: operations['drive/folders/delete'];
+    post: operations['drive___folders___delete'];
   };
   '/drive/folders/find': {
     /**
@@ -1401,7 +1401,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:drive*
      */
-    post: operations['drive/folders/find'];
+    post: operations['drive___folders___find'];
   };
   '/drive/folders/show': {
     /**
@@ -1410,7 +1410,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:drive*
      */
-    post: operations['drive/folders/show'];
+    post: operations['drive___folders___show'];
   };
   '/drive/folders/update': {
     /**
@@ -1419,7 +1419,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:drive*
      */
-    post: operations['drive/folders/update'];
+    post: operations['drive___folders___update'];
   };
   '/drive/stream': {
     /**
@@ -1428,7 +1428,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:drive*
      */
-    post: operations['drive/stream'];
+    post: operations['drive___stream'];
   };
   '/email-address/available': {
     /**
@@ -1437,7 +1437,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['email-address/available'];
+    post: operations['email-address___available'];
   };
   '/endpoint': {
     /**
@@ -1474,7 +1474,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['federation/followers'];
+    post: operations['federation___followers'];
   };
   '/federation/following': {
     /**
@@ -1483,7 +1483,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['federation/following'];
+    post: operations['federation___following'];
   };
   '/federation/instances': {
     /**
@@ -1492,14 +1492,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['federation/instances'];
+    get: operations['federation___instances'];
     /**
      * federation/instances
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['federation/instances'];
+    post: operations['federation___instances'];
   };
   '/federation/show-instance': {
     /**
@@ -1508,7 +1508,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['federation/show-instance'];
+    post: operations['federation___show-instance'];
   };
   '/federation/update-remote-user': {
     /**
@@ -1517,7 +1517,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['federation/update-remote-user'];
+    post: operations['federation___update-remote-user'];
   };
   '/federation/users': {
     /**
@@ -1526,7 +1526,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['federation/users'];
+    post: operations['federation___users'];
   };
   '/federation/stats': {
     /**
@@ -1535,14 +1535,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['federation/stats'];
+    get: operations['federation___stats'];
     /**
      * federation/stats
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['federation/stats'];
+    post: operations['federation___stats'];
   };
   '/following/create': {
     /**
@@ -1551,7 +1551,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:following*
      */
-    post: operations['following/create'];
+    post: operations['following___create'];
   };
   '/following/delete': {
     /**
@@ -1560,7 +1560,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:following*
      */
-    post: operations['following/delete'];
+    post: operations['following___delete'];
   };
   '/following/update': {
     /**
@@ -1569,7 +1569,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:following*
      */
-    post: operations['following/update'];
+    post: operations['following___update'];
   };
   '/following/update-all': {
     /**
@@ -1578,7 +1578,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:following*
      */
-    post: operations['following/update-all'];
+    post: operations['following___update-all'];
   };
   '/following/invalidate': {
     /**
@@ -1587,7 +1587,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:following*
      */
-    post: operations['following/invalidate'];
+    post: operations['following___invalidate'];
   };
   '/following/requests/accept': {
     /**
@@ -1596,7 +1596,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:following*
      */
-    post: operations['following/requests/accept'];
+    post: operations['following___requests___accept'];
   };
   '/following/requests/cancel': {
     /**
@@ -1605,7 +1605,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:following*
      */
-    post: operations['following/requests/cancel'];
+    post: operations['following___requests___cancel'];
   };
   '/following/requests/list': {
     /**
@@ -1614,7 +1614,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:following*
      */
-    post: operations['following/requests/list'];
+    post: operations['following___requests___list'];
   };
   '/following/requests/reject': {
     /**
@@ -1623,7 +1623,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:following*
      */
-    post: operations['following/requests/reject'];
+    post: operations['following___requests___reject'];
   };
   '/gallery/featured': {
     /**
@@ -1632,7 +1632,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['gallery/featured'];
+    post: operations['gallery___featured'];
   };
   '/gallery/popular': {
     /**
@@ -1641,7 +1641,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['gallery/popular'];
+    post: operations['gallery___popular'];
   };
   '/gallery/posts': {
     /**
@@ -1650,7 +1650,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['gallery/posts'];
+    post: operations['gallery___posts'];
   };
   '/gallery/posts/create': {
     /**
@@ -1659,7 +1659,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:gallery*
      */
-    post: operations['gallery/posts/create'];
+    post: operations['gallery___posts___create'];
   };
   '/gallery/posts/delete': {
     /**
@@ -1668,7 +1668,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:gallery*
      */
-    post: operations['gallery/posts/delete'];
+    post: operations['gallery___posts___delete'];
   };
   '/gallery/posts/like': {
     /**
@@ -1677,7 +1677,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:gallery-likes*
      */
-    post: operations['gallery/posts/like'];
+    post: operations['gallery___posts___like'];
   };
   '/gallery/posts/show': {
     /**
@@ -1686,7 +1686,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['gallery/posts/show'];
+    post: operations['gallery___posts___show'];
   };
   '/gallery/posts/unlike': {
     /**
@@ -1695,7 +1695,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:gallery-likes*
      */
-    post: operations['gallery/posts/unlike'];
+    post: operations['gallery___posts___unlike'];
   };
   '/gallery/posts/update': {
     /**
@@ -1704,7 +1704,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:gallery*
      */
-    post: operations['gallery/posts/update'];
+    post: operations['gallery___posts___update'];
   };
   '/get-online-users-count': {
     /**
@@ -1738,7 +1738,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['hashtags/list'];
+    post: operations['hashtags___list'];
   };
   '/hashtags/search': {
     /**
@@ -1747,7 +1747,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['hashtags/search'];
+    post: operations['hashtags___search'];
   };
   '/hashtags/show': {
     /**
@@ -1756,7 +1756,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['hashtags/show'];
+    post: operations['hashtags___show'];
   };
   '/hashtags/trend': {
     /**
@@ -1765,14 +1765,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['hashtags/trend'];
+    get: operations['hashtags___trend'];
     /**
      * hashtags/trend
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['hashtags/trend'];
+    post: operations['hashtags___trend'];
   };
   '/hashtags/users': {
     /**
@@ -1781,7 +1781,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['hashtags/users'];
+    post: operations['hashtags___users'];
   };
   '/i': {
     /**
@@ -1800,7 +1800,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/2fa/done'];
+    post: operations['i___2fa___done'];
   };
   '/i/2fa/key-done': {
     /**
@@ -1810,7 +1810,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/2fa/key-done'];
+    post: operations['i___2fa___key-done'];
   };
   '/i/2fa/password-less': {
     /**
@@ -1820,7 +1820,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/2fa/password-less'];
+    post: operations['i___2fa___password-less'];
   };
   '/i/2fa/register-key': {
     /**
@@ -1830,7 +1830,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/2fa/register-key'];
+    post: operations['i___2fa___register-key'];
   };
   '/i/2fa/register': {
     /**
@@ -1840,7 +1840,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/2fa/register'];
+    post: operations['i___2fa___register'];
   };
   '/i/2fa/update-key': {
     /**
@@ -1850,7 +1850,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/2fa/update-key'];
+    post: operations['i___2fa___update-key'];
   };
   '/i/2fa/remove-key': {
     /**
@@ -1860,7 +1860,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/2fa/remove-key'];
+    post: operations['i___2fa___remove-key'];
   };
   '/i/2fa/unregister': {
     /**
@@ -1870,7 +1870,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/2fa/unregister'];
+    post: operations['i___2fa___unregister'];
   };
   '/i/apps': {
     /**
@@ -1880,7 +1880,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/apps'];
+    post: operations['i___apps'];
   };
   '/i/authorized-apps': {
     /**
@@ -1890,7 +1890,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/authorized-apps'];
+    post: operations['i___authorized-apps'];
   };
   '/i/claim-achievement': {
     /**
@@ -1899,7 +1899,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['i/claim-achievement'];
+    post: operations['i___claim-achievement'];
   };
   '/i/change-password': {
     /**
@@ -1909,7 +1909,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/change-password'];
+    post: operations['i___change-password'];
   };
   '/i/delete-account': {
     /**
@@ -1919,7 +1919,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/delete-account'];
+    post: operations['i___delete-account'];
   };
   '/i/export-blocking': {
     /**
@@ -1929,7 +1929,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/export-blocking'];
+    post: operations['i___export-blocking'];
   };
   '/i/export-following': {
     /**
@@ -1939,7 +1939,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/export-following'];
+    post: operations['i___export-following'];
   };
   '/i/export-mute': {
     /**
@@ -1949,7 +1949,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/export-mute'];
+    post: operations['i___export-mute'];
   };
   '/i/export-notes': {
     /**
@@ -1959,7 +1959,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/export-notes'];
+    post: operations['i___export-notes'];
   };
   '/i/export-clips': {
     /**
@@ -1969,7 +1969,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/export-clips'];
+    post: operations['i___export-clips'];
   };
   '/i/export-favorites': {
     /**
@@ -1979,7 +1979,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/export-favorites'];
+    post: operations['i___export-favorites'];
   };
   '/i/export-user-lists': {
     /**
@@ -1989,7 +1989,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/export-user-lists'];
+    post: operations['i___export-user-lists'];
   };
   '/i/export-antennas': {
     /**
@@ -1999,7 +1999,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/export-antennas'];
+    post: operations['i___export-antennas'];
   };
   '/i/favorites': {
     /**
@@ -2008,7 +2008,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:favorites*
      */
-    post: operations['i/favorites'];
+    post: operations['i___favorites'];
   };
   '/i/gallery/likes': {
     /**
@@ -2017,7 +2017,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:gallery-likes*
      */
-    post: operations['i/gallery/likes'];
+    post: operations['i___gallery___likes'];
   };
   '/i/gallery/posts': {
     /**
@@ -2026,7 +2026,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:gallery*
      */
-    post: operations['i/gallery/posts'];
+    post: operations['i___gallery___posts'];
   };
   '/i/import-blocking': {
     /**
@@ -2036,7 +2036,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/import-blocking'];
+    post: operations['i___import-blocking'];
   };
   '/i/import-following': {
     /**
@@ -2046,7 +2046,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/import-following'];
+    post: operations['i___import-following'];
   };
   '/i/import-muting': {
     /**
@@ -2056,7 +2056,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/import-muting'];
+    post: operations['i___import-muting'];
   };
   '/i/import-user-lists': {
     /**
@@ -2066,7 +2066,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/import-user-lists'];
+    post: operations['i___import-user-lists'];
   };
   '/i/import-antennas': {
     /**
@@ -2076,7 +2076,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/import-antennas'];
+    post: operations['i___import-antennas'];
   };
   '/i/notifications': {
     /**
@@ -2085,7 +2085,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:notifications*
      */
-    post: operations['i/notifications'];
+    post: operations['i___notifications'];
   };
   '/i/notifications-grouped': {
     /**
@@ -2094,7 +2094,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:notifications*
      */
-    post: operations['i/notifications-grouped'];
+    post: operations['i___notifications-grouped'];
   };
   '/i/page-likes': {
     /**
@@ -2103,7 +2103,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:page-likes*
      */
-    post: operations['i/page-likes'];
+    post: operations['i___page-likes'];
   };
   '/i/pages': {
     /**
@@ -2112,7 +2112,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:pages*
      */
-    post: operations['i/pages'];
+    post: operations['i___pages'];
   };
   '/i/pin': {
     /**
@@ -2121,7 +2121,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['i/pin'];
+    post: operations['i___pin'];
   };
   '/i/read-all-unread-notes': {
     /**
@@ -2130,7 +2130,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['i/read-all-unread-notes'];
+    post: operations['i___read-all-unread-notes'];
   };
   '/i/read-announcement': {
     /**
@@ -2139,7 +2139,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['i/read-announcement'];
+    post: operations['i___read-announcement'];
   };
   '/i/regenerate-token': {
     /**
@@ -2149,7 +2149,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/regenerate-token'];
+    post: operations['i___regenerate-token'];
   };
   '/i/registry/get-all': {
     /**
@@ -2158,7 +2158,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['i/registry/get-all'];
+    post: operations['i___registry___get-all'];
   };
   '/i/registry/get-detail': {
     /**
@@ -2167,7 +2167,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['i/registry/get-detail'];
+    post: operations['i___registry___get-detail'];
   };
   '/i/registry/get': {
     /**
@@ -2176,7 +2176,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['i/registry/get'];
+    post: operations['i___registry___get'];
   };
   '/i/registry/keys-with-type': {
     /**
@@ -2185,7 +2185,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['i/registry/keys-with-type'];
+    post: operations['i___registry___keys-with-type'];
   };
   '/i/registry/keys': {
     /**
@@ -2194,7 +2194,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['i/registry/keys'];
+    post: operations['i___registry___keys'];
   };
   '/i/registry/remove': {
     /**
@@ -2203,7 +2203,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['i/registry/remove'];
+    post: operations['i___registry___remove'];
   };
   '/i/registry/scopes-with-domain': {
     /**
@@ -2213,7 +2213,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/registry/scopes-with-domain'];
+    post: operations['i___registry___scopes-with-domain'];
   };
   '/i/registry/set': {
     /**
@@ -2222,7 +2222,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['i/registry/set'];
+    post: operations['i___registry___set'];
   };
   '/i/revoke-token': {
     /**
@@ -2232,7 +2232,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/revoke-token'];
+    post: operations['i___revoke-token'];
   };
   '/i/signin-history': {
     /**
@@ -2242,7 +2242,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/signin-history'];
+    post: operations['i___signin-history'];
   };
   '/i/unpin': {
     /**
@@ -2251,7 +2251,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['i/unpin'];
+    post: operations['i___unpin'];
   };
   '/i/update-email': {
     /**
@@ -2261,7 +2261,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/update-email'];
+    post: operations['i___update-email'];
   };
   '/i/update': {
     /**
@@ -2270,7 +2270,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['i/update'];
+    post: operations['i___update'];
   };
   '/i/move': {
     /**
@@ -2280,7 +2280,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['i/move'];
+    post: operations['i___move'];
   };
   '/i/webhooks/create': {
     /**
@@ -2289,7 +2289,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['i/webhooks/create'];
+    post: operations['i___webhooks___create'];
   };
   '/i/webhooks/list': {
     /**
@@ -2298,7 +2298,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['i/webhooks/list'];
+    post: operations['i___webhooks___list'];
   };
   '/i/webhooks/show': {
     /**
@@ -2307,7 +2307,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['i/webhooks/show'];
+    post: operations['i___webhooks___show'];
   };
   '/i/webhooks/update': {
     /**
@@ -2316,7 +2316,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['i/webhooks/update'];
+    post: operations['i___webhooks___update'];
   };
   '/i/webhooks/delete': {
     /**
@@ -2325,7 +2325,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['i/webhooks/delete'];
+    post: operations['i___webhooks___delete'];
   };
   '/invite/create': {
     /**
@@ -2334,7 +2334,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:invite-codes*
      */
-    post: operations['invite/create'];
+    post: operations['invite___create'];
   };
   '/invite/delete': {
     /**
@@ -2343,7 +2343,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:invite-codes*
      */
-    post: operations['invite/delete'];
+    post: operations['invite___delete'];
   };
   '/invite/list': {
     /**
@@ -2352,7 +2352,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:invite-codes*
      */
-    post: operations['invite/list'];
+    post: operations['invite___list'];
   };
   '/invite/limit': {
     /**
@@ -2361,7 +2361,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:invite-codes*
      */
-    post: operations['invite/limit'];
+    post: operations['invite___limit'];
   };
   '/meta': {
     /**
@@ -2412,7 +2412,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['miauth/gen-token'];
+    post: operations['miauth___gen-token'];
   };
   '/mute/create': {
     /**
@@ -2421,7 +2421,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:mutes*
      */
-    post: operations['mute/create'];
+    post: operations['mute___create'];
   };
   '/mute/delete': {
     /**
@@ -2430,7 +2430,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:mutes*
      */
-    post: operations['mute/delete'];
+    post: operations['mute___delete'];
   };
   '/mute/list': {
     /**
@@ -2439,7 +2439,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:mutes*
      */
-    post: operations['mute/list'];
+    post: operations['mute___list'];
   };
   '/renote-mute/create': {
     /**
@@ -2448,7 +2448,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:mutes*
      */
-    post: operations['renote-mute/create'];
+    post: operations['renote-mute___create'];
   };
   '/renote-mute/delete': {
     /**
@@ -2457,7 +2457,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:mutes*
      */
-    post: operations['renote-mute/delete'];
+    post: operations['renote-mute___delete'];
   };
   '/renote-mute/list': {
     /**
@@ -2466,7 +2466,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:mutes*
      */
-    post: operations['renote-mute/list'];
+    post: operations['renote-mute___list'];
   };
   '/my/apps': {
     /**
@@ -2475,7 +2475,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['my/apps'];
+    post: operations['my___apps'];
   };
   '/notes': {
     /**
@@ -2493,7 +2493,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['notes/children'];
+    post: operations['notes___children'];
   };
   '/notes/clips': {
     /**
@@ -2502,7 +2502,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['notes/clips'];
+    post: operations['notes___clips'];
   };
   '/notes/conversation': {
     /**
@@ -2511,7 +2511,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['notes/conversation'];
+    post: operations['notes___conversation'];
   };
   '/notes/create': {
     /**
@@ -2520,7 +2520,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:notes*
      */
-    post: operations['notes/create'];
+    post: operations['notes___create'];
   };
   '/notes/delete': {
     /**
@@ -2529,7 +2529,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:notes*
      */
-    post: operations['notes/delete'];
+    post: operations['notes___delete'];
   };
   '/notes/favorites/create': {
     /**
@@ -2538,7 +2538,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:favorites*
      */
-    post: operations['notes/favorites/create'];
+    post: operations['notes___favorites___create'];
   };
   '/notes/favorites/delete': {
     /**
@@ -2547,7 +2547,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:favorites*
      */
-    post: operations['notes/favorites/delete'];
+    post: operations['notes___favorites___delete'];
   };
   '/notes/featured': {
     /**
@@ -2556,14 +2556,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['notes/featured'];
+    get: operations['notes___featured'];
     /**
      * notes/featured
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['notes/featured'];
+    post: operations['notes___featured'];
   };
   '/notes/global-timeline': {
     /**
@@ -2572,7 +2572,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['notes/global-timeline'];
+    post: operations['notes___global-timeline'];
   };
   '/notes/hybrid-timeline': {
     /**
@@ -2581,7 +2581,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['notes/hybrid-timeline'];
+    post: operations['notes___hybrid-timeline'];
   };
   '/notes/local-timeline': {
     /**
@@ -2590,7 +2590,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['notes/local-timeline'];
+    post: operations['notes___local-timeline'];
   };
   '/notes/mentions': {
     /**
@@ -2599,7 +2599,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['notes/mentions'];
+    post: operations['notes___mentions'];
   };
   '/notes/polls/recommendation': {
     /**
@@ -2608,7 +2608,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['notes/polls/recommendation'];
+    post: operations['notes___polls___recommendation'];
   };
   '/notes/polls/vote': {
     /**
@@ -2617,7 +2617,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:votes*
      */
-    post: operations['notes/polls/vote'];
+    post: operations['notes___polls___vote'];
   };
   '/notes/reactions': {
     /**
@@ -2626,14 +2626,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['notes/reactions'];
+    get: operations['notes___reactions'];
     /**
      * notes/reactions
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['notes/reactions'];
+    post: operations['notes___reactions'];
   };
   '/notes/reactions/create': {
     /**
@@ -2642,7 +2642,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:reactions*
      */
-    post: operations['notes/reactions/create'];
+    post: operations['notes___reactions___create'];
   };
   '/notes/reactions/delete': {
     /**
@@ -2651,7 +2651,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:reactions*
      */
-    post: operations['notes/reactions/delete'];
+    post: operations['notes___reactions___delete'];
   };
   '/notes/renotes': {
     /**
@@ -2660,7 +2660,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['notes/renotes'];
+    post: operations['notes___renotes'];
   };
   '/notes/replies': {
     /**
@@ -2669,7 +2669,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['notes/replies'];
+    post: operations['notes___replies'];
   };
   '/notes/search-by-tag': {
     /**
@@ -2678,7 +2678,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['notes/search-by-tag'];
+    post: operations['notes___search-by-tag'];
   };
   '/notes/search': {
     /**
@@ -2687,7 +2687,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['notes/search'];
+    post: operations['notes___search'];
   };
   '/notes/show': {
     /**
@@ -2696,7 +2696,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['notes/show'];
+    post: operations['notes___show'];
   };
   '/notes/state': {
     /**
@@ -2705,7 +2705,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['notes/state'];
+    post: operations['notes___state'];
   };
   '/notes/thread-muting/create': {
     /**
@@ -2714,7 +2714,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['notes/thread-muting/create'];
+    post: operations['notes___thread-muting___create'];
   };
   '/notes/thread-muting/delete': {
     /**
@@ -2723,7 +2723,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['notes/thread-muting/delete'];
+    post: operations['notes___thread-muting___delete'];
   };
   '/notes/timeline': {
     /**
@@ -2732,7 +2732,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['notes/timeline'];
+    post: operations['notes___timeline'];
   };
   '/notes/translate': {
     /**
@@ -2741,7 +2741,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['notes/translate'];
+    post: operations['notes___translate'];
   };
   '/notes/unrenote': {
     /**
@@ -2750,7 +2750,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:notes*
      */
-    post: operations['notes/unrenote'];
+    post: operations['notes___unrenote'];
   };
   '/notes/user-list-timeline': {
     /**
@@ -2759,7 +2759,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['notes/user-list-timeline'];
+    post: operations['notes___user-list-timeline'];
   };
   '/notifications/create': {
     /**
@@ -2768,7 +2768,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:notifications*
      */
-    post: operations['notifications/create'];
+    post: operations['notifications___create'];
   };
   '/notifications/flush': {
     /**
@@ -2777,7 +2777,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:notifications*
      */
-    post: operations['notifications/flush'];
+    post: operations['notifications___flush'];
   };
   '/notifications/mark-all-as-read': {
     /**
@@ -2786,7 +2786,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:notifications*
      */
-    post: operations['notifications/mark-all-as-read'];
+    post: operations['notifications___mark-all-as-read'];
   };
   '/notifications/test-notification': {
     /**
@@ -2795,7 +2795,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:notifications*
      */
-    post: operations['notifications/test-notification'];
+    post: operations['notifications___test-notification'];
   };
   '/page-push': {
     /**
@@ -2814,7 +2814,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:pages*
      */
-    post: operations['pages/create'];
+    post: operations['pages___create'];
   };
   '/pages/delete': {
     /**
@@ -2823,7 +2823,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:pages*
      */
-    post: operations['pages/delete'];
+    post: operations['pages___delete'];
   };
   '/pages/featured': {
     /**
@@ -2832,7 +2832,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['pages/featured'];
+    post: operations['pages___featured'];
   };
   '/pages/like': {
     /**
@@ -2841,7 +2841,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:page-likes*
      */
-    post: operations['pages/like'];
+    post: operations['pages___like'];
   };
   '/pages/show': {
     /**
@@ -2850,7 +2850,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['pages/show'];
+    post: operations['pages___show'];
   };
   '/pages/unlike': {
     /**
@@ -2859,7 +2859,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:page-likes*
      */
-    post: operations['pages/unlike'];
+    post: operations['pages___unlike'];
   };
   '/pages/update': {
     /**
@@ -2868,7 +2868,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:pages*
      */
-    post: operations['pages/update'];
+    post: operations['pages___update'];
   };
   '/flash/create': {
     /**
@@ -2877,7 +2877,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:flash*
      */
-    post: operations['flash/create'];
+    post: operations['flash___create'];
   };
   '/flash/delete': {
     /**
@@ -2886,7 +2886,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:flash*
      */
-    post: operations['flash/delete'];
+    post: operations['flash___delete'];
   };
   '/flash/featured': {
     /**
@@ -2895,7 +2895,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['flash/featured'];
+    post: operations['flash___featured'];
   };
   '/flash/like': {
     /**
@@ -2904,7 +2904,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:flash-likes*
      */
-    post: operations['flash/like'];
+    post: operations['flash___like'];
   };
   '/flash/show': {
     /**
@@ -2913,7 +2913,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['flash/show'];
+    post: operations['flash___show'];
   };
   '/flash/unlike': {
     /**
@@ -2922,7 +2922,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:flash-likes*
      */
-    post: operations['flash/unlike'];
+    post: operations['flash___unlike'];
   };
   '/flash/update': {
     /**
@@ -2931,7 +2931,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:flash*
      */
-    post: operations['flash/update'];
+    post: operations['flash___update'];
   };
   '/flash/my': {
     /**
@@ -2940,7 +2940,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:flash*
      */
-    post: operations['flash/my'];
+    post: operations['flash___my'];
   };
   '/flash/my-likes': {
     /**
@@ -2949,7 +2949,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:flash-likes*
      */
-    post: operations['flash/my-likes'];
+    post: operations['flash___my-likes'];
   };
   '/ping': {
     /**
@@ -2976,7 +2976,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['promo/read'];
+    post: operations['promo___read'];
   };
   '/roles/list': {
     /**
@@ -2985,7 +2985,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['roles/list'];
+    post: operations['roles___list'];
   };
   '/roles/show': {
     /**
@@ -2994,7 +2994,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['roles/show'];
+    post: operations['roles___show'];
   };
   '/roles/users': {
     /**
@@ -3003,7 +3003,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['roles/users'];
+    post: operations['roles___users'];
   };
   '/roles/notes': {
     /**
@@ -3012,7 +3012,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['roles/notes'];
+    post: operations['roles___notes'];
   };
   '/request-reset-password': {
     /**
@@ -3074,7 +3074,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['sw/show-registration'];
+    post: operations['sw___show-registration'];
   };
   '/sw/update-registration': {
     /**
@@ -3084,7 +3084,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['sw/update-registration'];
+    post: operations['sw___update-registration'];
   };
   '/sw/register': {
     /**
@@ -3094,7 +3094,7 @@ export type paths = {
      * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
      * **Credential required**: *Yes*
      */
-    post: operations['sw/register'];
+    post: operations['sw___register'];
   };
   '/sw/unregister': {
     /**
@@ -3103,7 +3103,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['sw/unregister'];
+    post: operations['sw___unregister'];
   };
   '/test': {
     /**
@@ -3121,7 +3121,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['username/available'];
+    post: operations['username___available'];
   };
   '/users': {
     /**
@@ -3139,7 +3139,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['users/clips'];
+    post: operations['users___clips'];
   };
   '/users/followers': {
     /**
@@ -3148,7 +3148,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['users/followers'];
+    post: operations['users___followers'];
   };
   '/users/following': {
     /**
@@ -3157,7 +3157,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['users/following'];
+    post: operations['users___following'];
   };
   '/users/gallery/posts': {
     /**
@@ -3166,7 +3166,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['users/gallery/posts'];
+    post: operations['users___gallery___posts'];
   };
   '/users/get-frequently-replied-users': {
     /**
@@ -3175,7 +3175,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['users/get-frequently-replied-users'];
+    post: operations['users___get-frequently-replied-users'];
   };
   '/users/featured-notes': {
     /**
@@ -3184,14 +3184,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['users/featured-notes'];
+    get: operations['users___featured-notes'];
     /**
      * users/featured-notes
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['users/featured-notes'];
+    post: operations['users___featured-notes'];
   };
   '/users/lists/create': {
     /**
@@ -3200,7 +3200,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['users/lists/create'];
+    post: operations['users___lists___create'];
   };
   '/users/lists/delete': {
     /**
@@ -3209,7 +3209,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['users/lists/delete'];
+    post: operations['users___lists___delete'];
   };
   '/users/lists/list': {
     /**
@@ -3218,7 +3218,7 @@ export type paths = {
      *
      * **Credential required**: *No* / **Permission**: *read:account*
      */
-    post: operations['users/lists/list'];
+    post: operations['users___lists___list'];
   };
   '/users/lists/pull': {
     /**
@@ -3227,7 +3227,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['users/lists/pull'];
+    post: operations['users___lists___pull'];
   };
   '/users/lists/push': {
     /**
@@ -3236,7 +3236,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['users/lists/push'];
+    post: operations['users___lists___push'];
   };
   '/users/lists/show': {
     /**
@@ -3245,7 +3245,7 @@ export type paths = {
      *
      * **Credential required**: *No* / **Permission**: *read:account*
      */
-    post: operations['users/lists/show'];
+    post: operations['users___lists___show'];
   };
   '/users/lists/favorite': {
     /**
@@ -3254,7 +3254,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['users/lists/favorite'];
+    post: operations['users___lists___favorite'];
   };
   '/users/lists/unfavorite': {
     /**
@@ -3263,7 +3263,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['users/lists/unfavorite'];
+    post: operations['users___lists___unfavorite'];
   };
   '/users/lists/update': {
     /**
@@ -3272,7 +3272,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['users/lists/update'];
+    post: operations['users___lists___update'];
   };
   '/users/lists/create-from-public': {
     /**
@@ -3281,7 +3281,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['users/lists/create-from-public'];
+    post: operations['users___lists___create-from-public'];
   };
   '/users/lists/update-membership': {
     /**
@@ -3290,7 +3290,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['users/lists/update-membership'];
+    post: operations['users___lists___update-membership'];
   };
   '/users/lists/get-memberships': {
     /**
@@ -3299,7 +3299,7 @@ export type paths = {
      *
      * **Credential required**: *No* / **Permission**: *read:account*
      */
-    post: operations['users/lists/get-memberships'];
+    post: operations['users___lists___get-memberships'];
   };
   '/users/notes': {
     /**
@@ -3308,7 +3308,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['users/notes'];
+    post: operations['users___notes'];
   };
   '/users/pages': {
     /**
@@ -3317,7 +3317,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['users/pages'];
+    post: operations['users___pages'];
   };
   '/users/flashs': {
     /**
@@ -3326,7 +3326,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['users/flashs'];
+    post: operations['users___flashs'];
   };
   '/users/reactions': {
     /**
@@ -3335,7 +3335,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['users/reactions'];
+    post: operations['users___reactions'];
   };
   '/users/recommendation': {
     /**
@@ -3344,7 +3344,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['users/recommendation'];
+    post: operations['users___recommendation'];
   };
   '/users/relation': {
     /**
@@ -3353,7 +3353,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['users/relation'];
+    post: operations['users___relation'];
   };
   '/users/report-abuse': {
     /**
@@ -3362,7 +3362,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:report-abuse*
      */
-    post: operations['users/report-abuse'];
+    post: operations['users___report-abuse'];
   };
   '/users/search-by-username-and-host': {
     /**
@@ -3371,7 +3371,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['users/search-by-username-and-host'];
+    post: operations['users___search-by-username-and-host'];
   };
   '/users/search': {
     /**
@@ -3380,7 +3380,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['users/search'];
+    post: operations['users___search'];
   };
   '/users/show': {
     /**
@@ -3389,7 +3389,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['users/show'];
+    post: operations['users___show'];
   };
   '/users/achievements': {
     /**
@@ -3398,7 +3398,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['users/achievements'];
+    post: operations['users___achievements'];
   };
   '/users/update-memo': {
     /**
@@ -3407,7 +3407,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['users/update-memo'];
+    post: operations['users___update-memo'];
   };
   '/fetch-rss': {
     /**
@@ -3458,7 +3458,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['bubble-game/register'];
+    post: operations['bubble-game___register'];
   };
   '/bubble-game/ranking': {
     /**
@@ -3467,14 +3467,14 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    get: operations['bubble-game/ranking'];
+    get: operations['bubble-game___ranking'];
     /**
      * bubble-game/ranking
      * @description No description provided.
      *
      * **Credential required**: *No*
      */
-    post: operations['bubble-game/ranking'];
+    post: operations['bubble-game___ranking'];
   };
   '/reversi/cancel-match': {
     /**
@@ -3483,7 +3483,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['reversi/cancel-match'];
+    post: operations['reversi___cancel-match'];
   };
   '/reversi/games': {
     /**
@@ -3492,7 +3492,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['reversi/games'];
+    post: operations['reversi___games'];
   };
   '/reversi/match': {
     /**
@@ -3501,7 +3501,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['reversi/match'];
+    post: operations['reversi___match'];
   };
   '/reversi/invitations': {
     /**
@@ -3510,7 +3510,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *read:account*
      */
-    post: operations['reversi/invitations'];
+    post: operations['reversi___invitations'];
   };
   '/reversi/show-game': {
     /**
@@ -3519,7 +3519,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['reversi/show-game'];
+    post: operations['reversi___show-game'];
   };
   '/reversi/surrender': {
     /**
@@ -3528,7 +3528,7 @@ export type paths = {
      *
      * **Credential required**: *Yes* / **Permission**: *write:account*
      */
-    post: operations['reversi/surrender'];
+    post: operations['reversi___surrender'];
   };
   '/reversi/verify': {
     /**
@@ -3537,7 +3537,7 @@ export type paths = {
      *
      * **Credential required**: *No*
      */
-    post: operations['reversi/verify'];
+    post: operations['reversi___verify'];
   };
 };
 
@@ -4860,7 +4860,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:meta*
    */
-  'admin/meta': {
+  admin___meta: {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -5019,7 +5019,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-user-reports*
    */
-  'admin/abuse-user-reports': {
+  'admin___abuse-user-reports': {
     requestBody: {
       content: {
         'application/json': {
@@ -5111,7 +5111,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'admin/accounts/create': {
+  admin___accounts___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -5165,7 +5165,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:account*
    */
-  'admin/accounts/delete': {
+  admin___accounts___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -5217,7 +5217,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:account*
    */
-  'admin/accounts/find-by-email': {
+  'admin___accounts___find-by-email': {
     requestBody: {
       content: {
         'application/json': {
@@ -5270,7 +5270,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:ad*
    */
-  'admin/ad/create': {
+  admin___ad___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -5331,7 +5331,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:ad*
    */
-  'admin/ad/delete': {
+  admin___ad___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -5383,7 +5383,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:ad*
    */
-  'admin/ad/list': {
+  admin___ad___list: {
     requestBody: {
       content: {
         'application/json': {
@@ -5443,7 +5443,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:ad*
    */
-  'admin/ad/update': {
+  admin___ad___update: {
     requestBody: {
       content: {
         'application/json': {
@@ -5504,7 +5504,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:announcements*
    */
-  'admin/announcements/create': {
+  admin___announcements___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -5593,7 +5593,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:announcements*
    */
-  'admin/announcements/delete': {
+  admin___announcements___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -5645,7 +5645,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:announcements*
    */
-  'admin/announcements/list': {
+  admin___announcements___list: {
     requestBody: {
       content: {
         'application/json': {
@@ -5719,7 +5719,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:announcements*
    */
-  'admin/announcements/update': {
+  admin___announcements___update: {
     requestBody: {
       content: {
         'application/json': {
@@ -5782,7 +5782,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations*
    */
-  'admin/avatar-decorations/create': {
+  'admin___avatar-decorations___create': {
     requestBody: {
       content: {
         'application/json': {
@@ -5836,7 +5836,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations*
    */
-  'admin/avatar-decorations/delete': {
+  'admin___avatar-decorations___delete': {
     requestBody: {
       content: {
         'application/json': {
@@ -5888,7 +5888,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:avatar-decorations*
    */
-  'admin/avatar-decorations/list': {
+  'admin___avatar-decorations___list': {
     requestBody: {
       content: {
         'application/json': {
@@ -5962,7 +5962,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations*
    */
-  'admin/avatar-decorations/update': {
+  'admin___avatar-decorations___update': {
     requestBody: {
       content: {
         'application/json': {
@@ -6018,7 +6018,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:delete-all-files-of-a-user*
    */
-  'admin/delete-all-files-of-a-user': {
+  'admin___delete-all-files-of-a-user': {
     requestBody: {
       content: {
         'application/json': {
@@ -6070,7 +6070,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:unset-user-avatar*
    */
-  'admin/unset-user-avatar': {
+  'admin___unset-user-avatar': {
     requestBody: {
       content: {
         'application/json': {
@@ -6122,7 +6122,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:unset-user-banner*
    */
-  'admin/unset-user-banner': {
+  'admin___unset-user-banner': {
     requestBody: {
       content: {
         'application/json': {
@@ -6174,7 +6174,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:drive*
    */
-  'admin/drive/clean-remote-files': {
+  'admin___drive___clean-remote-files': {
     responses: {
       /** @description OK (without any results) */
       204: {
@@ -6218,7 +6218,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:drive*
    */
-  'admin/drive/cleanup': {
+  admin___drive___cleanup: {
     responses: {
       /** @description OK (without any results) */
       204: {
@@ -6262,7 +6262,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:drive*
    */
-  'admin/drive/files': {
+  admin___drive___files: {
     requestBody: {
       content: {
         'application/json': {
@@ -6333,7 +6333,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:drive*
    */
-  'admin/drive/show-file': {
+  'admin___drive___show-file': {
     requestBody: {
       content: {
         'application/json': {
@@ -6442,7 +6442,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
    */
-  'admin/emoji/add-aliases-bulk': {
+  'admin___emoji___add-aliases-bulk': {
     requestBody: {
       content: {
         'application/json': {
@@ -6494,7 +6494,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
    */
-  'admin/emoji/add': {
+  admin___emoji___add: {
     requestBody: {
       content: {
         'application/json': {
@@ -6556,7 +6556,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
    */
-  'admin/emoji/copy': {
+  admin___emoji___copy: {
     requestBody: {
       content: {
         'application/json': {
@@ -6613,7 +6613,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
    */
-  'admin/emoji/delete-bulk': {
+  'admin___emoji___delete-bulk': {
     requestBody: {
       content: {
         'application/json': {
@@ -6664,7 +6664,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
    */
-  'admin/emoji/delete': {
+  admin___emoji___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -6717,7 +6717,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'admin/emoji/import-zip': {
+  'admin___emoji___import-zip': {
     requestBody: {
       content: {
         'application/json': {
@@ -6769,7 +6769,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:emoji*
    */
-  'admin/emoji/list-remote': {
+  'admin___emoji___list-remote': {
     requestBody: {
       content: {
         'application/json': {
@@ -6843,7 +6843,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:emoji*
    */
-  'admin/emoji/list': {
+  admin___emoji___list: {
     requestBody: {
       content: {
         'application/json': {
@@ -6912,7 +6912,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
    */
-  'admin/emoji/remove-aliases-bulk': {
+  'admin___emoji___remove-aliases-bulk': {
     requestBody: {
       content: {
         'application/json': {
@@ -6964,7 +6964,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
    */
-  'admin/emoji/set-aliases-bulk': {
+  'admin___emoji___set-aliases-bulk': {
     requestBody: {
       content: {
         'application/json': {
@@ -7016,7 +7016,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
    */
-  'admin/emoji/set-category-bulk': {
+  'admin___emoji___set-category-bulk': {
     requestBody: {
       content: {
         'application/json': {
@@ -7069,7 +7069,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
    */
-  'admin/emoji/set-license-bulk': {
+  'admin___emoji___set-license-bulk': {
     requestBody: {
       content: {
         'application/json': {
@@ -7122,7 +7122,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:emoji*
    */
-  'admin/emoji/update': {
+  admin___emoji___update: {
     requestBody: {
       content: {
         'application/json': {
@@ -7184,7 +7184,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:federation*
    */
-  'admin/federation/delete-all-files': {
+  'admin___federation___delete-all-files': {
     requestBody: {
       content: {
         'application/json': {
@@ -7235,7 +7235,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:federation*
    */
-  'admin/federation/refresh-remote-instance-metadata': {
+  'admin___federation___refresh-remote-instance-metadata': {
     requestBody: {
       content: {
         'application/json': {
@@ -7286,7 +7286,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:federation*
    */
-  'admin/federation/remove-all-following': {
+  'admin___federation___remove-all-following': {
     requestBody: {
       content: {
         'application/json': {
@@ -7337,7 +7337,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:federation*
    */
-  'admin/federation/update-instance': {
+  'admin___federation___update-instance': {
     requestBody: {
       content: {
         'application/json': {
@@ -7390,7 +7390,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:index-stats*
    */
-  'admin/get-index-stats': {
+  'admin___get-index-stats': {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -7439,7 +7439,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:table-stats*
    */
-  'admin/get-table-stats': {
+  'admin___get-table-stats': {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -7490,7 +7490,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:user-ips*
    */
-  'admin/get-user-ips': {
+  'admin___get-user-ips': {
     requestBody: {
       content: {
         'application/json': {
@@ -7548,7 +7548,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:invite-codes*
    */
-  'admin/invite/create': {
+  admin___invite___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -7603,7 +7603,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:invite-codes*
    */
-  'admin/invite/list': {
+  admin___invite___list: {
     requestBody: {
       content: {
         'application/json': {
@@ -7666,7 +7666,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:promo*
    */
-  'admin/promo/create': {
+  admin___promo___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -7719,7 +7719,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:queue*
    */
-  'admin/queue/clear': {
+  admin___queue___clear: {
     responses: {
       /** @description OK (without any results) */
       204: {
@@ -7763,7 +7763,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:queue*
    */
-  'admin/queue/deliver-delayed': {
+  'admin___queue___deliver-delayed': {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -7809,7 +7809,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:queue*
    */
-  'admin/queue/inbox-delayed': {
+  'admin___queue___inbox-delayed': {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -7855,7 +7855,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:queue*
    */
-  'admin/queue/promote': {
+  admin___queue___promote: {
     requestBody: {
       content: {
         'application/json': {
@@ -7907,7 +7907,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:emoji*
    */
-  'admin/queue/stats': {
+  admin___queue___stats: {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -7958,7 +7958,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:relays*
    */
-  'admin/relays/add': {
+  admin___relays___add: {
     requestBody: {
       content: {
         'application/json': {
@@ -8021,7 +8021,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:relays*
    */
-  'admin/relays/list': {
+  admin___relays___list: {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -8077,7 +8077,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:relays*
    */
-  'admin/relays/remove': {
+  admin___relays___remove: {
     requestBody: {
       content: {
         'application/json': {
@@ -8128,7 +8128,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:reset-password*
    */
-  'admin/reset-password': {
+  'admin___reset-password': {
     requestBody: {
       content: {
         'application/json': {
@@ -8184,7 +8184,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:resolve-abuse-user-report*
    */
-  'admin/resolve-abuse-user-report': {
+  'admin___resolve-abuse-user-report': {
     requestBody: {
       content: {
         'application/json': {
@@ -8238,7 +8238,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:send-email*
    */
-  'admin/send-email': {
+  'admin___send-email': {
     requestBody: {
       content: {
         'application/json': {
@@ -8291,7 +8291,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:server-info*
    */
-  'admin/server-info': {
+  'admin___server-info': {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -8361,7 +8361,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:show-moderation-log*
    */
-  'admin/show-moderation-logs': {
+  'admin___show-moderation-logs': {
     requestBody: {
       content: {
         'application/json': {
@@ -8432,7 +8432,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:show-user*
    */
-  'admin/show-user': {
+  'admin___show-user': {
     requestBody: {
       content: {
         'application/json': {
@@ -8641,7 +8641,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:show-users*
    */
-  'admin/show-users': {
+  'admin___show-users': {
     requestBody: {
       content: {
         'application/json': {
@@ -8716,7 +8716,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:suspend-user*
    */
-  'admin/suspend-user': {
+  'admin___suspend-user': {
     requestBody: {
       content: {
         'application/json': {
@@ -8768,7 +8768,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:unsuspend-user*
    */
-  'admin/unsuspend-user': {
+  'admin___unsuspend-user': {
     requestBody: {
       content: {
         'application/json': {
@@ -8820,7 +8820,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:meta*
    */
-  'admin/update-meta': {
+  'admin___update-meta': {
     requestBody: {
       content: {
         'application/json': {
@@ -8980,7 +8980,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:delete-account*
    */
-  'admin/delete-account': {
+  'admin___delete-account': {
     requestBody: {
       content: {
         'application/json': {
@@ -9032,7 +9032,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:user-note*
    */
-  'admin/update-user-note': {
+  'admin___update-user-note': {
     requestBody: {
       content: {
         'application/json': {
@@ -9085,7 +9085,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:roles*
    */
-  'admin/roles/create': {
+  admin___roles___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -9153,7 +9153,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:roles*
    */
-  'admin/roles/delete': {
+  admin___roles___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -9205,7 +9205,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:roles*
    */
-  'admin/roles/list': {
+  admin___roles___list: {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -9251,7 +9251,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:admin:roles*
    */
-  'admin/roles/show': {
+  admin___roles___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -9305,7 +9305,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:roles*
    */
-  'admin/roles/update': {
+  admin___roles___update: {
     requestBody: {
       content: {
         'application/json': {
@@ -9372,7 +9372,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:roles*
    */
-  'admin/roles/assign': {
+  admin___roles___assign: {
     requestBody: {
       content: {
         'application/json': {
@@ -9427,7 +9427,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:roles*
    */
-  'admin/roles/unassign': {
+  admin___roles___unassign: {
     requestBody: {
       content: {
         'application/json': {
@@ -9481,7 +9481,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:admin:roles*
    */
-  'admin/roles/update-default-policies': {
+  'admin___roles___update-default-policies': {
     requestBody: {
       content: {
         'application/json': {
@@ -9532,7 +9532,7 @@ export type operations = {
    *
    * **Credential required**: *No* / **Permission**: *read:admin:roles*
    */
-  'admin/roles/users': {
+  admin___roles___users: {
     requestBody: {
       content: {
         'application/json': {
@@ -9660,7 +9660,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'antennas/create': {
+  antennas___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -9726,7 +9726,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'antennas/delete': {
+  antennas___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -9778,7 +9778,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'antennas/list': {
+  antennas___list: {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -9824,7 +9824,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'antennas/notes': {
+  antennas___notes: {
     requestBody: {
       content: {
         'application/json': {
@@ -9886,7 +9886,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'antennas/show': {
+  antennas___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -9940,7 +9940,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'antennas/update': {
+  antennas___update: {
     requestBody: {
       content: {
         'application/json': {
@@ -10008,7 +10008,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:federation*
    */
-  'ap/get': {
+  ap___get: {
     requestBody: {
       content: {
         'application/json': {
@@ -10067,7 +10067,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'ap/show': {
+  ap___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -10134,7 +10134,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'app/create': {
+  app___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -10190,7 +10190,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'app/show': {
+  app___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -10245,7 +10245,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'auth/accept': {
+  auth___accept: {
     requestBody: {
       content: {
         'application/json': {
@@ -10296,7 +10296,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'auth/session/generate': {
+  auth___session___generate: {
     requestBody: {
       content: {
         'application/json': {
@@ -10353,7 +10353,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'auth/session/show': {
+  auth___session___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -10411,7 +10411,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'auth/session/userkey': {
+  auth___session___userkey: {
     requestBody: {
       content: {
         'application/json': {
@@ -10468,7 +10468,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:blocks*
    */
-  'blocking/create': {
+  blocking___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -10528,7 +10528,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:blocks*
    */
-  'blocking/delete': {
+  blocking___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -10588,7 +10588,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:blocks*
    */
-  'blocking/list': {
+  blocking___list: {
     requestBody: {
       content: {
         'application/json': {
@@ -10646,7 +10646,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:channels*
    */
-  'channels/create': {
+  channels___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -10711,7 +10711,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'channels/featured': {
+  channels___featured: {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -10757,7 +10757,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:channels*
    */
-  'channels/follow': {
+  channels___follow: {
     requestBody: {
       content: {
         'application/json': {
@@ -10809,7 +10809,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:channels*
    */
-  'channels/followed': {
+  channels___followed: {
     requestBody: {
       content: {
         'application/json': {
@@ -10867,7 +10867,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:channels*
    */
-  'channels/owned': {
+  channels___owned: {
     requestBody: {
       content: {
         'application/json': {
@@ -10925,7 +10925,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'channels/show': {
+  channels___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -10979,7 +10979,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'channels/timeline': {
+  channels___timeline: {
     requestBody: {
       content: {
         'application/json': {
@@ -11043,7 +11043,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:channels*
    */
-  'channels/unfollow': {
+  channels___unfollow: {
     requestBody: {
       content: {
         'application/json': {
@@ -11095,7 +11095,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:channels*
    */
-  'channels/update': {
+  channels___update: {
     requestBody: {
       content: {
         'application/json': {
@@ -11158,7 +11158,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:channels*
    */
-  'channels/favorite': {
+  channels___favorite: {
     requestBody: {
       content: {
         'application/json': {
@@ -11210,7 +11210,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:channels*
    */
-  'channels/unfavorite': {
+  channels___unfavorite: {
     requestBody: {
       content: {
         'application/json': {
@@ -11262,7 +11262,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:channels*
    */
-  'channels/my-favorites': {
+  'channels___my-favorites': {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -11308,7 +11308,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'channels/search': {
+  channels___search: {
     requestBody: {
       content: {
         'application/json': {
@@ -11372,7 +11372,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'charts/active-users': {
+  'charts___active-users': {
     requestBody: {
       content: {
         'application/json': {
@@ -11440,7 +11440,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'charts/ap-request': {
+  'charts___ap-request': {
     requestBody: {
       content: {
         'application/json': {
@@ -11502,7 +11502,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'charts/drive': {
+  charts___drive: {
     requestBody: {
       content: {
         'application/json': {
@@ -11573,7 +11573,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'charts/federation': {
+  charts___federation: {
     requestBody: {
       content: {
         'application/json': {
@@ -11640,7 +11640,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'charts/instance': {
+  charts___instance: {
     requestBody: {
       content: {
         'application/json': {
@@ -11738,7 +11738,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'charts/notes': {
+  charts___notes: {
     requestBody: {
       content: {
         'application/json': {
@@ -11819,7 +11819,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'charts/user/drive': {
+  charts___user___drive: {
     requestBody: {
       content: {
         'application/json': {
@@ -11886,7 +11886,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'charts/user/following': {
+  charts___user___following: {
     requestBody: {
       content: {
         'application/json': {
@@ -11971,7 +11971,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'charts/user/notes': {
+  charts___user___notes: {
     requestBody: {
       content: {
         'application/json': {
@@ -12041,7 +12041,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'charts/user/pv': {
+  charts___user___pv: {
     requestBody: {
       content: {
         'application/json': {
@@ -12110,7 +12110,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'charts/user/reactions': {
+  charts___user___reactions: {
     requestBody: {
       content: {
         'application/json': {
@@ -12177,7 +12177,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'charts/users': {
+  charts___users: {
     requestBody: {
       content: {
         'application/json': {
@@ -12246,7 +12246,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'clips/add-note': {
+  'clips___add-note': {
     requestBody: {
       content: {
         'application/json': {
@@ -12306,7 +12306,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'clips/remove-note': {
+  'clips___remove-note': {
     requestBody: {
       content: {
         'application/json': {
@@ -12360,7 +12360,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'clips/create': {
+  clips___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -12416,7 +12416,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'clips/delete': {
+  clips___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -12468,7 +12468,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'clips/list': {
+  clips___list: {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -12514,7 +12514,7 @@ export type operations = {
    *
    * **Credential required**: *No* / **Permission**: *read:account*
    */
-  'clips/notes': {
+  clips___notes: {
     requestBody: {
       content: {
         'application/json': {
@@ -12574,7 +12574,7 @@ export type operations = {
    *
    * **Credential required**: *No* / **Permission**: *read:account*
    */
-  'clips/show': {
+  clips___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -12628,7 +12628,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'clips/update': {
+  clips___update: {
     requestBody: {
       content: {
         'application/json': {
@@ -12685,7 +12685,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:clip-favorite*
    */
-  'clips/favorite': {
+  clips___favorite: {
     requestBody: {
       content: {
         'application/json': {
@@ -12737,7 +12737,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:clip-favorite*
    */
-  'clips/unfavorite': {
+  clips___unfavorite: {
     requestBody: {
       content: {
         'application/json': {
@@ -12789,7 +12789,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:clip-favorite*
    */
-  'clips/my-favorites': {
+  'clips___my-favorites': {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -12884,7 +12884,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:drive*
    */
-  'drive/files': {
+  drive___files: {
     requestBody: {
       content: {
         'application/json': {
@@ -12950,7 +12950,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:drive*
    */
-  'drive/files/attached-notes': {
+  'drive___files___attached-notes': {
     requestBody: {
       content: {
         'application/json': {
@@ -13010,7 +13010,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:drive*
    */
-  'drive/files/check-existence': {
+  'drive___files___check-existence': {
     requestBody: {
       content: {
         'application/json': {
@@ -13063,7 +13063,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:drive*
    */
-  'drive/files/create': {
+  drive___files___create: {
     requestBody: {
       content: {
         'multipart/form-data': {
@@ -13139,7 +13139,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:drive*
    */
-  'drive/files/delete': {
+  drive___files___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -13191,7 +13191,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:drive*
    */
-  'drive/files/find-by-hash': {
+  'drive___files___find-by-hash': {
     requestBody: {
       content: {
         'application/json': {
@@ -13244,7 +13244,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:drive*
    */
-  'drive/files/find': {
+  drive___files___find: {
     requestBody: {
       content: {
         'application/json': {
@@ -13302,7 +13302,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:drive*
    */
-  'drive/files/show': {
+  drive___files___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -13357,7 +13357,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:drive*
    */
-  'drive/files/update': {
+  drive___files___update: {
     requestBody: {
       content: {
         'application/json': {
@@ -13416,7 +13416,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:drive*
    */
-  'drive/files/upload-from-url': {
+  'drive___files___upload-from-url': {
     requestBody: {
       content: {
         'application/json': {
@@ -13486,7 +13486,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:drive*
    */
-  'drive/folders': {
+  drive___folders: {
     requestBody: {
       content: {
         'application/json': {
@@ -13549,7 +13549,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:drive*
    */
-  'drive/folders/create': {
+  drive___folders___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -13611,7 +13611,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:drive*
    */
-  'drive/folders/delete': {
+  drive___folders___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -13663,7 +13663,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:drive*
    */
-  'drive/folders/find': {
+  drive___folders___find: {
     requestBody: {
       content: {
         'application/json': {
@@ -13721,7 +13721,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:drive*
    */
-  'drive/folders/show': {
+  drive___folders___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -13775,7 +13775,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:drive*
    */
-  'drive/folders/update': {
+  drive___folders___update: {
     requestBody: {
       content: {
         'application/json': {
@@ -13832,7 +13832,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:drive*
    */
-  'drive/stream': {
+  drive___stream: {
     requestBody: {
       content: {
         'application/json': {
@@ -13891,7 +13891,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'email-address/available': {
+  'email-address___available': {
     requestBody: {
       content: {
         'application/json': {
@@ -14106,7 +14106,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'federation/followers': {
+  federation___followers: {
     requestBody: {
       content: {
         'application/json': {
@@ -14165,7 +14165,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'federation/following': {
+  federation___following: {
     requestBody: {
       content: {
         'application/json': {
@@ -14224,7 +14224,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'federation/instances': {
+  federation___instances: {
     requestBody: {
       content: {
         'application/json': {
@@ -14291,7 +14291,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'federation/show-instance': {
+  'federation___show-instance': {
     requestBody: {
       content: {
         'application/json': {
@@ -14348,7 +14348,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'federation/update-remote-user': {
+  'federation___update-remote-user': {
     requestBody: {
       content: {
         'application/json': {
@@ -14400,7 +14400,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'federation/users': {
+  federation___users: {
     requestBody: {
       content: {
         'application/json': {
@@ -14459,7 +14459,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'federation/stats': {
+  federation___stats: {
     requestBody: {
       content: {
         'application/json': {
@@ -14518,7 +14518,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:following*
    */
-  'following/create': {
+  following___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -14579,7 +14579,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:following*
    */
-  'following/delete': {
+  following___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -14639,7 +14639,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:following*
    */
-  'following/update': {
+  following___update: {
     requestBody: {
       content: {
         'application/json': {
@@ -14702,7 +14702,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:following*
    */
-  'following/update-all': {
+  'following___update-all': {
     requestBody: {
       content: {
         'application/json': {
@@ -14761,7 +14761,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:following*
    */
-  'following/invalidate': {
+  following___invalidate: {
     requestBody: {
       content: {
         'application/json': {
@@ -14821,7 +14821,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:following*
    */
-  'following/requests/accept': {
+  following___requests___accept: {
     requestBody: {
       content: {
         'application/json': {
@@ -14873,7 +14873,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:following*
    */
-  'following/requests/cancel': {
+  following___requests___cancel: {
     requestBody: {
       content: {
         'application/json': {
@@ -14927,7 +14927,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:following*
    */
-  'following/requests/list': {
+  following___requests___list: {
     requestBody: {
       content: {
         'application/json': {
@@ -14990,7 +14990,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:following*
    */
-  'following/requests/reject': {
+  following___requests___reject: {
     requestBody: {
       content: {
         'application/json': {
@@ -15042,7 +15042,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'gallery/featured': {
+  gallery___featured: {
     requestBody: {
       content: {
         'application/json': {
@@ -15098,7 +15098,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'gallery/popular': {
+  gallery___popular: {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -15144,7 +15144,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'gallery/posts': {
+  gallery___posts: {
     requestBody: {
       content: {
         'application/json': {
@@ -15202,7 +15202,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:gallery*
    */
-  'gallery/posts/create': {
+  gallery___posts___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -15265,7 +15265,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:gallery*
    */
-  'gallery/posts/delete': {
+  gallery___posts___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -15317,7 +15317,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:gallery-likes*
    */
-  'gallery/posts/like': {
+  gallery___posts___like: {
     requestBody: {
       content: {
         'application/json': {
@@ -15369,7 +15369,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'gallery/posts/show': {
+  gallery___posts___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -15423,7 +15423,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:gallery-likes*
    */
-  'gallery/posts/unlike': {
+  gallery___posts___unlike: {
     requestBody: {
       content: {
         'application/json': {
@@ -15475,7 +15475,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:gallery*
    */
-  'gallery/posts/update': {
+  gallery___posts___update: {
     requestBody: {
       content: {
         'application/json': {
@@ -15644,7 +15644,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'hashtags/list': {
+  hashtags___list: {
     requestBody: {
       content: {
         'application/json': {
@@ -15706,7 +15706,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'hashtags/search': {
+  hashtags___search: {
     requestBody: {
       content: {
         'application/json': {
@@ -15763,7 +15763,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'hashtags/show': {
+  hashtags___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -15816,7 +15816,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'hashtags/trend': {
+  hashtags___trend: {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -15866,7 +15866,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'hashtags/users': {
+  hashtags___users: {
     requestBody: {
       content: {
         'application/json': {
@@ -15980,7 +15980,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/2fa/done': {
+  i___2fa___done: {
     requestBody: {
       content: {
         'application/json': {
@@ -16036,7 +16036,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/2fa/key-done': {
+  'i___2fa___key-done': {
     requestBody: {
       content: {
         'application/json': {
@@ -16096,7 +16096,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/2fa/password-less': {
+  'i___2fa___password-less': {
     requestBody: {
       content: {
         'application/json': {
@@ -16148,7 +16148,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/2fa/register-key': {
+  'i___2fa___register-key': {
     requestBody: {
       content: {
         'application/json': {
@@ -16237,7 +16237,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/2fa/register': {
+  i___2fa___register: {
     requestBody: {
       content: {
         'application/json': {
@@ -16298,7 +16298,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/2fa/update-key': {
+  'i___2fa___update-key': {
     requestBody: {
       content: {
         'application/json': {
@@ -16351,7 +16351,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/2fa/remove-key': {
+  'i___2fa___remove-key': {
     requestBody: {
       content: {
         'application/json': {
@@ -16405,7 +16405,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/2fa/unregister': {
+  i___2fa___unregister: {
     requestBody: {
       content: {
         'application/json': {
@@ -16458,7 +16458,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/apps': {
+  i___apps: {
     requestBody: {
       content: {
         'application/json': {
@@ -16522,7 +16522,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/authorized-apps': {
+  'i___authorized-apps': {
     requestBody: {
       content: {
         'application/json': {
@@ -16590,7 +16590,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'i/claim-achievement': {
+  'i___claim-achievement': {
     requestBody: {
       content: {
         'application/json': {
@@ -16643,7 +16643,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/change-password': {
+  'i___change-password': {
     requestBody: {
       content: {
         'application/json': {
@@ -16697,7 +16697,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/delete-account': {
+  'i___delete-account': {
     requestBody: {
       content: {
         'application/json': {
@@ -16750,7 +16750,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/export-blocking': {
+  'i___export-blocking': {
     responses: {
       /** @description OK (without any results) */
       204: {
@@ -16801,7 +16801,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/export-following': {
+  'i___export-following': {
     requestBody: {
       content: {
         'application/json': {
@@ -16862,7 +16862,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/export-mute': {
+  'i___export-mute': {
     responses: {
       /** @description OK (without any results) */
       204: {
@@ -16913,7 +16913,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/export-notes': {
+  'i___export-notes': {
     responses: {
       /** @description OK (without any results) */
       204: {
@@ -16964,7 +16964,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/export-clips': {
+  'i___export-clips': {
     responses: {
       /** @description OK (without any results) */
       204: {
@@ -17015,7 +17015,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/export-favorites': {
+  'i___export-favorites': {
     responses: {
       /** @description OK (without any results) */
       204: {
@@ -17066,7 +17066,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/export-user-lists': {
+  'i___export-user-lists': {
     responses: {
       /** @description OK (without any results) */
       204: {
@@ -17117,7 +17117,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/export-antennas': {
+  'i___export-antennas': {
     responses: {
       /** @description OK (without any results) */
       204: {
@@ -17167,7 +17167,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:favorites*
    */
-  'i/favorites': {
+  i___favorites: {
     requestBody: {
       content: {
         'application/json': {
@@ -17225,7 +17225,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:gallery-likes*
    */
-  'i/gallery/likes': {
+  i___gallery___likes: {
     requestBody: {
       content: {
         'application/json': {
@@ -17287,7 +17287,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:gallery*
    */
-  'i/gallery/posts': {
+  i___gallery___posts: {
     requestBody: {
       content: {
         'application/json': {
@@ -17346,7 +17346,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/import-blocking': {
+  'i___import-blocking': {
     requestBody: {
       content: {
         'application/json': {
@@ -17405,7 +17405,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/import-following': {
+  'i___import-following': {
     requestBody: {
       content: {
         'application/json': {
@@ -17465,7 +17465,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/import-muting': {
+  'i___import-muting': {
     requestBody: {
       content: {
         'application/json': {
@@ -17524,7 +17524,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/import-user-lists': {
+  'i___import-user-lists': {
     requestBody: {
       content: {
         'application/json': {
@@ -17583,7 +17583,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/import-antennas': {
+  'i___import-antennas': {
     requestBody: {
       content: {
         'application/json': {
@@ -17641,7 +17641,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:notifications*
    */
-  'i/notifications': {
+  i___notifications: {
     requestBody: {
       content: {
         'application/json': {
@@ -17709,7 +17709,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:notifications*
    */
-  'i/notifications-grouped': {
+  'i___notifications-grouped': {
     requestBody: {
       content: {
         'application/json': {
@@ -17777,7 +17777,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:page-likes*
    */
-  'i/page-likes': {
+  'i___page-likes': {
     requestBody: {
       content: {
         'application/json': {
@@ -17839,7 +17839,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:pages*
    */
-  'i/pages': {
+  i___pages: {
     requestBody: {
       content: {
         'application/json': {
@@ -17897,7 +17897,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'i/pin': {
+  i___pin: {
     requestBody: {
       content: {
         'application/json': {
@@ -17951,7 +17951,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'i/read-all-unread-notes': {
+  'i___read-all-unread-notes': {
     responses: {
       /** @description OK (without any results) */
       204: {
@@ -17995,7 +17995,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'i/read-announcement': {
+  'i___read-announcement': {
     requestBody: {
       content: {
         'application/json': {
@@ -18048,7 +18048,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/regenerate-token': {
+  'i___regenerate-token': {
     requestBody: {
       content: {
         'application/json': {
@@ -18099,7 +18099,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'i/registry/get-all': {
+  'i___registry___get-all': {
     requestBody: {
       content: {
         'application/json': {
@@ -18154,7 +18154,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'i/registry/get-detail': {
+  'i___registry___get-detail': {
     requestBody: {
       content: {
         'application/json': {
@@ -18213,7 +18213,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'i/registry/get': {
+  i___registry___get: {
     requestBody: {
       content: {
         'application/json': {
@@ -18269,7 +18269,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'i/registry/keys-with-type': {
+  'i___registry___keys-with-type': {
     requestBody: {
       content: {
         'application/json': {
@@ -18326,7 +18326,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'i/registry/keys': {
+  i___registry___keys: {
     requestBody: {
       content: {
         'application/json': {
@@ -18381,7 +18381,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'i/registry/remove': {
+  i___registry___remove: {
     requestBody: {
       content: {
         'application/json': {
@@ -18436,7 +18436,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/registry/scopes-with-domain': {
+  'i___registry___scopes-with-domain': {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -18485,7 +18485,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'i/registry/set': {
+  i___registry___set: {
     requestBody: {
       content: {
         'application/json': {
@@ -18541,7 +18541,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/revoke-token': {
+  'i___revoke-token': {
     requestBody: {
       content: {
         'application/json': {
@@ -18595,7 +18595,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/signin-history': {
+  'i___signin-history': {
     requestBody: {
       content: {
         'application/json': {
@@ -18653,7 +18653,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'i/unpin': {
+  i___unpin: {
     requestBody: {
       content: {
         'application/json': {
@@ -18708,7 +18708,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/update-email': {
+  'i___update-email': {
     requestBody: {
       content: {
         'application/json': {
@@ -18769,7 +18769,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'i/update': {
+  i___update: {
     requestBody: {
       content: {
         'application/json': {
@@ -19003,7 +19003,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'i/move': {
+  i___move: {
     requestBody: {
       content: {
         'application/json': {
@@ -19062,7 +19062,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'i/webhooks/create': {
+  i___webhooks___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -19132,7 +19132,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'i/webhooks/list': {
+  i___webhooks___list: {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -19191,7 +19191,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'i/webhooks/show': {
+  i___webhooks___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -19258,7 +19258,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'i/webhooks/update': {
+  i___webhooks___update: {
     requestBody: {
       content: {
         'application/json': {
@@ -19316,7 +19316,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'i/webhooks/delete': {
+  i___webhooks___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -19368,7 +19368,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:invite-codes*
    */
-  'invite/create': {
+  invite___create: {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -19414,7 +19414,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:invite-codes*
    */
-  'invite/delete': {
+  invite___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -19466,7 +19466,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:invite-codes*
    */
-  'invite/list': {
+  invite___list: {
     requestBody: {
       content: {
         'application/json': {
@@ -19524,7 +19524,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:invite-codes*
    */
-  'invite/limit': {
+  invite___limit: {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -19728,7 +19728,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'miauth/gen-token': {
+  'miauth___gen-token': {
     requestBody: {
       content: {
         'application/json': {
@@ -19787,7 +19787,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:mutes*
    */
-  'mute/create': {
+  mute___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -19847,7 +19847,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:mutes*
    */
-  'mute/delete': {
+  mute___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -19899,7 +19899,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:mutes*
    */
-  'mute/list': {
+  mute___list: {
     requestBody: {
       content: {
         'application/json': {
@@ -19957,7 +19957,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:mutes*
    */
-  'renote-mute/create': {
+  'renote-mute___create': {
     requestBody: {
       content: {
         'application/json': {
@@ -20015,7 +20015,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:mutes*
    */
-  'renote-mute/delete': {
+  'renote-mute___delete': {
     requestBody: {
       content: {
         'application/json': {
@@ -20067,7 +20067,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:mutes*
    */
-  'renote-mute/list': {
+  'renote-mute___list': {
     requestBody: {
       content: {
         'application/json': {
@@ -20125,7 +20125,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'my/apps': {
+  my___apps: {
     requestBody: {
       content: {
         'application/json': {
@@ -20245,7 +20245,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'notes/children': {
+  notes___children: {
     requestBody: {
       content: {
         'application/json': {
@@ -20305,7 +20305,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'notes/clips': {
+  notes___clips: {
     requestBody: {
       content: {
         'application/json': {
@@ -20359,7 +20359,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'notes/conversation': {
+  notes___conversation: {
     requestBody: {
       content: {
         'application/json': {
@@ -20417,7 +20417,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:notes*
    */
-  'notes/create': {
+  notes___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -20512,7 +20512,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:notes*
    */
-  'notes/delete': {
+  notes___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -20570,7 +20570,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:favorites*
    */
-  'notes/favorites/create': {
+  notes___favorites___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -20628,7 +20628,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:favorites*
    */
-  'notes/favorites/delete': {
+  notes___favorites___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -20680,7 +20680,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'notes/featured': {
+  notes___featured: {
     requestBody: {
       content: {
         'application/json': {
@@ -20738,7 +20738,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'notes/global-timeline': {
+  'notes___global-timeline': {
     requestBody: {
       content: {
         'application/json': {
@@ -20802,7 +20802,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'notes/hybrid-timeline': {
+  'notes___hybrid-timeline': {
     requestBody: {
       content: {
         'application/json': {
@@ -20876,7 +20876,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'notes/local-timeline': {
+  'notes___local-timeline': {
     requestBody: {
       content: {
         'application/json': {
@@ -20944,7 +20944,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'notes/mentions': {
+  notes___mentions: {
     requestBody: {
       content: {
         'application/json': {
@@ -21005,7 +21005,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'notes/polls/recommendation': {
+  notes___polls___recommendation: {
     requestBody: {
       content: {
         'application/json': {
@@ -21061,7 +21061,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:votes*
    */
-  'notes/polls/vote': {
+  notes___polls___vote: {
     requestBody: {
       content: {
         'application/json': {
@@ -21114,7 +21114,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'notes/reactions': {
+  notes___reactions: {
     requestBody: {
       content: {
         'application/json': {
@@ -21175,7 +21175,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:reactions*
    */
-  'notes/reactions/create': {
+  notes___reactions___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -21228,7 +21228,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:reactions*
    */
-  'notes/reactions/delete': {
+  notes___reactions___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -21286,7 +21286,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'notes/renotes': {
+  notes___renotes: {
     requestBody: {
       content: {
         'application/json': {
@@ -21346,7 +21346,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'notes/replies': {
+  notes___replies: {
     requestBody: {
       content: {
         'application/json': {
@@ -21406,7 +21406,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'notes/search-by-tag': {
+  'notes___search-by-tag': {
     requestBody: {
       content: {
         'application/json': {
@@ -21478,7 +21478,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'notes/search': {
+  notes___search: {
     requestBody: {
       content: {
         'application/json': {
@@ -21551,7 +21551,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'notes/show': {
+  notes___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -21605,7 +21605,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'notes/state': {
+  notes___state: {
     requestBody: {
       content: {
         'application/json': {
@@ -21662,7 +21662,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'notes/thread-muting/create': {
+  'notes___thread-muting___create': {
     requestBody: {
       content: {
         'application/json': {
@@ -21720,7 +21720,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'notes/thread-muting/delete': {
+  'notes___thread-muting___delete': {
     requestBody: {
       content: {
         'application/json': {
@@ -21772,7 +21772,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'notes/timeline': {
+  notes___timeline: {
     requestBody: {
       content: {
         'application/json': {
@@ -21844,7 +21844,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'notes/translate': {
+  notes___translate: {
     requestBody: {
       content: {
         'application/json': {
@@ -21902,7 +21902,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:notes*
    */
-  'notes/unrenote': {
+  notes___unrenote: {
     requestBody: {
       content: {
         'application/json': {
@@ -21960,7 +21960,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'notes/user-list-timeline': {
+  'notes___user-list-timeline': {
     requestBody: {
       content: {
         'application/json': {
@@ -22037,7 +22037,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:notifications*
    */
-  'notifications/create': {
+  notifications___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -22096,7 +22096,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:notifications*
    */
-  'notifications/flush': {
+  notifications___flush: {
     responses: {
       /** @description OK (without any results) */
       204: {
@@ -22140,7 +22140,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:notifications*
    */
-  'notifications/mark-all-as-read': {
+  'notifications___mark-all-as-read': {
     responses: {
       /** @description OK (without any results) */
       204: {
@@ -22184,7 +22184,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:notifications*
    */
-  'notifications/test-notification': {
+  'notifications___test-notification': {
     responses: {
       /** @description OK (without any results) */
       204: {
@@ -22289,7 +22289,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:pages*
    */
-  'pages/create': {
+  pages___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -22368,7 +22368,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:pages*
    */
-  'pages/delete': {
+  pages___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -22420,7 +22420,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'pages/featured': {
+  pages___featured: {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -22466,7 +22466,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:page-likes*
    */
-  'pages/like': {
+  pages___like: {
     requestBody: {
       content: {
         'application/json': {
@@ -22518,7 +22518,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'pages/show': {
+  pages___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -22574,7 +22574,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:page-likes*
    */
-  'pages/unlike': {
+  pages___unlike: {
     requestBody: {
       content: {
         'application/json': {
@@ -22626,7 +22626,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:pages*
    */
-  'pages/update': {
+  pages___update: {
     requestBody: {
       content: {
         'application/json': {
@@ -22700,7 +22700,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:flash*
    */
-  'flash/create': {
+  flash___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -22767,7 +22767,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:flash*
    */
-  'flash/delete': {
+  flash___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -22819,7 +22819,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'flash/featured': {
+  flash___featured: {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -22865,7 +22865,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:flash-likes*
    */
-  'flash/like': {
+  flash___like: {
     requestBody: {
       content: {
         'application/json': {
@@ -22917,7 +22917,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'flash/show': {
+  flash___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -22971,7 +22971,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:flash-likes*
    */
-  'flash/unlike': {
+  flash___unlike: {
     requestBody: {
       content: {
         'application/json': {
@@ -23023,7 +23023,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:flash*
    */
-  'flash/update': {
+  flash___update: {
     requestBody: {
       content: {
         'application/json': {
@@ -23087,7 +23087,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:flash*
    */
-  'flash/my': {
+  flash___my: {
     requestBody: {
       content: {
         'application/json': {
@@ -23145,7 +23145,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:flash-likes*
    */
-  'flash/my-likes': {
+  'flash___my-likes': {
     requestBody: {
       content: {
         'application/json': {
@@ -23301,7 +23301,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'promo/read': {
+  promo___read: {
     requestBody: {
       content: {
         'application/json': {
@@ -23353,7 +23353,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'roles/list': {
+  roles___list: {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -23399,7 +23399,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'roles/show': {
+  roles___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -23453,7 +23453,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'roles/users': {
+  roles___users: {
     requestBody: {
       content: {
         'application/json': {
@@ -23517,7 +23517,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'roles/notes': {
+  roles___notes: {
     requestBody: {
       content: {
         'application/json': {
@@ -23847,7 +23847,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'sw/show-registration': {
+  'sw___show-registration': {
     requestBody: {
       content: {
         'application/json': {
@@ -23909,7 +23909,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'sw/update-registration': {
+  'sw___update-registration': {
     requestBody: {
       content: {
         'application/json': {
@@ -23968,7 +23968,7 @@ export type operations = {
    * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
    * **Credential required**: *Yes*
    */
-  'sw/register': {
+  sw___register: {
     requestBody: {
       content: {
         'application/json': {
@@ -24032,7 +24032,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'sw/unregister': {
+  sw___unregister: {
     requestBody: {
       content: {
         'application/json': {
@@ -24151,7 +24151,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'username/available': {
+  username___available: {
     requestBody: {
       content: {
         'application/json': {
@@ -24279,7 +24279,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'users/clips': {
+  users___clips: {
     requestBody: {
       content: {
         'application/json': {
@@ -24339,7 +24339,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'users/followers': {
+  users___followers: {
     requestBody: {
       content: {
         'application/json': {
@@ -24402,7 +24402,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'users/following': {
+  users___following: {
     requestBody: {
       content: {
         'application/json': {
@@ -24466,7 +24466,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'users/gallery/posts': {
+  users___gallery___posts: {
     requestBody: {
       content: {
         'application/json': {
@@ -24526,7 +24526,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'users/get-frequently-replied-users': {
+  'users___get-frequently-replied-users': {
     requestBody: {
       content: {
         'application/json': {
@@ -24585,7 +24585,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'users/featured-notes': {
+  'users___featured-notes': {
     requestBody: {
       content: {
         'application/json': {
@@ -24643,7 +24643,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'users/lists/create': {
+  users___lists___create: {
     requestBody: {
       content: {
         'application/json': {
@@ -24696,7 +24696,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'users/lists/delete': {
+  users___lists___delete: {
     requestBody: {
       content: {
         'application/json': {
@@ -24748,7 +24748,7 @@ export type operations = {
    *
    * **Credential required**: *No* / **Permission**: *read:account*
    */
-  'users/lists/list': {
+  users___lists___list: {
     requestBody: {
       content: {
         'application/json': {
@@ -24802,7 +24802,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'users/lists/pull': {
+  users___lists___pull: {
     requestBody: {
       content: {
         'application/json': {
@@ -24856,7 +24856,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'users/lists/push': {
+  users___lists___push: {
     requestBody: {
       content: {
         'application/json': {
@@ -24916,7 +24916,7 @@ export type operations = {
    *
    * **Credential required**: *No* / **Permission**: *read:account*
    */
-  'users/lists/show': {
+  users___lists___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -24972,7 +24972,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'users/lists/favorite': {
+  users___lists___favorite: {
     requestBody: {
       content: {
         'application/json': {
@@ -25024,7 +25024,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'users/lists/unfavorite': {
+  users___lists___unfavorite: {
     requestBody: {
       content: {
         'application/json': {
@@ -25076,7 +25076,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'users/lists/update': {
+  users___lists___update: {
     requestBody: {
       content: {
         'application/json': {
@@ -25132,7 +25132,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'users/lists/create-from-public': {
+  'users___lists___create-from-public': {
     requestBody: {
       content: {
         'application/json': {
@@ -25187,7 +25187,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'users/lists/update-membership': {
+  'users___lists___update-membership': {
     requestBody: {
       content: {
         'application/json': {
@@ -25242,7 +25242,7 @@ export type operations = {
    *
    * **Credential required**: *No* / **Permission**: *read:account*
    */
-  'users/lists/get-memberships': {
+  'users___lists___get-memberships': {
     requestBody: {
       content: {
         'application/json': {
@@ -25313,7 +25313,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'users/notes': {
+  users___notes: {
     requestBody: {
       content: {
         'application/json': {
@@ -25385,7 +25385,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'users/pages': {
+  users___pages: {
     requestBody: {
       content: {
         'application/json': {
@@ -25445,7 +25445,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'users/flashs': {
+  users___flashs: {
     requestBody: {
       content: {
         'application/json': {
@@ -25505,7 +25505,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'users/reactions': {
+  users___reactions: {
     requestBody: {
       content: {
         'application/json': {
@@ -25567,7 +25567,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'users/recommendation': {
+  users___recommendation: {
     requestBody: {
       content: {
         'application/json': {
@@ -25623,7 +25623,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'users/relation': {
+  users___relation: {
     requestBody: {
       content: {
         'application/json': {
@@ -25698,7 +25698,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:report-abuse*
    */
-  'users/report-abuse': {
+  'users___report-abuse': {
     requestBody: {
       content: {
         'application/json': {
@@ -25751,7 +25751,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'users/search-by-username-and-host': {
+  'users___search-by-username-and-host': {
     requestBody: {
       content: {
         'application/json': {
@@ -25809,7 +25809,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'users/search': {
+  users___search: {
     requestBody: {
       content: {
         'application/json': {
@@ -25873,7 +25873,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'users/show': {
+  users___show: {
     requestBody: {
       content: {
         'application/json': {
@@ -25931,7 +25931,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'users/achievements': {
+  users___achievements: {
     requestBody: {
       content: {
         'application/json': {
@@ -25988,7 +25988,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'users/update-memo': {
+  'users___update-memo': {
     requestBody: {
       content: {
         'application/json': {
@@ -26214,7 +26214,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'bubble-game/register': {
+  'bubble-game___register': {
     requestBody: {
       content: {
         'application/json': {
@@ -26275,7 +26275,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'bubble-game/ranking': {
+  'bubble-game___ranking': {
     requestBody: {
       content: {
         'application/json': {
@@ -26333,7 +26333,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'reversi/cancel-match': {
+  'reversi___cancel-match': {
     requestBody: {
       content: {
         'application/json': {
@@ -26385,7 +26385,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'reversi/games': {
+  reversi___games: {
     requestBody: {
       content: {
         'application/json': {
@@ -26445,7 +26445,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'reversi/match': {
+  reversi___match: {
     requestBody: {
       content: {
         'application/json': {
@@ -26507,7 +26507,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *read:account*
    */
-  'reversi/invitations': {
+  reversi___invitations: {
     responses: {
       /** @description OK (with results) */
       200: {
@@ -26553,7 +26553,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'reversi/show-game': {
+  'reversi___show-game': {
     requestBody: {
       content: {
         'application/json': {
@@ -26607,7 +26607,7 @@ export type operations = {
    *
    * **Credential required**: *Yes* / **Permission**: *write:account*
    */
-  'reversi/surrender': {
+  reversi___surrender: {
     requestBody: {
       content: {
         'application/json': {
@@ -26659,7 +26659,7 @@ export type operations = {
    *
    * **Credential required**: *No*
    */
-  'reversi/verify': {
+  reversi___verify: {
     requestBody: {
       content: {
         'application/json': {

From f90be427f51392ef3ed5a7eb7f35059274bb47fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 25 Mar 2024 18:31:30 +0900
Subject: [PATCH 053/191] =?UTF-8?q?fix(frontend):=20=E3=80=8C=E4=BB=8A?=
 =?UTF-8?q?=E6=97=A5=E8=AA=95=E7=94=9F=E6=97=A5=E3=81=AE=E3=83=95=E3=82=A9?=
 =?UTF-8?q?=E3=83=AD=E3=83=BC=E4=B8=AD=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC?=
 =?UTF-8?q?=E3=80=8D=E3=82=A6=E3=82=A3=E3=82=B8=E3=82=A7=E3=83=83=E3=83=88?=
 =?UTF-8?q?=E3=81=8C=E6=AD=A3=E3=81=97=E3=81=8F=E5=8B=95=E4=BD=9C=E3=81=97?=
 =?UTF-8?q?=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?=
 =?UTF-8?q?=20(#12835)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* (fix) タイムゾーンによっては誕生日のフォロー中ユーザーが正しく読み込まれない

* 文言をわかりやすく

* Update Changelog

* (add) reload button

* Update CHANGELOG.md

* run misskey-js

* fix

* Revert "文言をわかりやすく"

This reverts commit c5ab6419563cc70ec8ba758e800c74d3469131e3.

* Update packages/frontend/src/widgets/WidgetBirthdayFollowings.vue

* Update packages/frontend/src/widgets/WidgetBirthdayFollowings.vue

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 CHANGELOG.md                                  |  2 ++
 .../server/api/endpoints/users/following.ts   |  7 ++--
 .../src/widgets/WidgetBirthdayFollowings.vue  | 35 ++++++++++++++-----
 3 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d90b1425c1..f41ff2171f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,7 @@
   - 実装の都合により、プラグインは1つエラーを起こした時に即時停止するようになりました
 - Enhance: ページのデザインを変更
 - Enhance: 2要素認証(ワンタイムパスワード)の入力欄を改善
+- Enhance: 「今日誕生日のフォロー中ユーザー」ウィジェットを手動でリロードできるように
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
 - Fix: ローカルURLのプレビューポップアップが左上に表示される
@@ -27,6 +28,7 @@
   (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/528)
 - Fix: コードブロックのシンタックスハイライトで使用される定義ファイルをCDNから取得するように #13177
   - CDNから取得せずMisskey本体にバンドルする場合は`pacakges/frontend/vite.config.ts`を修正してください。
+- Fix: タイムゾーンによっては、「今日誕生日のフォロー中ユーザー」ウィジェットが正しく動作しない問題を修正
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
diff --git a/packages/backend/src/server/api/endpoints/users/following.ts b/packages/backend/src/server/api/endpoints/users/following.ts
index 5d52ebba76..6b3389f0b2 100644
--- a/packages/backend/src/server/api/endpoints/users/following.ts
+++ b/packages/backend/src/server/api/endpoints/users/following.ts
@@ -6,6 +6,7 @@
 import { IsNull } from 'typeorm';
 import { Inject, Injectable } from '@nestjs/common';
 import type { UsersRepository, FollowingsRepository, UserProfilesRepository } from '@/models/_.js';
+import { birthdaySchema } from '@/models/User.js';
 import { Endpoint } from '@/server/api/endpoint-base.js';
 import { QueryService } from '@/core/QueryService.js';
 import { FollowingEntityService } from '@/core/entities/FollowingEntityService.js';
@@ -66,7 +67,7 @@ export const paramDef = {
 			description: 'The local host is represented with `null`.',
 		},
 
-		birthday: { type: 'string', nullable: true },
+		birthday: { ...birthdaySchema, nullable: true },
 	},
 	anyOf: [
 		{ required: ['userId'] },
@@ -127,9 +128,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 
 			if (ps.birthday) {
 				try {
-					const d = new Date(ps.birthday);
-					d.setHours(0, 0, 0, 0);
-					const birthday = `${(d.getMonth() + 1).toString().padStart(2, '0')}-${d.getDate().toString().padStart(2, '0')}`;
+					const birthday = ps.birthday.substring(5, 10);
 					const birthdayUserQuery = this.userProfilesRepository.createQueryBuilder('user_profile');
 					birthdayUserQuery.select('user_profile.userId')
 						.where(`SUBSTR(user_profile.birthday, 6, 5) = '${birthday}'`);
diff --git a/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue b/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue
index 5b448e2c3b..49fd103d37 100644
--- a/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue
+++ b/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue
@@ -7,6 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 <MkContainer :showHeader="widgetProps.showHeader" class="mkw-bdayfollowings">
 	<template #icon><i class="ti ti-cake"></i></template>
 	<template #header>{{ i18n.ts._widgets.birthdayFollowings }}</template>
+	<template #func="{ buttonStyleClass }"><button class="_button" :class="buttonStyleClass" @click="actualFetch()"><i class="ti ti-refresh"></i></button></template>
 
 	<div :class="$style.bdayFRoot">
 		<MkLoading v-if="fetching"/>
@@ -53,7 +54,7 @@ const { widgetProps, configure } = useWidgetPropsManager(name,
 	emit,
 );
 
-const users = ref<Misskey.entities.FollowingFolloweePopulated[]>([]);
+const users = ref<Misskey.Endpoints['users/following']['res']>([]);
 const fetching = ref(true);
 let lastFetchedAt = '1970-01-01';
 
@@ -70,19 +71,35 @@ const fetch = () => {
 	now.setHours(0, 0, 0, 0);
 
 	if (now > lfAtD) {
-		misskeyApi('users/following', {
-			limit: 18,
-			birthday: now.toISOString(),
-			userId: $i.id,
-		}).then(res => {
-			users.value = res;
-			fetching.value = false;
-		});
+		actualFetch();
 
 		lastFetchedAt = now.toISOString();
 	}
 };
 
+function actualFetch() {
+	if ($i == null) {
+		users.value = [];
+		fetching.value = false;
+		return;
+	}
+
+	const now = new Date();
+	now.setHours(0, 0, 0, 0);
+	fetching.value = true;
+	misskeyApi('users/following', {
+		limit: 18,
+		birthday: `${now.getFullYear().toString().padStart(4, '0')}-${(now.getMonth() + 1).toString().padStart(2, '0')}-${now.getDate().toString().padStart(2, '0')}`,
+		userId: $i.id,
+	}).then(res => {
+		users.value = res;
+		window.setTimeout(() => {
+			// 早すぎるとチカチカする
+			fetching.value = false;
+		}, 100);
+	});
+}
+
 useInterval(fetch, 1000 * 60, {
 	immediate: true,
 	afterMounted: true,

From f3500ffda96913e41708a6ca04ef9bbf07af74e4 Mon Sep 17 00:00:00 2001
From: Nila <43315617+nilathedragon@users.noreply.github.com>
Date: Sat, 30 Mar 2024 02:28:47 +0100
Subject: [PATCH 054/191] fix: report progress out of 100% in
 CleanRemoteFilesProcessorService (#13633)

* Report progress out of 100% in CleanRemoteFilesProcessorService

* Add changelog entry
---
 CHANGELOG.md                                                    | 1 +
 .../src/queue/processors/CleanRemoteFilesProcessorService.ts    | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index f41ff2171f..3cfbb5f9c8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -35,6 +35,7 @@
 - Enhance: misskey-dev/summaly@5.1.0の取り込み(プレビュー生成処理の効率化)
 - Fix: フォローリクエストを作成する際に既存のものは削除するように  
   (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/440)
+- Fix: CleanRemoteFilesProcessorService report progress from 100% (#13632)
 
 ## 2024.3.1
 
diff --git a/packages/backend/src/queue/processors/CleanRemoteFilesProcessorService.ts b/packages/backend/src/queue/processors/CleanRemoteFilesProcessorService.ts
index 917de8b72c..728fc9e72b 100644
--- a/packages/backend/src/queue/processors/CleanRemoteFilesProcessorService.ts
+++ b/packages/backend/src/queue/processors/CleanRemoteFilesProcessorService.ts
@@ -63,7 +63,7 @@ export class CleanRemoteFilesProcessorService {
 				isLink: false,
 			});
 
-			job.updateProgress(deletedCount / total);
+			job.updateProgress(100 / total * deletedCount);
 		}
 
 		this.logger.succ('All cached remote files has been deleted.');

From b35ae97ba7b57ae2b04eb0cc25dd3360e321e537 Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Sat, 30 Mar 2024 13:51:53 +0900
Subject: [PATCH 055/191] fix(backend): better `notes/translate` error response
 (#13631)

* fix(backend): better `notes/translate` error response

* Update CHANGELOG.md

* test(backend): perform administrative operations as `root`

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 CHANGELOG.md                                  |   1 +
 .../server/api/endpoints/notes/translate.ts   |  13 ++-
 packages/backend/test/e2e/note.ts             | 107 ++++++++++++++----
 packages/misskey-js/src/autogen/types.ts      |   4 +
 4 files changed, 97 insertions(+), 28 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3cfbb5f9c8..5963549cc6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -35,6 +35,7 @@
 - Enhance: misskey-dev/summaly@5.1.0の取り込み(プレビュー生成処理の効率化)
 - Fix: フォローリクエストを作成する際に既存のものは削除するように  
   (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/440)
+- Fix: エンドポイント`notes/translate`のエラーを改善
 - Fix: CleanRemoteFilesProcessorService report progress from 100% (#13632)
 
 ## 2024.3.1
diff --git a/packages/backend/src/server/api/endpoints/notes/translate.ts b/packages/backend/src/server/api/endpoints/notes/translate.ts
index 78812351f4..38a9660aa2 100644
--- a/packages/backend/src/server/api/endpoints/notes/translate.ts
+++ b/packages/backend/src/server/api/endpoints/notes/translate.ts
@@ -21,7 +21,7 @@ export const meta = {
 
 	res: {
 		type: 'object',
-		optional: false, nullable: false,
+		optional: true, nullable: false,
 		properties: {
 			sourceLang: { type: 'string' },
 			text: { type: 'string' },
@@ -39,6 +39,11 @@ export const meta = {
 			code: 'NO_SUCH_NOTE',
 			id: 'bea9b03f-36e0-49c5-a4db-627a029f8971',
 		},
+		cannotTranslateInvisibleNote: {
+			message: 'Cannot translate invisible note.',
+			code: 'CANNOT_TRANSLATE_INVISIBLE_NOTE',
+			id: 'ea29f2ca-c368-43b3-aaf1-5ac3e74bbe5d',
+		},
 	},
 } as const;
 
@@ -72,17 +77,17 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 			});
 
 			if (!(await this.noteEntityService.isVisibleForMe(note, me.id))) {
-				return 204; // TODO: 良い感じのエラー返す
+				throw new ApiError(meta.errors.cannotTranslateInvisibleNote);
 			}
 
 			if (note.text == null) {
-				return 204;
+				return;
 			}
 
 			const instance = await this.metaService.fetch();
 
 			if (instance.deeplAuthKey == null) {
-				return 204; // TODO: 良い感じのエラー返す
+				throw new ApiError(meta.errors.unavailable);
 			}
 
 			let targetLang = ps.targetLang;
diff --git a/packages/backend/test/e2e/note.ts b/packages/backend/test/e2e/note.ts
index 11016f58ae..bda31d9640 100644
--- a/packages/backend/test/e2e/note.ts
+++ b/packages/backend/test/e2e/note.ts
@@ -8,12 +8,13 @@ process.env.NODE_ENV = 'test';
 import * as assert from 'assert';
 import { MiNote } from '@/models/Note.js';
 import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
-import { api, initTestDb, post, signup, uploadFile, uploadUrl } from '../utils.js';
+import { api, initTestDb, post, role, signup, uploadFile, uploadUrl } from '../utils.js';
 import type * as misskey from 'misskey-js';
 
 describe('Note', () => {
 	let Notes: any;
 
+	let root: misskey.entities.SignupResponse;
 	let alice: misskey.entities.SignupResponse;
 	let bob: misskey.entities.SignupResponse;
 	let tom: misskey.entities.SignupResponse;
@@ -21,6 +22,7 @@ describe('Note', () => {
 	beforeAll(async () => {
 		const connection = await initTestDb(true);
 		Notes = connection.getRepository(MiNote);
+		root = await signup({ username: 'root' });
 		alice = await signup({ username: 'alice' });
 		bob = await signup({ username: 'bob' });
 		tom = await signup({ username: 'tom', host: 'example.com' });
@@ -473,14 +475,14 @@ describe('Note', () => {
 						value: true,
 					},
 				} as any,
-			}, alice);
+			}, root);
 
 			assert.strictEqual(res.status, 200);
 
 			const assign = await api('admin/roles/assign', {
 				userId: alice.id,
 				roleId: res.body.id,
-			}, alice);
+			}, root);
 
 			assert.strictEqual(assign.status, 204);
 			assert.strictEqual(file.body!.isSensitive, false);
@@ -508,11 +510,11 @@ describe('Note', () => {
 			await api('admin/roles/unassign', {
 				userId: alice.id,
 				roleId: res.body.id,
-			});
+			}, root);
 
 			await api('admin/roles/delete', {
 				roleId: res.body.id,
-			}, alice);
+			}, root);
 		});
 	});
 
@@ -644,7 +646,7 @@ describe('Note', () => {
 				sensitiveWords: [
 					'test',
 				],
-			}, alice);
+			}, root);
 
 			assert.strictEqual(sensitive.status, 204);
 
@@ -663,7 +665,7 @@ describe('Note', () => {
 				sensitiveWords: [
 					'/Test/i',
 				],
-			}, alice);
+			}, root);
 
 			assert.strictEqual(sensitive.status, 204);
 
@@ -680,7 +682,7 @@ describe('Note', () => {
 				sensitiveWords: [
 					'Test hoge',
 				],
-			}, alice);
+			}, root);
 
 			assert.strictEqual(sensitive.status, 204);
 
@@ -697,7 +699,7 @@ describe('Note', () => {
 				prohibitedWords: [
 					'test',
 				],
-			}, alice);
+			}, root);
 
 			assert.strictEqual(prohibited.status, 204);
 
@@ -716,7 +718,7 @@ describe('Note', () => {
 				prohibitedWords: [
 					'/Test/i',
 				],
-			}, alice);
+			}, root);
 
 			assert.strictEqual(prohibited.status, 204);
 
@@ -733,7 +735,7 @@ describe('Note', () => {
 				prohibitedWords: [
 					'Test hoge',
 				],
-			}, alice);
+			}, root);
 
 			assert.strictEqual(prohibited.status, 204);
 
@@ -750,7 +752,7 @@ describe('Note', () => {
 				prohibitedWords: [
 					'test',
 				],
-			}, alice);
+			}, root);
 
 			assert.strictEqual(prohibited.status, 204);
 
@@ -785,7 +787,7 @@ describe('Note', () => {
 						value: 0,
 					},
 				} as any,
-			}, alice);
+			}, root);
 
 			assert.strictEqual(res.status, 200);
 
@@ -794,7 +796,7 @@ describe('Note', () => {
 			const assign = await api('admin/roles/assign', {
 				userId: alice.id,
 				roleId: res.body.id,
-			}, alice);
+			}, root);
 
 			assert.strictEqual(assign.status, 204);
 
@@ -810,11 +812,11 @@ describe('Note', () => {
 			await api('admin/roles/unassign', {
 				userId: alice.id,
 				roleId: res.body.id,
-			});
+			}, root);
 
 			await api('admin/roles/delete', {
 				roleId: res.body.id,
-			}, alice);
+			}, root);
 		});
 
 		test('ダイレクト投稿もエラーになる', async () => {
@@ -839,7 +841,7 @@ describe('Note', () => {
 						value: 0,
 					},
 				} as any,
-			}, alice);
+			}, root);
 
 			assert.strictEqual(res.status, 200);
 
@@ -848,7 +850,7 @@ describe('Note', () => {
 			const assign = await api('admin/roles/assign', {
 				userId: alice.id,
 				roleId: res.body.id,
-			}, alice);
+			}, root);
 
 			assert.strictEqual(assign.status, 204);
 
@@ -866,11 +868,11 @@ describe('Note', () => {
 			await api('admin/roles/unassign', {
 				userId: alice.id,
 				roleId: res.body.id,
-			});
+			}, root);
 
 			await api('admin/roles/delete', {
 				roleId: res.body.id,
-			}, alice);
+			}, root);
 		});
 
 		test('ダイレクトの宛先とメンションが同じ場合は重複してカウントしない', async () => {
@@ -895,7 +897,7 @@ describe('Note', () => {
 						value: 1,
 					},
 				} as any,
-			}, alice);
+			}, root);
 
 			assert.strictEqual(res.status, 200);
 
@@ -904,7 +906,7 @@ describe('Note', () => {
 			const assign = await api('admin/roles/assign', {
 				userId: alice.id,
 				roleId: res.body.id,
-			}, alice);
+			}, root);
 
 			assert.strictEqual(assign.status, 204);
 
@@ -921,11 +923,11 @@ describe('Note', () => {
 			await api('admin/roles/unassign', {
 				userId: alice.id,
 				roleId: res.body.id,
-			});
+			}, root);
 
 			await api('admin/roles/delete', {
 				roleId: res.body.id,
-			}, alice);
+			}, root);
 		});
 	});
 
@@ -960,4 +962,61 @@ describe('Note', () => {
 			assert.strictEqual(mainNote.repliesCount, 0);
 		});
 	});
+
+	describe('notes/translate', () => {
+		describe('翻訳機能の利用が許可されていない場合', () => {
+			let cannotTranslateRole: misskey.entities.Role;
+
+			beforeAll(async () => {
+				cannotTranslateRole = await role(root, {}, { canUseTranslator: false });
+				await api('admin/roles/assign', { roleId: cannotTranslateRole.id, userId: alice.id }, root);
+			});
+
+			test('翻訳機能の利用が許可されていない場合翻訳できない', async () => {
+				const aliceNote = await post(alice, { text: 'Hello' });
+				const res = await api('notes/translate', {
+					noteId: aliceNote.id,
+					targetLang: 'ja',
+				}, alice);
+
+				assert.strictEqual(res.status, 400);
+				assert.strictEqual(res.body.error.code, 'UNAVAILABLE');
+			});
+
+			afterAll(async () => {
+				await api('admin/roles/unassign', { roleId: cannotTranslateRole.id, userId: alice.id }, root);
+			});
+		});
+
+		test('存在しないノートは翻訳できない', async () => {
+			const res = await api('notes/translate', { noteId: 'foo', targetLang: 'ja' }, alice);
+
+			assert.strictEqual(res.status, 400);
+			assert.strictEqual(res.body.error.code, 'NO_SUCH_NOTE');
+		});
+
+		test('不可視なノートは翻訳できない', async () => {
+			const aliceNote = await post(alice, { visibility: 'followers', text: 'Hello' });
+			const bobTranslateAttempt = await api('notes/translate', { noteId: aliceNote.id, targetLang: 'ja' }, bob);
+
+			assert.strictEqual(bobTranslateAttempt.status, 400);
+			assert.strictEqual(bobTranslateAttempt.body.error.code, 'CANNOT_TRANSLATE_INVISIBLE_NOTE');
+		});
+
+		test('text: null なノートを翻訳すると空のレスポンスが返ってくる', async () => {
+			const aliceNote = await post(alice, { text: null, poll: { choices: ['kinoko', 'takenoko'] } });
+			const res = await api('notes/translate', { noteId: aliceNote.id, targetLang: 'ja' }, alice);
+
+			assert.strictEqual(res.status, 204);
+		});
+
+		test('サーバーに DeepL 認証キーが登録されていない場合翻訳できない', async () => {
+			const aliceNote = await post(alice, { text: 'Hello' });
+			const res = await api('notes/translate', { noteId: aliceNote.id, targetLang: 'ja' }, alice);
+
+			// NOTE: デフォルトでは登録されていないので落ちる
+			assert.strictEqual(res.status, 400);
+			assert.strictEqual(res.body.error.code, 'UNAVAILABLE');
+		});
+	});
 });
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 4b2ad16b0f..b6b26c000c 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -21864,6 +21864,10 @@ export type operations = {
           };
         };
       };
+      /** @description OK (without any results) */
+      204: {
+        content: never;
+      };
       /** @description Client error */
       400: {
         content: {

From 2a851437ffcd8778d157a6841875f03330c994b5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?=
 <46447427+samunohito@users.noreply.github.com>
Date: Sat, 30 Mar 2024 15:28:19 +0900
Subject: [PATCH 056/191] =?UTF-8?q?fix:=20misskey-js=E3=80=81bubble-game?=
 =?UTF-8?q?=E3=80=81reversi=E3=81=AE=E3=83=93=E3=83=AB=E3=83=89=E3=82=92es?=
 =?UTF-8?q?build=E3=81=AB=E7=B5=B1=E5=90=88=E3=81=99=E3=82=8B=20(#13600)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix: ビルドが遅いパッケージのビルド速度を改善

* dependenciesの整理

* fix ci

* ビルド開始時に古いファイルを消す

* fix ci

* fix ci
---
 .github/workflows/lint.yml                 |   2 +-
 package.json                               |   4 +-
 packages/backend/.swcrc                    |   3 +-
 packages/misskey-bubble-game/.eslintignore |   1 +
 packages/misskey-bubble-game/build.js      | 114 ++++++++++---
 packages/misskey-bubble-game/package.json  |  26 ++-
 packages/misskey-bubble-game/src/index.ts  |   6 +-
 packages/misskey-bubble-game/tsconfig.json |   2 +-
 packages/misskey-js/.eslintignore          |   1 +
 packages/misskey-js/api-extractor.json     |   2 +-
 packages/misskey-js/build.js               | 105 ++++++++++++
 packages/misskey-js/package.json           |  29 ++--
 packages/misskey-js/src/api.ts             |   2 +-
 packages/misskey-js/src/index.ts           |  15 +-
 packages/misskey-js/tsconfig.json          |   2 +-
 packages/misskey-reversi/.eslintignore     |   1 +
 packages/misskey-reversi/build.js          | 114 ++++++++++---
 packages/misskey-reversi/package.json      |  26 ++-
 packages/misskey-reversi/tsconfig.json     |   2 +-
 pnpm-lock.yaml                             | 188 ++++-----------------
 scripts/dev.mjs                            |  57 ++++---
 21 files changed, 421 insertions(+), 281 deletions(-)
 create mode 100644 packages/misskey-js/build.js

diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 31e974edaa..9b3f85fe1d 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -92,6 +92,6 @@ jobs:
     - run: pnpm i --frozen-lockfile
     - run: pnpm --filter misskey-js run build
       if: ${{ matrix.workspace == 'backend' }}
-    - run: pnpm --filter misskey-reversi run build:tsc
+    - run: pnpm --filter misskey-reversi run build
       if: ${{ matrix.workspace == 'backend' }}
     - run: pnpm --filter ${{ matrix.workspace }} run typecheck
diff --git a/package.json b/package.json
index 8f5ab0b124..84d6db5124 100644
--- a/package.json
+++ b/package.json
@@ -56,7 +56,9 @@
 		"postcss": "8.4.35",
 		"tar": "6.2.0",
 		"terser": "5.28.1",
-		"typescript": "5.3.3"
+		"typescript": "5.3.3",
+		"esbuild": "0.19.11",
+		"glob": "10.3.10"
 	},
 	"devDependencies": {
 		"@types/node": "^20.11.28",
diff --git a/packages/backend/.swcrc b/packages/backend/.swcrc
index 0504a2d389..845190b5f4 100644
--- a/packages/backend/.swcrc
+++ b/packages/backend/.swcrc
@@ -19,5 +19,6 @@
 		},
 		"target": "es2022"
 	},
-	"minify": false
+	"minify": false,
+	"sourceMaps": "inline"
 }
diff --git a/packages/misskey-bubble-game/.eslintignore b/packages/misskey-bubble-game/.eslintignore
index f22128f047..52ea8b3362 100644
--- a/packages/misskey-bubble-game/.eslintignore
+++ b/packages/misskey-bubble-game/.eslintignore
@@ -5,3 +5,4 @@ node_modules
 /jest.config.ts
 /test
 /test-d
+build.js
diff --git a/packages/misskey-bubble-game/build.js b/packages/misskey-bubble-game/build.js
index 4744dfaf7b..0b79f4b915 100644
--- a/packages/misskey-bubble-game/build.js
+++ b/packages/misskey-bubble-game/build.js
@@ -1,31 +1,105 @@
+import * as esbuild from "esbuild";
 import { build } from "esbuild";
 import { globSync } from "glob";
+import { execa } from "execa";
+import fs from "node:fs";
+import { fileURLToPath } from "node:url";
+import { dirname } from "node:path";
+
+const _filename = fileURLToPath(import.meta.url);
+const _dirname = dirname(_filename);
+const _package = JSON.parse(fs.readFileSync(_dirname + '/package.json', 'utf-8'));
 
 const entryPoints = globSync("./src/**/**.{ts,tsx}");
 
 /** @type {import('esbuild').BuildOptions} */
 const options = {
-  entryPoints,
-  minify: true,
-  outdir: "./built/esm",
-  target: "es2022",
-  platform: "browser",
-  format: "esm",
+	entryPoints,
+	minify: process.env.NODE_ENV === 'production',
+	outdir: "./built",
+	target: "es2022",
+	platform: "browser",
+	format: "esm",
+	sourcemap: 'linked',
 };
 
-if (process.env.WATCH === "true") {
-  options.watch = {
-    onRebuild(error, result) {
-      if (error) {
-        console.error("watch build failed:", error);
-      } else {
-        console.log("watch build succeeded:", result);
-      }
-    },
-  };
+// built配下をすべて削除する
+fs.rmSync('./built', { recursive: true, force: true });
+
+if (process.argv.map(arg => arg.toLowerCase()).includes("--watch")) {
+	await watchSrc();
+} else {
+	await buildSrc();
 }
 
-build(options).catch((err) => {
-  process.stderr.write(err.stderr);
-  process.exit(1);
-});
+async function buildSrc() {
+	console.log(`[${_package.name}] start building...`);
+
+	await build(options)
+		.then(it => {
+			console.log(`[${_package.name}] build succeeded.`);
+		})
+		.catch((err) => {
+			process.stderr.write(err.stderr);
+			process.exit(1);
+		});
+
+	if (process.env.NODE_ENV === 'production') {
+		console.log(`[${_package.name}] skip building d.ts because NODE_ENV is production.`);
+	} else {
+		await buildDts();
+	}
+
+	console.log(`[${_package.name}] finish building.`);
+}
+
+function buildDts() {
+	return execa(
+		'tsc',
+		[
+			'--project', 'tsconfig.json',
+			'--outDir', 'built',
+			'--declaration', 'true',
+			'--emitDeclarationOnly', 'true',
+		],
+		{
+			stdout: process.stdout,
+			stderr: process.stderr,
+		}
+	);
+}
+
+async function watchSrc() {
+	const plugins = [{
+		name: 'gen-dts',
+		setup(build) {
+			build.onStart(() => {
+				console.log(`[${_package.name}] detect changed...`);
+			});
+			build.onEnd(async result => {
+				if (result.errors.length > 0) {
+					console.error(`[${_package.name}] watch build failed:`, result);
+					return;
+				}
+				await buildDts();
+			});
+		},
+	}];
+
+	console.log(`[${_package.name}] start watching...`)
+
+	const context = await esbuild.context({ ...options, plugins });
+	await context.watch();
+
+	await new Promise((resolve, reject) => {
+		process.on('SIGHUP', resolve);
+		process.on('SIGINT', resolve);
+		process.on('SIGTERM', resolve);
+		process.on('SIGKILL', resolve);
+		process.on('uncaughtException', reject);
+		process.on('exit', resolve);
+	}).finally(async () => {
+		await context.dispose();
+		console.log(`[${_package.name}] finish watching.`);
+	});
+}
diff --git a/packages/misskey-bubble-game/package.json b/packages/misskey-bubble-game/package.json
index ddc4c2134b..a3aad147a9 100644
--- a/packages/misskey-bubble-game/package.json
+++ b/packages/misskey-bubble-game/package.json
@@ -2,24 +2,21 @@
 	"type": "module",
 	"name": "misskey-bubble-game",
 	"version": "0.0.1",
-	"types": "./built/dts/index.d.ts",
+	"main": "./built/index.js",
+	"types": "./built/index.d.ts",
 	"exports": {
 		".": {
-			"import": "./built/esm/index.js",
-			"types": "./built/dts/index.d.ts"
+			"import": "./built/index.js",
+			"types": "./built/index.d.ts"
 		},
 		"./*": {
-			"import": "./built/esm/*",
-			"types": "./built/dts/*"
+			"import": "./built/*",
+			"types": "./built/*"
 		}
 	},
 	"scripts": {
 		"build": "node ./build.js",
-		"build:tsc": "npm run tsc",
-		"tsc": "npm run tsc-esm && npm run tsc-dts",
-		"tsc-esm": "tsc --outDir built/esm",
-		"tsc-dts": "tsc --outDir built/dts --declaration true --emitDeclarationOnly true --declarationMap true",
-		"watch": "nodemon -w src -e ts,js,cjs,mjs,json --exec \"pnpm run build:tsc\"",
+		"watch": "nodemon -w package.json -e json --exec \"node ./build.js --watch\"",
 		"eslint": "eslint . --ext .js,.jsx,.ts,.tsx",
 		"typecheck": "tsc --noEmit",
 		"lint": "pnpm typecheck && pnpm eslint"
@@ -27,21 +24,22 @@
 	"devDependencies": {
 		"@misskey-dev/eslint-plugin": "1.0.0",
 		"@types/matter-js": "0.19.6",
-		"@types/node": "20.11.5",
 		"@types/seedrandom": "3.0.8",
+		"@types/node": "20.11.5",
 		"@typescript-eslint/eslint-plugin": "7.1.0",
 		"@typescript-eslint/parser": "7.1.0",
 		"eslint": "8.57.0",
 		"nodemon": "3.0.2",
-		"typescript": "5.3.3"
+		"execa": "8.0.1",
+		"typescript": "5.3.3",
+		"esbuild": "0.19.11",
+		"glob": "10.3.10"
 	},
 	"files": [
 		"built"
 	],
 	"dependencies": {
-		"esbuild": "0.19.11",
 		"eventemitter3": "5.0.1",
-		"glob": "^10.3.10",
 		"matter-js": "0.19.0",
 		"seedrandom": "3.0.5"
 	}
diff --git a/packages/misskey-bubble-game/src/index.ts b/packages/misskey-bubble-game/src/index.ts
index 004a7d008e..c5f1f68062 100644
--- a/packages/misskey-bubble-game/src/index.ts
+++ b/packages/misskey-bubble-game/src/index.ts
@@ -6,5 +6,9 @@
 import { DropAndFusionGame, Mono } from './game.js';
 
 export {
-	DropAndFusionGame, Mono,
+	DropAndFusionGame,
+};
+
+export type {
+	Mono,
 };
diff --git a/packages/misskey-bubble-game/tsconfig.json b/packages/misskey-bubble-game/tsconfig.json
index f56b65e868..6e34e332e0 100644
--- a/packages/misskey-bubble-game/tsconfig.json
+++ b/packages/misskey-bubble-game/tsconfig.json
@@ -6,7 +6,7 @@
 		"moduleResolution": "nodenext",
 		"declaration": true,
 		"declarationMap": true,
-		"sourceMap": true,
+		"sourceMap": false,
 		"outDir": "./built/",
 		"removeComments": true,
 		"strict": true,
diff --git a/packages/misskey-js/.eslintignore b/packages/misskey-js/.eslintignore
index f22128f047..52ea8b3362 100644
--- a/packages/misskey-js/.eslintignore
+++ b/packages/misskey-js/.eslintignore
@@ -5,3 +5,4 @@ node_modules
 /jest.config.ts
 /test
 /test-d
+build.js
diff --git a/packages/misskey-js/api-extractor.json b/packages/misskey-js/api-extractor.json
index f80d0f20a8..a95281a6d5 100644
--- a/packages/misskey-js/api-extractor.json
+++ b/packages/misskey-js/api-extractor.json
@@ -45,7 +45,7 @@
    *
    * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
    */
-  "mainEntryPointFilePath": "<projectFolder>/built/dts/index.d.ts",
+  "mainEntryPointFilePath": "<projectFolder>/built/index.d.ts",
 
   /**
    * A list of NPM package names whose exports should be treated as part of this package.
diff --git a/packages/misskey-js/build.js b/packages/misskey-js/build.js
new file mode 100644
index 0000000000..0b79f4b915
--- /dev/null
+++ b/packages/misskey-js/build.js
@@ -0,0 +1,105 @@
+import * as esbuild from "esbuild";
+import { build } from "esbuild";
+import { globSync } from "glob";
+import { execa } from "execa";
+import fs from "node:fs";
+import { fileURLToPath } from "node:url";
+import { dirname } from "node:path";
+
+const _filename = fileURLToPath(import.meta.url);
+const _dirname = dirname(_filename);
+const _package = JSON.parse(fs.readFileSync(_dirname + '/package.json', 'utf-8'));
+
+const entryPoints = globSync("./src/**/**.{ts,tsx}");
+
+/** @type {import('esbuild').BuildOptions} */
+const options = {
+	entryPoints,
+	minify: process.env.NODE_ENV === 'production',
+	outdir: "./built",
+	target: "es2022",
+	platform: "browser",
+	format: "esm",
+	sourcemap: 'linked',
+};
+
+// built配下をすべて削除する
+fs.rmSync('./built', { recursive: true, force: true });
+
+if (process.argv.map(arg => arg.toLowerCase()).includes("--watch")) {
+	await watchSrc();
+} else {
+	await buildSrc();
+}
+
+async function buildSrc() {
+	console.log(`[${_package.name}] start building...`);
+
+	await build(options)
+		.then(it => {
+			console.log(`[${_package.name}] build succeeded.`);
+		})
+		.catch((err) => {
+			process.stderr.write(err.stderr);
+			process.exit(1);
+		});
+
+	if (process.env.NODE_ENV === 'production') {
+		console.log(`[${_package.name}] skip building d.ts because NODE_ENV is production.`);
+	} else {
+		await buildDts();
+	}
+
+	console.log(`[${_package.name}] finish building.`);
+}
+
+function buildDts() {
+	return execa(
+		'tsc',
+		[
+			'--project', 'tsconfig.json',
+			'--outDir', 'built',
+			'--declaration', 'true',
+			'--emitDeclarationOnly', 'true',
+		],
+		{
+			stdout: process.stdout,
+			stderr: process.stderr,
+		}
+	);
+}
+
+async function watchSrc() {
+	const plugins = [{
+		name: 'gen-dts',
+		setup(build) {
+			build.onStart(() => {
+				console.log(`[${_package.name}] detect changed...`);
+			});
+			build.onEnd(async result => {
+				if (result.errors.length > 0) {
+					console.error(`[${_package.name}] watch build failed:`, result);
+					return;
+				}
+				await buildDts();
+			});
+		},
+	}];
+
+	console.log(`[${_package.name}] start watching...`)
+
+	const context = await esbuild.context({ ...options, plugins });
+	await context.watch();
+
+	await new Promise((resolve, reject) => {
+		process.on('SIGHUP', resolve);
+		process.on('SIGINT', resolve);
+		process.on('SIGTERM', resolve);
+		process.on('SIGKILL', resolve);
+		process.on('uncaughtException', reject);
+		process.on('exit', resolve);
+	}).finally(async () => {
+		await context.dispose();
+		console.log(`[${_package.name}] finish watching.`);
+	});
+}
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index 772f001c07..a9c75c95c2 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -3,23 +3,21 @@
 	"name": "misskey-js",
 	"version": "2024.3.1",
 	"description": "Misskey SDK for JavaScript",
-	"types": "./built/dts/index.d.ts",
+	"main": "./built/index.js",
+	"types": "./built/index.d.ts",
 	"exports": {
 		".": {
-			"import": "./built/esm/index.js",
-			"types": "./built/dts/index.d.ts"
+			"import": "./built/index.js",
+			"types": "./built/index.d.ts"
 		},
 		"./*": {
-			"import": "./built/esm/*",
-			"types": "./built/dts/*"
+			"import": "./built/*",
+			"types": "./built/*"
 		}
 	},
 	"scripts": {
-		"build": "npm run ts",
-		"ts": "npm run ts-esm && npm run ts-dts",
-		"ts-esm": "tsc --outDir built/esm",
-		"ts-dts": "tsc --outDir built/dts --declaration true --emitDeclarationOnly true --declarationMap true",
-		"watch": "nodemon -w src -e ts,js,cjs,mjs,json --exec \"pnpm run ts\"",
+		"build": "node ./build.js",
+		"watch": "nodemon -w package.json -e json --exec \"node ./build.js --watch\"",
 		"tsd": "tsd",
 		"api": "pnpm api-extractor run --local --verbose",
 		"api-prod": "pnpm api-extractor run --verbose",
@@ -49,17 +47,16 @@
 		"mock-socket": "9.3.1",
 		"ncp": "2.0.0",
 		"nodemon": "3.1.0",
+		"execa": "8.0.1",
 		"tsd": "0.30.7",
-		"typescript": "5.3.3"
+		"typescript": "5.3.3",
+		"esbuild": "0.19.11",
+		"glob": "10.3.10"
 	},
 	"files": [
-		"built",
-		"built/esm",
-		"built/dts"
+		"built"
 	],
 	"dependencies": {
-		"@swc/cli": "0.1.63",
-		"@swc/core": "1.3.105",
 		"eventemitter3": "5.0.1",
 		"reconnecting-websocket": "4.4.0"
 	}
diff --git a/packages/misskey-js/src/api.ts b/packages/misskey-js/src/api.ts
index 134ead0d79..959a634a74 100644
--- a/packages/misskey-js/src/api.ts
+++ b/packages/misskey-js/src/api.ts
@@ -3,7 +3,7 @@ import './autogen/apiClientJSDoc.js';
 import { SwitchCaseResponseType } from './api.types.js';
 import type { Endpoints } from './api.types.js';
 
-export {
+export type {
 	SwitchCaseResponseType,
 } from './api.types.js';
 
diff --git a/packages/misskey-js/src/index.ts b/packages/misskey-js/src/index.ts
index 54cae8ec03..28007a8ade 100644
--- a/packages/misskey-js/src/index.ts
+++ b/packages/misskey-js/src/index.ts
@@ -1,17 +1,20 @@
-import { Endpoints } from './api.types.js';
+import { type Endpoints } from './api.types.js';
 import Stream, { Connection } from './streaming.js';
-import { Channels } from './streaming.types.js';
-import { Acct } from './acct.js';
+import { type Channels } from './streaming.types.js';
+import { type Acct } from './acct.js';
 import * as consts from './consts.js';
 
-export {
+export type {
 	Endpoints,
-	Stream,
-	Connection as ChannelConnection,
 	Channels,
 	Acct,
 };
 
+export {
+	Stream,
+	Connection as ChannelConnection,
+};
+
 export const permissions = consts.permissions;
 export const notificationTypes = consts.notificationTypes;
 export const noteVisibilities = consts.noteVisibilities;
diff --git a/packages/misskey-js/tsconfig.json b/packages/misskey-js/tsconfig.json
index f56b65e868..6e34e332e0 100644
--- a/packages/misskey-js/tsconfig.json
+++ b/packages/misskey-js/tsconfig.json
@@ -6,7 +6,7 @@
 		"moduleResolution": "nodenext",
 		"declaration": true,
 		"declarationMap": true,
-		"sourceMap": true,
+		"sourceMap": false,
 		"outDir": "./built/",
 		"removeComments": true,
 		"strict": true,
diff --git a/packages/misskey-reversi/.eslintignore b/packages/misskey-reversi/.eslintignore
index f22128f047..52ea8b3362 100644
--- a/packages/misskey-reversi/.eslintignore
+++ b/packages/misskey-reversi/.eslintignore
@@ -5,3 +5,4 @@ node_modules
 /jest.config.ts
 /test
 /test-d
+build.js
diff --git a/packages/misskey-reversi/build.js b/packages/misskey-reversi/build.js
index 4744dfaf7b..0b79f4b915 100644
--- a/packages/misskey-reversi/build.js
+++ b/packages/misskey-reversi/build.js
@@ -1,31 +1,105 @@
+import * as esbuild from "esbuild";
 import { build } from "esbuild";
 import { globSync } from "glob";
+import { execa } from "execa";
+import fs from "node:fs";
+import { fileURLToPath } from "node:url";
+import { dirname } from "node:path";
+
+const _filename = fileURLToPath(import.meta.url);
+const _dirname = dirname(_filename);
+const _package = JSON.parse(fs.readFileSync(_dirname + '/package.json', 'utf-8'));
 
 const entryPoints = globSync("./src/**/**.{ts,tsx}");
 
 /** @type {import('esbuild').BuildOptions} */
 const options = {
-  entryPoints,
-  minify: true,
-  outdir: "./built/esm",
-  target: "es2022",
-  platform: "browser",
-  format: "esm",
+	entryPoints,
+	minify: process.env.NODE_ENV === 'production',
+	outdir: "./built",
+	target: "es2022",
+	platform: "browser",
+	format: "esm",
+	sourcemap: 'linked',
 };
 
-if (process.env.WATCH === "true") {
-  options.watch = {
-    onRebuild(error, result) {
-      if (error) {
-        console.error("watch build failed:", error);
-      } else {
-        console.log("watch build succeeded:", result);
-      }
-    },
-  };
+// built配下をすべて削除する
+fs.rmSync('./built', { recursive: true, force: true });
+
+if (process.argv.map(arg => arg.toLowerCase()).includes("--watch")) {
+	await watchSrc();
+} else {
+	await buildSrc();
 }
 
-build(options).catch((err) => {
-  process.stderr.write(err.stderr);
-  process.exit(1);
-});
+async function buildSrc() {
+	console.log(`[${_package.name}] start building...`);
+
+	await build(options)
+		.then(it => {
+			console.log(`[${_package.name}] build succeeded.`);
+		})
+		.catch((err) => {
+			process.stderr.write(err.stderr);
+			process.exit(1);
+		});
+
+	if (process.env.NODE_ENV === 'production') {
+		console.log(`[${_package.name}] skip building d.ts because NODE_ENV is production.`);
+	} else {
+		await buildDts();
+	}
+
+	console.log(`[${_package.name}] finish building.`);
+}
+
+function buildDts() {
+	return execa(
+		'tsc',
+		[
+			'--project', 'tsconfig.json',
+			'--outDir', 'built',
+			'--declaration', 'true',
+			'--emitDeclarationOnly', 'true',
+		],
+		{
+			stdout: process.stdout,
+			stderr: process.stderr,
+		}
+	);
+}
+
+async function watchSrc() {
+	const plugins = [{
+		name: 'gen-dts',
+		setup(build) {
+			build.onStart(() => {
+				console.log(`[${_package.name}] detect changed...`);
+			});
+			build.onEnd(async result => {
+				if (result.errors.length > 0) {
+					console.error(`[${_package.name}] watch build failed:`, result);
+					return;
+				}
+				await buildDts();
+			});
+		},
+	}];
+
+	console.log(`[${_package.name}] start watching...`)
+
+	const context = await esbuild.context({ ...options, plugins });
+	await context.watch();
+
+	await new Promise((resolve, reject) => {
+		process.on('SIGHUP', resolve);
+		process.on('SIGINT', resolve);
+		process.on('SIGTERM', resolve);
+		process.on('SIGKILL', resolve);
+		process.on('uncaughtException', reject);
+		process.on('exit', resolve);
+	}).finally(async () => {
+		await context.dispose();
+		console.log(`[${_package.name}] finish watching.`);
+	});
+}
diff --git a/packages/misskey-reversi/package.json b/packages/misskey-reversi/package.json
index 7bfc890fef..45a6120861 100644
--- a/packages/misskey-reversi/package.json
+++ b/packages/misskey-reversi/package.json
@@ -2,24 +2,21 @@
 	"type": "module",
 	"name": "misskey-reversi",
 	"version": "0.0.1",
-	"types": "./built/dts/index.d.ts",
+	"main": "./built/index.js",
+	"types": "./built/index.d.ts",
 	"exports": {
 		".": {
-			"import": "./built/esm/index.js",
-			"types": "./built/dts/index.d.ts"
+			"import": "./built/index.js",
+			"types": "./built/index.d.ts"
 		},
 		"./*": {
-			"import": "./built/esm/*",
-			"types": "./built/dts/*"
+			"import": "./built/*",
+			"types": "./built/*"
 		}
 	},
 	"scripts": {
 		"build": "node ./build.js",
-		"build:tsc": "npm run tsc",
-		"tsc": "npm run tsc-esm && npm run tsc-dts",
-		"tsc-esm": "tsc --outDir built/esm",
-		"tsc-dts": "tsc --outDir built/dts --declaration true --emitDeclarationOnly true --declarationMap true",
-		"watch": "nodemon -w src -e ts,js,cjs,mjs,json --exec \"pnpm run build:tsc\"",
+		"watch": "nodemon -w package.json -e json --exec \"node ./build.js --watch\"",
 		"eslint": "eslint . --ext .js,.jsx,.ts,.tsx",
 		"typecheck": "tsc --noEmit",
 		"lint": "pnpm typecheck && pnpm eslint"
@@ -30,15 +27,16 @@
 		"@typescript-eslint/eslint-plugin": "7.1.0",
 		"@typescript-eslint/parser": "7.1.0",
 		"eslint": "8.57.0",
+		"execa": "8.0.1",
 		"nodemon": "3.0.2",
-		"typescript": "5.3.3"
+		"typescript": "5.3.3",
+		"esbuild": "0.19.11",
+		"glob": "10.3.10"
 	},
 	"files": [
 		"built"
 	],
 	"dependencies": {
-		"crc-32": "1.2.2",
-		"esbuild": "0.19.11",
-		"glob": "10.3.10"
+		"crc-32": "1.2.2"
 	}
 }
diff --git a/packages/misskey-reversi/tsconfig.json b/packages/misskey-reversi/tsconfig.json
index f56b65e868..6e34e332e0 100644
--- a/packages/misskey-reversi/tsconfig.json
+++ b/packages/misskey-reversi/tsconfig.json
@@ -6,7 +6,7 @@
 		"moduleResolution": "nodenext",
 		"declaration": true,
 		"declarationMap": true,
-		"sourceMap": true,
+		"sourceMap": false,
 		"outDir": "./built/",
 		"removeComments": true,
 		"strict": true,
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 383b31b1f3..46512784c3 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -15,12 +15,18 @@ importers:
       cssnano:
         specifier: 6.0.5
         version: 6.0.5(postcss@8.4.35)
+      esbuild:
+        specifier: 0.19.11
+        version: 0.19.11
       execa:
         specifier: 8.0.1
         version: 8.0.1
       fast-glob:
         specifier: 3.3.2
         version: 3.3.2
+      glob:
+        specifier: 10.3.10
+        version: 10.3.10
       ignore-walk:
         specifier: 6.0.4
         version: 6.0.4
@@ -1037,15 +1043,9 @@ importers:
 
   packages/misskey-bubble-game:
     dependencies:
-      esbuild:
-        specifier: 0.19.11
-        version: 0.19.11
       eventemitter3:
         specifier: 5.0.1
         version: 5.0.1
-      glob:
-        specifier: ^10.3.10
-        version: 10.3.10
       matter-js:
         specifier: 0.19.0
         version: 0.19.0
@@ -1071,9 +1071,18 @@ importers:
       '@typescript-eslint/parser':
         specifier: 7.1.0
         version: 7.1.0(eslint@8.57.0)(typescript@5.3.3)
+      esbuild:
+        specifier: 0.19.11
+        version: 0.19.11
       eslint:
         specifier: 8.57.0
         version: 8.57.0
+      execa:
+        specifier: 8.0.1
+        version: 8.0.1
+      glob:
+        specifier: 10.3.10
+        version: 10.3.10
       nodemon:
         specifier: 3.0.2
         version: 3.0.2
@@ -1083,12 +1092,6 @@ importers:
 
   packages/misskey-js:
     dependencies:
-      '@swc/cli':
-        specifier: 0.1.63
-        version: 0.1.63(@swc/core@1.3.105)
-      '@swc/core':
-        specifier: 1.3.105
-        version: 1.3.105
       eventemitter3:
         specifier: 5.0.1
         version: 5.0.1
@@ -1104,7 +1107,7 @@ importers:
         version: 1.0.0(@typescript-eslint/eslint-plugin@7.1.0)(@typescript-eslint/parser@7.1.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
       '@swc/jest':
         specifier: 0.2.31
-        version: 0.2.31(@swc/core@1.3.105)
+        version: 0.2.31(@swc/core@1.3.107)
       '@types/jest':
         specifier: 29.5.12
         version: 29.5.12
@@ -1117,9 +1120,18 @@ importers:
       '@typescript-eslint/parser':
         specifier: 7.1.0
         version: 7.1.0(eslint@8.57.0)(typescript@5.3.3)
+      esbuild:
+        specifier: 0.19.11
+        version: 0.19.11
       eslint:
         specifier: 8.57.0
         version: 8.57.0
+      execa:
+        specifier: 8.0.1
+        version: 8.0.1
+      glob:
+        specifier: 10.3.10
+        version: 10.3.10
       jest:
         specifier: 29.7.0
         version: 29.7.0(@types/node@20.11.22)
@@ -1186,12 +1198,6 @@ importers:
       crc-32:
         specifier: 1.2.2
         version: 1.2.2
-      esbuild:
-        specifier: 0.19.11
-        version: 0.19.11
-      glob:
-        specifier: 10.3.10
-        version: 10.3.10
     devDependencies:
       '@misskey-dev/eslint-plugin':
         specifier: 1.0.0
@@ -1205,9 +1211,18 @@ importers:
       '@typescript-eslint/parser':
         specifier: 7.1.0
         version: 7.1.0(eslint@8.57.0)(typescript@5.3.3)
+      esbuild:
+        specifier: 0.19.11
+        version: 0.19.11
       eslint:
         specifier: 8.57.0
         version: 8.57.0
+      execa:
+        specifier: 8.0.1
+        version: 8.0.1
+      glob:
+        specifier: 10.3.10
+        version: 10.3.10
       nodemon:
         specifier: 3.0.2
         version: 3.0.2
@@ -6669,26 +6684,6 @@ packages:
       - supports-color
     dev: true
 
-  /@swc/cli@0.1.63(@swc/core@1.3.105):
-    resolution: {integrity: sha512-EM9oxxHzmmsprYRbGqsS2M4M/Gr5Gkcl0ROYYIdlUyTkhOiX822EQiRCpPCwdutdnzH2GyaTN7wc6i0Y+CKd3A==}
-    engines: {node: '>= 12.13'}
-    hasBin: true
-    peerDependencies:
-      '@swc/core': ^1.2.66
-      chokidar: 3.5.3
-    peerDependenciesMeta:
-      chokidar:
-        optional: true
-    dependencies:
-      '@mole-inc/bin-wrapper': 8.0.1
-      '@swc/core': 1.3.105
-      commander: 7.2.0
-      fast-glob: 3.3.2
-      semver: 7.5.4
-      slash: 3.0.0
-      source-map: 0.7.4
-    dev: false
-
   /@swc/cli@0.1.63(@swc/core@1.3.107)(chokidar@3.5.3):
     resolution: {integrity: sha512-EM9oxxHzmmsprYRbGqsS2M4M/Gr5Gkcl0ROYYIdlUyTkhOiX822EQiRCpPCwdutdnzH2GyaTN7wc6i0Y+CKd3A==}
     engines: {node: '>= 12.13'}
@@ -6721,14 +6716,6 @@ packages:
     dev: false
     optional: true
 
-  /@swc/core-darwin-arm64@1.3.105:
-    resolution: {integrity: sha512-buWeweLVDXXmcnfIemH4PGnpjwsDTUGitnPchdftb0u1FU8zSSP/lw/pUCBDG/XvWAp7c/aFxgN4CyG0j7eayA==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
-    optional: true
-
   /@swc/core-darwin-arm64@1.3.107:
     resolution: {integrity: sha512-47tD/5vSXWxPd0j/ZllyQUg4bqalbQTsmqSw0J4dDdS82MWqCAwUErUrAZPRjBkjNQ6Kmrf5rpCWaGTtPw+ngw==}
     engines: {node: '>=10'}
@@ -6746,14 +6733,6 @@ packages:
     dev: false
     optional: true
 
-  /@swc/core-darwin-x64@1.3.105:
-    resolution: {integrity: sha512-hFmXPApqjA/8sy/9NpljHVaKi1OvL9QkJ2MbbTCCbJERuHMpMUeMBUWipHRfepGHFhU+9B9zkEup/qJaJR4XIg==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
-    optional: true
-
   /@swc/core-darwin-x64@1.3.107:
     resolution: {integrity: sha512-hwiLJ2ulNkBGAh1m1eTfeY1417OAYbRGcb/iGsJ+LuVLvKAhU/itzsl535CvcwAlt2LayeCFfcI8gdeOLeZa9A==}
     engines: {node: '>=10'}
@@ -6782,14 +6761,6 @@ packages:
     dev: false
     optional: true
 
-  /@swc/core-linux-arm-gnueabihf@1.3.105:
-    resolution: {integrity: sha512-mwXyMC41oMKkKrPpL8uJpOxw7fyfQoVtIw3Y5p0Blabk+espNYqix0E8VymHdRKuLmM//z5wVmMsuHdGBHvZeg==}
-    engines: {node: '>=10'}
-    cpu: [arm]
-    os: [linux]
-    requiresBuild: true
-    optional: true
-
   /@swc/core-linux-arm-gnueabihf@1.3.107:
     resolution: {integrity: sha512-I2wzcC0KXqh0OwymCmYwNRgZ9nxX7DWnOOStJXV3pS0uB83TXAkmqd7wvMBuIl9qu4Hfomi9aDM7IlEEn9tumQ==}
     engines: {node: '>=10'}
@@ -6807,14 +6778,6 @@ packages:
     dev: false
     optional: true
 
-  /@swc/core-linux-arm64-gnu@1.3.105:
-    resolution: {integrity: sha512-H7yEIVydnUtqBSUxwmO6vpIQn7j+Rr0DF6ZOORPyd/SFzQJK9cJRtmJQ3ZMzlJ1Bb+1gr3MvjgLEnmyCYEm2Hg==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
-    optional: true
-
   /@swc/core-linux-arm64-gnu@1.3.107:
     resolution: {integrity: sha512-HWgnn7JORYlOYnGsdunpSF8A+BCZKPLzLtEUA27/M/ZuANcMZabKL9Zurt7XQXq888uJFAt98Gy+59PU90aHKg==}
     engines: {node: '>=10'}
@@ -6832,14 +6795,6 @@ packages:
     dev: false
     optional: true
 
-  /@swc/core-linux-arm64-musl@1.3.105:
-    resolution: {integrity: sha512-Jg7RTFT3pGFdGt5elPV6oDkinRy7q9cXpenjXnJnM2uvx3jOwnsAhexPyCDHom8SHL0j+9kaLLC66T3Gz1E4UA==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
-    optional: true
-
   /@swc/core-linux-arm64-musl@1.3.107:
     resolution: {integrity: sha512-vfPF74cWfAm8hyhS8yvYI94ucMHIo8xIYU+oFOW9uvDlGQRgnUf/6DEVbLyt/3yfX5723Ln57U8uiMALbX5Pyw==}
     engines: {node: '>=10'}
@@ -6857,14 +6812,6 @@ packages:
     dev: false
     optional: true
 
-  /@swc/core-linux-x64-gnu@1.3.105:
-    resolution: {integrity: sha512-DJghplpyusAmp1X5pW/y93MmS/u83Sx5GrpJxI6KLPa82+NItTgMcl8KBQmW5GYAJpVKZyaIvBanS5TdR8aN2w==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
-    optional: true
-
   /@swc/core-linux-x64-gnu@1.3.107:
     resolution: {integrity: sha512-uBVNhIg0ip8rH9OnOsCARUFZ3Mq3tbPHxtmWk9uAa5u8jQwGWeBx5+nTHpDOVd3YxKb6+5xDEI/edeeLpha/9g==}
     engines: {node: '>=10'}
@@ -6882,14 +6829,6 @@ packages:
     dev: false
     optional: true
 
-  /@swc/core-linux-x64-musl@1.3.105:
-    resolution: {integrity: sha512-wD5jL2dZH/5nPNssBo6jhOvkI0lmWnVR4vnOXWjuXgjq1S0AJpO5jdre/6pYLmf26hft3M42bteDnjR4AAZ38w==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
-    optional: true
-
   /@swc/core-linux-x64-musl@1.3.107:
     resolution: {integrity: sha512-mvACkUvzSIB12q1H5JtabWATbk3AG+pQgXEN95AmEX2ZA5gbP9+B+mijsg7Sd/3tboHr7ZHLz/q3SHTvdFJrEw==}
     engines: {node: '>=10'}
@@ -6907,14 +6846,6 @@ packages:
     dev: false
     optional: true
 
-  /@swc/core-win32-arm64-msvc@1.3.105:
-    resolution: {integrity: sha512-UqJtwILUHRw2+3UTPnRkZrzM/bGdQtbR4UFdp79mZQYfryeOUVNg7aJj/bWUTkKtLiZ3o+FBNrM/x2X1mJX5bA==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [win32]
-    requiresBuild: true
-    optional: true
-
   /@swc/core-win32-arm64-msvc@1.3.107:
     resolution: {integrity: sha512-J3P14Ngy/1qtapzbguEH41kY109t6DFxfbK4Ntz9dOWNuVY3o9/RTB841ctnJk0ZHEG+BjfCJjsD2n8H5HcaOA==}
     engines: {node: '>=10'}
@@ -6932,14 +6863,6 @@ packages:
     dev: false
     optional: true
 
-  /@swc/core-win32-ia32-msvc@1.3.105:
-    resolution: {integrity: sha512-Z95C6vZgBEJ1snidYyjVKnVWiy/ZpPiIFIXGWkDr4ZyBgL3eZX12M6LzZ+NApHKffrbO4enbFyFomueBQgS2oA==}
-    engines: {node: '>=10'}
-    cpu: [ia32]
-    os: [win32]
-    requiresBuild: true
-    optional: true
-
   /@swc/core-win32-ia32-msvc@1.3.107:
     resolution: {integrity: sha512-ZBUtgyjTHlz8TPJh7kfwwwFma+ktr6OccB1oXC8fMSopD0AxVnQasgun3l3099wIsAB9eEsJDQ/3lDkOLs1gBA==}
     engines: {node: '>=10'}
@@ -6957,14 +6880,6 @@ packages:
     dev: false
     optional: true
 
-  /@swc/core-win32-x64-msvc@1.3.105:
-    resolution: {integrity: sha512-3J8fkyDPFsS3mszuYUY4Wfk7/B2oio9qXUwF3DzOs2MK+XgdyMLIptIxL7gdfitXJBH8k39uVjrIw1JGJDjyFA==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [win32]
-    requiresBuild: true
-    optional: true
-
   /@swc/core-win32-x64-msvc@1.3.107:
     resolution: {integrity: sha512-Eyzo2XRqWOxqhE1gk9h7LWmUf4Bp4Xn2Ttb0ayAXFp6YSTxQIThXcT9kipXZqcpxcmDwoq8iWbbf2P8XL743EA==}
     engines: {node: '>=10'}
@@ -6982,30 +6897,6 @@ packages:
     dev: false
     optional: true
 
-  /@swc/core@1.3.105:
-    resolution: {integrity: sha512-me2VZyr3OjqRpFrYQJJYy7x/zbFSl9nt+MAGnIcBtjDsN00iTVqEaKxBjPBFQV9BDAgPz2SRWes/DhhVm5SmMw==}
-    engines: {node: '>=10'}
-    requiresBuild: true
-    peerDependencies:
-      '@swc/helpers': ^0.5.0
-    peerDependenciesMeta:
-      '@swc/helpers':
-        optional: true
-    dependencies:
-      '@swc/counter': 0.1.1
-      '@swc/types': 0.1.5
-    optionalDependencies:
-      '@swc/core-darwin-arm64': 1.3.105
-      '@swc/core-darwin-x64': 1.3.105
-      '@swc/core-linux-arm-gnueabihf': 1.3.105
-      '@swc/core-linux-arm64-gnu': 1.3.105
-      '@swc/core-linux-arm64-musl': 1.3.105
-      '@swc/core-linux-x64-gnu': 1.3.105
-      '@swc/core-linux-x64-musl': 1.3.105
-      '@swc/core-win32-arm64-msvc': 1.3.105
-      '@swc/core-win32-ia32-msvc': 1.3.105
-      '@swc/core-win32-x64-msvc': 1.3.105
-
   /@swc/core@1.3.107:
     resolution: {integrity: sha512-zKhqDyFcTsyLIYK1iEmavljZnf4CCor5pF52UzLAz4B6Nu/4GLU+2LQVAf+oRHjusG39PTPjd2AlRT3f3QWfsQ==}
     engines: {node: '>=10'}
@@ -7033,17 +6924,6 @@ packages:
   /@swc/counter@0.1.1:
     resolution: {integrity: sha512-xVRaR4u9hcYjFvcSg71Lz5Bo4//CyjAAfMxa7UsaDSYxAshflUkVJWiyVWrfxC59z2kP1IzI4/1BEpnhI9o3Mw==}
 
-  /@swc/jest@0.2.31(@swc/core@1.3.105):
-    resolution: {integrity: sha512-Gh0Ste380O8KUY1IqsKr+aOvqqs2Loa+WcWWVNwl+lhXqOWK1iTFAP1K0IDfLqAuFP68+D/PxcpBJn21e6Quvw==}
-    engines: {npm: '>= 7.0.0'}
-    peerDependencies:
-      '@swc/core': '*'
-    dependencies:
-      '@jest/create-cache-key-function': 29.7.0
-      '@swc/core': 1.3.105
-      jsonc-parser: 3.2.0
-    dev: true
-
   /@swc/jest@0.2.31(@swc/core@1.3.107):
     resolution: {integrity: sha512-Gh0Ste380O8KUY1IqsKr+aOvqqs2Loa+WcWWVNwl+lhXqOWK1iTFAP1K0IDfLqAuFP68+D/PxcpBJn21e6Quvw==}
     engines: {npm: '>= 7.0.0'}
diff --git a/scripts/dev.mjs b/scripts/dev.mjs
index 1ca2c6c2ea..bbb2547758 100644
--- a/scripts/dev.mjs
+++ b/scripts/dev.mjs
@@ -16,35 +16,36 @@ await execa('pnpm', ['clean'], {
 	stderr: process.stderr,
 });
 
-await execa('pnpm', ['build-pre'], {
-	cwd: _dirname + '/../',
-	stdout: process.stdout,
-	stderr: process.stderr,
-});
+await Promise.all([
+	execa('pnpm', ['build-pre'], {
+		cwd: _dirname + '/../',
+		stdout: process.stdout,
+		stderr: process.stderr,
+	}),
+	execa('pnpm', ['build-assets'], {
+		cwd: _dirname + '/../',
+		stdout: process.stdout,
+		stderr: process.stderr,
+	}),
+	execa('pnpm', ['--filter', 'misskey-js', 'build'], {
+		cwd: _dirname + '/../',
+		stdout: process.stdout,
+		stderr: process.stderr,
+	}),
+]);
 
-await execa('pnpm', ['build-assets'], {
-	cwd: _dirname + '/../',
-	stdout: process.stdout,
-	stderr: process.stderr,
-});
-
-await execa('pnpm', ['--filter', 'misskey-js', 'ts'], {
-	cwd: _dirname + '/../',
-	stdout: process.stdout,
-	stderr: process.stderr,
-});
-
-await execa('pnpm', ['--filter', 'misskey-reversi', 'build:tsc'], {
-	cwd: _dirname + '/../',
-	stdout: process.stdout,
-	stderr: process.stderr,
-});
-
-await execa('pnpm', ['--filter', 'misskey-bubble-game', 'build:tsc'], {
-	cwd: _dirname + '/../',
-	stdout: process.stdout,
-	stderr: process.stderr,
-});
+await Promise.all([
+	execa('pnpm', ['--filter', 'misskey-reversi', 'build'], {
+		cwd: _dirname + '/../',
+		stdout: process.stdout,
+		stderr: process.stderr,
+	}),
+	execa('pnpm', ['--filter', 'misskey-bubble-game', 'build'], {
+		cwd: _dirname + '/../',
+		stdout: process.stdout,
+		stderr: process.stderr,
+	}),
+]);
 
 execa('pnpm', ['build-pre', '--watch'], {
 	cwd: _dirname + '/../',

From 50da7d2a2728745bcf29cf71fb230c85a1845060 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sat, 30 Mar 2024 15:34:05 +0900
Subject: [PATCH 057/191] =?UTF-8?q?enhance(frontend):=202=E8=A6=81?=
 =?UTF-8?q?=E7=B4=A0=E8=AA=8D=E8=A8=BC=E3=82=BB=E3=83=83=E3=83=88=E3=82=A2?=
 =?UTF-8?q?=E3=83=83=E3=83=97=E3=82=A6=E3=82=A3=E3=82=B6=E3=83=BC=E3=83=89?=
 =?UTF-8?q?=E3=81=AB=E3=82=A2=E3=83=97=E3=83=AA=E3=82=92=E8=B5=B7=E5=8B=95?=
 =?UTF-8?q?=E3=81=99=E3=82=8B=E3=83=9C=E3=82=BF=E3=83=B3=E3=82=92=E6=96=B0?=
 =?UTF-8?q?=E8=A8=AD=20(#13636)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance(frontend): 2要素認証セットアップウィザードにアプリを起動するボタンを新設

* add comment

* use css module
---
 locales/index.d.ts                               | 10 +++++-----
 locales/ja-JP.yml                                |  4 ++--
 packages/frontend/src/components/MkButton.vue    |  2 ++
 .../frontend/src/pages/settings/2fa.qrdialog.vue | 16 +++++++++++++---
 4 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/locales/index.d.ts b/locales/index.d.ts
index e1250946f3..428cf9135c 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -4928,6 +4928,10 @@ export interface Locale extends ILocale {
      * バックアップコードを使う
      */
     "useBackupCode": string;
+    /**
+     * アプリを起動
+     */
+    "launchApp": string;
     "_bubbleGame": {
         /**
          * 遊び方
@@ -7542,13 +7546,9 @@ export interface Locale extends ILocale {
          */
         "step1": ParameterizedString<"a" | "b">;
         /**
-         * 次に、表示されているQRコードをアプリでスキャンします。
+         * 次に、表示されているQRコードをアプリでスキャンするか、ボタンをクリックして端末上でアプリを開きます。
          */
         "step2": string;
-        /**
-         * QRコードをクリックすると、お使いの端末にインストールされている認証アプリやキーリングに登録できます。
-         */
-        "step2Click": string;
         /**
          * デスクトップアプリを使用する場合は次のURIを入力します
          */
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 1c4df27d92..9e76e420c3 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1228,6 +1228,7 @@ gameRetry: "リトライ"
 notUsePleaseLeaveBlank: "使用しない場合は空欄にしてください"
 useTotp: "ワンタイムパスワードを使う"
 useBackupCode: "バックアップコードを使う"
+launchApp: "アプリを起動"
 
 _bubbleGame:
   howToPlay: "遊び方"
@@ -1983,8 +1984,7 @@ _2fa:
   alreadyRegistered: "既に設定は完了しています。"
   registerTOTP: "認証アプリの設定を開始"
   step1: "まず、{a}や{b}などの認証アプリをお使いのデバイスにインストールします。"
-  step2: "次に、表示されているQRコードをアプリでスキャンします。"
-  step2Click: "QRコードをクリックすると、お使いの端末にインストールされている認証アプリやキーリングに登録できます。"
+  step2: "次に、表示されているQRコードをアプリでスキャンするか、ボタンをクリックして端末上でアプリを開きます。"
   step2Uri: "デスクトップアプリを使用する場合は次のURIを入力します"
   step3Title: "確認コードを入力"
   step3: "アプリに表示されている確認コード(トークン)を入力します。"
diff --git a/packages/frontend/src/components/MkButton.vue b/packages/frontend/src/components/MkButton.vue
index 817f1aadf3..3489255b91 100644
--- a/packages/frontend/src/components/MkButton.vue
+++ b/packages/frontend/src/components/MkButton.vue
@@ -23,6 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 	v-else class="_button"
 	:class="[$style.root, { [$style.inline]: inline, [$style.primary]: primary, [$style.gradate]: gradate, [$style.danger]: danger, [$style.rounded]: rounded, [$style.full]: full, [$style.small]: small, [$style.large]: large, [$style.transparent]: transparent, [$style.asLike]: asLike }]"
 	:to="to ?? '#'"
+	:behavior="linkBehavior"
 	@mousedown="onMousedown"
 >
 	<div ref="ripples" :class="$style.ripples" :data-children-class="$style.ripple"></div>
@@ -43,6 +44,7 @@ const props = defineProps<{
 	inline?: boolean;
 	link?: boolean;
 	to?: string;
+	linkBehavior?: null | 'window' | 'browser';
 	autofocus?: boolean;
 	wait?: boolean;
 	danger?: boolean;
diff --git a/packages/frontend/src/pages/settings/2fa.qrdialog.vue b/packages/frontend/src/pages/settings/2fa.qrdialog.vue
index 2ef664b9a3..73253b1ef4 100644
--- a/packages/frontend/src/pages/settings/2fa.qrdialog.vue
+++ b/packages/frontend/src/pages/settings/2fa.qrdialog.vue
@@ -33,8 +33,12 @@ SPDX-License-Identifier: AGPL-3.0-only
 									<a href="https://support.google.com/accounts/answer/1066447" rel="noopener" target="_blank" class="_link">Google Authenticator</a>
 								</template>
 							</I18n>
-							<div>{{ i18n.ts._2fa.step2 }}<br>{{ i18n.ts._2fa.step2Click }}</div>
-							<a :href="twoFactorData.url"><img :class="$style.qr" :src="twoFactorData.qr"></a>
+							<div>{{ i18n.ts._2fa.step2 }}</div>
+							<div>
+								<a :class="$style.qrRoot" :href="twoFactorData.url"><img :class="$style.qr" :src="twoFactorData.qr"></a>
+								<!-- QRコード側にマージンが入っているので直下でOK -->
+								<div><MkButton inline rounded link :to="twoFactorData.url" :linkBehavior="'browser'">{{ i18n.ts.launchApp }}</MkButton></div>
+							</div>
 							<MkKeyValue :copy="twoFactorData.url">
 								<template #key>{{ i18n.ts._2fa.step2Uri }}</template>
 								<template #value>{{ twoFactorData.url }}</template>
@@ -177,8 +181,14 @@ function allDone() {
 	transform: translateX(-50px);
 }
 
-.qr {
+.qrRoot {
+	display: block;
+	margin: 0 auto;
 	width: 200px;
 	max-width: 100%;
 }
+
+.qr {
+	width: 100%;
+}
 </style>

From b96d9c6973b1c861306fdb9f51256cee5325a2b1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sat, 30 Mar 2024 16:02:03 +0900
Subject: [PATCH 058/191] =?UTF-8?q?fix/enhance(frontend):=20=E6=98=A0?=
 =?UTF-8?q?=E5=83=8F=E3=83=BB=E9=9F=B3=E5=A3=B0=E5=91=A8=E3=82=8A=E3=81=AE?=
 =?UTF-8?q?=E6=94=B9=E4=BF=AE=20(#13206)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance(frontend): 映像・音声周りの改修

* fix

* fix design

* fix lint

* キーボードショートカットを整備

* Update Changelog

* fix

* feat: ループ再生

* ネイティブの動作と同期されるように

* Update Changelog

* key指定を消す
---
 CHANGELOG.md                                  |   3 +
 locales/index.d.ts                            |  18 +++
 locales/ja-JP.yml                             |   7 +
 .../frontend/src/components/MkMediaAudio.vue  | 112 ++++++++++++++-
 .../frontend/src/components/MkMediaVideo.vue  | 131 +++++++++++++++++-
 packages/frontend/src/components/MkMenu.vue   |  91 +++++++++++-
 .../src/components/MkSwitch.button.vue        |  13 +-
 .../frontend/src/pages/settings/general.vue   |   2 +
 packages/frontend/src/scripts/keycode.ts      |   1 +
 packages/frontend/src/store.ts                |   4 +
 packages/frontend/src/types/menu.ts           |  10 +-
 11 files changed, 373 insertions(+), 19 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5963549cc6..ebf9320129 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,9 @@
 - Enhance: ページのデザインを変更
 - Enhance: 2要素認証(ワンタイムパスワード)の入力欄を改善
 - Enhance: 「今日誕生日のフォロー中ユーザー」ウィジェットを手動でリロードできるように
+- Enhance: 映像・音声の再生にブラウザのネイティブプレイヤーを使用できるように
+- Enhance: 映像・音声の再生メニューに「再生速度」「ループ再生」「ピクチャインピクチャ」を追加
+- Enhance: 映像・音声の再生にキーボードショートカットが使えるように
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
 - Fix: ローカルURLのプレビューポップアップが左上に表示される
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 428cf9135c..3dbe46c7b2 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -4932,6 +4932,10 @@ export interface Locale extends ILocale {
      * アプリを起動
      */
     "launchApp": string;
+    /**
+     * 動画・音声の再生にブラウザのUIを使用する
+     */
+    "useNativeUIForVideoAudioPlayer": string;
     "_bubbleGame": {
         /**
          * 遊び方
@@ -9834,6 +9838,20 @@ export interface Locale extends ILocale {
          */
         "summaryProxyDescription2": string;
     };
+    "_mediaControls": {
+        /**
+         * ピクチャインピクチャ
+         */
+        "pip": string;
+        /**
+         * 再生速度
+         */
+        "playbackRate": string;
+        /**
+         * ループ再生
+         */
+        "loop": string;
+    };
 }
 declare const locales: {
     [lang: string]: Locale;
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 9e76e420c3..aa765d1310 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1229,6 +1229,7 @@ notUsePleaseLeaveBlank: "使用しない場合は空欄にしてください"
 useTotp: "ワンタイムパスワードを使う"
 useBackupCode: "バックアップコードを使う"
 launchApp: "アプリを起動"
+useNativeUIForVideoAudioPlayer: "動画・音声の再生にブラウザのUIを使用する"
 
 _bubbleGame:
   howToPlay: "遊び方"
@@ -2619,3 +2620,9 @@ _urlPreviewSetting:
   summaryProxy: "プレビューを生成するプロキシのエンドポイント"
   summaryProxyDescription: "Misskey本体ではなく、サマリープロキシを使用してプレビューを生成します。"
   summaryProxyDescription2: "プロキシには下記パラメータがクエリ文字列として連携されます。プロキシ側がこれらをサポートしない場合、設定値は無視されます。"
+
+_mediaControls:
+  pip: "ピクチャインピクチャ"
+  playbackRate: "再生速度"
+  loop: "ループ再生"
+  
\ No newline at end of file
diff --git a/packages/frontend/src/components/MkMediaAudio.vue b/packages/frontend/src/components/MkMediaAudio.vue
index 96c9b9fd66..5d2edf467e 100644
--- a/packages/frontend/src/components/MkMediaAudio.vue
+++ b/packages/frontend/src/components/MkMediaAudio.vue
@@ -5,11 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <template>
 <div
+	ref="playerEl"
+	v-hotkey="keymap"
+	tabindex="0"
 	:class="[
 		$style.audioContainer,
 		(audio.isSensitive && defaultStore.state.highlightSensitiveMedia) && $style.sensitive,
 	]"
 	@contextmenu.stop
+	@keydown.stop
 >
 	<button v-if="hide" :class="$style.hidden" @click="hide = false">
 		<div :class="$style.hiddenTextWrapper">
@@ -18,6 +22,19 @@ SPDX-License-Identifier: AGPL-3.0-only
 			<span style="display: block;">{{ i18n.ts.clickToShow }}</span>
 		</div>
 	</button>
+
+	<div v-else-if="defaultStore.reactiveState.useNativeUIForVideoAudioPlayer.value" :class="$style.nativeAudioContainer">
+		<audio
+			ref="audioEl"
+			preload="metadata"
+			controls
+			:class="$style.nativeAudio"
+			@keydown.prevent
+		>
+			<source :src="audio.url">
+		</audio>
+	</div>
+
 	<div v-else :class="$style.audioControls">
 		<audio
 			ref="audioEl"
@@ -72,6 +89,41 @@ const props = defineProps<{
 	audio: Misskey.entities.DriveFile;
 }>();
 
+const keymap = {
+	'up': () => {
+		if (hasFocus() && audioEl.value) {
+			volume.value = Math.min(volume.value + 0.1, 1);
+		}
+	},
+	'down': () => {
+		if (hasFocus() && audioEl.value) {
+			volume.value = Math.max(volume.value - 0.1, 0);
+		}
+	},
+	'left': () => {
+		if (hasFocus() && audioEl.value) {
+			audioEl.value.currentTime = Math.max(audioEl.value.currentTime - 5, 0);
+		}
+	},
+	'right': () => {
+		if (hasFocus() && audioEl.value) {
+			audioEl.value.currentTime = Math.min(audioEl.value.currentTime + 5, audioEl.value.duration);
+		}
+	},
+	'space': () => {
+		if (hasFocus()) {
+			togglePlayPause();
+		}
+	},
+};
+
+// PlayerElもしくはその子要素にフォーカスがあるかどうか
+function hasFocus() {
+	if (!playerEl.value) return false;
+	return playerEl.value === document.activeElement || playerEl.value.contains(document.activeElement);
+}
+
+const playerEl = shallowRef<HTMLDivElement>();
 const audioEl = shallowRef<HTMLAudioElement>();
 
 // eslint-disable-next-line vue/no-setup-props-destructure
@@ -85,6 +137,30 @@ function showMenu(ev: MouseEvent) {
 
 	menu = [
 		// TODO: 再生キューに追加
+		{
+			type: 'switch',
+			text: i18n.ts._mediaControls.loop,
+			icon: 'ti ti-repeat',
+			ref: loop,
+		},
+		{
+			type: 'radio',
+			text: i18n.ts._mediaControls.playbackRate,
+			icon: 'ti ti-clock-play',
+			ref: speed,
+			options: {
+				'0.25x': 0.25,
+				'0.5x': 0.5,
+				'0.75x': 0.75,
+				'1.0x': 1,
+				'1.25x': 1.25,
+				'1.5x': 1.5,
+				'2.0x': 2,
+			},
+		},
+		{
+			type: 'divider',
+		},
 		{
 			text: i18n.ts.hide,
 			icon: 'ti ti-eye-off',
@@ -147,6 +223,8 @@ const rangePercent = computed({
 	},
 });
 const volume = ref(.25);
+const speed = ref(1);
+const loop = ref(false); // TODO: ドライブファイルのフラグに置き換える
 const bufferedEnd = ref(0);
 const bufferedDataRatio = computed(() => {
 	if (!audioEl.value) return 0;
@@ -176,6 +254,7 @@ function toggleMute() {
 }
 
 let onceInit = false;
+let mediaTickFrameId: number | null = null;
 let stopAudioElWatch: () => void;
 
 function init() {
@@ -195,8 +274,12 @@ function init() {
 					}
 
 					elapsedTimeMs.value = audioEl.value.currentTime * 1000;
+
+					if (audioEl.value.loop !== loop.value) {
+						loop.value = audioEl.value.loop;
+					}
 				}
-				window.requestAnimationFrame(updateMediaTick);
+				mediaTickFrameId = window.requestAnimationFrame(updateMediaTick);
 			}
 
 			updateMediaTick();
@@ -234,6 +317,14 @@ watch(volume, (to) => {
 	if (audioEl.value) audioEl.value.volume = to;
 });
 
+watch(speed, (to) => {
+	if (audioEl.value) audioEl.value.playbackRate = to;
+});
+
+watch(loop, (to) => {
+	if (audioEl.value) audioEl.value.loop = to;
+});
+
 onMounted(() => {
 	init();
 });
@@ -252,6 +343,10 @@ onDeactivated(() => {
 	hide.value = (defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.audio.isSensitive && defaultStore.state.nsfw !== 'ignore');
 	stopAudioElWatch();
 	onceInit = false;
+	if (mediaTickFrameId) {
+		window.cancelAnimationFrame(mediaTickFrameId);
+		mediaTickFrameId = null;
+	}
 });
 </script>
 
@@ -262,6 +357,10 @@ onDeactivated(() => {
 	border: .5px solid var(--divider);
 	border-radius: var(--radius);
 	overflow: clip;
+
+	&:focus {
+		outline: none;
+	}
 }
 
 .sensitive {
@@ -367,4 +466,15 @@ onDeactivated(() => {
 		}
 	}
 }
+
+.nativeAudioContainer {
+	display: flex;
+	align-items: center;
+	padding: 6px;
+}
+
+.nativeAudio {
+	display: block;
+	width: 100%;
+}
 </style>
diff --git a/packages/frontend/src/components/MkMediaVideo.vue b/packages/frontend/src/components/MkMediaVideo.vue
index 73c1b6ff9d..1e3868bc36 100644
--- a/packages/frontend/src/components/MkMediaVideo.vue
+++ b/packages/frontend/src/components/MkMediaVideo.vue
@@ -6,6 +6,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 <template>
 <div
 	ref="playerEl"
+	v-hotkey="keymap"
+	tabindex="0"
 	:class="[
 		$style.videoContainer,
 		controlsShowing && $style.active,
@@ -14,15 +16,37 @@ SPDX-License-Identifier: AGPL-3.0-only
 	@mouseover="onMouseOver"
 	@mouseleave="onMouseLeave"
 	@contextmenu.stop
+	@keydown.stop
 >
 	<button v-if="hide" :class="$style.hidden" @click="hide = false">
 		<div :class="$style.hiddenTextWrapper">
 			<b v-if="video.isSensitive" style="display: block;"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.dataSaver.media ? ` (${i18n.ts.video}${video.size ? ' ' + bytes(video.size) : ''})` : '' }}</b>
-			<b v-else style="display: block;"><i class="ti ti-photo"></i> {{ defaultStore.state.dataSaver.media && video.size ? bytes(video.size) : i18n.ts.video }}</b>
+			<b v-else style="display: block;"><i class="ti ti-movie"></i> {{ defaultStore.state.dataSaver.media && video.size ? bytes(video.size) : i18n.ts.video }}</b>
 			<span style="display: block;">{{ i18n.ts.clickToShow }}</span>
 		</div>
 	</button>
-	<div v-else :class="$style.videoRoot" @click.self="togglePlayPause">
+
+	<div v-else-if="defaultStore.reactiveState.useNativeUIForVideoAudioPlayer.value" :class="$style.videoRoot">
+		<video
+			ref="videoEl"
+			:class="$style.video"
+			:poster="video.thumbnailUrl ?? undefined"
+			:title="video.comment ?? undefined"
+			:alt="video.comment"
+			preload="metadata"
+			controls
+			@keydown.prevent
+		>
+			<source :src="video.url">
+		</video>
+		<i class="ti ti-eye-off" :class="$style.hide" @click="hide = true"></i>
+		<div :class="$style.indicators">
+			<div v-if="video.comment" :class="$style.indicator">ALT</div>
+			<div v-if="video.isSensitive" :class="$style.indicator" style="color: var(--warn);" :title="i18n.ts.sensitive"><i class="ti ti-eye-exclamation"></i></div>
+		</div>
+	</div>
+
+	<div v-else :class="$style.videoRoot">
 		<video
 			ref="videoEl"
 			:class="$style.video"
@@ -31,6 +55,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 			:alt="video.comment"
 			preload="metadata"
 			playsinline
+			@keydown.prevent
+			@click.self="togglePlayPause"
 		>
 			<source :src="video.url">
 		</video>
@@ -100,6 +126,40 @@ const props = defineProps<{
 	video: Misskey.entities.DriveFile;
 }>();
 
+const keymap = {
+	'up': () => {
+		if (hasFocus() && videoEl.value) {
+			volume.value = Math.min(volume.value + 0.1, 1);
+		}
+	},
+	'down': () => {
+		if (hasFocus() && videoEl.value) {
+			volume.value = Math.max(volume.value - 0.1, 0);
+		}
+	},
+	'left': () => {
+		if (hasFocus() && videoEl.value) {
+			videoEl.value.currentTime = Math.max(videoEl.value.currentTime - 5, 0);
+		}
+	},
+	'right': () => {
+		if (hasFocus() && videoEl.value) {
+			videoEl.value.currentTime = Math.min(videoEl.value.currentTime + 5, videoEl.value.duration);
+		}
+	},
+	'space': () => {
+		if (hasFocus()) {
+			togglePlayPause();
+		}
+	},
+};
+
+// PlayerElもしくはその子要素にフォーカスがあるかどうか
+function hasFocus() {
+	if (!playerEl.value) return false;
+	return playerEl.value === document.activeElement || playerEl.value.contains(document.activeElement);
+}
+
 // eslint-disable-next-line vue/no-setup-props-destructure
 const hide = ref((defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.video.isSensitive && defaultStore.state.nsfw !== 'ignore'));
 
@@ -111,6 +171,35 @@ function showMenu(ev: MouseEvent) {
 
 	menu = [
 		// TODO: 再生キューに追加
+		{
+			type: 'switch',
+			text: i18n.ts._mediaControls.loop,
+			icon: 'ti ti-repeat',
+			ref: loop,
+		},
+		{
+			type: 'radio',
+			text: i18n.ts._mediaControls.playbackRate,
+			icon: 'ti ti-clock-play',
+			ref: speed,
+			options: {
+				'0.25x': 0.25,
+				'0.5x': 0.5,
+				'0.75x': 0.75,
+				'1.0x': 1,
+				'1.25x': 1.25,
+				'1.5x': 1.5,
+				'2.0x': 2,
+			},
+		},
+		...(document.pictureInPictureEnabled ? [{
+			text: i18n.ts._mediaControls.pip,
+			icon: 'ti ti-picture-in-picture',
+			action: togglePictureInPicture,
+		}] : []),
+		{
+			type: 'divider',
+		},
 		{
 			text: i18n.ts.hide,
 			icon: 'ti ti-eye-off',
@@ -186,6 +275,8 @@ const rangePercent = computed({
 	},
 });
 const volume = ref(.25);
+const speed = ref(1);
+const loop = ref(false); // TODO: ドライブファイルのフラグに置き換える
 const bufferedEnd = ref(0);
 const bufferedDataRatio = computed(() => {
 	if (!videoEl.value) return 0;
@@ -243,6 +334,16 @@ function toggleFullscreen() {
 	}
 }
 
+function togglePictureInPicture() {
+	if (videoEl.value) {
+		if (document.pictureInPictureElement) {
+			document.exitPictureInPicture();
+		} else {
+			videoEl.value.requestPictureInPicture();
+		}
+	}
+}
+
 function toggleMute() {
 	if (volume.value === 0) {
 		volume.value = .25;
@@ -252,6 +353,7 @@ function toggleMute() {
 }
 
 let onceInit = false;
+let mediaTickFrameId: number | null = null;
 let stopVideoElWatch: () => void;
 
 function init() {
@@ -271,8 +373,12 @@ function init() {
 					}
 
 					elapsedTimeMs.value = videoEl.value.currentTime * 1000;
+
+					if (videoEl.value.loop !== loop.value) {
+						loop.value = videoEl.value.loop;
+					}
 				}
-				window.requestAnimationFrame(updateMediaTick);
+				mediaTickFrameId = window.requestAnimationFrame(updateMediaTick);
 			}
 
 			updateMediaTick();
@@ -316,6 +422,14 @@ watch(volume, (to) => {
 	if (videoEl.value) videoEl.value.volume = to;
 });
 
+watch(speed, (to) => {
+	if (videoEl.value) videoEl.value.playbackRate = to;
+});
+
+watch(loop, (to) => {
+	if (videoEl.value) videoEl.value.loop = to;
+});
+
 watch(hide, (to) => {
 	if (to && isFullscreen.value) {
 		document.exitFullscreen();
@@ -341,6 +455,10 @@ onDeactivated(() => {
 	hide.value = (defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.video.isSensitive && defaultStore.state.nsfw !== 'ignore');
 	stopVideoElWatch();
 	onceInit = false;
+	if (mediaTickFrameId) {
+		window.cancelAnimationFrame(mediaTickFrameId);
+		mediaTickFrameId = null;
+	}
 });
 </script>
 
@@ -349,6 +467,10 @@ onDeactivated(() => {
 	container-type: inline-size;
 	position: relative;
 	overflow: clip;
+
+	&:focus {
+		outline: none;
+	}
 }
 
 .sensitive {
@@ -412,7 +534,7 @@ onDeactivated(() => {
 	font: inherit;
 	color: inherit;
 	cursor: pointer;
-	padding: 120px 0;
+	padding: 60px 0;
 	display: flex;
 	align-items: center;
 	justify-content: center;
@@ -436,7 +558,6 @@ onDeactivated(() => {
 	display: block;
 	height: 100%;
 	width: 100%;
-	pointer-events: none;
 }
 
 .videoOverlayPlayButton {
diff --git a/packages/frontend/src/components/MkMenu.vue b/packages/frontend/src/components/MkMenu.vue
index faed6416d0..d91239b9e2 100644
--- a/packages/frontend/src/components/MkMenu.vue
+++ b/packages/frontend/src/components/MkMenu.vue
@@ -42,9 +42,26 @@ SPDX-License-Identifier: AGPL-3.0-only
 				</div>
 			</button>
 			<button v-else-if="item.type === 'switch'" role="menuitemcheckbox" :tabindex="i" class="_button" :class="[$style.item, $style.switch, { [$style.switchDisabled]: item.disabled } ]" @click="switchItem(item)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
-				<MkSwitchButton :class="$style.switchButton" :checked="item.ref" :disabled="item.disabled" @toggle="switchItem(item)"/>
+				<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
+				<MkSwitchButton v-else :class="$style.switchButton" :checked="item.ref" :disabled="item.disabled" @toggle="switchItem(item)"/>
 				<div :class="$style.item_content">
-					<span :class="[$style.item_content_text, $style.switchText]">{{ item.text }}</span>
+					<span :class="[$style.item_content_text, { [$style.switchText]: !item.icon }]">{{ item.text }}</span>
+					<MkSwitchButton v-if="item.icon" :class="[$style.switchButton, $style.caret]" :checked="item.ref" :disabled="item.disabled" @toggle="switchItem(item)"/>
+				</div>
+			</button>
+			<button v-else-if="item.type === 'radio'" class="_button" role="menuitem" :tabindex="i" :class="[$style.item, $style.parent, { [$style.childShowing]: childShowingItem === item }]" @mouseenter="preferClick ? null : showRadioOptions(item, $event)" @click="!preferClick ? null : showRadioOptions(item, $event)">
+				<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]" style="pointer-events: none;"></i>
+				<div :class="$style.item_content">
+					<span :class="$style.item_content_text" style="pointer-events: none;">{{ item.text }}</span>
+					<span :class="$style.caret" style="pointer-events: none;"><i class="ti ti-chevron-right ti-fw"></i></span>
+				</div>
+			</button>
+			<button v-else-if="item.type === 'radioOption'" :tabindex="i" class="_button" role="menuitem" :class="[$style.item, { [$style.radioActive]: item.active }]" @click="clicked(item.action, $event, false)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
+				<div :class="$style.icon">
+					<span :class="[$style.radio, { [$style.radioChecked]: item.active }]"></span>
+				</div>
+				<div :class="$style.item_content">
+					<span :class="$style.item_content_text">{{ item.text }}</span>
 				</div>
 			</button>
 			<button v-else-if="item.type === 'parent'" class="_button" role="menuitem" :tabindex="i" :class="[$style.item, $style.parent, { [$style.childShowing]: childShowingItem === item }]" @mouseenter="preferClick ? null : showChildren(item, $event)" @click="!preferClick ? null : showChildren(item, $event)">
@@ -77,7 +94,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 import { ComputedRef, computed, defineAsyncComponent, isRef, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue';
 import { focusPrev, focusNext } from '@/scripts/focus.js';
 import MkSwitchButton from '@/components/MkSwitch.button.vue';
-import { MenuItem, InnerMenuItem, MenuPending, MenuAction, MenuSwitch, MenuParent } from '@/types/menu.js';
+import { MenuItem, InnerMenuItem, MenuPending, MenuAction, MenuSwitch, MenuRadio, MenuRadioOption, MenuParent } from '@/types/menu.js';
 import * as os from '@/os.js';
 import { i18n } from '@/i18n.js';
 import { isTouchUsing } from '@/scripts/touch.js';
@@ -168,6 +185,31 @@ function onItemMouseLeave(item) {
 	if (childCloseTimer) window.clearTimeout(childCloseTimer);
 }
 
+async function showRadioOptions(item: MenuRadio, ev: MouseEvent) {
+	const children: MenuItem[] = Object.keys(item.options).map<MenuRadioOption>(key => {
+		const value = item.options[key];
+		return {
+			type: 'radioOption',
+			text: key,
+			action: () => {
+				item.ref = value;
+			},
+			active: computed(() => item.ref === value),
+		};
+	});
+
+	if (props.asDrawer) {
+		os.popupMenu(children, ev.currentTarget ?? ev.target).finally(() => {
+			emit('close');
+		});
+		emit('hide');
+	} else {
+		childTarget.value = (ev.currentTarget ?? ev.target) as HTMLElement;
+		childMenu.value = children;
+		childShowingItem.value = item;
+	}
+}
+
 async function showChildren(item: MenuParent, ev: MouseEvent) {
 	const children: MenuItem[] = await (async () => {
 		if (childrenCache.has(item)) {
@@ -196,8 +238,10 @@ async function showChildren(item: MenuParent, ev: MouseEvent) {
 	}
 }
 
-function clicked(fn: MenuAction, ev: MouseEvent) {
+function clicked(fn: MenuAction, ev: MouseEvent, doClose = true) {
 	fn(ev);
+
+	if (!doClose) return;
 	close(true);
 }
 
@@ -350,6 +394,15 @@ onBeforeUnmount(() => {
 		}
 	}
 
+	&.radioActive {
+		color: var(--accent) !important;
+		opacity: 1;
+
+		&:before {
+			background-color: var(--accentedBg) !important;
+		}
+	}
+
 	&:not(:active):focus-visible {
 		box-shadow: 0 0 0 2px var(--focus) inset;
 	}
@@ -417,11 +470,11 @@ onBeforeUnmount(() => {
 
 .switchButton {
 	margin-left: -2px;
+	--height: 1.35em;
 }
 
 .switchText {
 	margin-left: 8px;
-	margin-top: 2px;
 	overflow: hidden;
 	text-overflow: ellipsis;
 }
@@ -461,4 +514,32 @@ onBeforeUnmount(() => {
 	margin: 8px 0;
 	border-top: solid 0.5px var(--divider);
 }
+
+.radio {
+	display: inline-block;
+	position: relative;
+	width: 1em;
+	height: 1em;
+	vertical-align: -.125em;
+	border-radius: 50%;
+	border: solid 2px var(--divider);
+	background-color: var(--panel);
+
+	&.radioChecked {
+		border-color: var(--accent);
+
+		&::after {
+			content: "";
+			display: block;
+			position: absolute;
+			top: 50%;
+			left: 50%;
+			transform: translate(-50%, -50%);
+			width: 50%;
+			height: 50%;
+			border-radius: 50%;
+			background-color: var(--accent);
+		}
+	}
+}
 </style>
diff --git a/packages/frontend/src/components/MkSwitch.button.vue b/packages/frontend/src/components/MkSwitch.button.vue
index c95c933663..226908e221 100644
--- a/packages/frontend/src/components/MkSwitch.button.vue
+++ b/packages/frontend/src/components/MkSwitch.button.vue
@@ -41,13 +41,15 @@ const toggle = () => {
 
 <style lang="scss" module>
 .button {
+	--height: 21px;
+
 	position: relative;
 	display: inline-flex;
 	flex-shrink: 0;
 	margin: 0;
 	box-sizing: border-box;
-	width: 32px;
-	height: 23px;
+	width: calc(var(--height) * 1.6);
+	height: calc(var(--height) + 2px); // 枠線
 	outline: none;
 	background: var(--switchOffBg);
 	background-clip: content-box;
@@ -69,9 +71,10 @@ const toggle = () => {
 
 .knob {
 	position: absolute;
+	box-sizing: border-box;
 	top: 3px;
-	width: 15px;
-	height: 15px;
+	width: calc(var(--height) - 6px);
+	height: calc(var(--height) - 6px);
 	border-radius: 999px;
 	transition: all 0.2s ease;
 
@@ -82,7 +85,7 @@ const toggle = () => {
 }
 
 .knobChecked {
-	left: 12px;
+	left: calc(calc(100% - var(--height)) + 3px);
 	background: var(--switchOnFg);
 }
 </style>
diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue
index 285f874dde..f2f82c4808 100644
--- a/packages/frontend/src/pages/settings/general.vue
+++ b/packages/frontend/src/pages/settings/general.vue
@@ -132,6 +132,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 				<MkSwitch v-model="disableDrawer">{{ i18n.ts.disableDrawer }}</MkSwitch>
 				<MkSwitch v-model="forceShowAds">{{ i18n.ts.forceShowAds }}</MkSwitch>
 				<MkSwitch v-model="enableSeasonalScreenEffect">{{ i18n.ts.seasonalScreenEffect }}</MkSwitch>
+				<MkSwitch v-model="useNativeUIForVideoAudioPlayer">{{ i18n.ts.useNativeUIForVideoAudioPlayer }}</MkSwitch>
 			</div>
 			<div>
 				<MkRadios v-model="emojiStyle">
@@ -308,6 +309,7 @@ const disableStreamingTimeline = computed(defaultStore.makeGetterSetter('disable
 const useGroupedNotifications = computed(defaultStore.makeGetterSetter('useGroupedNotifications'));
 const enableSeasonalScreenEffect = computed(defaultStore.makeGetterSetter('enableSeasonalScreenEffect'));
 const enableHorizontalSwipe = computed(defaultStore.makeGetterSetter('enableHorizontalSwipe'));
+const useNativeUIForVideoAudioPlayer = computed(defaultStore.makeGetterSetter('useNativeUIForVideoAudioPlayer'));
 
 watch(lang, () => {
 	miLocalStorage.setItem('lang', lang.value as string);
diff --git a/packages/frontend/src/scripts/keycode.ts b/packages/frontend/src/scripts/keycode.ts
index bc1f485f5e..7ffceafada 100644
--- a/packages/frontend/src/scripts/keycode.ts
+++ b/packages/frontend/src/scripts/keycode.ts
@@ -15,6 +15,7 @@ export default (input: string): string[] => {
 export const aliases = {
 	'esc': 'Escape',
 	'enter': ['Enter', 'NumpadEnter'],
+	'space': [' ', 'Spacebar'],
 	'up': 'ArrowUp',
 	'down': 'ArrowDown',
 	'left': 'ArrowLeft',
diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts
index 7742acc60d..faefbd8ce4 100644
--- a/packages/frontend/src/store.ts
+++ b/packages/frontend/src/store.ts
@@ -442,6 +442,10 @@ export const defaultStore = markRaw(new Storage('base', {
 		where: 'device',
 		default: true,
 	},
+	useNativeUIForVideoAudioPlayer: {
+		where: 'device',
+		default: false,
+	},
 
 	sound_masterVolume: {
 		where: 'device',
diff --git a/packages/frontend/src/types/menu.ts b/packages/frontend/src/types/menu.ts
index 712f3464e5..138eb7dd62 100644
--- a/packages/frontend/src/types/menu.ts
+++ b/packages/frontend/src/types/menu.ts
@@ -6,6 +6,8 @@
 import * as Misskey from 'misskey-js';
 import { ComputedRef, Ref } from 'vue';
 
+interface MenuRadioOptionsDef extends Record<string, any> { }
+
 export type MenuAction = (ev: MouseEvent) => void;
 
 export type MenuDivider = { type: 'divider' };
@@ -14,13 +16,15 @@ export type MenuLabel = { type: 'label', text: string };
 export type MenuLink = { type: 'link', to: string, text: string, icon?: string, indicate?: boolean, avatar?: Misskey.entities.User };
 export type MenuA = { type: 'a', href: string, target?: string, download?: string, text: string, icon?: string, indicate?: boolean };
 export type MenuUser = { type: 'user', user: Misskey.entities.User, active?: boolean, indicate?: boolean, action: MenuAction };
-export type MenuSwitch = { type: 'switch', ref: Ref<boolean>, text: string, disabled?: boolean | Ref<boolean> };
+export type MenuSwitch = { type: 'switch', ref: Ref<boolean>, text: string, icon?: string, disabled?: boolean | Ref<boolean> };
 export type MenuButton = { type?: 'button', text: string, icon?: string, indicate?: boolean, danger?: boolean, active?: boolean | ComputedRef<boolean>, avatar?: Misskey.entities.User; action: MenuAction };
+export type MenuRadio = { type: 'radio', text: string, icon?: string, ref: Ref<MenuRadioOptionsDef[keyof MenuRadioOptionsDef]>, options: MenuRadioOptionsDef, disabled?: boolean | Ref<boolean> };
+export type MenuRadioOption = { type: 'radioOption', text: string, action: MenuAction; active?: boolean | ComputedRef<boolean> };
 export type MenuParent = { type: 'parent', text: string, icon?: string, children: MenuItem[] | (() => Promise<MenuItem[]> | MenuItem[]) };
 
 export type MenuPending = { type: 'pending' };
 
-type OuterMenuItem = MenuDivider | MenuNull | MenuLabel | MenuLink | MenuA | MenuUser | MenuSwitch | MenuButton | MenuParent;
+type OuterMenuItem = MenuDivider | MenuNull | MenuLabel | MenuLink | MenuA | MenuUser | MenuSwitch | MenuButton | MenuRadio | MenuRadioOption | MenuParent;
 type OuterPromiseMenuItem = Promise<MenuLabel | MenuLink | MenuA | MenuUser | MenuSwitch | MenuButton | MenuParent>;
 export type MenuItem = OuterMenuItem | OuterPromiseMenuItem;
-export type InnerMenuItem = MenuDivider | MenuPending | MenuLabel | MenuLink | MenuA | MenuUser | MenuSwitch | MenuButton | MenuParent;
+export type InnerMenuItem = MenuDivider | MenuPending | MenuLabel | MenuLink | MenuA | MenuUser | MenuSwitch | MenuButton | MenuRadio | MenuRadioOption | MenuParent;

From d4ca973e3408a7d28788efe57bcd882c0ce9eedc Mon Sep 17 00:00:00 2001
From: 1Step621 <86859447+1STEP621@users.noreply.github.com>
Date: Sat, 30 Mar 2024 20:30:22 +0900
Subject: [PATCH 059/191] =?UTF-8?q?Enhance(frontend):=20=E3=82=82=E3=81=A3?=
 =?UTF-8?q?=E3=81=A8=EF=BC=81=E3=83=9C=E3=82=BF=E3=83=B3=E3=81=A7=E3=83=AA?=
 =?UTF-8?q?=E3=82=A2=E3=82=AF=E3=82=B7=E3=83=A7=E3=83=B3=E4=B8=80=E8=A6=A7?=
 =?UTF-8?q?=E3=81=8C=E9=96=8B=E3=81=91=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?=
 =?UTF-8?q?=20(#12935)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* もっと!ボタンでリアクション一覧が開けるように

* update CHANGELOG.md && デバッグ用に最大リアクション表示数を1にしてたのを一応戻した

* fix

* デザイン調整

* maxNumberもどす

* fix CHANGELOG

* fix

* move changelog

* :art:

---------

Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 CHANGELOG.md                                           | 1 +
 packages/frontend/src/components/MkNote.vue            | 7 +++----
 packages/frontend/src/components/MkNoteDetailed.vue    | 9 ++++++---
 packages/frontend/src/components/MkReactionsViewer.vue | 3 +++
 packages/frontend/src/pages/note.vue                   | 3 ++-
 packages/frontend/src/router/definition.ts             | 2 +-
 6 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ebf9320129..390639bd69 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -22,6 +22,7 @@
 - Enhance: 映像・音声の再生にブラウザのネイティブプレイヤーを使用できるように
 - Enhance: 映像・音声の再生メニューに「再生速度」「ループ再生」「ピクチャインピクチャ」を追加
 - Enhance: 映像・音声の再生にキーボードショートカットが使えるように
+- Enhance: ノートについているリアクションの「もっと!」から、リアクションの一覧を表示できるように
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
 - Fix: ローカルURLのプレビューポップアップが左上に表示される
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index 4add3aa6dd..f5536e79bf 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -97,7 +97,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 			</div>
 			<MkReactionsViewer v-if="appearNote.reactionAcceptance !== 'likeOnly'" :note="appearNote" :maxNumber="16" @mockUpdateMyReaction="emitUpdReaction">
 				<template #more>
-					<div :class="$style.reactionOmitted">{{ i18n.ts.more }}</div>
+					<MkA :to="`/notes/${appearNote.id}/reactions`" :class="[$style.reactionOmitted]">{{ i18n.ts.more }}</MkA>
 				</template>
 			</MkReactionsViewer>
 			<footer :class="$style.footer">
@@ -1020,9 +1020,8 @@ function emitUpdReaction(emoji: string, delta: number) {
 
 .reactionOmitted {
 	display: inline-block;
-	height: 32px;
-	margin: 2px;
-	padding: 0 6px;
+	margin-left: 8px;
 	opacity: .8;
+	font-size: 95%;
 }
 </style>
diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue
index ebccd60986..eec1aad53c 100644
--- a/packages/frontend/src/components/MkNoteDetailed.vue
+++ b/packages/frontend/src/components/MkNoteDetailed.vue
@@ -234,9 +234,12 @@ import MkReactionIcon from '@/components/MkReactionIcon.vue';
 import MkButton from '@/components/MkButton.vue';
 import { isEnabledUrlPreview } from '@/instance.js';
 
-const props = defineProps<{
+const props = withDefaults(defineProps<{
 	note: Misskey.entities.Note;
-}>();
+	initialTab: string;
+}>(), {
+	initialTab: 'replies',
+});
 
 const inChannel = inject('inChannel', null);
 
@@ -304,7 +307,7 @@ provide('react', (reaction: string) => {
 	});
 });
 
-const tab = ref('replies');
+const tab = ref(props.initialTab);
 const reactionTabType = ref<string | null>(null);
 
 const renotesPagination = computed<Paging>(() => ({
diff --git a/packages/frontend/src/components/MkReactionsViewer.vue b/packages/frontend/src/components/MkReactionsViewer.vue
index 1bd37d842b..63b202f9f3 100644
--- a/packages/frontend/src/components/MkReactionsViewer.vue
+++ b/packages/frontend/src/components/MkReactionsViewer.vue
@@ -100,6 +100,9 @@ watch([() => props.note.reactions, () => props.maxNumber], ([newSource, maxNumbe
 }
 
 .root {
+	display: flex;
+	flex-wrap: wrap;
+	align-items: center;
 	margin: 4px -2px 0 -2px;
 
 	&:empty {
diff --git a/packages/frontend/src/pages/note.vue b/packages/frontend/src/pages/note.vue
index 4c985b96e6..e14651742a 100644
--- a/packages/frontend/src/pages/note.vue
+++ b/packages/frontend/src/pages/note.vue
@@ -21,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 						</div>
 						<div class="_margin _gaps_s">
 							<MkRemoteCaution v-if="note.user.host != null" :href="note.url ?? note.uri"/>
-							<MkNoteDetailed :key="note.id" v-model:note="note" :class="$style.note"/>
+							<MkNoteDetailed :key="note.id" v-model:note="note" :initialTab="initialTab" :class="$style.note"/>
 						</div>
 						<div v-if="clips && clips.length > 0" class="_margin">
 							<div style="font-weight: bold; padding: 12px;">{{ i18n.ts.clip }}</div>
@@ -66,6 +66,7 @@ import { defaultStore } from '@/store.js';
 
 const props = defineProps<{
 	noteId: string;
+	initialTab?: string;
 }>();
 
 const note = ref<null | Misskey.entities.Note>();
diff --git a/packages/frontend/src/router/definition.ts b/packages/frontend/src/router/definition.ts
index eaeeafd499..c9f03b738f 100644
--- a/packages/frontend/src/router/definition.ts
+++ b/packages/frontend/src/router/definition.ts
@@ -35,7 +35,7 @@ const routes: RouteDef[] = [{
 	component: page(() => import('@/pages/user/index.vue')),
 }, {
 	name: 'note',
-	path: '/notes/:noteId',
+	path: '/notes/:noteId/:initialTab?',
 	component: page(() => import('@/pages/note.vue')),
 }, {
 	name: 'list',

From 0f2e6513318e05b0a88526b52130b911b5631ec9 Mon Sep 17 00:00:00 2001
From: Zero King <l2dy@icloud.com>
Date: Sun, 31 Mar 2024 09:43:28 +0800
Subject: [PATCH 060/191] fix(frontend): remove duplicate CSS declaration
 (#13640)

---
 packages/frontend/src/components/MkCode.vue | 2 --
 1 file changed, 2 deletions(-)

diff --git a/packages/frontend/src/components/MkCode.vue b/packages/frontend/src/components/MkCode.vue
index ede068b20d..a3c80e743b 100644
--- a/packages/frontend/src/components/MkCode.vue
+++ b/packages/frontend/src/components/MkCode.vue
@@ -80,11 +80,9 @@ function copy() {
 .codePlaceholderRoot {
 	display: block;
 	width: 100%;
-	background: none;
 	border: none;
 	outline: none;
   font: inherit;
-  color: inherit;
 	cursor: pointer;
 
 	box-sizing: border-box;

From efafa02f6820a31df5dded620cf0f6ef30454e0c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sun, 31 Mar 2024 12:43:39 +0900
Subject: [PATCH 061/191] =?UTF-8?q?enhance(backend):=20=E3=83=93=E3=83=87?=
 =?UTF-8?q?=E3=82=AA=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=AB=E3=83=93?=
 =?UTF-8?q?=E3=83=87=E3=82=AA=E3=83=88=E3=83=A9=E3=83=83=E3=82=AF=E3=81=8C?=
 =?UTF-8?q?=E3=81=82=E3=82=8B=E3=81=8B=E3=82=92=E7=A2=BA=E8=AA=8D=E3=81=99?=
 =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=20(#13568)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance(backend): ビデオファイルにビデオトラックがあるかを確認するように

(cherry picked from commit 23d38a2d6492a2b24e9b2c031d66c3e8a5d382ef)

* Update Changelog

* Update Changelog

* Revert "Update Changelog"

This reverts commit 93fd996932b87ef550c38b48bd0678060f3ed1af.

* fix(test) ffmpegをインストールするように

* 入れる方間違えた

* fix test

* 拡張子変わらなかったのでそのまま行く

* ログを出力するように

* msg

* remove unused import

* add log

* attempt to fix test error

* Revert "attempt to fix test error"

This reverts commit d9d6524cadd655e6d8e9398b26fdfef332f30f4d.

* Update FileInfoService.ts

* oggも検査の対象にする
---
 .github/workflows/test-backend.yml            |   2 +
 CHANGELOG.md                                  |   1 +
 packages/backend/src/core/FileInfoService.ts  |  49 +++++++++++++++++-
 .../backend/test/resources/kick_gaba7.m4a     | Bin 0 -> 9817 bytes
 packages/backend/test/unit/FileInfoService.ts |  27 ++++++++--
 5 files changed, 74 insertions(+), 5 deletions(-)
 create mode 100644 packages/backend/test/resources/kick_gaba7.m4a

diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml
index 49a6a39805..a803db4508 100644
--- a/.github/workflows/test-backend.yml
+++ b/.github/workflows/test-backend.yml
@@ -45,6 +45,8 @@ jobs:
       with:
         version: 8
         run_install: false
+    - name: Install FFmpeg
+      uses: FedericoCarboni/setup-ffmpeg@v3
     - name: Use Node.js ${{ matrix.node-version }}
       uses: actions/setup-node@v4.0.2
       with:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 390639bd69..f6b9cf0939 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -41,6 +41,7 @@
   (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/440)
 - Fix: エンドポイント`notes/translate`のエラーを改善
 - Fix: CleanRemoteFilesProcessorService report progress from 100% (#13632)
+- Fix: 一部の音声ファイルが映像ファイルとして扱われる問題を修正
 
 ## 2024.3.1
 
diff --git a/packages/backend/src/core/FileInfoService.ts b/packages/backend/src/core/FileInfoService.ts
index b8babcb3a7..169285f033 100644
--- a/packages/backend/src/core/FileInfoService.ts
+++ b/packages/backend/src/core/FileInfoService.ts
@@ -14,11 +14,12 @@ import FFmpeg from 'fluent-ffmpeg';
 import isSvg from 'is-svg';
 import probeImageSize from 'probe-image-size';
 import { type predictionType } from 'nsfwjs';
-import sharp from 'sharp';
 import { sharpBmp } from '@misskey-dev/sharp-read-bmp';
 import { encode } from 'blurhash';
 import { createTempDir } from '@/misc/create-temp.js';
 import { AiService } from '@/core/AiService.js';
+import { LoggerService } from '@/core/LoggerService.js';
+import type Logger from '@/logger.js';
 import { bindThis } from '@/decorators.js';
 
 export type FileInfo = {
@@ -49,9 +50,13 @@ const TYPE_SVG = {
 
 @Injectable()
 export class FileInfoService {
+	private logger: Logger;
+
 	constructor(
 		private aiService: AiService,
+		private loggerService: LoggerService,
 	) {
+		this.logger = this.loggerService.getLogger('file-info');
 	}
 
 	/**
@@ -317,6 +322,34 @@ export class FileInfoService {
 		return mime;
 	}
 
+	/**
+	 * ビデオファイルにビデオトラックがあるかどうかチェック
+	 * (ない場合:m4a, webmなど)
+	 *
+	 * @param path ファイルパス
+	 * @returns ビデオトラックがあるかどうか(エラー発生時は常に`true`を返す)
+	 */
+	@bindThis
+	private hasVideoTrackOnVideoFile(path: string): Promise<boolean> {
+		const sublogger = this.logger.createSubLogger('ffprobe');
+		sublogger.info(`Checking the video file. File path: ${path}`);
+		return new Promise((resolve) => {
+			try {
+				FFmpeg.ffprobe(path, (err, metadata) => {
+					if (err) {
+						sublogger.warn(`Could not check the video file. Returns true. File path: ${path}`, err);
+						resolve(true);
+						return;
+					}
+					resolve(metadata.streams.some((stream) => stream.codec_type === 'video'));
+				});
+			} catch (err) {
+				sublogger.warn(`Could not check the video file. Returns true. File path: ${path}`, err as Error);
+				resolve(true);
+			}
+		});
+	}
+
 	/**
 	 * Detect MIME Type and extension
 	 */
@@ -339,6 +372,20 @@ export class FileInfoService {
 				return TYPE_SVG;
 			}
 
+			if ((type.mime.startsWith('video') || type.mime === 'application/ogg') && !(await this.hasVideoTrackOnVideoFile(path))) {
+				const newMime = `audio/${type.mime.split('/')[1]}`;
+				if (newMime === 'audio/mp4') {
+					return {
+						mime: 'audio/mp4',
+						ext: 'm4a',
+					};
+				}
+				return {
+					mime: newMime,
+					ext: type.ext,
+				};
+			}
+
 			return {
 				mime: this.fixMime(type.mime),
 				ext: type.ext,
diff --git a/packages/backend/test/resources/kick_gaba7.m4a b/packages/backend/test/resources/kick_gaba7.m4a
new file mode 100644
index 0000000000000000000000000000000000000000..321df6349f016358b24b7bac2df8273ec5c448e5
GIT binary patch
literal 9817
zcmeHtWmFtZ^Y1Pm+?`}`C%6P#+}%A3i@SS(1%d<%0fGj1cPF?8cTJGsK?5WNxyvK>
z{onW8ulL)nGry_o?wYFVuAZ4beHs7&P+EETy4boqI|2X*fF}+Ix1$R$7XSc2vvRYv
z1ORB(9ib2pYCIVLp*m3Z@f_Xo|I@!CU~&K>Z1{gf9n>uGj{wx?$EQ9nIjK-y+*pKd
zY{U0)O676m&q&e1P4bF2Vw=CwtyyEz;*|Tkdu|`bwtiy+m&shW1n*x$jy%1be*aiF
zyvs!>2{i^wJPcL&4IQ8Xq){|cC6IDLLI;Rnc<w(~{K>Yzd9n7$IPc`xbMzwfYQkYh
zT#o_p=4;!Zc-G)FY!xMj#ET&LpuR_()Z=*lKM{N4zz4N0?=Tx-_gORm6kQXUY6-i$
zNo4zH_CwI-IbQy!?51<E)t*^|zBQkS5V>!%@AWh?3sbZPmMs%sTF1w$k#V0sYEI&{
zkMY)iOiro`J1*k{mG06c;-obVJ7=rN2`O}K;zeXvlZN^6oZX8rKPK?si9rw0-^J|Y
zds2T=`-KIp0N|bNVq#tbSkV%aC9+s*I)fH&&Ja6`BF9{!)L}47g%o5cgchL>V9!Wj
zGIWoS*oKfHI7<n6%wFC9$kox$814Q|+@M`}HTAl~^rijEb%!hsS6)<0%bRg(XpV2G
zBv2ZVybMjTPVEN+nATI|%K*W6DO&xq2CBgTFDtGWyFY!#!Jp4_?<xEqaBVj^UBrYQ
z`whCYeR?b<B&2mkg&lD8{S?0^T^-fD7XN*@Jrqe(Gpk;J;uBpz%01nL`AwYZjpme=
zAT#FX86~yy;OvEH(BtE9lDP;iN41u9z^og9C;@=M{PC8&JrP>K98Mcfy2xNq>wMxn
zV)afHZ;q7KfSF9oF&f+ZgzEMEz*O?9eopn8LM?FiNFUJ{DiSQ3C`}+(jes(=GNB^R
z+?O9iXF5$CiW`kf$ay>Xm?YTSk-?zmhP|3JgZDnZ^0LqeRy5SroLUORsa5MMB{E&7
zNo<k2H)15{d2@ena8#2;HQV}|=I}-I;jgb|{<`-K66O&#r6-NIrn*?+D=V_r$bMHJ
zz;{Kw)#pwL=g$21<*}3jAU2nCoYtiv&FwE<>-LMkKfk-=##xkGGI|kN*dzPv<?Rvu
zPvzc-+r|y1CZEUWZ&8iMiI>XK=y5(&gWH=o-$|v;>NYH794|y)y(`oGdJNXTpX}ec
zet@hUJgUV`2nC2z`i4o<43X24qp)gn+4MmReghqSfam~gh^NDQbcp;nx=%gihhC~D
zD>KOhXs(V8CX~mTr@W*Y;Wy1EP`20P6RD8Zm|ujI<qbp|sSVhn+n<DHP^cwNIMx@A
zt0KE${y7K|n2^cZhX=2sBnNM@XJdY=Y5_4>Ns3CMwOpd>cTq|mf~LWRiKG`zase=}
zjTu#t=;D{lS(2qD_Eyai=~wKqP~C+Ig{w+2Np>#%FKzUFl$_gJ#z#8_60T15?-8C+
z%d`s}MV;6Z(iv9kGPECDBpNa=eR+-Qv)}dW>X-kU$E$PVA3HCeS6l74Q2QmD)KLz~
zh`zO=IV1xm(^Ct$B-O+Veo6Wr)Lkm0&H77LR4%<#IDJ{`)3xW9gUv)^L~)Jv@`Y?#
zWsRx&wY8%^l^lENW{biPj*op<5Ydy#>!sZ#6$eoBOrdj535&S9qr-Z~9I~TVhWpDY
z>O>Z&{Dq1UNL{t+FU7K2+Go6WMIAjL>DvTmB&%(;lB$P`V%Vlr^df2%y9jf{QHDm9
zfP$1B-D-1{uAVCS09ZKzb1iqLE&@G6Q;(j=!crhZi~B1IvAD{h1`rv2Moyn=(~Dfm
zNd9Hb7_6#NW}+i+eSr#Gp6TK8sra<Z@#QGxV3*=u)eMGMAV0utKF?TPlEg7D@qnp<
zYvua$S+N-n>Vv*jtGBnGIvI6hBsEArk{e_pkb}!?7s&?fFuR|5^}gsg)5J0Ku<Otc
zQ3(TY^dbV;pDJZW;@$I@k>bVlY+C}@pIQ-AF&aH5N+*79#RMw`yDpTF*mdCNHxtYI
z8J{<O>}v@JqxyRGT<9}smaaFiw|5xB+}u&ySr3bdf_{kpgnlZRTn$oVgvA%F9!9>X
z@{dL+H)lvL8O)_YI`W`VYg>6H<TgSg{cEz5_k#HR6BP&`NKKy19-TfIT$^xA$Vr$Z
zkndLuL;_*%X%HkQ(Ci$gb`bNy9%iSFd;h4}EN#p1g*POXNh;Zi!7A20xv-ajMIQoN
zzAHOqY$lt1Zs)Kpj_cx&q4`Rd$<0R&>*qTLH?rEL+q5Os&(E-Y?WM$)FE5=H@v6A$
zpFIfg5yGzKZI}vot+;5kh3M&WuBqKflwDd*T|Fpc+_5WBUsjL$Wy5}kR$_-m;|j>#
zT3L4Ev=o=kJotkXf4T~y-k);pmMEtRQFAFDQn~Wf;|?%=Rm`H0QeMW*O-(%7Vwx^U
zLiO!ld#6LMn6OzJc#F?qB~BmVxxY-xeR8T^7Ro)1B#j&9GEArg0PC{>kkd=!+O99j
z*`?`2F6}m;1#F>#QLb^ZiUj<oYQjS0^9GZ=m_@X&R1vcnO-czzdJb6dFztM!SS)Qh
zilAi@X%|`@Wi2rG&S)ho06Q%wjg$Yrza8-+KlTmI4=A~8Vk1g>8}YO6kPHxl`YozJ
z?IoAyBQ%)kQ|vf*Q^TBR?WK?}Hwsbc{<zskYGC=9O7tJmj93z>vxiuwpr0$na@C^t
zwx%msNZr0$<@UKs+KGogh^X)kibf}mN#TB>dvB|u$d#)r*<+5dYz_t_w{YMj?<J-@
zxGkhQbO}(kUEgdBsBiKevwxXG53A>h<#t9&FS}UXO+{)`P+8$yFCKGLDP^wf9}7HT
zoX-Nn6ul?spRH=JM+%YFU(wDma`@ccf^J0_fp4qh>EdEy><gT0IrW1+X%>(j_%$-i
zM2}NEwqNx|;(YVPuP-S@D<5_yshA91U)Sl2PaFD>%2wgeSOVsyH6+q8`}4JYa0>mQ
zGtF61R;HXz%3X=hGdFRSOw<KT_?lOX3s)XDm>Z~>u2Ufmbf^UZ6xWEhI#|e5Ka*P@
z=heJlmDYD-llM>_(^0Uk)tq6*2eH#_>W`Duw<_rH&=MmkDbk6+Y*mN`f9ohqK0HWC
za+H6I{;h)m73C1oEG7uBWgW}iL6NH*^~!R#?@0;K#ONR!>pnD<_@M^o25|3S2$7W^
z)!lIZc;Dxjg!#$s17>Gd`h8%R#f10I3LUW(oP)uby}^85*eaRAn|b|#+XJmv>IvWA
z$uLRG9G1cDx1W#TM-SlvhXBwDqgyk7O(e{%VbQlE&vKfr=ia<}hAGR9Q@y;%Jq*;a
z$DMv3mhW!W!n!x)Le0oI)q6GRl*L42vN!)$gkO#4{z}QAYKHQ>&e}Q!d73TCE0ZK}
zcI8UVlFu>4O;t-zol^N@^B>37oP%EhmL2!TWgl@i@Sl_U?dcVZff=ovWBh#mkhYlI
zM_|PSYVj?Q*y2fXmLbs0d*iW#-)oL{gBUSfLg(q=_5kE!JAj7RdUDl|At%!@_K=SU
z37PfK!b?~Fdq2~e{p}evWpogQ2DuDws0SFC7z2PLGwQ{&N{b;Zshi(e(Ng6fPqAbw
zS!K1zbi%4=kt&Bwfj)}Ja^jmgm~4Q(-$awBZ{~MCAu0M^&iyQycS^w%{}ZX;x0?3f
z4lh;@;!LEr&H}{Hf(sfoRF7d?$^K>A&R~kI4GnX%0PMZ&Fbcz@UfT#a%E_PLca^72
zJ9xwL=bl%ipVxF4L+A4wCvBg9*IlZMhP6rUdCCjS74gO_(QoO(VvaYau;H1Zic6T1
z#>0KRfhmpPw8a9($YJ2bpH}Qqxi8lbQXg%8&=i#;wNUHa*t>3?YaBpMF4`sj`0J~<
zD2WouW18jO>}uTn>~+zo-;c9R&AD+~?=z|5?Ld?J#0m|2f-E@{q!?L7^RS8JMoo>(
z9h|^0*d>g;N=Bwqme+6`hbPt<EFDU*;4eNqiPlk_Lf0~dnK`;w5g*kiDV`iFpQ#D;
z3llRu=F7h?_*S=*U-K3_41v?&2#MPC_r=>E>=bWeN-1JH`C10NN?(+nn%^U90*C}#
zn)>n`^@p8NaW!M%f1d_rtfVL!P-HN{H=**<iKJ2kdk}K4@IlvC_Rn_c#54?*i>SoI
z7>;rbHXaM)_#&m^lY#S-LR%;oS}!GyC}U-aG@PNBtgg!epIz?#Po9f}{`4kr05bGc
zG+|N4tYmvG8*GYOAr~clRqdE}i5Xp7wA!OBC%;Q5Ti;jCQCYW{+oZdZHI7=dz_feQ
z_z7C9u#4iKr*-kEOF6EqQ%_Z5hN-4Iq9KoO_J^>EV;ub)W_gV$lK)5g2);8Hc!pG>
zQwL@7q)U`${jsk;YPTv$&I5=?sis6o5)&e0GI3Z)7CfG<PKYNgwnNgJ2Tk0&^b#gP
zN{Z=$E`#{|et4Swc-E-jjq6sWhKP1!Og1w*PB1heju<OJ#(2*bgCUx`pbf96imY2B
zt$^NuLx#a3QHIJ=aIFrfjs{~F+N{lmeB5v*IPOyfEAAK46?D8bk-%Z>Uv4X0VFLWu
zTxObwr}{+6*RO)U6>X&8+=epfX|AxcWf{3EH47Eg)y2Td^_jscgbKLYt%ehuO=Fe`
z(g<kSvm89xW@F;docCr<uRZrBxXHko_piEwUWo+qxqX$~^I<ee@++;4_S0QA`6#ci
zFZccEP42{>IwIT4(~cl<WZX8Oi4jSe{TYJCoI+a)w^{HAZ){5iChS~*b}PG2X{OSK
z&I}8(#9PYNxtL*2cvr3@JL2)0h4DJ6ynUnRkJ?#V0BOO?GGUf=;jet!@|btvr@^MG
zOijcMo<!s*80V1yLIAjgGlDlOktHgjA?y4kVHXYS)sV|?w3y1Y$SsGWTHxI%7S491
za}frf7CHP6y3suE!(wQ~2=;jY98HKI07lyAZf*=4x~^+Nk?_hVUvN`AaIBH(g?YBj
z7yfa?Qh%i$>cxV782W*9XI>+9e$YrE8LIi7&dcJ$O7dq};|9<n>_Hzy9$Zhb?VyD}
zP6+xTJYAPC=v!E1^XDgf&xLoi$bM1jb0B?!Nm9#mGUz7aQr#<oF}5q00gG64#}#x=
zLcZuI+NiKxgK?%0Y~eEq0JMAtQWI_iz^4$e=R#9bG!z{wG?2Jnny!tlC@oak9~YSy
z(-~zlS`8t*iR$k()w{O>O$&L}!n|J#bGj1md$!A4jg|VsK(R++zUxtmHF&%xzBMt|
zxWZkB-$kc>RDZnem@c>yg0yoy{%rH&ymdj#q5A%=<hj)bm!Ra9K~gReny{#%HOzRi
zc()*zI7It;aN4&~1)@*o3+#qxfW9blN;cd!ZU8T_cM24SqTQabIuc~{ef*uuGFz3k
z*nVme!(J8j2kgZk=K6+8P}V=;(0W=DM<Fx8A#=qwMxj63lPF8`pI2MohJzBx(xCN7
zebUOiEZvO*dioyelW&ylYAG5o!MZdUh$0p2#2?13@!E)qz}+DSUUQmeXi+FA7$b~`
z`&8e03S5e`OJ|S2X`?7NgEPMEPLy3uC9DNwZjWbt7JfY>dB!Jczh)S&WE(d*4*Ro_
z<C>|pPLROFsVgmEh~7f~u0fkj1(OloePhi{y67X`DlE<0yGBz=eaF?{0hIxBJgo#7
zhFpQTP6x2<HDY?MnCpSgq}^zTO-g)mlk9<7DS4*pCix=hYoCSs=v=QvUWEIsr~b3T
zUKCV{Bu&dye!B^B8>9!ViJ6?juyP@8^#Y&vPu{y!CS=QR6mO9=@UGrD)doDK94;>V
z(7d&LlsTH#6XfuYMi?j=U7Vp#VBed3G1aq*75cPX;wwWNrbmC9<EKN&f?o;o!LzLE
z2S%XAFVR(C(@(bGZu!WV9E}pIzJO|5SpU?h$Z4q-vAa@kwi#AOyskabO1YNm)R|a=
z7&s{Jzs`X9o2jDj2a~){o4G^=wC&fC{W@5kZXKCG@p)@O?L9KNSHIX-B_~y(V*==`
zRy#~)O7NapFG1xvWULLRw-h~K>vYvcnbEi&3+=Ee;4mf&ku)FRl9oyPC9&*}5Q8)=
zk2mHGqsUeM7FpNbV8jL{bOBSLW6QN^hl0_<smZ>Y9)z;k2I;1?czMnDcA<tJ3c(ta
z%=oZ?*J&~d4f4h1gDM}s2UsiJnU%=I@GkS|HzKZ!=^-E$rg2Hos_@S%Ifci0_Zp80
z0VMUK5g7v^X;o~ddc6`Y$Pp-e$PzXw>Od5PgGerGXvdtzB(eVVov~ytq{24fgoQ+T
ztd02S=v8?qy8G~Yv0yl`H#e7M3h=ZJqAx=kkqB0&Id{+zs4G`2%n1SJSSvIKmQ_Wv
zIj$R8qn%<#(OY5cRlK-mo1lMKROj~AzS=3$H?pTB-DLYkt!!1TvRqajK3As{|DHV>
zmM1~qsL~g`t%2I^*H^TB$W(3zRvGjg@MlPKRSaMcW%zzm`*qv+SETuk@5~R~)`hdc
zF<5<4E?`_3LVP}+uf*l)ly}oouSJEX=KmaY;bt@+-`<3)0Z3=2W_tZaUDqI;1{pSH
zX@iKXMwyH+RW3LVLUQhS+xk`cqIYgP?7<^nc|l<&{krTkWun(qWkAXTA`eJ_JH2?)
z8_e4EhVCr{B+uh<t2<+5938KBnuAvGu_rr-snU3^*CI!Y?VufRN+7c}ruA*UjAUt(
zdyZ-bmAy~8VtcF@+feLIJQhV7+b%>+8Od4INPr7f+NaW1SwIA<g6Pu$#OTy8-I+t&
z;QqVf(9ioW>Zgwfdl_M$Toghr7@@g@e7FXe44Ak+x$bs+!>{Sg!Be7b_Db`fwBX&T
z@l~l^P_!i)YkIMOoHtL!PyLm;JeW$yG7>DTq`>U0ACYd|2l=G9U8HVxl1!bdeBDI5
zsbY^T<p$TC^=z8bEsEpA;-pBjf*@T9%r$@l`=r{<VU=UX_Zr*T_#{fPx5xPSXH3?V
z!hYXAyhUVwqyHO2@<snP{R)I?|CAbwIk-Irr7~k-i(YE0;}}OsV?^6VrDcjfOIra-
z-ON+qq2c2_^bQS~=~;Rl?Xz`(779!5c_PbTPz@e_5fl2<fl4jg#rNfxlY{Qj%z2~i
zuje9Gr$dCSAUhtY?{0ivqU;X6=KrPEUtf?=QPD+WPz=h5-Ee>Db^7u3D2CltH)mUO
zwQY?3mgQvc<W6LUF<BtX+Rj{gt}PW_mW3O6mIJ+Nsehhon^6OokG?hjJ|3Db{-3c9
zBZ$uXLS?$(mX@bqB~e_;m?VKjnsHUKk|rAqHK1k~Sby1{6FrOS=&zc@zwQ^*G~f0$
z)tKbB(aBw?1klnem2SWwskb}=Ie@*ZwYmO*r#?UXwBUzUU)^CzC2%jwx2>H-X{VDR
zTNJ8WtF6`3(HuUb-?%7@CFlGN0XuXzd-o>%2J%tqoI2$tMmhpl)F5Nb1HRsIb+a9<
ziYdlL)iu^!$$j9f>eGF{&L-!pt9YDkna4dAY{e+)53DY&VH}c&Tt_CI@>HK}P`9Xo
z&jA$nzRnkm@-fp)0H$t-ehA^*+Z!vP5^A6e@O4;Kt}+2~xTBWXE0;%sG~QNGY7<6!
zE@S&ea@M=+-rV>)(`K)Ig_rYm9`Yx6qHZH@s-u^NgKB<4fp~?E+9Xa0K1e22BJXeV
zZk7r1vn)<Cno~kAi)Oe9D$ZM(JndWBmJY{a5PcfW4VUn%>ekvy3c1L;%VVMMt^z38
zpF0izwLY)RjHHc(9krEpmLlOwA_4rFg{Ks_=E&+?eNW1W|CF`a>-BkuS>kkD#US(s
zw1Hy8$ZSKtuP^4%wp$tZDrNKk<RJUyQbug?ha+4l_DB1E;z_7=-O3j%=qGzzn4S9j
zX`Sa~xUJ-o9^vQ1q(2?^RH%ibgOFTgh)ivbZ*gl!<YMv~n95ZL13VFlb{T$|Rm?>4
z1*Vjpc-LT5_hbe9I!EIzgAT`=<r$@qQcm)s8!cQS;vb*%dW6~)5vCWBAPr|8DQL|!
zN*FRjbBAHvpwu@+6TJDXE^KIQ08D+~73&@w=6CHybnX|unkJ6xrBOC9gm057Le!u!
zg-v&3?IyXCIIk3aIEySZE8RRN8lgO@uCPMV);0usS++#R6}^w`ri8mc`$kImhx8X+
zpt(0@L7tYdbwQ#(U^!H#YyUKYyjB9)TH-_PP`f46syr79R+pz4j1>ppBEUliRI7|g
zFr#5kA@nRDoz-#e{1!nX6mzcY{9f_L;sk>w8IhuGc2_-SRH#%FH2%8#LB_N)J;3oD
zQ(v8ZV|7=$iRppfqF1hBb-Lo1R?ec2ZnT1ATV-mB>f36g8oUj@?R-oD)?8zW1_S}|
zNIB&D$A*`oY=+l+JWL{nG~2Bo_C7RAf6^;|Ol0Bi2QE>3g{&dU+^ee>y38nUOpc8@
z$bKklmz8Z}%%iwvHkmUt#Htxn@wcxTQ)k6I<Cmn1Va8b#uCjZrIgAUa!H&2#ziOY0
z%HvrWiOo@ERN3DpI!rAn%SsM4p-D@oOl$k1@WlpF?DsX9TsZp&gs^t!Jr~os%dDXn
zukL=MAv&RwsdEo?>-yu%`~eZnc;_$Iqn@nxAWl&?!;32DRj=CBmvolE@5UY58<bfK
zxC4n(1xbBu-h|Yoi3BgDOT>K&CwSWa{ubA!hS5EH#~i1HUIhfOgHf?c_jPF&{&>!#
zs16lNQ;}sHa0^>bPrDqYGr4Yb=Z)A_eki?s!T8$w(!%A^-}JV<cIW~_YxDTXzThaQ
zQPgXBfukWAM@YwbB<rMo%f?XW$U|f_P-iXmu5;X4;LvPK#;BP_exrcab*PMl`TJ+7
z?GqZ&u4)^827fj-W6BN2bHxh#A8i7e<9yM#f>IcyOemITX0KV42c69Je=W5MR24c^
zMEVGSNs~Ti#AO16=^B!z(&@UDVh?lWfP-sRPe*I6T4{%~w|VEjCxx+-$SeEkVoGta
zsUk#2FKBvji1?bqw`f`ES@o`oSD$|{Y{WZU2#nGadDIkbF_e&KzP$4<3NG6i{m>Ep
za~8$d@eEy~{InWxiCP~yt((*(i?JWQl=t*il3pwjvPjG{a7{iBla=ApV37sO>`Y@6
z7JWQ_TB^y!rS?nXhgB8oK)=+ETP~;5;p&5((w|j6nhux=$l}+RuAcel?d5;<v090d
zsfZkdYJzgz1?39*pYOaU$dtidH$)q%5;o)8uG4^#6Q2FN`LJEE`a^4%$egH-A*qmv
zDN#P2s3z~DfHT*w0O{T4T`jU8nvHu%L0wXPG;ked#yyj%cj}o!FVnq)*Ick?V0MXE
zh`8|ZYs7q6ONer(PK0a3xL{A-DiDlloi|bu=Uq~Ef`(hyV@^Ce^NJQGNQOY%f{T#Y
zlxERXozk7%cwAH@=SR9*m0QT%R$qwuvsj|@&;vc{%|a#R_|HDyg{abOKFe?y^-%1W
zu=C!?y*>gT1XdQ%`%sinj*Zh#%xMpP&WSe}v~|yA(M)aO`}>dM%Fw|pBfiggyHjzQ
z34Y=<INY&gnrb(9^Lq!_Z!lCV?&2W@*wRJAXF|+Azm=g6Rt-nz!EH_e_%}D{M|9$Z
z<omE;q0ziF1?0$(*C=(KIr96@Y_nb`)*_x|&f8QQ==<olJ4ad`=xVQ-kZ@S)Q-#n_
zGL4I|wnrwvq-3Gi%qcgrnP^=vl`~R|1$~?n0Qb#TN$Y$n0JX-XqW>lz+Q#Ea{(-D;
z)Wuw3m+@uOfeBB{r|bF(kGczszm#fJVNSXKu-5+sfnVIM<IUqv{mJy3Yaa^h%jQE-
z#Hq@=_O#yG7*xHc?_mKx?7IH1-->*Usy;)W#O-U%3<FJtNxC47$pp&}<CA8g_a-j^
zk%NO5^b4Me;N2n^f`nt)MfyO&wux_r#d!Tp*{>ZPP={p1LCbBiYF`Al(>uc+n9dMp
zLJJS(Gq91xOpnmLard|;WrBod#J<!$?>Pz&I4~Dqd!c#cs(MYjYWZE;INkn(PQIO6
zN+{bVnvy3^La7nwEgPd4AF2I&aCq%POVjnKwsg{gsG?+6m2x8C(++J?V-eaHDcmU<
zmw4cFcJ*4^nhsohW}|Ppbx62<{a`okZ9HZ-caFL-gsnZ3khpe+@^dN$io2KOYG&zJ
zn4`9h{1ifA({)|>MMG`2EYbC_PDRheHP_zbGNGlTmdmPRNq!C&T^%wV=yyo>wU%qF
zi^l*4hzCa4wJn3yYN__d<Fkv5_bdA$WUQM>=7O6lDVYhF!ifQfyH}#Y4#d7HAGVlg
z&|SzGp@HvcpJZjsj6oyzZcHyM1zjypYfQ#Dxnio<-M&BNz&t8hK7<VknujUvfmee2
z)h!qUq>oaU+=c%lM*>ZxV)xp|Xz}-aeDCtB=Bw{vv!Xd4J&TQjU`7c9la?|4CS#^9
z#J(S|*jeR^pJ{PL0qEtpKSo~!7`DnpH1sTKAPQ8aPy+12d$b2m)WYi90*+XuF&tLh
zKijyRdi|MmIJF*KS9EusSZaFzs!AJA;#2+fn4Pv{99aTo-X-*DLhHoE#X{%^smHZp
zm5~^AQ_)HDSe7)U5y6i+5*k=H`10{QAM#qoF9eb<8?=M`UB7(p+`f7CtUkwZ#W4dW
z=>JRHe7{E^>YH%VA8{6Fb3?GVKWdgo&K*trv1(;fqWU~RP`z}`1@Giopmt~5NF%*K
zVNm*I<M7LQX#wqm&zlF}CIxLTDxLM90zK~C=BV@XeYhXK+nR+4&z=VDj03+Zf%E}s
z#%bLp+w%1T#9ST%!rH(ZJJJ%HEG%vZ^SnI;E#8ie3byasDOs;L&%o|{aZ7&3G`Sk=
zwTX3kmFond&p)O1BiW>fA<9HW4u%W>_yO-g#C*wU1<z?8m<Y9{a0iYsXkQheXH8bh
zRW(du*&6ONSTVdk7paFpPdFmAH$T5v?GW2ab$cEAdsA4+4HA4umit)nn*z+O3kB{j
zw(yimRqr~mE#pT3&{?!)Cyq+oB8Yq?Bz#|r;coV&B3bto&h^q!2gpN|2s>r>sL4Mh
z=i;jo(G@}~BGFj@On?Rbyk|%-MPx%jWHcUW#qW6RC|8g9!cA_g+!a$C0_1OzNhCMx
zQi{J-_GZ`p(C6P~&!D_>wFhC^NqR>V_bd7A4ujr!`JujICl_SFMbKMvt&i^^#g%T&
zjg%ZAHz#;To=h!JoF@3YB>BVVl%L59&g@a@h4QennPL)V2|t0s-ggxnx(zvA$OK^p
z-RSV6Bp`b>&7EKgdLVmD5j%r%NV*08ER9}5i)gb#gzA-}n%P^5g9Gg?i)*t+Ixb0G
zbNlh-GCV~urO}fgkSM3L8aneM6$dW<t>9<57DQXXbBszHszI72CplFHJ3Ih}B0;!p
zq|28+F1~ZRU-V*5g?{26Up4v`KfU|ifsU5uC671}@i`jWpS6HjmC4chcVf@Qda1hs
z07QL9XJ;>Xgbt2gHc&VRY!RbUKLOsh4?h(10ssU&UH_r~qX4h|uQK>Qn*TQm0d5oK
z;RdmXHyV4`|K$_$KR*Ap2KW0P0{-RVzx@2G`L7!IU*T^~X9@Lihl`Y!4(=ZRG{G$Z
z&*0~J{)riQ>j<@lz}rBM(Esjxg){(Q60Fnz*OTlvPzSevYyjMyJ)QoQpSTvh43&pC
zK^-igbby79woX=X0oUE}Z=+92aH50$T~7&hvwUiQqNgrldb&A){+5BZ?jGh2aM{}3
z!~L&h{9O;wgP%xx3iOGdp81;)0Ju-WQ>bv_v2=$%br^sc92`soS3`nxLNL)&6#~%e
z3GiQ2Faka<3Y-Dqc>sXiJ^mV_zf|Bi5&!_{Nrt-s2E#ceJPeDc3OGHveFEt}+yma`
z2bcdPcs&sA9(WA*#s=qOaP-0v3r9K}d2qlFSpi{ic*6l70^n;n;NAU8HimOkI1J!`
zz+nxC9USnv38aKOd72M|?j9D-|2TY#1?~qx?r!Y@eJZ#)JHTzhPjSH?czlH4Dc#Mj
zUEuuRmj4;OxhK>E?ge1zX!#d^QltK#S%%LHH;9YNlg0l{?6!YTCHhhi=ch2J;K#zA
Vj64|zC_}ug_yjq)IN=xP{{mAaTcH2|

literal 0
HcmV?d00001

diff --git a/packages/backend/test/unit/FileInfoService.ts b/packages/backend/test/unit/FileInfoService.ts
index 2eec80d763..40d187f5a8 100644
--- a/packages/backend/test/unit/FileInfoService.ts
+++ b/packages/backend/test/unit/FileInfoService.ts
@@ -15,6 +15,7 @@ import { GlobalModule } from '@/GlobalModule.js';
 import { FileInfoService } from '@/core/FileInfoService.js';
 //import { DI } from '@/di-symbols.js';
 import { AiService } from '@/core/AiService.js';
+import { LoggerService } from '@/core/LoggerService.js';
 import type { TestingModule } from '@nestjs/testing';
 import type { MockFunctionMetadata } from 'jest-mock';
 
@@ -35,6 +36,7 @@ describe('FileInfoService', () => {
 			],
 			providers: [
 				AiService,
+				LoggerService,
 				FileInfoService,
 			],
 		})
@@ -323,8 +325,26 @@ describe('FileInfoService', () => {
 			});
 		});
 
-		/*
-		 * video/webmとして検出されてしまう
+		test('MPEG-4 AUDIO (M4A)', async () => {
+			const path = `${resources}/kick_gaba7.m4a`;
+			const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
+			delete info.warnings;
+			delete info.blurhash;
+			delete info.sensitive;
+			delete info.porn;
+			delete info.width;
+			delete info.height;
+			delete info.orientation;
+			assert.deepStrictEqual(info, {
+				size: 9817,
+				md5: '74c9279a4abe98789565f1dc1a541a42',
+				type: {
+					mime: 'audio/mp4',
+					ext: 'm4a',
+				},
+			});
+		});
+
 		test('WEBM AUDIO', async () => {
 			const path = `${resources}/kick_gaba7.webm`;
 			const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
@@ -337,13 +357,12 @@ describe('FileInfoService', () => {
 			delete info.orientation;
 			assert.deepStrictEqual(info, {
 				size: 8879,
-				md5: '3350083dec312419cfdc06c16413aca7',
+				md5: '53bc1adcb6acbbda67ff9bd484896438',
 				type: {
 					mime: 'audio/webm',
 					ext: 'webm',
 				},
 			});
 		});
-		 */
 	});
 });

From 61978cb4ca481f099828ef1b0b95258029937008 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sun, 31 Mar 2024 14:16:42 +0900
Subject: [PATCH 062/191] =?UTF-8?q?fix(frontend):=20=E3=83=9A=E3=83=BC?=
 =?UTF-8?q?=E3=82=B8=E3=83=87=E3=82=B6=E3=82=A4=E3=83=B3=E3=81=AE=E4=BF=AE?=
 =?UTF-8?q?=E6=AD=A3=20(#13642)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 locales/index.d.ts                            |  8 ++++
 locales/ja-JP.yml                             |  3 +-
 .../src/components/page/page.block.vue        | 15 +++++++
 .../src/components/page/page.dynamic.vue      | 43 +++++++++++++++++++
 .../src/components/page/page.text.vue         |  2 +-
 5 files changed, 69 insertions(+), 2 deletions(-)
 create mode 100644 packages/frontend/src/components/page/page.dynamic.vue

diff --git a/locales/index.d.ts b/locales/index.d.ts
index 3dbe46c7b2..01bec41d9e 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -8830,6 +8830,14 @@ export interface Locale extends ILocale {
              * ボタン
              */
             "button": string;
+            /**
+             * 動的ブロック
+             */
+            "dynamic": string;
+            /**
+             * このブロックは廃止されています。今後は{play}を利用してください。
+             */
+            "dynamicDescription": ParameterizedString<"play">;
             /**
              * ノート埋め込み
              */
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index aa765d1310..4ba9ea0221 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -2331,6 +2331,8 @@ _pages:
     section: "セクション"
     image: "画像"
     button: "ボタン"
+    dynamic: "動的ブロック"
+    dynamicDescription: "このブロックは廃止されています。今後は{play}を利用してください。"
 
     note: "ノート埋め込み"
     _note:
@@ -2625,4 +2627,3 @@ _mediaControls:
   pip: "ピクチャインピクチャ"
   playbackRate: "再生速度"
   loop: "ループ再生"
-  
\ No newline at end of file
diff --git a/packages/frontend/src/components/page/page.block.vue b/packages/frontend/src/components/page/page.block.vue
index 164720ac6b..c7f72dce8c 100644
--- a/packages/frontend/src/components/page/page.block.vue
+++ b/packages/frontend/src/components/page/page.block.vue
@@ -14,6 +14,7 @@ import XText from './page.text.vue';
 import XSection from './page.section.vue';
 import XImage from './page.image.vue';
 import XNote from './page.note.vue';
+import XDynamic from './page.dynamic.vue';
 
 function getComponent(type: string) {
 	switch (type) {
@@ -21,6 +22,20 @@ function getComponent(type: string) {
 		case 'section': return XSection;
 		case 'image': return XImage;
 		case 'note': return XNote;
+
+		// 動的ページの代替用ブロック
+		case 'button':
+		case 'if':
+		case 'textarea':
+		case 'post':
+		case 'canvas':
+		case 'numberInput':
+		case 'textInput':
+		case 'switch':
+		case 'radioButton':
+		case 'counter':
+			return XDynamic;
+
 		default: return null;
 	}
 }
diff --git a/packages/frontend/src/components/page/page.dynamic.vue b/packages/frontend/src/components/page/page.dynamic.vue
new file mode 100644
index 0000000000..8c511a690d
--- /dev/null
+++ b/packages/frontend/src/components/page/page.dynamic.vue
@@ -0,0 +1,43 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<!-- 動的ページのブロックの代替。利用できないということを表示する -->
+<template>
+<div :class="$style.root">
+	<div :class="$style.heading"><i class="ti ti-dice-5"></i> {{ i18n.ts._pages.blocks.dynamic }}</div>
+	<I18n :src="i18n.ts._pages.blocks.dynamicDescription" tag="div" :class="$style.text">
+		<template #play>
+			<MkA to="/play" class="_link">Play</MkA>
+		</template>
+	</I18n>
+</div>
+</template>
+
+<script lang="ts" setup>
+import * as Misskey from 'misskey-js';
+import { i18n } from '@/i18n.js';
+
+const props = defineProps<{
+	block: Misskey.entities.PageBlock,
+	page: Misskey.entities.Page,
+}>();
+</script>
+
+<style lang="scss" module>
+.root {
+	border: 1px solid var(--divider);
+	border-radius: var(--radius);
+	padding: var(--margin);
+	text-align: center;
+}
+
+.heading {
+	font-weight: 700;
+}
+
+.text {
+	font-size: 90%;
+}
+</style>
diff --git a/packages/frontend/src/components/page/page.text.vue b/packages/frontend/src/components/page/page.text.vue
index 4e501bd699..e0c7956f6e 100644
--- a/packages/frontend/src/components/page/page.text.vue
+++ b/packages/frontend/src/components/page/page.text.vue
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 <template>
 <div class="_gaps" :class="$style.textRoot">
 	<Mfm :text="block.text ?? ''" :isNote="false"/>
-	<div v-if="isEnabledUrlPreview">
+	<div v-if="isEnabledUrlPreview" class="_gaps_s">
 		<MkUrlPreview v-for="url in urls" :key="url" :url="url"/>
 	</div>
 </div>

From b4b47d85cf50486980cc3fa3575cf48c7fb0a2e7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 1 Apr 2024 20:44:24 +0900
Subject: [PATCH 063/191] refactor(frontend): use `scrollX` or `scrollY`
 (#13645)

---
 .../frontend/src/components/MkContextMenu.vue |  8 ++--
 packages/frontend/src/components/MkModal.vue  | 24 ++++++------
 .../src/components/MkUrlPreviewPopup.vue      |  4 +-
 .../frontend/src/components/MkUserPopup.vue   |  4 +-
 .../frontend/src/scripts/popup-position.ts    | 38 +++++++++----------
 .../frontend/src/scripts/use-chart-tooltip.ts |  6 +--
 6 files changed, 42 insertions(+), 42 deletions(-)

diff --git a/packages/frontend/src/components/MkContextMenu.vue b/packages/frontend/src/components/MkContextMenu.vue
index 5ca3c77fb2..a807742bb9 100644
--- a/packages/frontend/src/components/MkContextMenu.vue
+++ b/packages/frontend/src/components/MkContextMenu.vue
@@ -47,12 +47,12 @@ onMounted(() => {
 	const width = rootEl.value!.offsetWidth;
 	const height = rootEl.value!.offsetHeight;
 
-	if (left + width - window.pageXOffset >= (window.innerWidth - SCROLLBAR_THICKNESS)) {
-		left = (window.innerWidth - SCROLLBAR_THICKNESS) - width + window.pageXOffset;
+	if (left + width - window.scrollX >= (window.innerWidth - SCROLLBAR_THICKNESS)) {
+		left = (window.innerWidth - SCROLLBAR_THICKNESS) - width + window.scrollX;
 	}
 
-	if (top + height - window.pageYOffset >= (window.innerHeight - SCROLLBAR_THICKNESS)) {
-		top = (window.innerHeight - SCROLLBAR_THICKNESS) - height + window.pageYOffset;
+	if (top + height - window.scrollY >= (window.innerHeight - SCROLLBAR_THICKNESS)) {
+		top = (window.innerHeight - SCROLLBAR_THICKNESS) - height + window.scrollY;
 	}
 
 	if (top < 0) {
diff --git a/packages/frontend/src/components/MkModal.vue b/packages/frontend/src/components/MkModal.vue
index 40e67fb4e0..eb240da759 100644
--- a/packages/frontend/src/components/MkModal.vue
+++ b/packages/frontend/src/components/MkModal.vue
@@ -175,8 +175,8 @@ const align = () => {
 	let left;
 	let top;
 
-	const x = srcRect.left + (fixed.value ? 0 : window.pageXOffset);
-	const y = srcRect.top + (fixed.value ? 0 : window.pageYOffset);
+	const x = srcRect.left + (fixed.value ? 0 : window.scrollX);
+	const y = srcRect.top + (fixed.value ? 0 : window.scrollY);
 
 	if (props.anchor.x === 'center') {
 		left = x + (props.src.offsetWidth / 2) - (width / 2);
@@ -220,24 +220,24 @@ const align = () => {
 		}
 	} else {
 		// 画面から横にはみ出る場合
-		if (left + width - window.pageXOffset > (window.innerWidth - SCROLLBAR_THICKNESS)) {
-			left = (window.innerWidth - SCROLLBAR_THICKNESS) - width + window.pageXOffset - 1;
+		if (left + width - window.scrollX > (window.innerWidth - SCROLLBAR_THICKNESS)) {
+			left = (window.innerWidth - SCROLLBAR_THICKNESS) - width + window.scrollX - 1;
 		}
 
-		const underSpace = ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN) - (top - window.pageYOffset);
+		const underSpace = ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN) - (top - window.scrollY);
 		const upperSpace = (srcRect.top - MARGIN);
 
 		// 画面から縦にはみ出る場合
-		if (top + height - window.pageYOffset > ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN)) {
+		if (top + height - window.scrollY > ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN)) {
 			if (props.noOverlap && props.anchor.x === 'center') {
 				if (underSpace >= (upperSpace / 3)) {
 					maxHeight.value = underSpace;
 				} else {
 					maxHeight.value = upperSpace;
-					top = window.pageYOffset + ((upperSpace + MARGIN) - height);
+					top = window.scrollY + ((upperSpace + MARGIN) - height);
 				}
 			} else {
-				top = ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN) - height + window.pageYOffset - 1;
+				top = ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN) - height + window.scrollY - 1;
 			}
 		} else {
 			maxHeight.value = underSpace;
@@ -255,15 +255,15 @@ const align = () => {
 	let transformOriginX = 'center';
 	let transformOriginY = 'center';
 
-	if (top >= srcRect.top + props.src.offsetHeight + (fixed.value ? 0 : window.pageYOffset)) {
+	if (top >= srcRect.top + props.src.offsetHeight + (fixed.value ? 0 : window.scrollY)) {
 		transformOriginY = 'top';
-	} else if ((top + height) <= srcRect.top + (fixed.value ? 0 : window.pageYOffset)) {
+	} else if ((top + height) <= srcRect.top + (fixed.value ? 0 : window.scrollY)) {
 		transformOriginY = 'bottom';
 	}
 
-	if (left >= srcRect.left + props.src.offsetWidth + (fixed.value ? 0 : window.pageXOffset)) {
+	if (left >= srcRect.left + props.src.offsetWidth + (fixed.value ? 0 : window.scrollX)) {
 		transformOriginX = 'left';
-	} else if ((left + width) <= srcRect.left + (fixed.value ? 0 : window.pageXOffset)) {
+	} else if ((left + width) <= srcRect.left + (fixed.value ? 0 : window.scrollX)) {
 		transformOriginX = 'right';
 	}
 
diff --git a/packages/frontend/src/components/MkUrlPreviewPopup.vue b/packages/frontend/src/components/MkUrlPreviewPopup.vue
index cf75064be7..e972973dba 100644
--- a/packages/frontend/src/components/MkUrlPreviewPopup.vue
+++ b/packages/frontend/src/components/MkUrlPreviewPopup.vue
@@ -33,8 +33,8 @@ const left = ref(0);
 
 onMounted(() => {
 	const rect = props.source.getBoundingClientRect();
-	const x = Math.max((rect.left + (props.source.offsetWidth / 2)) - (300 / 2), 6) + window.pageXOffset;
-	const y = rect.top + props.source.offsetHeight + window.pageYOffset;
+	const x = Math.max((rect.left + (props.source.offsetWidth / 2)) - (300 / 2), 6) + window.scrollX;
+	const y = rect.top + props.source.offsetHeight + window.scrollY;
 
 	top.value = y;
 	left.value = x;
diff --git a/packages/frontend/src/components/MkUserPopup.vue b/packages/frontend/src/components/MkUserPopup.vue
index fb1a8f4fdc..41b27a1afb 100644
--- a/packages/frontend/src/components/MkUserPopup.vue
+++ b/packages/frontend/src/components/MkUserPopup.vue
@@ -106,8 +106,8 @@ onMounted(() => {
 	}
 
 	const rect = props.source.getBoundingClientRect();
-	const x = ((rect.left + (props.source.offsetWidth / 2)) - (300 / 2)) + window.pageXOffset;
-	const y = rect.top + props.source.offsetHeight + window.pageYOffset;
+	const x = ((rect.left + (props.source.offsetWidth / 2)) - (300 / 2)) + window.scrollX;
+	const y = rect.top + props.source.offsetHeight + window.scrollY;
 
 	top.value = y;
 	left.value = x;
diff --git a/packages/frontend/src/scripts/popup-position.ts b/packages/frontend/src/scripts/popup-position.ts
index 8c9e3c02c3..3dad41a8b3 100644
--- a/packages/frontend/src/scripts/popup-position.ts
+++ b/packages/frontend/src/scripts/popup-position.ts
@@ -26,8 +26,8 @@ export function calcPopupPosition(el: HTMLElement, props: {
 		let top: number;
 
 		if (props.anchorElement) {
-			left = rect.left + window.pageXOffset + (props.anchorElement.offsetWidth / 2);
-			top = (rect.top + window.pageYOffset - contentHeight) - props.innerMargin;
+			left = rect.left + window.scrollX + (props.anchorElement.offsetWidth / 2);
+			top = (rect.top + window.scrollY - contentHeight) - props.innerMargin;
 		} else {
 			left = props.x;
 			top = (props.y - contentHeight) - props.innerMargin;
@@ -35,8 +35,8 @@ export function calcPopupPosition(el: HTMLElement, props: {
 
 		left -= (el.offsetWidth / 2);
 
-		if (left + contentWidth - window.pageXOffset > window.innerWidth) {
-			left = window.innerWidth - contentWidth + window.pageXOffset - 1;
+		if (left + contentWidth - window.scrollX > window.innerWidth) {
+			left = window.innerWidth - contentWidth + window.scrollX - 1;
 		}
 
 		return [left, top];
@@ -47,8 +47,8 @@ export function calcPopupPosition(el: HTMLElement, props: {
 		let top: number;
 
 		if (props.anchorElement) {
-			left = rect.left + window.pageXOffset + (props.anchorElement.offsetWidth / 2);
-			top = (rect.top + window.pageYOffset + props.anchorElement.offsetHeight) + props.innerMargin;
+			left = rect.left + window.scrollX + (props.anchorElement.offsetWidth / 2);
+			top = (rect.top + window.scrollY + props.anchorElement.offsetHeight) + props.innerMargin;
 		} else {
 			left = props.x;
 			top = (props.y) + props.innerMargin;
@@ -56,8 +56,8 @@ export function calcPopupPosition(el: HTMLElement, props: {
 
 		left -= (el.offsetWidth / 2);
 
-		if (left + contentWidth - window.pageXOffset > window.innerWidth) {
-			left = window.innerWidth - contentWidth + window.pageXOffset - 1;
+		if (left + contentWidth - window.scrollX > window.innerWidth) {
+			left = window.innerWidth - contentWidth + window.scrollX - 1;
 		}
 
 		return [left, top];
@@ -68,8 +68,8 @@ export function calcPopupPosition(el: HTMLElement, props: {
 		let top: number;
 
 		if (props.anchorElement) {
-			left = (rect.left + window.pageXOffset - contentWidth) - props.innerMargin;
-			top = rect.top + window.pageYOffset + (props.anchorElement.offsetHeight / 2);
+			left = (rect.left + window.scrollX - contentWidth) - props.innerMargin;
+			top = rect.top + window.scrollY + (props.anchorElement.offsetHeight / 2);
 		} else {
 			left = (props.x - contentWidth) - props.innerMargin;
 			top = props.y;
@@ -77,8 +77,8 @@ export function calcPopupPosition(el: HTMLElement, props: {
 
 		top -= (el.offsetHeight / 2);
 
-		if (top + contentHeight - window.pageYOffset > window.innerHeight) {
-			top = window.innerHeight - contentHeight + window.pageYOffset - 1;
+		if (top + contentHeight - window.scrollY > window.innerHeight) {
+			top = window.innerHeight - contentHeight + window.scrollY - 1;
 		}
 
 		return [left, top];
@@ -89,15 +89,15 @@ export function calcPopupPosition(el: HTMLElement, props: {
 		let top: number;
 
 		if (props.anchorElement) {
-			left = (rect.left + props.anchorElement.offsetWidth + window.pageXOffset) + props.innerMargin;
+			left = (rect.left + props.anchorElement.offsetWidth + window.scrollX) + props.innerMargin;
 
 			if (props.align === 'top') {
-				top = rect.top + window.pageYOffset;
+				top = rect.top + window.scrollY;
 				if (props.alignOffset != null) top += props.alignOffset;
 			} else if (props.align === 'bottom') {
 				// TODO
 			} else { // center
-				top = rect.top + window.pageYOffset + (props.anchorElement.offsetHeight / 2);
+				top = rect.top + window.scrollY + (props.anchorElement.offsetHeight / 2);
 				top -= (el.offsetHeight / 2);
 			}
 		} else {
@@ -106,8 +106,8 @@ export function calcPopupPosition(el: HTMLElement, props: {
 			top -= (el.offsetHeight / 2);
 		}
 
-		if (top + contentHeight - window.pageYOffset > window.innerHeight) {
-			top = window.innerHeight - contentHeight + window.pageYOffset - 1;
+		if (top + contentHeight - window.scrollY > window.innerHeight) {
+			top = window.innerHeight - contentHeight + window.scrollY - 1;
 		}
 
 		return [left, top];
@@ -123,7 +123,7 @@ export function calcPopupPosition(el: HTMLElement, props: {
 				const [left, top] = calcPosWhenTop();
 
 				// ツールチップを上に向かって表示するスペースがなければ下に向かって出す
-				if (top - window.pageYOffset < 0) {
+				if (top - window.scrollY < 0) {
 					const [left, top] = calcPosWhenBottom();
 					return { left, top, transformOrigin: 'center top' };
 				}
@@ -141,7 +141,7 @@ export function calcPopupPosition(el: HTMLElement, props: {
 				const [left, top] = calcPosWhenLeft();
 
 				// ツールチップを左に向かって表示するスペースがなければ右に向かって出す
-				if (left - window.pageXOffset < 0) {
+				if (left - window.scrollX < 0) {
 					const [left, top] = calcPosWhenRight();
 					return { left, top, transformOrigin: 'left center' };
 				}
diff --git a/packages/frontend/src/scripts/use-chart-tooltip.ts b/packages/frontend/src/scripts/use-chart-tooltip.ts
index 7e4bf5c9c6..bed221a622 100644
--- a/packages/frontend/src/scripts/use-chart-tooltip.ts
+++ b/packages/frontend/src/scripts/use-chart-tooltip.ts
@@ -53,11 +53,11 @@ export function useChartTooltip(opts: { position: 'top' | 'middle' } = { positio
 		const rect = context.chart.canvas.getBoundingClientRect();
 
 		tooltipShowing.value = true;
-		tooltipX.value = rect.left + window.pageXOffset + context.tooltip.caretX;
+		tooltipX.value = rect.left + window.scrollX + context.tooltip.caretX;
 		if (opts.position === 'top') {
-			tooltipY.value = rect.top + window.pageYOffset;
+			tooltipY.value = rect.top + window.scrollY;
 		} else if (opts.position === 'middle') {
-			tooltipY.value = rect.top + window.pageYOffset + context.tooltip.caretY;
+			tooltipY.value = rect.top + window.scrollY + context.tooltip.caretY;
 		}
 	}
 

From c4fc582469a2596a4802496367699b9e04aed9f7 Mon Sep 17 00:00:00 2001
From: Jorge <46056498+jorgectf@users.noreply.github.com>
Date: Wed, 3 Apr 2024 06:02:36 +0200
Subject: [PATCH 064/191] Merge pull request from GHSA-fpvp-74wx-35p3

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 .github/workflows/storybook.yml | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml
index 87481b12cf..ca82f4bcf3 100644
--- a/.github/workflows/storybook.yml
+++ b/.github/workflows/storybook.yml
@@ -87,12 +87,13 @@ jobs:
         if [ "$CHROMATIC_PARAMETER" = " --skip" ]; then
           echo "skip=true" >> $GITHUB_OUTPUT
         fi
-        BRANCH="${{ github.event.pull_request.head.user.login }}:${{ github.event.pull_request.head.ref }}"
-        if [ "$BRANCH" = "misskey-dev:${{ github.event.pull_request.head.ref }}" ]; then
-          BRANCH="${{ github.event.pull_request.head.ref }}"
+        BRANCH="${{ github.event.pull_request.head.user.login }}:$HEAD_REF"
+        if [ "$BRANCH" = "misskey-dev:$HEAD_REF" ]; then
+          BRANCH="$HEAD_REF"
         fi
         pnpm --filter frontend chromatic --exit-once-uploaded -d storybook-static --branch-name $BRANCH $(echo "$CHROMATIC_PARAMETER")
       env:
+        HEAD_REF: ${{ github.event.pull_request.head.ref }}
         CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
     - name: Notify that Chromatic detects changes
       uses: actions/github-script@v7.0.1

From efa42a1624b0727232263f4ec196e4908ef1e712 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?=
 <46447427+samunohito@users.noreply.github.com>
Date: Thu, 4 Apr 2024 22:25:28 +0900
Subject: [PATCH 065/191] =?UTF-8?q?fix(backend):=20=E3=83=90=E3=83=83?=
 =?UTF-8?q?=E3=82=AF=E3=82=A8=E3=83=B3=E3=83=89=E3=81=AEpnpm=20dev?=
 =?UTF-8?q?=E3=81=AB=E3=82=88=E3=82=8B=E3=83=93=E3=83=AB=E3=83=89=E5=BE=8C?=
 =?UTF-8?q?=E3=81=ABbuild-assets=E3=82=92=E8=A1=8C=E3=81=86=E3=82=88?=
 =?UTF-8?q?=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B=20(#13659)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* moveto scripts

* add scripts/dev.mjs
---
 packages/backend/package.json                 |  8 +--
 .../backend/{ => scripts}/check_connect.js    |  2 +-
 packages/backend/scripts/dev.mjs              | 61 +++++++++++++++++++
 .../{ => scripts}/generate_api_json.js        |  4 +-
 packages/backend/{ => scripts}/watch.mjs      |  0
 pnpm-lock.yaml                                |  6 +-
 6 files changed, 71 insertions(+), 10 deletions(-)
 rename packages/backend/{ => scripts}/check_connect.js (85%)
 create mode 100644 packages/backend/scripts/dev.mjs
 rename packages/backend/{ => scripts}/generate_api_json.js (70%)
 rename packages/backend/{ => scripts}/watch.mjs (100%)

diff --git a/packages/backend/package.json b/packages/backend/package.json
index d64fcc3d2a..7f70ae0c97 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -11,14 +11,14 @@
 		"start:test": "cross-env NODE_ENV=test node ./built/boot/entry.js",
 		"migrate": "pnpm typeorm migration:run -d ormconfig.js",
 		"revert": "pnpm typeorm migration:revert -d ormconfig.js",
-		"check:connect": "node ./check_connect.js",
+		"check:connect": "node ./scripts/check_connect.js",
 		"build": "swc src -d built -D",
 		"build:test": "swc test-server -d built-test -D --config-file test-server/.swcrc",
 		"watch:swc": "swc src -d built -D -w",
 		"build:tsc": "tsc -p tsconfig.json && tsc-alias -p tsconfig.json",
-		"watch": "node watch.mjs",
+		"watch": "node ./scripts/watch.mjs",
 		"restart": "pnpm build && pnpm start",
-		"dev": "nodemon -w src -e ts,js,mjs,cjs,json --exec \"cross-env NODE_ENV=development pnpm run restart\"",
+		"dev": "node ./scripts/dev.mjs",
 		"typecheck": "tsc --noEmit && tsc -p test --noEmit",
 		"eslint": "eslint --quiet \"src/**/*.ts\"",
 		"lint": "pnpm typecheck && pnpm eslint",
@@ -31,7 +31,7 @@
 		"test:e2e": "pnpm build && pnpm build:test && pnpm jest:e2e",
 		"test-and-coverage": "pnpm jest-and-coverage",
 		"test-and-coverage:e2e": "pnpm build && pnpm build:test && pnpm jest-and-coverage:e2e",
-		"generate-api-json": "pnpm build && node ./generate_api_json.js"
+		"generate-api-json": "pnpm build && node ./scripts/generate_api_json.js"
 	},
 	"optionalDependencies": {
 		"@swc/core-android-arm64": "1.3.11",
diff --git a/packages/backend/check_connect.js b/packages/backend/scripts/check_connect.js
similarity index 85%
rename from packages/backend/check_connect.js
rename to packages/backend/scripts/check_connect.js
index d88e649c09..ba25fd416c 100644
--- a/packages/backend/check_connect.js
+++ b/packages/backend/scripts/check_connect.js
@@ -4,7 +4,7 @@
  */
 
 import Redis from 'ioredis';
-import { loadConfig } from './built/config.js';
+import { loadConfig } from '../built/config.js';
 
 const config = loadConfig();
 const redis = new Redis(config.redis);
diff --git a/packages/backend/scripts/dev.mjs b/packages/backend/scripts/dev.mjs
new file mode 100644
index 0000000000..2d0de0f916
--- /dev/null
+++ b/packages/backend/scripts/dev.mjs
@@ -0,0 +1,61 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { execa, execaNode } from 'execa';
+
+/** @type {import('execa').ExecaChildProcess | undefined} */
+let backendProcess;
+
+async function execBuildAssets() {
+	await execa('pnpm', ['run', 'build-assets'], {
+		cwd: '../../',
+		stdout: process.stdout,
+		stderr: process.stderr,
+	})
+}
+
+function execStart() {
+	// pnpm run start を呼び出したいが、windowsだとプロセスグループ単位でのkillが出来ずゾンビプロセス化するので
+	// 上記と同等の動きをするコマンドで子・孫プロセスを作らないようにしたい
+	backendProcess = execaNode('./built/boot/entry.js', [], {
+		stdout: process.stdout,
+		stderr: process.stderr,
+		env: {
+			'NODE_ENV': 'development',
+		},
+	});
+}
+
+async function killProc() {
+	if (backendProcess) {
+		backendProcess.kill();
+		await new Promise(resolve => backendProcess.on('exit', resolve));
+		backendProcess = undefined;
+	}
+}
+
+(async () => {
+	execaNode(
+		'./node_modules/nodemon/bin/nodemon.js',
+		[
+			'-w', 'src',
+			'-e', 'ts,js,mjs,cjs,json',
+			'--exec', 'pnpm', 'run', 'build',
+		],
+		{
+			stdio: [process.stdin, process.stdout, process.stderr, 'ipc'],
+		})
+		.on('message', async (message) => {
+			if (message.type === 'exit') {
+				// かならずbuild->build-assetsの順番で呼び出したいので、
+				// 少々トリッキーだがnodemonからのexitイベントを利用してbuild-assets->startを行う。
+				// pnpm restartをbuildが終わる前にbuild-assetsが動いてしまうので、バラバラに呼び出す必要がある
+
+				await killProc();
+				await execBuildAssets();
+				execStart();
+			}
+		})
+})();
diff --git a/packages/backend/generate_api_json.js b/packages/backend/scripts/generate_api_json.js
similarity index 70%
rename from packages/backend/generate_api_json.js
rename to packages/backend/scripts/generate_api_json.js
index 602ced1d75..b4769ef801 100644
--- a/packages/backend/generate_api_json.js
+++ b/packages/backend/scripts/generate_api_json.js
@@ -3,8 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { loadConfig } from './built/config.js'
-import { genOpenapiSpec } from './built/server/api/openapi/gen-spec.js'
+import { loadConfig } from '../built/config.js'
+import { genOpenapiSpec } from '../built/server/api/openapi/gen-spec.js'
 import { writeFileSync } from "node:fs";
 
 const config = loadConfig();
diff --git a/packages/backend/watch.mjs b/packages/backend/scripts/watch.mjs
similarity index 100%
rename from packages/backend/watch.mjs
rename to packages/backend/scripts/watch.mjs
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 46512784c3..91c2a704e2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -6678,7 +6678,7 @@ packages:
       ts-dedent: 2.2.0
       type-fest: 2.19.0
       vue: 3.4.21(typescript@5.3.3)
-      vue-component-type-helpers: 2.0.6
+      vue-component-type-helpers: 2.0.7
     transitivePeerDependencies:
       - encoding
       - supports-color
@@ -19348,8 +19348,8 @@ packages:
     resolution: {integrity: sha512-6bnLkn8O0JJyiFSIF0EfCogzeqNXpnjJ0vW/SZzNHfe6sPx30lTtTXlE5TFs2qhJlAtDFybStVNpL73cPe3OMQ==}
     dev: true
 
-  /vue-component-type-helpers@2.0.6:
-    resolution: {integrity: sha512-qdGXCtoBrwqk1BT6r2+1Wcvl583ZVkuSZ3or7Y1O2w5AvWtlvvxwjGhmz5DdPJS9xqRdDlgTJ/38ehWnEi0tFA==}
+  /vue-component-type-helpers@2.0.7:
+    resolution: {integrity: sha512-7e12Evdll7JcTIocojgnCgwocX4WzIYStGClBQ+QuWPinZo/vQolv2EMq4a3lg16TKfwWafLimG77bxb56UauA==}
     dev: true
 
   /vue-demi@0.14.7(vue@3.4.21):

From 2f8fb105a5b1d2f6e5cd70ff3246ead07e63144d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Fri, 5 Apr 2024 15:59:43 +0900
Subject: [PATCH 066/191] =?UTF-8?q?fix(deps):=20aiscript-vscode=E3=81=AE?=
 =?UTF-8?q?=E3=82=A4=E3=83=B3=E3=82=B9=E3=83=88=E3=83=BC=E3=83=AB=E4=B8=AD?=
 =?UTF-8?q?=E3=81=ABWARN=E3=81=8C=E5=87=BA=E3=82=8B=E3=81=AE=E3=82=92?=
 =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20(#13661)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 packages/frontend/package.json |  2 +-
 pnpm-lock.yaml                 | 39 +++++++++++++++++-----------------
 2 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/packages/frontend/package.json b/packages/frontend/package.json
index db7f7b76f6..cbf4e59592 100644
--- a/packages/frontend/package.json
+++ b/packages/frontend/package.json
@@ -29,7 +29,7 @@
 		"@twemoji/parser": "15.0.0",
 		"@vitejs/plugin-vue": "5.0.4",
 		"@vue/compiler-sfc": "3.4.21",
-		"aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.2",
+		"aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.4",
 		"astring": "1.8.6",
 		"broadcast-channel": "7.0.0",
 		"buraha": "0.0.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 91c2a704e2..1dbb172b5d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -722,8 +722,8 @@ importers:
         specifier: 3.4.21
         version: 3.4.21
       aiscript-vscode:
-        specifier: github:aiscript-dev/aiscript-vscode#v0.1.2
-        version: github.com/aiscript-dev/aiscript-vscode/793211d40243c8775f6b85f015c221c82cbffb07
+        specifier: github:aiscript-dev/aiscript-vscode#v0.1.4
+        version: github.com/aiscript-dev/aiscript-vscode/3f79d6f0550369267220aa67702287948d885424
       astring:
         specifier: 1.8.6
         version: 1.8.6
@@ -5009,7 +5009,7 @@ packages:
     resolution: {integrity: sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
-      semver: 7.5.4
+      semver: 7.6.0
     dev: false
 
   /@nsfw-filter/gif-frames@1.0.2:
@@ -6678,7 +6678,7 @@ packages:
       ts-dedent: 2.2.0
       type-fest: 2.19.0
       vue: 3.4.21(typescript@5.3.3)
-      vue-component-type-helpers: 2.0.7
+      vue-component-type-helpers: 2.0.10
     transitivePeerDependencies:
       - encoding
       - supports-color
@@ -10595,7 +10595,7 @@ packages:
       '@one-ini/wasm': 0.1.1
       commander: 10.0.1
       minimatch: 9.0.1
-      semver: 7.5.4
+      semver: 7.6.0
     dev: true
 
   /ee-first@1.1.1:
@@ -13125,7 +13125,7 @@ packages:
       '@babel/parser': 7.23.9
       '@istanbuljs/schema': 0.1.3
       istanbul-lib-coverage: 3.2.2
-      semver: 7.5.4
+      semver: 7.6.0
     transitivePeerDependencies:
       - supports-color
     dev: true
@@ -14121,7 +14121,7 @@ packages:
     resolution: {integrity: sha512-Yj9mA8fPiVgOUpByoTZO5pNrcl5Yk37FcSHsUINpAsaBIEZIuqcCclDZJCVxqQShDsmYX8QG63svJiTbOATZwg==}
     engines: {node: 14 || >=16.14}
     dependencies:
-      semver: 7.5.4
+      semver: 7.6.0
 
   /lru-cache@4.1.5:
     resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
@@ -14192,7 +14192,7 @@ packages:
     resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
     engines: {node: '>=10'}
     dependencies:
-      semver: 7.5.4
+      semver: 7.6.0
     dev: true
 
   /make-fetch-happen@13.0.0:
@@ -15303,7 +15303,7 @@ packages:
     dependencies:
       hosted-git-info: 4.1.0
       is-core-module: 2.13.1
-      semver: 7.5.4
+      semver: 7.6.0
       validate-npm-package-license: 3.0.4
     dev: true
 
@@ -17446,7 +17446,6 @@ packages:
     hasBin: true
     dependencies:
       lru-cache: 6.0.0
-    dev: true
 
   /send@0.18.0:
     resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
@@ -19299,7 +19298,7 @@ packages:
     engines: {vscode: ^1.82.0}
     dependencies:
       minimatch: 5.1.2
-      semver: 7.5.4
+      semver: 7.6.0
       vscode-languageserver-protocol: 3.17.5
     dev: false
 
@@ -19348,8 +19347,8 @@ packages:
     resolution: {integrity: sha512-6bnLkn8O0JJyiFSIF0EfCogzeqNXpnjJ0vW/SZzNHfe6sPx30lTtTXlE5TFs2qhJlAtDFybStVNpL73cPe3OMQ==}
     dev: true
 
-  /vue-component-type-helpers@2.0.7:
-    resolution: {integrity: sha512-7e12Evdll7JcTIocojgnCgwocX4WzIYStGClBQ+QuWPinZo/vQolv2EMq4a3lg16TKfwWafLimG77bxb56UauA==}
+  /vue-component-type-helpers@2.0.10:
+    resolution: {integrity: sha512-FC5fKJjDks3Ue/KRSYBdsiCaZa0kUPQfs8yQpb8W9mlO6BenV8G1z58xobeRMzevnmEcDa09LLwuXDwb4f6NMQ==}
     dev: true
 
   /vue-demi@0.14.7(vue@3.4.21):
@@ -19871,10 +19870,10 @@ packages:
     resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
     dev: true
 
-  '@github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.5/aiscript-dev-aiscript-languageserver-0.1.5.tgz':
-    resolution: {tarball: https://github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.5/aiscript-dev-aiscript-languageserver-0.1.5.tgz}
+  '@github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz':
+    resolution: {tarball: https://github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz}
     name: '@aiscript-dev/aiscript-languageserver'
-    version: 0.1.5
+    version: 0.1.6
     hasBin: true
     dependencies:
       seedrandom: 3.0.5
@@ -19884,13 +19883,13 @@ packages:
       vscode-languageserver-textdocument: 1.0.11
     dev: false
 
-  github.com/aiscript-dev/aiscript-vscode/793211d40243c8775f6b85f015c221c82cbffb07:
-    resolution: {tarball: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/793211d40243c8775f6b85f015c221c82cbffb07}
+  github.com/aiscript-dev/aiscript-vscode/3f79d6f0550369267220aa67702287948d885424:
+    resolution: {tarball: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/3f79d6f0550369267220aa67702287948d885424}
     name: aiscript-vscode
-    version: 0.1.2
+    version: 0.1.4
     engines: {vscode: ^1.83.0}
     dependencies:
-      '@aiscript-dev/aiscript-languageserver': '@github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.5/aiscript-dev-aiscript-languageserver-0.1.5.tgz'
+      '@aiscript-dev/aiscript-languageserver': '@github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz'
       vscode-languageclient: 9.0.1
     dev: false
 

From 959cc8ff37de620bf0082f48f59963c00d045fe9 Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Sun, 7 Apr 2024 21:14:13 +0900
Subject: [PATCH 067/191] refactor(general): use `Date.now()` instead of
 creating a new `Date` instance (#13671)

---
 packages/backend/src/core/AccountMoveService.ts             | 4 ++--
 packages/backend/src/core/PushNotificationService.ts        | 2 +-
 .../backend/src/server/api/endpoints/i/import-blocking.ts   | 2 +-
 .../backend/src/server/api/endpoints/i/import-following.ts  | 2 +-
 .../backend/src/server/api/endpoints/i/import-muting.ts     | 2 +-
 .../backend/src/server/api/endpoints/i/import-user-lists.ts | 2 +-
 packages/frontend/src/components/global/MkTime.vue          | 4 ++--
 packages/frontend/src/widgets/WidgetUnixClock.vue           | 6 +++---
 packages/sw/src/sw.ts                                       | 2 +-
 9 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/packages/backend/src/core/AccountMoveService.ts b/packages/backend/src/core/AccountMoveService.ts
index 5bd885df40..b6b591d240 100644
--- a/packages/backend/src/core/AccountMoveService.ts
+++ b/packages/backend/src/core/AccountMoveService.ts
@@ -305,7 +305,7 @@ export class AccountMoveService {
 		let resultUser: MiLocalUser | MiRemoteUser | null = null;
 
 		if (this.userEntityService.isRemoteUser(dst)) {
-			if ((new Date()).getTime() - (dst.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) {
+			if (Date.now() - (dst.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) {
 				await this.apPersonService.updatePerson(dst.uri);
 			}
 			dst = await this.apPersonService.fetchPerson(dst.uri) ?? dst;
@@ -321,7 +321,7 @@ export class AccountMoveService {
 				if (!src) continue; // oldAccountを探してもこのサーバーに存在しない場合はフォロー関係もないということなのでスルー
 
 				if (this.userEntityService.isRemoteUser(dst)) {
-					if ((new Date()).getTime() - (src.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) {
+					if (Date.now() - (src.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) {
 						await this.apPersonService.updatePerson(srcUri);
 					}
 
diff --git a/packages/backend/src/core/PushNotificationService.ts b/packages/backend/src/core/PushNotificationService.ts
index 3b706d9854..6a845b951d 100644
--- a/packages/backend/src/core/PushNotificationService.ts
+++ b/packages/backend/src/core/PushNotificationService.ts
@@ -101,7 +101,7 @@ export class PushNotificationService implements OnApplicationShutdown {
 				type,
 				body: (type === 'notification' || type === 'unreadAntennaNote') ? truncateBody(type, body) : body,
 				userId,
-				dateTime: (new Date()).getTime(),
+				dateTime: Date.now(),
 			}), {
 				proxy: this.config.proxy,
 			}).catch((err: any) => {
diff --git a/packages/backend/src/server/api/endpoints/i/import-blocking.ts b/packages/backend/src/server/api/endpoints/i/import-blocking.ts
index 8ddbe5663e..2606108539 100644
--- a/packages/backend/src/server/api/endpoints/i/import-blocking.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-blocking.ts
@@ -75,7 +75,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 
 			const checkMoving = await this.accountMoveService.validateAlsoKnownAs(
 				me,
-				(old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > (new Date()).getTime(),
+				(old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > Date.now(),
 				true,
 			);
 			if (checkMoving ? file.size > 32 * 1024 * 1024 : file.size > 64 * 1024) throw new ApiError(meta.errors.tooBigFile);
diff --git a/packages/backend/src/server/api/endpoints/i/import-following.ts b/packages/backend/src/server/api/endpoints/i/import-following.ts
index 390dd9cd71..d5e824df27 100644
--- a/packages/backend/src/server/api/endpoints/i/import-following.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-following.ts
@@ -75,7 +75,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 
 			const checkMoving = await this.accountMoveService.validateAlsoKnownAs(
 				me,
-				(old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > (new Date()).getTime(),
+				(old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > Date.now(),
 				true,
 			);
 			if (checkMoving ? file.size > 32 * 1024 * 1024 : file.size > 64 * 1024) throw new ApiError(meta.errors.tooBigFile);
diff --git a/packages/backend/src/server/api/endpoints/i/import-muting.ts b/packages/backend/src/server/api/endpoints/i/import-muting.ts
index 51a9cdf5a5..0f5800404e 100644
--- a/packages/backend/src/server/api/endpoints/i/import-muting.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-muting.ts
@@ -75,7 +75,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 
 			const checkMoving = await this.accountMoveService.validateAlsoKnownAs(
 				me,
-				(old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > (new Date()).getTime(),
+				(old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > Date.now(),
 				true,
 			);
 			if (checkMoving ? file.size > 32 * 1024 * 1024 : file.size > 64 * 1024) throw new ApiError(meta.errors.tooBigFile);
diff --git a/packages/backend/src/server/api/endpoints/i/import-user-lists.ts b/packages/backend/src/server/api/endpoints/i/import-user-lists.ts
index a3b67301a7..bacdd5c88f 100644
--- a/packages/backend/src/server/api/endpoints/i/import-user-lists.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-user-lists.ts
@@ -74,7 +74,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 
 			const checkMoving = await this.accountMoveService.validateAlsoKnownAs(
 				me,
-				(old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > (new Date()).getTime(),
+				(old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > Date.now(),
 				true,
 			);
 			if (checkMoving ? file.size > 32 * 1024 * 1024 : file.size > 64 * 1024) throw new ApiError(meta.errors.tooBigFile);
diff --git a/packages/frontend/src/components/global/MkTime.vue b/packages/frontend/src/components/global/MkTime.vue
index 67532268d3..23fe99bd9c 100644
--- a/packages/frontend/src/components/global/MkTime.vue
+++ b/packages/frontend/src/components/global/MkTime.vue
@@ -47,7 +47,7 @@ const invalid = Number.isNaN(_time);
 const absolute = !invalid ? dateTimeFormat.format(_time) : i18n.ts._ago.invalid;
 
 // eslint-disable-next-line vue/no-setup-props-destructure
-const now = ref((props.origin ?? new Date()).getTime());
+const now = ref(props.origin?.getTime() ?? Date.now());
 const ago = computed(() => (now.value - _time) / 1000/*ms*/);
 
 const relative = computed<string>(() => {
@@ -77,7 +77,7 @@ let tickId: number;
 let currentInterval: number;
 
 function tick() {
-	now.value = (new Date()).getTime();
+	now.value = Date.now();
 	const nextInterval = ago.value < 60 ? 10000 : ago.value < 3600 ? 60000 : 180000;
 
 	if (currentInterval !== nextInterval) {
diff --git a/packages/frontend/src/widgets/WidgetUnixClock.vue b/packages/frontend/src/widgets/WidgetUnixClock.vue
index 2ac7d1c781..832cd575cc 100644
--- a/packages/frontend/src/widgets/WidgetUnixClock.vue
+++ b/packages/frontend/src/widgets/WidgetUnixClock.vue
@@ -68,9 +68,9 @@ watch(showColon, (v) => {
 });
 
 const tick = () => {
-	const now = new Date();
-	ss.value = Math.floor(now.getTime() / 1000).toString();
-	ms.value = Math.floor(now.getTime() % 1000 / 10).toString().padStart(2, '0');
+	const now = Date.now();
+	ss.value = Math.floor(now / 1000).toString();
+	ms.value = Math.floor(now % 1000 / 10).toString().padStart(2, '0');
 	if (ss.value !== prevSec) showColon.value = true;
 	prevSec = ss.value;
 };
diff --git a/packages/sw/src/sw.ts b/packages/sw/src/sw.ts
index 46fe9fc90f..cc79d88713 100644
--- a/packages/sw/src/sw.ts
+++ b/packages/sw/src/sw.ts
@@ -76,7 +76,7 @@ globalThis.addEventListener('push', ev => {
 			case 'notification':
 			case 'unreadAntennaNote':
 				// 1日以上経過している場合は無視
-				if ((new Date()).getTime() - data.dateTime > 1000 * 60 * 60 * 24) break;
+				if (Date.now() - data.dateTime > 1000 * 60 * 60 * 24) break;
 
 				return createNotification(data);
 			case 'readAllNotifications':

From 960c4df48e31483209ac0421a009686685acd82d Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Sun, 7 Apr 2024 21:16:37 +0900
Subject: [PATCH 068/191] enhance(frontend): better condition for posting and
 displaying Notes (#13670)

* enhance(frontend): better condition for posting and displaying Notes

* Update CHANGELOG.md
---
 CHANGELOG.md                                        | 4 ++++
 packages/frontend/src/components/MkNote.vue         | 1 +
 packages/frontend/src/components/MkNoteDetailed.vue | 4 +++-
 packages/frontend/src/components/MkPostForm.vue     | 8 +++++++-
 4 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index f6b9cf0939..41cbdea023 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,8 @@
 - Enhance: 映像・音声の再生メニューに「再生速度」「ループ再生」「ピクチャインピクチャ」を追加
 - Enhance: 映像・音声の再生にキーボードショートカットが使えるように
 - Enhance: ノートについているリアクションの「もっと!」から、リアクションの一覧を表示できるように
+- Enhance: リプライにて引用がある場合テキストが空でもノートできるように
+  - 引用したいノートのURLをコピーしリプライ投稿画面にペーストして添付することで達成できます
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
 - Fix: ローカルURLのプレビューポップアップが左上に表示される
@@ -33,6 +35,8 @@
 - Fix: コードブロックのシンタックスハイライトで使用される定義ファイルをCDNから取得するように #13177
   - CDNから取得せずMisskey本体にバンドルする場合は`pacakges/frontend/vite.config.ts`を修正してください。
 - Fix: タイムゾーンによっては、「今日誕生日のフォロー中ユーザー」ウィジェットが正しく動作しない問題を修正
+- Fix: CWのみの引用リノートが詳細ページで純粋なリノートとして誤って扱われてしまう問題を修正
+- Fix: ノート詳細ページにおいてCW付き引用リノートのCWボタンのラベルに「引用」が含まれていない問題を修正
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index f5536e79bf..22b1691a86 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -242,6 +242,7 @@ if (noteViewInterruptors.length > 0) {
 
 const isRenote = (
 	note.value.renote != null &&
+	note.value.reply == null &&
 	note.value.text == null &&
 	note.value.cw == null &&
 	note.value.fileIds && note.value.fileIds.length === 0 &&
diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue
index eec1aad53c..ed1c0a9e96 100644
--- a/packages/frontend/src/components/MkNoteDetailed.vue
+++ b/packages/frontend/src/components/MkNoteDetailed.vue
@@ -68,7 +68,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 		<div :class="$style.noteContent">
 			<p v-if="appearNote.cw != null" :class="$style.cw">
 				<Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :nyaize="'respect'"/>
-				<MkCwButton v-model="showContent" :text="appearNote.text" :files="appearNote.files" :poll="appearNote.poll"/>
+				<MkCwButton v-model="showContent" :text="appearNote.text" :renote="appearNote.renote" :files="appearNote.files" :poll="appearNote.poll"/>
 			</p>
 			<div v-show="appearNote.cw == null || showContent">
 				<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span>
@@ -266,7 +266,9 @@ if (noteViewInterruptors.length > 0) {
 
 const isRenote = (
 	note.value.renote != null &&
+	note.value.reply == null &&
 	note.value.text == null &&
+	note.value.cw == null &&
 	note.value.fileIds && note.value.fileIds.length === 0 &&
 	note.value.poll == null
 );
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index e03faeaf55..014b866fbd 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -253,7 +253,13 @@ const maxTextLength = computed((): number => {
 
 const canPost = computed((): boolean => {
 	return !props.mock && !posting.value && !posted.value &&
-		(1 <= textLength.value || 1 <= files.value.length || !!poll.value || !!props.renote) &&
+		(
+			1 <= textLength.value ||
+			1 <= files.value.length ||
+			poll.value != null ||
+			props.renote != null ||
+			(props.reply != null && quoteId.value != null)
+		) &&
 		(textLength.value <= maxTextLength.value) &&
 		(!poll.value || poll.value.choices.length >= 2);
 });

From b322f55c8791493da9788313fd3df9d52f1327ef Mon Sep 17 00:00:00 2001
From: Srgr0 <66754887+Srgr0@users.noreply.github.com>
Date: Mon, 8 Apr 2024 22:41:26 +0900
Subject: [PATCH 069/191] dev: fix misskey-tga (#13312)

* Update deploy-test-environment.yml

* Update deploy-test-environment.yml

* use github.repository

---------

Co-authored-by: anatawa12 <anatawa12@icloud.com>
---
 .github/workflows/deploy-test-environment.yml | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/.github/workflows/deploy-test-environment.yml b/.github/workflows/deploy-test-environment.yml
index 77cdcfaf88..66b15beb91 100644
--- a/.github/workflows/deploy-test-environment.yml
+++ b/.github/workflows/deploy-test-environment.yml
@@ -50,12 +50,9 @@ jobs:
 
       - name: Get PR ref
         id: get-ref
-        env:
-          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         run: |
-          PR_NUMBER=$(jq --raw-output .issue.number $GITHUB_EVENT_PATH)
-          PR_REF=$(gh pr view $PR_NUMBER --json headRefName -q '.headRefName')
-          echo "pr-ref=$PR_REF" > $GITHUB_OUTPUT
+          PR_REF="refs/pull/${{ github.event.issue.number }}/head"
+          echo "pr-ref=$PR_REF" >> $GITHUB_OUTPUT
 
       - name: Extract wait time
         id: get-wait-time

From 7586ef7ba86ae9516e4a9460c0845750dda22e77 Mon Sep 17 00:00:00 2001
From: 1Step621 <86859447+1STEP621@users.noreply.github.com>
Date: Tue, 9 Apr 2024 14:20:00 +0900
Subject: [PATCH 070/191] =?UTF-8?q?fix(frontend):=20MkDialog=E3=81=AEinput?=
 =?UTF-8?q?=E3=81=A7=E5=AD=97=E6=95=B0=E5=88=B6=E9=99=90=E3=81=AB=E9=81=95?=
 =?UTF-8?q?=E5=8F=8D=E3=81=97=E3=81=A6=E3=81=84=E3=81=A6=E3=82=82Enter?=
 =?UTF-8?q?=E3=82=AD=E3=83=BC=E3=81=8C=E6=8A=BC=E3=81=9B=E3=81=A6=E3=81=97?=
 =?UTF-8?q?=E3=81=BE=E3=81=86=E3=81=AE=E3=82=92=E4=BF=AE=E6=AD=A3=20(#1367?=
 =?UTF-8?q?7)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* MkDialogのinputで字数制限に違反していてもEnterキーが押せてしまうのを修正

* update CHANGELOG.md
---
 CHANGELOG.md                                  | 1 +
 packages/frontend/src/components/MkDialog.vue | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 41cbdea023..ab4ecb3ffe 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,6 +37,7 @@
 - Fix: タイムゾーンによっては、「今日誕生日のフォロー中ユーザー」ウィジェットが正しく動作しない問題を修正
 - Fix: CWのみの引用リノートが詳細ページで純粋なリノートとして誤って扱われてしまう問題を修正
 - Fix: ノート詳細ページにおいてCW付き引用リノートのCWボタンのラベルに「引用」が含まれていない問題を修正
+- Fix: ダイアログの入力で字数制限に違反していてもEnterキーが押せてしまう問題を修正
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
diff --git a/packages/frontend/src/components/MkDialog.vue b/packages/frontend/src/components/MkDialog.vue
index 4577d37c08..c52404a319 100644
--- a/packages/frontend/src/components/MkDialog.vue
+++ b/packages/frontend/src/components/MkDialog.vue
@@ -161,7 +161,7 @@ function onKeydown(evt: KeyboardEvent) {
 }
 
 function onInputKeydown(evt: KeyboardEvent) {
-	if (evt.key === 'Enter') {
+	if (evt.key === 'Enter' && okButtonDisabledReason.value === null) {
 		evt.preventDefault();
 		evt.stopPropagation();
 		ok();

From eb1ef1484afbdb09407a603ff69414e7f88bb9ff Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Tue, 9 Apr 2024 20:52:29 +0900
Subject: [PATCH 071/191] enhance(frontend): add link of 2fa guide

---
 locales/index.d.ts                                    | 4 ++++
 locales/ja-JP.yml                                     | 1 +
 packages/frontend/src/pages/settings/2fa.qrdialog.vue | 3 +++
 packages/frontend/src/pages/settings/2fa.vue          | 6 +++++-
 4 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/locales/index.d.ts b/locales/index.d.ts
index 01bec41d9e..54f0285726 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -7645,6 +7645,10 @@ export interface Locale extends ILocale {
          * バックアップコードが全て使用されました。認証アプリを利用できない場合、これ以上アカウントにアクセスできなくなります。認証アプリを再登録してください。
          */
         "backupCodesExhaustedWarning": string;
+        /**
+         * 詳細なガイドはこちら
+         */
+        "moreDetailedGuideHere": string;
     };
     "_permissions": {
         /**
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 4ba9ea0221..ac88420b9d 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -2009,6 +2009,7 @@ _2fa:
   backupCodesDescription: "認証アプリが使用できなくなった場合、以下のバックアップコードを使ってアカウントにアクセスできます。これらのコードは必ず安全な場所に保管してください。各コードは一回だけ使用できます。"
   backupCodeUsedWarning: "バックアップコードが使用されました。認証アプリが使えなくなっている場合、なるべく早く認証アプリを再設定してください。"
   backupCodesExhaustedWarning: "バックアップコードが全て使用されました。認証アプリを利用できない場合、これ以上アカウントにアクセスできなくなります。認証アプリを再登録してください。"
+  moreDetailedGuideHere: "詳細なガイドはこちら"
 
 _permissions:
   "read:account": "アカウントの情報を見る"
diff --git a/packages/frontend/src/pages/settings/2fa.qrdialog.vue b/packages/frontend/src/pages/settings/2fa.qrdialog.vue
index 73253b1ef4..2244047b31 100644
--- a/packages/frontend/src/pages/settings/2fa.qrdialog.vue
+++ b/packages/frontend/src/pages/settings/2fa.qrdialog.vue
@@ -25,6 +25,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 				<div style="height: 100cqh; overflow: auto; text-align: center;">
 					<MkSpacer :marginMin="20" :marginMax="28">
 						<div class="_gaps">
+							<MkInfo><MkLink url="https://misskey-hub.net/docs/for-users/stepped-guides/how-to-enable-2fa/" target="_blank">{{ i18n.ts._2fa.moreDetailedGuideHere }}</MkLink></MkInfo>
+
 							<I18n :src="i18n.ts._2fa.step1" tag="div">
 								<template #a>
 									<a href="https://authy.com/" rel="noopener" target="_blank" class="_link">Authy</a>
@@ -113,6 +115,7 @@ import { i18n } from '@/i18n.js';
 import * as os from '@/os.js';
 import MkFolder from '@/components/MkFolder.vue';
 import MkInfo from '@/components/MkInfo.vue';
+import MkLink from '@/components/MkLink.vue';
 import { confetti } from '@/scripts/confetti.js';
 import { signinRequired } from '@/account.js';
 
diff --git a/packages/frontend/src/pages/settings/2fa.vue b/packages/frontend/src/pages/settings/2fa.vue
index 975f23cdd1..b7d648c1a4 100644
--- a/packages/frontend/src/pages/settings/2fa.vue
+++ b/packages/frontend/src/pages/settings/2fa.vue
@@ -30,7 +30,10 @@ SPDX-License-Identifier: AGPL-3.0-only
 				<MkButton v-else danger @click="unregisterTOTP">{{ i18n.ts.unregister }}</MkButton>
 			</div>
 
-			<MkButton v-else-if="!$i.twoFactorEnabled" primary gradate @click="registerTOTP">{{ i18n.ts._2fa.registerTOTP }}</MkButton>
+			<div v-else-if="!$i.twoFactorEnabled" class="_gaps_s">
+				<MkButton primary gradate @click="registerTOTP">{{ i18n.ts._2fa.registerTOTP }}</MkButton>
+				<MkLink url="https://misskey-hub.net/docs/for-users/stepped-guides/how-to-enable-2fa/" target="_blank"><i class="ti ti-help-circle"></i> {{ i18n.ts.learnMore }}</MkLink>
+			</div>
 		</MkFolder>
 
 		<MkFolder>
@@ -79,6 +82,7 @@ import MkInfo from '@/components/MkInfo.vue';
 import MkSwitch from '@/components/MkSwitch.vue';
 import FormSection from '@/components/form/section.vue';
 import MkFolder from '@/components/MkFolder.vue';
+import MkLink from '@/components/MkLink.vue';
 import * as os from '@/os.js';
 import { signinRequired, updateAccount } from '@/account.js';
 import { i18n } from '@/i18n.js';

From f5100cc81f6ffdcfe2b9bf6041f97098a4e82d02 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sat, 13 Apr 2024 12:51:37 +0900
Subject: [PATCH 072/191] =?UTF-8?q?feat(frontend):=20=E3=82=A2=E3=83=83?=
 =?UTF-8?q?=E3=83=97=E3=83=AD=E3=83=BC=E3=83=89=E3=81=99=E3=82=8B=E3=83=95?=
 =?UTF-8?q?=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=AE=E5=90=8D=E5=89=8D=E3=82=92?=
 =?UTF-8?q?=E3=83=A9=E3=83=B3=E3=83=80=E3=83=A0=E6=96=87=E5=AD=97=E5=88=97?=
 =?UTF-8?q?=E3=81=AB=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?=
 =?UTF-8?q?=20(#13688)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* feat(frontend): アップロードするファイルの名前をランダム文字列にできるように

* Update Changelog

* refactor

* 設定項目を移動

* fix

* 「オリジナルのファイル名を保持」に変更

* 拡張子を付加するように
---
 CHANGELOG.md                                   |  1 +
 locales/index.d.ts                             |  8 ++++++++
 locales/ja-JP.yml                              |  2 ++
 packages/frontend/src/pages/settings/drive.vue |  5 +++++
 packages/frontend/src/scripts/upload.ts        | 10 +++++++---
 packages/frontend/src/store.ts                 |  4 ++++
 6 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ab4ecb3ffe..1332da69f9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@
 - Fix: Play作成時に設定した公開範囲が機能していない問題を修正
 
 ### Client
+- Feat: アップロードするファイルの名前をランダム文字列にできるように
 - Enhance: 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるように
 - Enhance: 広告がMisskeyと同一ドメインの場合はRouterで遷移するように
 - Enhance: リアクション・いいねの総数を表示するように
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 54f0285726..d6875c0868 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -4936,6 +4936,14 @@ export interface Locale extends ILocale {
      * 動画・音声の再生にブラウザのUIを使用する
      */
     "useNativeUIForVideoAudioPlayer": string;
+    /**
+     * オリジナルのファイル名を保持
+     */
+    "keepOriginalFilename": string;
+    /**
+     * この設定をオフにすると、アップロード時にファイル名が自動でランダム文字列に置き換えられます。
+     */
+    "keepOriginalFilenameDescription": string;
     "_bubbleGame": {
         /**
          * 遊び方
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index ac88420b9d..0b581a01e3 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1230,6 +1230,8 @@ useTotp: "ワンタイムパスワードを使う"
 useBackupCode: "バックアップコードを使う"
 launchApp: "アプリを起動"
 useNativeUIForVideoAudioPlayer: "動画・音声の再生にブラウザのUIを使用する"
+keepOriginalFilename: "オリジナルのファイル名を保持"
+keepOriginalFilenameDescription: "この設定をオフにすると、アップロード時にファイル名が自動でランダム文字列に置き換えられます。"
 
 _bubbleGame:
   howToPlay: "遊び方"
diff --git a/packages/frontend/src/pages/settings/drive.vue b/packages/frontend/src/pages/settings/drive.vue
index 1919f80864..81a8d474d2 100644
--- a/packages/frontend/src/pages/settings/drive.vue
+++ b/packages/frontend/src/pages/settings/drive.vue
@@ -44,6 +44,10 @@ SPDX-License-Identifier: AGPL-3.0-only
 				<template #label>{{ i18n.ts.keepOriginalUploading }}</template>
 				<template #caption>{{ i18n.ts.keepOriginalUploadingDescription }}</template>
 			</MkSwitch>
+			<MkSwitch v-model="keepOriginalFilename">
+				<template #label>{{ i18n.ts.keepOriginalFilename }}</template>
+				<template #caption>{{ i18n.ts.keepOriginalFilenameDescription }}</template>
+			</MkSwitch>
 			<MkSwitch v-model="alwaysMarkNsfw" @update:modelValue="saveProfile()">
 				<template #label>{{ i18n.ts.alwaysMarkSensitive }}</template>
 			</MkSwitch>
@@ -96,6 +100,7 @@ const meterStyle = computed(() => {
 });
 
 const keepOriginalUploading = computed(defaultStore.makeGetterSetter('keepOriginalUploading'));
+const keepOriginalFilename = computed(defaultStore.makeGetterSetter('keepOriginalFilename'));
 
 misskeyApi('drive').then(info => {
 	capacity.value = info.capacity;
diff --git a/packages/frontend/src/scripts/upload.ts b/packages/frontend/src/scripts/upload.ts
index 6c46b2bc1b..3e947183c9 100644
--- a/packages/frontend/src/scripts/upload.ts
+++ b/packages/frontend/src/scripts/upload.ts
@@ -5,6 +5,7 @@
 
 import { reactive, ref } from 'vue';
 import * as Misskey from 'misskey-js';
+import { v4 as uuid } from 'uuid';
 import { readAndCompressImage } from '@misskey-dev/browser-image-resizer';
 import { getCompressionConfig } from './upload/compress-config.js';
 import { defaultStore } from '@/store.js';
@@ -39,13 +40,16 @@ export function uploadFile(
 	if (folder && typeof folder === 'object') folder = folder.id;
 
 	return new Promise((resolve, reject) => {
-		const id = Math.random().toString();
+		const id = uuid();
 
 		const reader = new FileReader();
 		reader.onload = async (): Promise<void> => {
+			const filename = name ?? file.name ?? 'untitled';
+			const extension = filename.split('.').length > 1 ? '.' + filename.split('.').pop() : '';
+
 			const ctx = reactive<Uploading>({
-				id: id,
-				name: name ?? file.name ?? 'untitled',
+				id,
+				name: defaultStore.state.keepOriginalFilename ? filename : id + extension,
 				progressMax: undefined,
 				progressValue: undefined,
 				img: window.URL.createObjectURL(file),
diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts
index faefbd8ce4..9b5011739a 100644
--- a/packages/frontend/src/store.ts
+++ b/packages/frontend/src/store.ts
@@ -446,6 +446,10 @@ export const defaultStore = markRaw(new Storage('base', {
 		where: 'device',
 		default: false,
 	},
+	keepOriginalFilename: {
+		where: 'device',
+		default: true,
+	},
 
 	sound_masterVolume: {
 		where: 'device',

From 5c7c44c9ebd12e9ae0dd6d7fab8f6dd78ba54eb7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sat, 13 Apr 2024 20:38:25 +0900
Subject: [PATCH 073/191] =?UTF-8?q?fix(backend):=20=E7=99=BB=E9=8C=B2?=
 =?UTF-8?q?=E3=81=AB=E3=83=A1=E3=83=BC=E3=83=AB=E8=AA=8D=E8=A8=BC=E3=81=8C?=
 =?UTF-8?q?=E5=BF=85=E9=A0=88=E3=81=AB=E3=81=AA=E3=81=A3=E3=81=A6=E3=81=84?=
 =?UTF-8?q?=E3=82=8B=E5=A0=B4=E5=90=88=E3=80=81=E7=99=BB=E9=8C=B2=E3=81=95?=
 =?UTF-8?q?=E3=82=8C=E3=81=A6=E3=81=84=E3=82=8B=E3=83=A1=E3=83=BC=E3=83=AB?=
 =?UTF-8?q?=E3=82=A2=E3=83=89=E3=83=AC=E3=82=B9=E3=82=92=E5=89=8A=E9=99=A4?=
 =?UTF-8?q?=E3=81=A7=E3=81=8D=E3=81=AA=E3=81=84=E3=82=88=E3=81=86=E3=81=AB?=
 =?UTF-8?q?=20(#13703)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(backend): 登録にメール認証が必須になっている場合、登録されているメールアドレスを削除できないように (MisskeyIO#606)

(cherry picked from commit 6b7df2bd10dc28b84f525a621b66fc49bf59cac6)

* Update Changelog

---------

Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com>
---
 CHANGELOG.md                                           |  2 ++
 .../backend/src/server/api/endpoints/i/update-email.ts | 10 ++++++++++
 2 files changed, 12 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1332da69f9..d184a0b398 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -48,6 +48,8 @@
 - Fix: エンドポイント`notes/translate`のエラーを改善
 - Fix: CleanRemoteFilesProcessorService report progress from 100% (#13632)
 - Fix: 一部の音声ファイルが映像ファイルとして扱われる問題を修正
+- Fix: 登録にメール認証が必須になっている場合、登録されているメールアドレスを削除できないように  
+  (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/606)
 
 ## 2024.3.1
 
diff --git a/packages/backend/src/server/api/endpoints/i/update-email.ts b/packages/backend/src/server/api/endpoints/i/update-email.ts
index 3868278690..eea657ebbd 100644
--- a/packages/backend/src/server/api/endpoints/i/update-email.ts
+++ b/packages/backend/src/server/api/endpoints/i/update-email.ts
@@ -15,6 +15,7 @@ import { DI } from '@/di-symbols.js';
 import { GlobalEventService } from '@/core/GlobalEventService.js';
 import { L_CHARS, secureRndstr } from '@/misc/secure-rndstr.js';
 import { UserAuthService } from '@/core/UserAuthService.js';
+import { MetaService } from '@/core/MetaService.js';
 import { ApiError } from '../../error.js';
 
 export const meta = {
@@ -39,6 +40,12 @@ export const meta = {
 			code: 'UNAVAILABLE',
 			id: 'a2defefb-f220-8849-0af6-17f816099323',
 		},
+
+		emailRequired: {
+			message: 'Email address is required.',
+			code: 'EMAIL_REQUIRED',
+			id: '324c7a88-59f2-492f-903f-89134f93e47e',
+		},
 	},
 
 	res: {
@@ -66,6 +73,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 		@Inject(DI.userProfilesRepository)
 		private userProfilesRepository: UserProfilesRepository,
 
+		private metaService: MetaService,
 		private userEntityService: UserEntityService,
 		private emailService: EmailService,
 		private userAuthService: UserAuthService,
@@ -97,6 +105,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				if (!res.available) {
 					throw new ApiError(meta.errors.unavailable);
 				}
+			} else if ((await this.metaService.fetch()).emailRequiredForSignup) {
+				throw new ApiError(meta.errors.emailRequired);
 			}
 
 			await this.userProfilesRepository.update(me.id, {

From 48a7679b8a8b3df80d7f90ac6f4a852f47a8df22 Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Sun, 14 Apr 2024 08:08:26 +0900
Subject: [PATCH 074/191] test: do not use indexedDB in cypress environment due
 to chrome bug (#13709)

---
 cypress/support/commands.ts                |  4 ++++
 packages/frontend/src/scripts/idb-proxy.ts | 10 ++++++++++
 2 files changed, 14 insertions(+)

diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts
index c2d92e1663..281f2e6ccd 100644
--- a/cypress/support/commands.ts
+++ b/cypress/support/commands.ts
@@ -30,9 +30,13 @@ Cypress.Commands.add('visitHome', () => {
 })
 
 Cypress.Commands.add('resetState', () => {
+	// iframe.contentWindow.indexedDB.deleteDatabase() がchromeのバグで使用できないため、indexedDBを無効化している。
+	// see https://github.com/misskey-dev/misskey/issues/13605#issuecomment-2053652123
+	/*
 	cy.window().then(win => {
 		win.indexedDB.deleteDatabase('keyval-store');
 	});
+	 */
 	cy.request('POST', '/api/reset-db', {}).as('reset');
 	cy.get('@reset').its('status').should('equal', 204);
 	cy.reload(true);
diff --git a/packages/frontend/src/scripts/idb-proxy.ts b/packages/frontend/src/scripts/idb-proxy.ts
index 1ca0990ba9..6b511f2a5f 100644
--- a/packages/frontend/src/scripts/idb-proxy.ts
+++ b/packages/frontend/src/scripts/idb-proxy.ts
@@ -15,6 +15,16 @@ const fallbackName = (key: string) => `idbfallback::${key}`;
 
 let idbAvailable = typeof window !== 'undefined' ? !!(window.indexedDB && window.indexedDB.open) : true;
 
+// iframe.contentWindow.indexedDB.deleteDatabase() がchromeのバグで使用できないため、indexedDBを無効化している。
+// バグが治って再度有効化するのであれば、cypressのコマンド内のコメントアウトを外すこと
+// see https://github.com/misskey-dev/misskey/issues/13605#issuecomment-2053652123
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-expect-error
+if (window.Cypress) {
+	idbAvailable = false;
+	console.log('Cypress detected. It will use localStorage.');
+}
+
 if (idbAvailable) {
 	await iset('idb-test', 'test')
 		.catch(err => {

From 7cf0c18f83f82416c9b1bb5bca5b669e77240527 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sun, 14 Apr 2024 10:22:03 +0900
Subject: [PATCH 075/191] =?UTF-8?q?fix(backend):=20FileServerService?=
 =?UTF-8?q?=E3=81=A7=E3=83=AC=E3=83=B3=E3=82=B8=E3=83=AA=E3=82=AF=E3=82=A8?=
 =?UTF-8?q?=E3=82=B9=E3=83=88=E3=81=AE=E5=A0=B4=E5=90=88=E3=81=AB=E9=81=A9?=
 =?UTF-8?q?=E5=88=87=E3=81=AA=E3=83=AC=E3=82=B9=E3=83=9D=E3=83=B3=E3=82=B9?=
 =?UTF-8?q?=E3=82=B3=E3=83=BC=E3=83=89=E3=81=8C=E8=BF=94=E3=82=89=E3=81=AA?=
 =?UTF-8?q?=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3=20(#1370?=
 =?UTF-8?q?1)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* return 206 for every ranged response - fixes #494

(cherry picked from commit 92eec2178fd103e9ea2bcd646aacab1fb496a33b)

* detect size of remote files - fixes #494

without this, remote files are assumed to have size 0 (even if we just
downloaded them!) and the range-related code won't run

(cherry picked from commit 960f4fcff78a1f019c9a9377853fcd90dbfb7575)

---------

Co-authored-by: dakkar <dakkar@thenautilus.net>
---
 packages/backend/src/server/FileServerService.ts | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts
index f51d7aebca..ce7702143e 100644
--- a/packages/backend/src/server/FileServerService.ts
+++ b/packages/backend/src/server/FileServerService.ts
@@ -194,6 +194,7 @@ export class FileServerService {
 						reply.header('Content-Range', `bytes ${start}-${end}/${file.file.size}`);
 						reply.header('Accept-Ranges', 'bytes');
 						reply.header('Content-Length', chunksize);
+						reply.code(206);
 					} else {
 						image = {
 							data: fs.createReadStream(file.path),
@@ -263,7 +264,6 @@ export class FileServerService {
 					const parts = range.replace(/bytes=/, '').split('-');
 					const start = parseInt(parts[0], 10);
 					let end = parts[1] ? parseInt(parts[1], 10) : file.file.size - 1;
-					console.log(end);
 					if (end > file.file.size) {
 						end = file.file.size - 1;
 					}
@@ -433,6 +433,7 @@ export class FileServerService {
 					reply.header('Content-Range', `bytes ${start}-${end}/${file.file.size}`);
 					reply.header('Accept-Ranges', 'bytes');
 					reply.header('Content-Length', chunksize);
+					reply.code(206);
 				} else {
 					image = {
 						data: fs.createReadStream(file.path),
@@ -529,6 +530,9 @@ export class FileServerService {
 		if (!file.storedInternal) {
 			if (!(file.isLink && file.uri)) return '204';
 			const result = await this.downloadAndDetectTypeFromUrl(file.uri);
+			if (!file.size) {
+				file.size = (await fs.promises.stat(result.path)).size;
+			}
 			return {
 				...result,
 				url: file.uri,

From 8c5d9a6295ab506b935bbd5856894239997a8158 Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Sun, 14 Apr 2024 10:23:48 +0900
Subject: [PATCH 076/191] fix(backend): incorrect logic for determining whether
 Quote or not (#13700)

* fix(backend): incorrect logic for determining whether Quote or not

* Update CHANGELOG.md

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 CHANGELOG.md                                  |   1 +
 .../src/core/FanoutTimelineEndpointService.ts |   6 +-
 .../backend/src/core/NoteCreateService.ts     |  23 ++-
 .../backend/src/core/NoteDeleteService.ts     |   4 +-
 packages/backend/src/misc/is-pure-renote.ts   |  15 --
 packages/backend/src/misc/is-quote.ts         |  12 --
 packages/backend/src/misc/is-renote.ts        |  36 +++++
 .../src/server/ActivityPubServerService.ts    |   4 +-
 .../src/server/api/endpoints/notes/create.ts  |   6 +-
 .../backend/test/unit/NoteCreateService.ts    | 144 ++++++++++++++++++
 packages/backend/test/unit/misc/is-renote.ts  |  88 +++++++++++
 11 files changed, 296 insertions(+), 43 deletions(-)
 delete mode 100644 packages/backend/src/misc/is-pure-renote.ts
 delete mode 100644 packages/backend/src/misc/is-quote.ts
 create mode 100644 packages/backend/src/misc/is-renote.ts
 create mode 100644 packages/backend/test/unit/NoteCreateService.ts
 create mode 100644 packages/backend/test/unit/misc/is-renote.ts

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d184a0b398..47e8e0cf19 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -48,6 +48,7 @@
 - Fix: エンドポイント`notes/translate`のエラーを改善
 - Fix: CleanRemoteFilesProcessorService report progress from 100% (#13632)
 - Fix: 一部の音声ファイルが映像ファイルとして扱われる問題を修正
+- Fix: リプライのみの引用リノートと、CWのみの引用リノートが純粋なリノートとして誤って扱われてしまう問題を修正
 - Fix: 登録にメール認証が必須になっている場合、登録されているメールアドレスを削除できないように  
   (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/606)
 
diff --git a/packages/backend/src/core/FanoutTimelineEndpointService.ts b/packages/backend/src/core/FanoutTimelineEndpointService.ts
index 9c239b4dfc..006433df7a 100644
--- a/packages/backend/src/core/FanoutTimelineEndpointService.ts
+++ b/packages/backend/src/core/FanoutTimelineEndpointService.ts
@@ -13,7 +13,7 @@ import type { NotesRepository } from '@/models/_.js';
 import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
 import { FanoutTimelineName, FanoutTimelineService } from '@/core/FanoutTimelineService.js';
 import { isUserRelated } from '@/misc/is-user-related.js';
-import { isPureRenote } from '@/misc/is-pure-renote.js';
+import { isQuote, isRenote } from '@/misc/is-renote.js';
 import { CacheService } from '@/core/CacheService.js';
 import { isReply } from '@/misc/is-reply.js';
 import { isInstanceMuted } from '@/misc/is-instance-muted.js';
@@ -95,7 +95,7 @@ export class FanoutTimelineEndpointService {
 
 			if (ps.excludePureRenotes) {
 				const parentFilter = filter;
-				filter = (note) => !isPureRenote(note) && parentFilter(note);
+				filter = (note) => (!isRenote(note) || isQuote(note)) && parentFilter(note);
 			}
 
 			if (ps.me) {
@@ -116,7 +116,7 @@ export class FanoutTimelineEndpointService {
 				filter = (note) => {
 					if (isUserRelated(note, userIdsWhoBlockingMe, ps.ignoreAuthorFromBlock)) return false;
 					if (isUserRelated(note, userIdsWhoMeMuting, ps.ignoreAuthorFromMute)) return false;
-					if (isPureRenote(note) && isUserRelated(note, userIdsWhoMeMutingRenotes, ps.ignoreAuthorFromMute)) return false;
+					if (isRenote(note) && !isQuote(note) && isUserRelated(note, userIdsWhoMeMutingRenotes, ps.ignoreAuthorFromMute)) return false;
 					if (isInstanceMuted(note, userMutedInstances)) return false;
 
 					return parentFilter(note);
diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts
index 81ae2908d3..32104fea90 100644
--- a/packages/backend/src/core/NoteCreateService.ts
+++ b/packages/backend/src/core/NoteCreateService.ts
@@ -306,7 +306,7 @@ export class NoteCreateService implements OnApplicationShutdown {
 		}
 
 		// Check blocking
-		if (data.renote && !this.isQuote(data)) {
+		if (this.isRenote(data) && !this.isQuote(data)) {
 			if (data.renote.userHost === null) {
 				if (data.renote.userId !== user.id) {
 					const blocked = await this.userBlockingService.checkBlocked(data.renote.userId, user.id);
@@ -641,7 +641,7 @@ export class NoteCreateService implements OnApplicationShutdown {
 			}
 
 			// If it is renote
-			if (data.renote) {
+			if (this.isRenote(data)) {
 				const type = this.isQuote(data) ? 'quote' : 'renote';
 
 				// Notify
@@ -725,9 +725,20 @@ export class NoteCreateService implements OnApplicationShutdown {
 	}
 
 	@bindThis
-	private isQuote(note: Option): note is Option & { renote: MiNote } {
-		// sync with misc/is-quote.ts
-		return !!note.renote && (!!note.text || !!note.cw || (!!note.files && !!note.files.length) || !!note.poll);
+	private isRenote(note: Option): note is Option & { renote: MiNote } {
+		return note.renote != null;
+	}
+
+	@bindThis
+	private isQuote(note: Option & { renote: MiNote }): note is Option & { renote: MiNote } & (
+		{ text: string } | { cw: string } | { reply: MiNote } | { poll: IPoll } | { files: MiDriveFile[] }
+	) {
+		// NOTE: SYNC WITH misc/is-quote.ts
+		return note.text != null ||
+			note.reply != null ||
+			note.cw != null ||
+			note.poll != null ||
+			(note.files != null && note.files.length > 0);
 	}
 
 	@bindThis
@@ -795,7 +806,7 @@ export class NoteCreateService implements OnApplicationShutdown {
 	private async renderNoteOrRenoteActivity(data: Option, note: MiNote) {
 		if (data.localOnly) return null;
 
-		const content = data.renote && !this.isQuote(data)
+		const content = this.isRenote(data) && !this.isQuote(data)
 			? this.apRendererService.renderAnnounce(data.renote.uri ? data.renote.uri : `${this.config.url}/notes/${data.renote.id}`, note)
 			: this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, false), note);
 
diff --git a/packages/backend/src/core/NoteDeleteService.ts b/packages/backend/src/core/NoteDeleteService.ts
index fdf843c3e8..801ed02e00 100644
--- a/packages/backend/src/core/NoteDeleteService.ts
+++ b/packages/backend/src/core/NoteDeleteService.ts
@@ -24,7 +24,7 @@ import { bindThis } from '@/decorators.js';
 import { MetaService } from '@/core/MetaService.js';
 import { SearchService } from '@/core/SearchService.js';
 import { ModerationLogService } from '@/core/ModerationLogService.js';
-import { isPureRenote } from '@/misc/is-pure-renote.js';
+import { isQuote, isRenote } from '@/misc/is-renote.js';
 
 @Injectable()
 export class NoteDeleteService {
@@ -79,7 +79,7 @@ export class NoteDeleteService {
 				let renote: MiNote | null = null;
 
 				// if deleted note is renote
-				if (isPureRenote(note)) {
+				if (isRenote(note) && !isQuote(note)) {
 					renote = await this.notesRepository.findOneBy({
 						id: note.renoteId,
 					});
diff --git a/packages/backend/src/misc/is-pure-renote.ts b/packages/backend/src/misc/is-pure-renote.ts
deleted file mode 100644
index f9c2243a06..0000000000
--- a/packages/backend/src/misc/is-pure-renote.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import type { MiNote } from '@/models/Note.js';
-
-export function isPureRenote(note: MiNote): note is MiNote & { renoteId: NonNullable<MiNote['renoteId']> } {
-	if (!note.renoteId) return false;
-
-	if (note.text) return false; // it's quoted with text
-	if (note.fileIds.length !== 0) return false; // it's quoted with files
-	if (note.hasPoll) return false; // it's quoted with poll
-	return true;
-}
diff --git a/packages/backend/src/misc/is-quote.ts b/packages/backend/src/misc/is-quote.ts
deleted file mode 100644
index 75b29f63f4..0000000000
--- a/packages/backend/src/misc/is-quote.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import type { MiNote } from '@/models/Note.js';
-
-// eslint-disable-next-line import/no-default-export
-export default function(note: MiNote): boolean {
-	// sync with NoteCreateService.isQuote
-	return note.renoteId != null && (note.text != null || note.hasPoll || (note.fileIds != null && note.fileIds.length > 0));
-}
diff --git a/packages/backend/src/misc/is-renote.ts b/packages/backend/src/misc/is-renote.ts
new file mode 100644
index 0000000000..5d48aba360
--- /dev/null
+++ b/packages/backend/src/misc/is-renote.ts
@@ -0,0 +1,36 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import type { MiNote } from '@/models/Note.js';
+
+type Renote =
+	MiNote & {
+		renoteId: NonNullable<MiNote['renoteId']>
+	};
+
+type Quote =
+	Renote & ({
+		text: NonNullable<MiNote['text']>
+	} | {
+		cw: NonNullable<MiNote['cw']>
+	} | {
+		replyId: NonNullable<MiNote['replyId']>
+		reply: NonNullable<MiNote['reply']>
+	} | {
+		hasPoll: true
+	});
+
+export function isRenote(note: MiNote): note is Renote {
+	return note.renoteId != null;
+}
+
+export function isQuote(note: Renote): note is Quote {
+	// NOTE: SYNC WITH NoteCreateService.isQuote
+	return note.text != null ||
+		note.cw != null ||
+		note.replyId != null ||
+		note.hasPoll ||
+		note.fileIds.length > 0;
+}
diff --git a/packages/backend/src/server/ActivityPubServerService.ts b/packages/backend/src/server/ActivityPubServerService.ts
index 60366dd5c2..3255d64621 100644
--- a/packages/backend/src/server/ActivityPubServerService.ts
+++ b/packages/backend/src/server/ActivityPubServerService.ts
@@ -28,7 +28,7 @@ import { UtilityService } from '@/core/UtilityService.js';
 import { UserEntityService } from '@/core/entities/UserEntityService.js';
 import { bindThis } from '@/decorators.js';
 import { IActivity } from '@/core/activitypub/type.js';
-import { isPureRenote } from '@/misc/is-pure-renote.js';
+import { isQuote, isRenote } from '@/misc/is-renote.js';
 import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions, FastifyBodyParser } from 'fastify';
 import type { FindOptionsWhere } from 'typeorm';
 
@@ -91,7 +91,7 @@ export class ActivityPubServerService {
 	 */
 	@bindThis
 	private async packActivity(note: MiNote): Promise<any> {
-		if (isPureRenote(note)) {
+		if (isRenote(note) && !isQuote(note)) {
 			const renote = await this.notesRepository.findOneByOrFail({ id: note.renoteId });
 			return this.apRendererService.renderAnnounce(renote.uri ? renote.uri : `${this.config.url}/notes/${renote.id}`, note);
 		}
diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts
index bfb9214439..beb77ca7ab 100644
--- a/packages/backend/src/server/api/endpoints/notes/create.ts
+++ b/packages/backend/src/server/api/endpoints/notes/create.ts
@@ -16,7 +16,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
 import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
 import { NoteCreateService } from '@/core/NoteCreateService.js';
 import { DI } from '@/di-symbols.js';
-import { isPureRenote } from '@/misc/is-pure-renote.js';
+import { isQuote, isRenote } from '@/misc/is-renote.js';
 import { MetaService } from '@/core/MetaService.js';
 import { UtilityService } from '@/core/UtilityService.js';
 import { IdentifiableError } from '@/misc/identifiable-error.js';
@@ -275,7 +275,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 
 				if (renote == null) {
 					throw new ApiError(meta.errors.noSuchRenoteTarget);
-				} else if (isPureRenote(renote)) {
+				} else if (isRenote(renote) && !isQuote(renote)) {
 					throw new ApiError(meta.errors.cannotReRenote);
 				}
 
@@ -321,7 +321,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 
 				if (reply == null) {
 					throw new ApiError(meta.errors.noSuchReplyTarget);
-				} else if (isPureRenote(reply)) {
+				} else if (isRenote(reply) && !isQuote(reply)) {
 					throw new ApiError(meta.errors.cannotReplyToPureRenote);
 				} else if (!await this.noteEntityService.isVisibleForMe(reply, me.id)) {
 					throw new ApiError(meta.errors.cannotReplyToInvisibleNote);
diff --git a/packages/backend/test/unit/NoteCreateService.ts b/packages/backend/test/unit/NoteCreateService.ts
new file mode 100644
index 0000000000..f2d4c8ffbb
--- /dev/null
+++ b/packages/backend/test/unit/NoteCreateService.ts
@@ -0,0 +1,144 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Test } from '@nestjs/testing';
+
+import { CoreModule } from '@/core/CoreModule.js';
+import { NoteCreateService } from '@/core/NoteCreateService.js';
+import { GlobalModule } from '@/GlobalModule.js';
+import { MiNote } from '@/models/Note.js';
+import { IPoll } from '@/models/Poll.js';
+import { MiDriveFile } from '@/models/DriveFile.js';
+
+describe('NoteCreateService', () => {
+	let noteCreateService: NoteCreateService;
+
+	beforeAll(async () => {
+		const app = await Test.createTestingModule({
+			imports: [GlobalModule, CoreModule],
+		}).compile();
+		noteCreateService = app.get<NoteCreateService>(NoteCreateService);
+	});
+
+	describe('is-renote', () => {
+		const base: MiNote = {
+			id: 'some-note-id',
+			replyId: null,
+			reply: null,
+			renoteId: null,
+			renote: null,
+			threadId: null,
+			text: null,
+			name: null,
+			cw: null,
+			userId: 'some-user-id',
+			user: null,
+			localOnly: false,
+			reactionAcceptance: null,
+			renoteCount: 0,
+			repliesCount: 0,
+			clippedCount: 0,
+			reactions: {},
+			visibility: 'public',
+			uri: null,
+			url: null,
+			fileIds: [],
+			attachedFileTypes: [],
+			visibleUserIds: [],
+			mentions: [],
+			mentionedRemoteUsers: '',
+			reactionAndUserPairCache: [],
+			emojis: [],
+			tags: [],
+			hasPoll: false,
+			channelId: null,
+			channel: null,
+			userHost: null,
+			replyUserId: null,
+			replyUserHost: null,
+			renoteUserId: null,
+			renoteUserHost: null,
+		};
+
+		const poll: IPoll = {
+			choices: ['kinoko', 'takenoko'],
+			multiple: false,
+			expiresAt: null,
+		};
+
+		const file: MiDriveFile = {
+			id: 'some-file-id',
+			userId: null,
+			user: null,
+			userHost: null,
+			md5: '',
+			name: '',
+			type: '',
+			size: 0,
+			comment: null,
+			blurhash: null,
+			properties: {},
+			storedInternal: false,
+			url: '',
+			thumbnailUrl: null,
+			webpublicUrl: null,
+			webpublicType: null,
+			accessKey: null,
+			thumbnailAccessKey: null,
+			webpublicAccessKey: null,
+			uri: null,
+			src: null,
+			folderId: null,
+			folder: null,
+			isSensitive: false,
+			maybeSensitive: false,
+			maybePorn: false,
+			isLink: false,
+			requestHeaders: null,
+			requestIp: null,
+		};
+
+		test('note without renote should not be Renote', () => {
+			const note = { renote: null };
+			expect(noteCreateService['isRenote'](note)).toBe(false);
+		});
+
+		test('note with renote should be Renote and not be Quote', () => {
+			const note = { renote: base };
+			expect(noteCreateService['isRenote'](note)).toBe(true);
+			expect(noteCreateService['isQuote'](note)).toBe(false);
+		});
+
+		test('note with renote and text should be Quote', () => {
+			const note = { renote: base, text: 'some-text' };
+			expect(noteCreateService['isRenote'](note)).toBe(true);
+			expect(noteCreateService['isQuote'](note)).toBe(true);
+		});
+
+		test('note with renote and cw should be Quote', () => {
+			const note = { renote: base, cw: 'some-cw' };
+			expect(noteCreateService['isRenote'](note)).toBe(true);
+			expect(noteCreateService['isQuote'](note)).toBe(true);
+		});
+
+		test('note with renote and reply should be Quote', () => {
+			const note = { renote: base, reply: { ...base, id: 'another-note-id' } };
+			expect(noteCreateService['isRenote'](note)).toBe(true);
+			expect(noteCreateService['isQuote'](note)).toBe(true);
+		});
+
+		test('note with renote and poll should be Quote', () => {
+			const note = { renote: base, poll };
+			expect(noteCreateService['isRenote'](note)).toBe(true);
+			expect(noteCreateService['isQuote'](note)).toBe(true);
+		});
+
+		test('note with renote and non-empty files should be Quote', () => {
+			const note = { renote: base, files: [file] };
+			expect(noteCreateService['isRenote'](note)).toBe(true);
+			expect(noteCreateService['isQuote'](note)).toBe(true);
+		});
+	});
+});
diff --git a/packages/backend/test/unit/misc/is-renote.ts b/packages/backend/test/unit/misc/is-renote.ts
new file mode 100644
index 0000000000..0b713e8bf6
--- /dev/null
+++ b/packages/backend/test/unit/misc/is-renote.ts
@@ -0,0 +1,88 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { isQuote, isRenote } from '@/misc/is-renote.js';
+import { MiNote } from '@/models/Note.js';
+
+const base: MiNote = {
+	id: 'some-note-id',
+	replyId: null,
+	reply: null,
+	renoteId: null,
+	renote: null,
+	threadId: null,
+	text: null,
+	name: null,
+	cw: null,
+	userId: 'some-user-id',
+	user: null,
+	localOnly: false,
+	reactionAcceptance: null,
+	renoteCount: 0,
+	repliesCount: 0,
+	clippedCount: 0,
+	reactions: {},
+	visibility: 'public',
+	uri: null,
+	url: null,
+	fileIds: [],
+	attachedFileTypes: [],
+	visibleUserIds: [],
+	mentions: [],
+	mentionedRemoteUsers: '',
+	reactionAndUserPairCache: [],
+	emojis: [],
+	tags: [],
+	hasPoll: false,
+	channelId: null,
+	channel: null,
+	userHost: null,
+	replyUserId: null,
+	replyUserHost: null,
+	renoteUserId: null,
+	renoteUserHost: null,
+};
+
+describe('misc:is-renote', () => {
+	test('note without renoteId should not be Renote', () => {
+		expect(isRenote(base)).toBe(false);
+	});
+
+	test('note with renoteId should be Renote and not be Quote', () => {
+		const note: MiNote = { ...base, renoteId: 'some-renote-id' };
+		expect(isRenote(note)).toBe(true);
+		expect(isQuote(note as any)).toBe(false);
+	});
+
+	test('note with renoteId and text should be Quote', () => {
+		const note: MiNote = { ...base, renoteId: 'some-renote-id', text: 'some-text' };
+		expect(isRenote(note)).toBe(true);
+		expect(isQuote(note as any)).toBe(true);
+	});
+
+	test('note with renoteId and cw should be Quote', () => {
+		const note: MiNote = { ...base, renoteId: 'some-renote-id', cw: 'some-cw' };
+		expect(isRenote(note)).toBe(true);
+		expect(isQuote(note as any)).toBe(true);
+	});
+
+	test('note with renoteId and replyId should be Quote', () => {
+		const note: MiNote = { ...base, renoteId: 'some-renote-id', replyId: 'some-reply-id' };
+		expect(isRenote(note)).toBe(true);
+		expect(isQuote(note as any)).toBe(true);
+	});
+
+	test('note with renoteId and poll should be Quote', () => {
+		const note: MiNote = { ...base, renoteId: 'some-renote-id', hasPoll: true };
+		expect(isRenote(note)).toBe(true);
+		expect(isQuote(note as any)).toBe(true);
+	});
+
+	test('note with renoteId and non-empty fileIds should be Quote', () => {
+		const note: MiNote = { ...base, renoteId: 'some-renote-id', fileIds: ['some-file-id'] };
+		expect(isRenote(note)).toBe(true);
+		expect(isQuote(note as any)).toBe(true);
+	});
+});

From bba3097765317cbf95d09627961b5b5dce16a972 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sun, 14 Apr 2024 21:30:24 +0900
Subject: [PATCH 077/191] =?UTF-8?q?enhance:=20=E3=82=AF=E3=83=AA=E3=83=83?=
 =?UTF-8?q?=E3=83=97=E3=81=AE=E3=83=8E=E3=83=BC=E3=83=88=E6=95=B0=E3=82=92?=
 =?UTF-8?q?=E8=A1=A8=E7=A4=BA=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?=
 =?UTF-8?q?=20(#13686)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance: クリップのノート数を表示できるように

* Update Changelog
---
 CHANGELOG.md                                  |  1 +
 locales/index.d.ts                            |  4 ++
 locales/ja-JP.yml                             |  1 +
 .../src/core/entities/ClipEntityService.ts    |  6 ++-
 .../backend/src/models/json-schema/clip.ts    |  4 ++
 .../frontend/src/components/MkClipPreview.vue | 52 +++++++++++++------
 packages/frontend/src/pages/clip.vue          | 13 +++--
 .../frontend/src/pages/my-clips/index.vue     | 10 ++--
 packages/frontend/src/pages/note.vue          |  4 +-
 .../frontend/src/scripts/get-note-menu.ts     | 36 +++++++++++--
 packages/misskey-js/src/autogen/types.ts      |  1 +
 11 files changed, 99 insertions(+), 33 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 47e8e0cf19..a238d99a06 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
 - Enhance: URLプレビューの有効化・無効化を設定できるように #13569
 - Enhance: アンテナでBotによるノートを除外できるように  
   (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/545)
+- Enhance: クリップのノート数を表示するように
 - Fix: Play作成時に設定した公開範囲が機能していない問題を修正
 
 ### Client
diff --git a/locales/index.d.ts b/locales/index.d.ts
index d6875c0868..cbea39f1cd 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -4944,6 +4944,10 @@ export interface Locale extends ILocale {
      * この設定をオフにすると、アップロード時にファイル名が自動でランダム文字列に置き換えられます。
      */
     "keepOriginalFilenameDescription": string;
+    /**
+     * 説明文はありません
+     */
+    "noDescription": string;
     "_bubbleGame": {
         /**
          * 遊び方
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 0b581a01e3..4ab2f5adb0 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1232,6 +1232,7 @@ launchApp: "アプリを起動"
 useNativeUIForVideoAudioPlayer: "動画・音声の再生にブラウザのUIを使用する"
 keepOriginalFilename: "オリジナルのファイル名を保持"
 keepOriginalFilenameDescription: "この設定をオフにすると、アップロード時にファイル名が自動でランダム文字列に置き換えられます。"
+noDescription: "説明文はありません"
 
 _bubbleGame:
   howToPlay: "遊び方"
diff --git a/packages/backend/src/core/entities/ClipEntityService.ts b/packages/backend/src/core/entities/ClipEntityService.ts
index 26fcd6714d..ce49c3458c 100644
--- a/packages/backend/src/core/entities/ClipEntityService.ts
+++ b/packages/backend/src/core/entities/ClipEntityService.ts
@@ -5,7 +5,7 @@
 
 import { Inject, Injectable } from '@nestjs/common';
 import { DI } from '@/di-symbols.js';
-import type { ClipFavoritesRepository, ClipsRepository, MiUser } from '@/models/_.js';
+import type { ClipNotesRepository, ClipFavoritesRepository, ClipsRepository, MiUser } from '@/models/_.js';
 import { awaitAll } from '@/misc/prelude/await-all.js';
 import type { Packed } from '@/misc/json-schema.js';
 import type { } from '@/models/Blocking.js';
@@ -20,6 +20,9 @@ export class ClipEntityService {
 		@Inject(DI.clipsRepository)
 		private clipsRepository: ClipsRepository,
 
+		@Inject(DI.clipNotesRepository)
+		private clipNotesRepository: ClipNotesRepository,
+
 		@Inject(DI.clipFavoritesRepository)
 		private clipFavoritesRepository: ClipFavoritesRepository,
 
@@ -47,6 +50,7 @@ export class ClipEntityService {
 			isPublic: clip.isPublic,
 			favoritedCount: await this.clipFavoritesRepository.countBy({ clipId: clip.id }),
 			isFavorited: meId ? await this.clipFavoritesRepository.exists({ where: { clipId: clip.id, userId: meId } }) : undefined,
+			notesCount: meId ? await this.clipNotesRepository.countBy({ clipId: clip.id }) : undefined,
 		});
 	}
 
diff --git a/packages/backend/src/models/json-schema/clip.ts b/packages/backend/src/models/json-schema/clip.ts
index ca4886c978..c4e7055cd8 100644
--- a/packages/backend/src/models/json-schema/clip.ts
+++ b/packages/backend/src/models/json-schema/clip.ts
@@ -52,5 +52,9 @@ export const packedClipSchema = {
 			type: 'boolean',
 			optional: true, nullable: false,
 		},
+		notesCount: {
+			type: 'integer',
+			optional: true, nullable: false,
+		},
 	},
 } as const;
diff --git a/packages/frontend/src/components/MkClipPreview.vue b/packages/frontend/src/components/MkClipPreview.vue
index c51ad4356d..6299a28e9f 100644
--- a/packages/frontend/src/components/MkClipPreview.vue
+++ b/packages/frontend/src/components/MkClipPreview.vue
@@ -4,37 +4,59 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-<div :class="$style.root" class="_panel">
-	<b>{{ clip.name }}</b>
-	<div v-if="clip.description" :class="$style.description">{{ clip.description }}</div>
-	<div v-if="clip.lastClippedAt">{{ i18n.ts.updatedAt }}: <MkTime :time="clip.lastClippedAt" mode="detail"/></div>
-	<div :class="$style.user">
-		<MkAvatar :user="clip.user" :class="$style.userAvatar" indicator link preview/> <MkUserName :user="clip.user" :nowrap="false"/>
+<MkA :to="`/clips/${clip.id}`" :class="$style.link">
+	<div :class="$style.root" class="_panel _gaps_s">
+		<b>{{ clip.name }}</b>
+		<div :class="$style.description">
+			<div v-if="clip.description"><Mfm :text="clip.description" :plain="true" :nowrap="true"/></div>
+			<div v-if="clip.lastClippedAt">{{ i18n.ts.updatedAt }}: <MkTime :time="clip.lastClippedAt" mode="detail"/></div>
+			<div v-if="clip.notesCount != null">{{ i18n.ts.notesCount }}: {{ number(clip.notesCount) }} / {{ $i?.policies.noteEachClipsLimit }} ({{ i18n.tsx.remainingN({ n: remaining }) }})</div>
+		</div>
+		<div :class="$style.divider"></div>
+		<div>
+			<MkAvatar :user="clip.user" :class="$style.userAvatar" indicator link preview/> <MkUserName :user="clip.user" :nowrap="false"/>
+		</div>
 	</div>
-</div>
+</MkA>
 </template>
 
 <script lang="ts" setup>
+import * as Misskey from 'misskey-js';
+import { computed } from 'vue';
 import { i18n } from '@/i18n.js';
+import { $i } from '@/account.js';
+import number from '@/filters/number.js';
 
-defineProps<{
-	clip: any;
+const props = defineProps<{
+	clip: Misskey.entities.Clip;
 }>();
+
+const remaining = computed(() => {
+	return ($i?.policies && props.clip.notesCount != null) ? ($i.policies.noteEachClipsLimit - props.clip.notesCount) : i18n.ts.unknown;
+});
 </script>
 
 <style lang="scss" module>
-.root {
+.link {
 	display: block;
+
+	&:hover {
+		text-decoration: none;
+		color: var(--accent);
+	}
+}
+
+.root {
 	padding: 16px;
 }
 
-.description {
-	padding: 8px 0;
+.divider {
+	height: 1px;
+	background: var(--divider);
 }
 
-.user {
-	padding-top: 16px;
-	border-top: solid 0.5px var(--divider);
+.description {
+	font-size: 90%;
 }
 
 .userAvatar {
diff --git a/packages/frontend/src/pages/clip.vue b/packages/frontend/src/pages/clip.vue
index c38cc117bc..fd64a55c65 100644
--- a/packages/frontend/src/pages/clip.vue
+++ b/packages/frontend/src/pages/clip.vue
@@ -9,11 +9,16 @@ SPDX-License-Identifier: AGPL-3.0-only
 	<MkSpacer :contentMax="800">
 		<div v-if="clip" class="_gaps">
 			<div class="_panel">
-				<div v-if="clip.description" :class="$style.description">
-					<Mfm :text="clip.description" :isNote="false"/>
+				<div class="_gaps_s" :class="$style.description">
+					<div v-if="clip.description">
+						<Mfm :text="clip.description" :isNote="false"/>
+					</div>
+					<div v-else>({{ i18n.ts.noDescription }})</div>
+					<div>
+						<MkButton v-if="favorited" v-tooltip="i18n.ts.unfavorite" asLike rounded primary @click="unfavorite()"><i class="ti ti-heart"></i><span v-if="clip.favoritedCount > 0" style="margin-left: 6px;">{{ clip.favoritedCount }}</span></MkButton>
+						<MkButton v-else v-tooltip="i18n.ts.favorite" asLike rounded @click="favorite()"><i class="ti ti-heart"></i><span v-if="clip.favoritedCount > 0" style="margin-left: 6px;">{{ clip.favoritedCount }}</span></MkButton>
+					</div>
 				</div>
-				<MkButton v-if="favorited" v-tooltip="i18n.ts.unfavorite" asLike rounded primary @click="unfavorite()"><i class="ti ti-heart"></i><span v-if="clip.favoritedCount > 0" style="margin-left: 6px;">{{ clip.favoritedCount }}</span></MkButton>
-				<MkButton v-else v-tooltip="i18n.ts.favorite" asLike rounded @click="favorite()"><i class="ti ti-heart"></i><span v-if="clip.favoritedCount > 0" style="margin-left: 6px;">{{ clip.favoritedCount }}</span></MkButton>
 				<div :class="$style.user">
 					<MkAvatar :user="clip.user" :class="$style.avatar" indicator link preview/> <MkUserName :user="clip.user" :nowrap="false"/>
 				</div>
diff --git a/packages/frontend/src/pages/my-clips/index.vue b/packages/frontend/src/pages/my-clips/index.vue
index 803b28899a..1a0d7177fc 100644
--- a/packages/frontend/src/pages/my-clips/index.vue
+++ b/packages/frontend/src/pages/my-clips/index.vue
@@ -11,16 +11,12 @@ SPDX-License-Identifier: AGPL-3.0-only
 			<div v-if="tab === 'my'" key="my" class="_gaps">
 				<MkButton primary rounded class="add" @click="create"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
 
-				<MkPagination v-slot="{items}" ref="pagingComponent" :pagination="pagination" class="_gaps">
-					<MkA v-for="item in items" :key="item.id" :to="`/clips/${item.id}`">
-						<MkClipPreview :clip="item"/>
-					</MkA>
+				<MkPagination v-slot="{ items }" ref="pagingComponent" :pagination="pagination" class="_gaps">
+					<MkClipPreview v-for="item in items" :key="item.id" :clip="item"/>
 				</MkPagination>
 			</div>
 			<div v-else-if="tab === 'favorites'" key="favorites" class="_gaps">
-				<MkA v-for="item in favorites" :key="item.id" :to="`/clips/${item.id}`">
-					<MkClipPreview :clip="item"/>
-				</MkA>
+				<MkClipPreview v-for="item in favorites" :key="item.id" :clip="item"/>
 			</div>
 		</MkHorizontalSwipe>
 	</MkSpacer>
diff --git a/packages/frontend/src/pages/note.vue b/packages/frontend/src/pages/note.vue
index e14651742a..97f32d35cd 100644
--- a/packages/frontend/src/pages/note.vue
+++ b/packages/frontend/src/pages/note.vue
@@ -26,9 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 						<div v-if="clips && clips.length > 0" class="_margin">
 							<div style="font-weight: bold; padding: 12px;">{{ i18n.ts.clip }}</div>
 							<div class="_gaps">
-								<MkA v-for="item in clips" :key="item.id" :to="`/clips/${item.id}`">
-									<MkClipPreview :clip="item"/>
-								</MkA>
+								<MkClipPreview v-for="item in clips" :key="item.id" :clip="item"/>
 							</div>
 						</div>
 						<div v-if="!showPrev" class="_buttons" :class="$style.loadPrev">
diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts
index b273bd36f3..87921bc67f 100644
--- a/packages/frontend/src/scripts/get-note-menu.ts
+++ b/packages/frontend/src/scripts/get-note-menu.ts
@@ -26,6 +26,14 @@ export async function getNoteClipMenu(props: {
 	isDeleted: Ref<boolean>;
 	currentClip?: Misskey.entities.Clip;
 }) {
+	function getClipName(clip: Misskey.entities.Clip) {
+		if ($i && clip.userId === $i.id && clip.notesCount != null) {
+			return `${clip.name} (${clip.notesCount}/${$i.policies.noteEachClipsLimit})`;
+		} else {
+			return clip.name;
+		}
+	}
+
 	const isRenote = (
 		props.note.renote != null &&
 		props.note.text == null &&
@@ -37,7 +45,7 @@ export async function getNoteClipMenu(props: {
 
 	const clips = await clipsCache.fetch();
 	const menu: MenuItem[] = [...clips.map(clip => ({
-		text: clip.name,
+		text: getClipName(clip),
 		action: () => {
 			claimAchievement('noteClipped1');
 			os.promiseDialog(
@@ -50,7 +58,18 @@ export async function getNoteClipMenu(props: {
 							text: i18n.tsx.confirmToUnclipAlreadyClippedNote({ name: clip.name }),
 						});
 						if (!confirm.canceled) {
-							os.apiWithDialog('clips/remove-note', { clipId: clip.id, noteId: appearNote.id });
+							os.apiWithDialog('clips/remove-note', { clipId: clip.id, noteId: appearNote.id }).then(() => {
+								clipsCache.set(clips.map(c => {
+									if (c.id === clip.id) {
+										return {
+											...c,
+											notesCount: Math.max(0, ((c.notesCount ?? 0) - 1)),
+										};
+									} else {
+										return c;
+									}
+								}));
+							});
 							if (props.currentClip?.id === clip.id) props.isDeleted.value = true;
 						}
 					} else {
@@ -60,7 +79,18 @@ export async function getNoteClipMenu(props: {
 						});
 					}
 				},
-			);
+			).then(() => {
+				clipsCache.set(clips.map(c => {
+					if (c.id === clip.id) {
+						return {
+							...c,
+							notesCount: (c.notesCount ?? 0) + 1,
+						};
+					} else {
+						return c;
+					}
+				}));
+			});
 		},
 	})), { type: 'divider' }, {
 		icon: 'ti ti-plus',
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index b6b26c000c..ae001cf874 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -4460,6 +4460,7 @@ export type components = {
       isPublic: boolean;
       favoritedCount: number;
       isFavorited?: boolean;
+      notesCount?: number;
     };
     FederationInstance: {
       /** Format: id */

From b4faa7c4ec7f8557c4b29d4af7db5cdd92a5bb84 Mon Sep 17 00:00:00 2001
From: MeiMei <30769358+mei23@users.noreply.github.com>
Date: Mon, 15 Apr 2024 09:25:11 +0900
Subject: [PATCH 078/191] chore: Use integrity for Redoc script (#13716)

* Use integrity for redoc scripts

* official?
---
 packages/backend/assets/redoc.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/backend/assets/redoc.html b/packages/backend/assets/redoc.html
index a9ebf662fc..2557b4532e 100644
--- a/packages/backend/assets/redoc.html
+++ b/packages/backend/assets/redoc.html
@@ -19,6 +19,6 @@
 	</head>
 	<body>
 		<redoc spec-url="/api.json" expand-responses="200" expand-single-schema-field="true"></redoc>
-		<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"></script>
+		<script src="https://cdn.redoc.ly/redoc/v2.1.3/bundles/redoc.standalone.js" integrity="sha256-u4DgqzYXoArvNF/Ymw3puKexfOC6lYfw0sfmeliBJ1I=" crossorigin="anonymous"></script>
 	</body>
 </html>

From c687b4eaa558aa3138d81f8fa4d9bbc376d0bd6c Mon Sep 17 00:00:00 2001
From: MeiMei <30769358+mei23@users.noreply.github.com>
Date: Mon, 15 Apr 2024 09:28:09 +0900
Subject: [PATCH 079/191] =?UTF-8?q?fix(backend):=20nginx=E7=B5=8C=E7=94=B1?=
 =?UTF-8?q?=E3=81=A7/files/=E3=81=ABRange=E3=83=AA=E3=82=AF=E3=82=A8?=
 =?UTF-8?q?=E3=82=B9=E3=83=88=E3=81=95=E3=82=8C=E3=81=9F=E5=A0=B4=E5=90=88?=
 =?UTF-8?q?=E3=81=AB=E6=AD=A3=E3=81=97=E3=81=8F=E5=BF=9C=E7=AD=94=E3=81=A7?=
 =?UTF-8?q?=E3=81=8D=E3=81=AA=E3=81=84=E3=81=AE=E3=82=92=E4=BF=AE=E6=AD=A3?=
 =?UTF-8?q?=20(#13712)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Fix files

* CHANGELOG
---
 CHANGELOG.md                                     | 1 +
 packages/backend/src/server/FileServerService.ts | 7 ++++---
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index a238d99a06..de18aded0c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -52,6 +52,7 @@
 - Fix: リプライのみの引用リノートと、CWのみの引用リノートが純粋なリノートとして誤って扱われてしまう問題を修正
 - Fix: 登録にメール認証が必須になっている場合、登録されているメールアドレスを削除できないように  
   (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/606)
+- Fix: nginx経由で/files/にRangeリクエストされた場合に正しく応答できないのを修正
 
 ## 2024.3.1
 
diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts
index ce7702143e..9db3aa1bfb 100644
--- a/packages/backend/src/server/FileServerService.ts
+++ b/packages/backend/src/server/FileServerService.ts
@@ -214,6 +214,8 @@ export class FileServerService {
 				}
 
 				reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(image.type) ? image.type : 'application/octet-stream');
+				reply.header('Content-Length', file.file.size);
+				reply.header('Cache-Control', 'max-age=31536000, immutable');
 				reply.header('Content-Disposition',
 					contentDisposition(
 						'inline',
@@ -256,6 +258,7 @@ export class FileServerService {
 				return fs.createReadStream(file.path);
 			} else {
 				reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(file.file.type) ? file.file.type : 'application/octet-stream');
+				reply.header('Content-Length', file.file.size);
 				reply.header('Cache-Control', 'max-age=31536000, immutable');
 				reply.header('Content-Disposition', contentDisposition('inline', file.filename));
 
@@ -530,9 +533,7 @@ export class FileServerService {
 		if (!file.storedInternal) {
 			if (!(file.isLink && file.uri)) return '204';
 			const result = await this.downloadAndDetectTypeFromUrl(file.uri);
-			if (!file.size) {
-				file.size = (await fs.promises.stat(result.path)).size;
-			}
+			file.size = (await fs.promises.stat(result.path)).size;	// DB file.sizeは正確とは限らないので
 			return {
 				...result,
 				url: file.uri,

From ca0d148a78bd1277479a38565f08c22cdfb4fcc2 Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Mon, 15 Apr 2024 22:11:17 +0900
Subject: [PATCH 080/191] =?UTF-8?q?ci:=20Check=20Misskey=20JS=20autogen?=
 =?UTF-8?q?=E3=82=92=E6=A7=98=E3=80=85=E6=94=B9=E5=96=84=20(#13718)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../workflows/check-misskey-js-autogen.yml    | 141 +++++++++---------
 1 file changed, 71 insertions(+), 70 deletions(-)

diff --git a/.github/workflows/check-misskey-js-autogen.yml b/.github/workflows/check-misskey-js-autogen.yml
index 8fad129115..4aa0646b7b 100644
--- a/.github/workflows/check-misskey-js-autogen.yml
+++ b/.github/workflows/check-misskey-js-autogen.yml
@@ -5,24 +5,23 @@ on:
     branches:
       - master
       - develop
+      - improve-misskey-js-autogen-check
     paths:
       - packages/backend/**
 
 jobs:
-  check-misskey-js-autogen:
+  # pull_request_target safety: permissions: read-all, and there are no secrets used in this job
+  generate-misskey-js:
     runs-on: ubuntu-latest
     permissions:
-      pull-requests: write
-
-    env:
-      api_json_name: "api-head.json"
-
+      contents: read
+    if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
     steps:
       - name: checkout
         uses: actions/checkout@v4.1.1
         with:
           submodules: true
-          ref: ${{ github.event.pull_request.head.sha }}
+          ref: refs/pull/${{ github.event.pull_request.number }}/merge
 
       - name: setup pnpm
         uses: pnpm/action-setup@v3
@@ -39,79 +38,81 @@ jobs:
       - name: install dependencies
         run: pnpm i --frozen-lockfile
 
-      - name: wait get-api-diff
-        uses: lewagon/wait-on-check-action@v1.3.3
+      # generate api.json
+      - name: Copy Config
+        run: cp .config/example.yml .config/default.yml
+      - name: Build
+        run: pnpm build
+      - name: Generate API JSON
+        run: pnpm --filter backend generate-api-json
+
+      # build misskey js
+      - name: Build misskey-js
+        run: |-
+          cp packages/backend/built/api.json packages/misskey-js/generator/api.json
+          pnpm run --filter misskey-js-type-generator generate
+
+      # packages/misskey-js/generator/built/autogen
+      - name: Upload Generated
+        uses: actions/upload-artifact@v4
         with:
-          ref: ${{ github.event.pull_request.head.sha }}
-          check-regexp: get-from-misskey .+
-          repo-token: ${{ secrets.GITHUB_TOKEN }}
-          wait-interval: 30
+          name: generated-misskey-js
+          path: packages/misskey-js/generator/built/autogen
 
-      - name: Download artifact
-        uses: actions/github-script@v7.0.1
+  # pull_request_target safety: permissions: read-all, and there are no secrets used in this job
+  get-actual-misskey-js:
+    runs-on: ubuntu-latest
+    permissions:
+      contents: read
+    if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
+    steps:
+      - name: checkout
+        uses: actions/checkout@v4.1.1
         with:
-          script: |
-            const fs = require('fs');
+          submodules: true
+          ref: refs/pull/${{ github.event.pull_request.number }}/merge
 
-            const workflows = await github.rest.actions.listWorkflowRunsForRepo({
-              owner: context.repo.owner,
-              repo: context.repo.repo,
-              head_sha: `${{ github.event.pull_request.head.sha }}`
-            }).then(x => x.data.workflow_runs);
+      - name: Upload From Merged
+        uses: actions/upload-artifact@v4
+        with:
+          name: actual-misskey-js
+          path: packages/misskey-js/src/autogen
 
-            console.log(workflows.map(x => ({name: x.name, title: x.display_title})));
+  # pull_request_target safety: nothing is cloned from repository
+  comment-misskey-js-autogen:
+    runs-on: ubuntu-latest
+    needs: [generate-misskey-js, get-actual-misskey-js]
+    permissions:
+      pull-requests: write
+    steps:
+      - name: download generated-misskey-js
+        uses: actions/download-artifact@v4
+        with:
+          name: generated-misskey-js
+          path: misskey-js-generated
 
-            const run_id = workflows.find(x => x.name.includes("Get api.json from Misskey")).id;
+      - name: download actual-misskey-js
+        uses: actions/download-artifact@v4
+        with:
+          name: actual-misskey-js
+          path: misskey-js-actual
 
-            let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
-               owner: context.repo.owner,
-               repo: context.repo.repo,
-               run_id: run_id,
-            });
+      - name: check misskey-js changes
+        id: check-changes
+        run: |
+          diff -r -u --label=generated --label=on-tree ./misskey-js-generated ./misskey-js-actual > misskey-js.diff || true
 
-            let matchArtifacts = allArtifacts.data.artifacts.filter((artifact) => {
-              return artifact.name.startsWith("api-artifact-") || artifact.name == "api-artifact"
-            });
+          if [ -s misskey-js.diff ]; then
+            echo "changes=true" >> $GITHUB_OUTPUT
+          else
+            echo "changes=false" >> $GITHUB_OUTPUT
+          fi
 
-            await Promise.all(matchArtifacts.map(async (artifact) => {
-              let download = await github.rest.actions.downloadArtifact({
-                owner: context.repo.owner,
-                repo: context.repo.repo,
-                artifact_id: artifact.id,
-                archive_format: 'zip',
-              });
-              await fs.promises.writeFile(`${process.env.GITHUB_WORKSPACE}/${artifact.name}.zip`, Buffer.from(download.data));
-            }));
-
-      - name: unzip artifacts
-        run: |-
-          find . -mindepth 1 -maxdepth 1 -type f -name '*.zip' -exec unzip {} -d . ';'
-          ls -la
-
-      - name: get head checksum
-        run: |-
-          checksum=$(realpath head_checksum)
-
-          cd packages/misskey-js/src
-          find autogen -type f -exec sh -c 'echo $(sed -E "s/^\s+\*\s+generatedAt:.+$//" {} | sha256sum | cut -d" " -f 1) {}' \; > $checksum
-          cd ../../..
-
-      - name: build autogen
-        run: |-
-            checksum=$(realpath ${api_json_name}_checksum)
-            mv $api_json_name packages/misskey-js/generator/api.json
-
-            cd packages/misskey-js/generator
-            pnpm run generate
-            cd built
-            find autogen -type f -exec sh -c 'echo $(sed -E "s/^\s+\*\s+generatedAt:.+$//" {} | sha256sum | cut -d" " -f 1) {}' \; > $checksum
-            cd ../../../..
-
-      - name: check update for type definitions
-        run: diff head_checksum ${api_json_name}_checksum
+      - name: Print full diff
+        run: cat ./misskey-js.diff
 
       - name: send message
-        if: failure()
+        if: steps.check-changes.outputs.changes == 'true'
         uses: thollander/actions-comment-pull-request@v2
         with:
           comment_tag: check-misskey-js-autogen
@@ -125,7 +126,7 @@ jobs:
             ```
 
       - name: send message
-        if: success()
+        if: steps.check-changes.outputs.changes == 'false'
         uses: thollander/actions-comment-pull-request@v2
         with:
           comment_tag: check-misskey-js-autogen

From e9e877f64e83bf34f90373a366567b852d3cce18 Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Tue, 16 Apr 2024 13:37:14 +0900
Subject: [PATCH 081/191] =?UTF-8?q?fix:=20=E3=83=80=E3=82=A4=E3=83=AC?=
 =?UTF-8?q?=E3=82=AF=E3=83=88=E6=8A=95=E7=A8=BF=E3=81=AE=E5=AE=9B=E5=85=88?=
 =?UTF-8?q?=E3=81=8C=E4=BF=9D=E5=AD=98=E3=81=95=E3=82=8C=E3=81=AA=E3=81=84?=
 =?UTF-8?q?=20(#13717)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix: ダイレクト投稿の宛先が保存されない

* fix: 同じユーザーが複数回宛先に追加できる問題

* fix: 関係ないユーザーが宛先に追加される可能性がある
---
 CHANGELOG.md                                    |  1 +
 packages/frontend/src/components/MkPostForm.vue | 12 +++++++++++-
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index de18aded0c..4aad65d837 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -40,6 +40,7 @@
 - Fix: CWのみの引用リノートが詳細ページで純粋なリノートとして誤って扱われてしまう問題を修正
 - Fix: ノート詳細ページにおいてCW付き引用リノートのCWボタンのラベルに「引用」が含まれていない問題を修正
 - Fix: ダイアログの入力で字数制限に違反していてもEnterキーが押せてしまう問題を修正
+- Fix: ダイレクト投稿の宛先が保存されない問題を修正
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index 014b866fbd..d7efca9de9 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -388,7 +388,7 @@ function addMissingMention() {
 	for (const x of extractMentions(ast)) {
 		if (!visibleUsers.value.some(u => (u.username === x.username) && (u.host === x.host))) {
 			misskeyApi('users/show', { username: x.username, host: x.host }).then(user => {
-				visibleUsers.value.push(user);
+				pushVisibleUser(user);
 			});
 		}
 	}
@@ -679,6 +679,7 @@ function saveDraft() {
 			localOnly: localOnly.value,
 			files: files.value,
 			poll: poll.value,
+			visibleUserIds: visibility.value === 'specified' ? visibleUsers.value.map(x => x.id) : undefined,
 		},
 	};
 
@@ -960,6 +961,15 @@ onMounted(() => {
 				if (draft.data.poll) {
 					poll.value = draft.data.poll;
 				}
+				if (draft.data.visibleUserIds) {
+					misskeyApi('users/show', { userIds: draft.data.visibleUserIds }).then(users => {
+						for (let i = 0; i < users.length; i++) {
+							if (users[i].id === draft.data.visibleUserIds[i]) {
+								pushVisibleUser(users[i]);
+							}
+						}
+					});
+				}
 			}
 		}
 

From 6f489b58a18310fa9d8aef695d984f7ceb312102 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Wed, 17 Apr 2024 10:48:42 +0900
Subject: [PATCH 082/191] =?UTF-8?q?enhance(frontend):=20=E3=83=9A=E3=83=BC?=
 =?UTF-8?q?=E3=82=B8=E3=81=AE=E8=A1=A8=E7=A4=BA=E9=83=A8=E4=B8=8A=E9=83=A8?=
 =?UTF-8?q?=E3=81=AB=E7=B7=A8=E9=9B=86=E3=83=AA=E3=83=B3=E3=82=AF=E3=82=92?=
 =?UTF-8?q?=E8=BF=BD=E5=8A=A0=20(#13724)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 packages/frontend/src/pages/page.vue | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/packages/frontend/src/pages/page.vue b/packages/frontend/src/pages/page.vue
index ab44533b81..893c2deebf 100644
--- a/packages/frontend/src/pages/page.vue
+++ b/packages/frontend/src/pages/page.vue
@@ -12,6 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 			:leaveActiveClass="defaultStore.state.animation ? $style.fadeLeaveActive : ''"
 			:enterFromClass="defaultStore.state.animation ? $style.fadeEnterFrom : ''"
 			:leaveToClass="defaultStore.state.animation ? $style.fadeLeaveTo : ''"
+			mode="out-in"
 		>
 			<div v-if="page" :key="page.id" class="_gaps">
 				<div :class="$style.pageMain">
@@ -41,8 +42,14 @@ SPDX-License-Identifier: AGPL-3.0-only
 						</div>
 						<div :class="$style.pageBannerTitle" class="_gaps_s">
 							<h1>{{ page.title || page.name }}</h1>
-							<div v-if="page.user" :class="$style.pageBannerTitleUser">
-								<MkAvatar :user="page.user" :class="$style.avatar" indicator link preview/> <MkA :to="`/@${username}`"><MkUserName :user="page.user" :nowrap="false"/></MkA>
+							<div :class="$style.pageBannerTitleSub">
+								<div v-if="page.user" :class="$style.pageBannerTitleUser">
+									<MkAvatar :user="page.user" :class="$style.avatar" indicator link preview/> <MkA :to="`/@${username}`"><MkUserName :user="page.user" :nowrap="false"/></MkA>
+								</div>
+								<div :class="$style.pageBannerTitleSubActions">
+									<button v-tooltip="i18n.ts.share" class="_button" :class="$style.generalActionButton" @click="share"><i class="ti ti-share ti-fw"></i></button>
+									<MkA v-if="page.userId === $i?.id" v-tooltip="i18n.ts._pages.editThisPage" :to="`/pages/edit/${page.id}`" class="_button" :class="$style.generalActionButton"><i class="ti ti-pencil ti-fw"></i></MkA>
+								</div>
 							</div>
 						</div>
 					</div>
@@ -355,8 +362,15 @@ definePageMetadata(() => ({
 			margin: 0;
 		}
 
+		.pageBannerTitleSub {
+			display: flex;
+			align-items: center;
+			width: 100%;
+		}
+
 		.pageBannerTitleUser {
 			--height: 32px;
+			flex-shrink: 0;
 
 			.avatar {
 				height: var(--height);
@@ -365,6 +379,14 @@ definePageMetadata(() => ({
 
 			line-height: var(--height);
 		}
+
+		.pageBannerTitleSubActions {
+			flex-shrink: 0;
+			display: flex;
+			align-items: center;
+			gap: var(--marginHalf);
+			margin-left: auto;
+		}
 	}
 }
 

From 977e2d2c09c3fbc2fd2eaead8fc7314d8d6f9fc4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Wed, 17 Apr 2024 10:53:16 +0900
Subject: [PATCH 083/191] =?UTF-8?q?enhance(frontend):=20=E3=83=95=E3=82=A9?=
 =?UTF-8?q?=E3=83=AD=E3=83=BC=E3=81=99=E3=82=8B=E3=81=8B=E3=81=A9=E3=81=86?=
 =?UTF-8?q?=E3=81=8B=E3=81=AE=E7=A2=BA=E8=AA=8D=E3=83=80=E3=82=A4=E3=82=A2?=
 =?UTF-8?q?=E3=83=AD=E3=82=B0=E3=82=92=E5=87=BA=E3=81=9B=E3=82=8B=E3=82=88?=
 =?UTF-8?q?=E3=81=86=E3=81=AB=20(#13723)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* feat(frontend): フォローするかどうかの確認ダイアログを出せるように

* Update Changelog
---
 CHANGELOG.md                                        |  1 +
 locales/index.d.ts                                  |  4 ++++
 locales/ja-JP.yml                                   |  1 +
 packages/frontend/src/components/MkFollowButton.vue | 12 ++++++++++++
 packages/frontend/src/pages/settings/general.vue    |  3 +++
 packages/frontend/src/store.ts                      |  4 ++++
 6 files changed, 25 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4aad65d837..d27979d88f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -27,6 +27,7 @@
 - Enhance: ノートについているリアクションの「もっと!」から、リアクションの一覧を表示できるように
 - Enhance: リプライにて引用がある場合テキストが空でもノートできるように
   - 引用したいノートのURLをコピーしリプライ投稿画面にペーストして添付することで達成できます
+- Enhance: フォローするかどうかの確認ダイアログを出せるように
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
 - Fix: ローカルURLのプレビューポップアップが左上に表示される
diff --git a/locales/index.d.ts b/locales/index.d.ts
index cbea39f1cd..8e31fc8d59 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -4948,6 +4948,10 @@ export interface Locale extends ILocale {
      * 説明文はありません
      */
     "noDescription": string;
+    /**
+     * フォローの際常に確認する
+     */
+    "alwaysConfirmFollow": string;
     "_bubbleGame": {
         /**
          * 遊び方
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 4ab2f5adb0..f598459792 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1233,6 +1233,7 @@ useNativeUIForVideoAudioPlayer: "動画・音声の再生にブラウザのUIを
 keepOriginalFilename: "オリジナルのファイル名を保持"
 keepOriginalFilenameDescription: "この設定をオフにすると、アップロード時にファイル名が自動でランダム文字列に置き換えられます。"
 noDescription: "説明文はありません"
+alwaysConfirmFollow: "フォローの際常に確認する"
 
 _bubbleGame:
   howToPlay: "遊び方"
diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue
index 28450e11fc..636e61db8f 100644
--- a/packages/frontend/src/components/MkFollowButton.vue
+++ b/packages/frontend/src/components/MkFollowButton.vue
@@ -93,6 +93,18 @@ async function onClick() {
 				userId: props.user.id,
 			});
 		} else {
+			if (defaultStore.state.alwaysConfirmFollow) {
+				const { canceled } = await os.confirm({
+					type: 'question',
+					text: i18n.tsx.followConfirm({ name: props.user.name || props.user.username }),
+				});
+
+				if (canceled) {
+					wait.value = false;
+					return;
+				}
+			}
+
 			if (hasPendingFollowRequestFromYou.value) {
 				await misskeyApi('following/requests/cancel', {
 					userId: props.user.id,
diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue
index f2f82c4808..55d514ddf9 100644
--- a/packages/frontend/src/pages/settings/general.vue
+++ b/packages/frontend/src/pages/settings/general.vue
@@ -165,6 +165,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 				<MkSwitch v-model="keepScreenOn">{{ i18n.ts.keepScreenOn }}</MkSwitch>
 				<MkSwitch v-model="disableStreamingTimeline">{{ i18n.ts.disableStreamingTimeline }}</MkSwitch>
 				<MkSwitch v-model="enableHorizontalSwipe">{{ i18n.ts.enableHorizontalSwipe }}</MkSwitch>
+				<MkSwitch v-model="alwaysConfirmFollow">{{ i18n.ts.alwaysConfirmFollow }}</MkSwitch>
 			</div>
 			<MkSelect v-model="serverDisconnectedBehavior">
 				<template #label>{{ i18n.ts.whenServerDisconnected }}</template>
@@ -310,6 +311,7 @@ const useGroupedNotifications = computed(defaultStore.makeGetterSetter('useGroup
 const enableSeasonalScreenEffect = computed(defaultStore.makeGetterSetter('enableSeasonalScreenEffect'));
 const enableHorizontalSwipe = computed(defaultStore.makeGetterSetter('enableHorizontalSwipe'));
 const useNativeUIForVideoAudioPlayer = computed(defaultStore.makeGetterSetter('useNativeUIForVideoAudioPlayer'));
+const alwaysConfirmFollow = computed(defaultStore.makeGetterSetter('alwaysConfirmFollow'));
 
 watch(lang, () => {
 	miLocalStorage.setItem('lang', lang.value as string);
@@ -351,6 +353,7 @@ watch([
 	keepScreenOn,
 	disableStreamingTimeline,
 	enableSeasonalScreenEffect,
+	alwaysConfirmFollow,
 ], async () => {
 	await reloadAsk();
 });
diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts
index 9b5011739a..e6a348b79f 100644
--- a/packages/frontend/src/store.ts
+++ b/packages/frontend/src/store.ts
@@ -450,6 +450,10 @@ export const defaultStore = markRaw(new Storage('base', {
 		where: 'device',
 		default: true,
 	},
+	alwaysConfirmFollow: {
+		where: 'device',
+		default: true,
+	},
 
 	sound_masterVolume: {
 		where: 'device',

From e423b8ce4b28ecbe4e300fc67389e4def3761eb6 Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Wed, 17 Apr 2024 14:23:41 +0900
Subject: [PATCH 084/191] =?UTF-8?q?=E7=B4=B0=E3=81=8B=E3=81=84=E3=83=9F?=
 =?UTF-8?q?=E3=83=A5=E3=83=BC=E3=83=88=E3=81=AE=E5=87=A6=E7=90=86=E3=81=AE?=
 =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20(#13695)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix: some replies are removed from global timeline

* refactor: 各チャンネルのミュートとブロックの処理をまとめる

* fix: リノートをミュートでその人のノートのリノートをミュートしていたを修正

* refactor: isPureRenotePackedを他のところでも使う

* docs(changelog): CHANGELOGを更新

* test: withReplies = falseでフォローしてる人によるリプライが流れてくる

* test: ノートミュートしているユーザーの通常ノートのリノートが流れてくる/含まれる
---
 CHANGELOG.md                                  |  3 ++
 .../src/core/FanoutTimelineEndpointService.ts |  2 +-
 packages/backend/src/misc/is-renote.ts        | 31 +++++++++++++++++++
 .../backend/src/server/api/stream/channel.ts  | 22 +++++++++++++
 .../src/server/api/stream/channels/antenna.ts |  8 +----
 .../src/server/api/stream/channels/channel.ts | 11 ++-----
 .../api/stream/channels/global-timeline.ts    | 25 +++------------
 .../src/server/api/stream/channels/hashtag.ts | 11 ++-----
 .../api/stream/channels/home-timeline.ts      | 18 +++--------
 .../api/stream/channels/hybrid-timeline.ts    | 16 ++--------
 .../api/stream/channels/local-timeline.ts     | 14 +++------
 .../api/stream/channels/role-timeline.ts      |  9 +-----
 .../server/api/stream/channels/user-list.ts   | 17 +++-------
 packages/backend/test/e2e/renote-mute.ts      | 29 +++++++++++++++++
 packages/backend/test/e2e/streaming.ts        | 12 ++++++-
 15 files changed, 124 insertions(+), 104 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d27979d88f..36632e5024 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -55,6 +55,9 @@
 - Fix: 登録にメール認証が必須になっている場合、登録されているメールアドレスを削除できないように  
   (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/606)
 - Fix: nginx経由で/files/にRangeリクエストされた場合に正しく応答できないのを修正
+- Fix: 一部のタイムラインのストリーミングでインスタンスミュートが効かない問題を修正
+- Fix: グローバルタイムラインで返信が表示されないことがある問題を修正
+- Fix: リノートをミュートしたユーザの投稿のリノートがミュートされる問題を修正
 
 ## 2024.3.1
 
diff --git a/packages/backend/src/core/FanoutTimelineEndpointService.ts b/packages/backend/src/core/FanoutTimelineEndpointService.ts
index 006433df7a..884723ff81 100644
--- a/packages/backend/src/core/FanoutTimelineEndpointService.ts
+++ b/packages/backend/src/core/FanoutTimelineEndpointService.ts
@@ -116,7 +116,7 @@ export class FanoutTimelineEndpointService {
 				filter = (note) => {
 					if (isUserRelated(note, userIdsWhoBlockingMe, ps.ignoreAuthorFromBlock)) return false;
 					if (isUserRelated(note, userIdsWhoMeMuting, ps.ignoreAuthorFromMute)) return false;
-					if (isRenote(note) && !isQuote(note) && isUserRelated(note, userIdsWhoMeMutingRenotes, ps.ignoreAuthorFromMute)) return false;
+					if (!ps.ignoreAuthorFromMute && isRenote(note) && !isQuote(note) && userIdsWhoMeMutingRenotes.has(note.userId)) return false;
 					if (isInstanceMuted(note, userMutedInstances)) return false;
 
 					return parentFilter(note);
diff --git a/packages/backend/src/misc/is-renote.ts b/packages/backend/src/misc/is-renote.ts
index 5d48aba360..48f821806c 100644
--- a/packages/backend/src/misc/is-renote.ts
+++ b/packages/backend/src/misc/is-renote.ts
@@ -4,6 +4,7 @@
  */
 
 import type { MiNote } from '@/models/Note.js';
+import type { Packed } from '@/misc/json-schema.js';
 
 type Renote =
 	MiNote & {
@@ -34,3 +35,33 @@ export function isQuote(note: Renote): note is Quote {
 		note.hasPoll ||
 		note.fileIds.length > 0;
 }
+
+type PackedRenote =
+	Packed<'Note'> & {
+		renoteId: NonNullable<Packed<'Note'>['renoteId']>
+	};
+
+type PackedQuote =
+	PackedRenote & ({
+		text: NonNullable<Packed<'Note'>['text']>
+	} | {
+		cw: NonNullable<Packed<'Note'>['cw']>
+	} | {
+		replyId: NonNullable<Packed<'Note'>['replyId']>
+	} | {
+		poll: NonNullable<Packed<'Note'>['poll']>
+	} | {
+		fileIds: NonNullable<Packed<'Note'>['fileIds']>
+	});
+
+export function isRenotePacked(note: Packed<'Note'>): note is PackedRenote {
+	return note.renoteId != null;
+}
+
+export function isQuotePacked(note: PackedRenote): note is PackedQuote {
+	return note.text != null ||
+		note.cw != null ||
+		note.replyId != null ||
+		note.poll != null ||
+		(note.fileIds != null && note.fileIds.length > 0);
+}
diff --git a/packages/backend/src/server/api/stream/channel.ts b/packages/backend/src/server/api/stream/channel.ts
index 44a143538b..a267d27fba 100644
--- a/packages/backend/src/server/api/stream/channel.ts
+++ b/packages/backend/src/server/api/stream/channel.ts
@@ -4,6 +4,10 @@
  */
 
 import { bindThis } from '@/decorators.js';
+import { isInstanceMuted } from '@/misc/is-instance-muted.js';
+import { isUserRelated } from '@/misc/is-user-related.js';
+import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
+import type { Packed } from '@/misc/json-schema.js';
 import type Connection from './Connection.js';
 
 /**
@@ -54,6 +58,24 @@ export default abstract class Channel {
 		return this.connection.subscriber;
 	}
 
+	/*
+	 * ミュートとブロックされてるを処理する
+	 */
+	protected isNoteMutedOrBlocked(note: Packed<'Note'>): boolean {
+		// 流れてきたNoteがインスタンスミュートしたインスタンスが関わる
+		if (isInstanceMuted(note, new Set<string>(this.userProfile?.mutedInstances ?? []))) return true;
+
+		// 流れてきたNoteがミュートしているユーザーが関わる
+		if (isUserRelated(note, this.userIdsWhoMeMuting)) return true;
+		// 流れてきたNoteがブロックされているユーザーが関わる
+		if (isUserRelated(note, this.userIdsWhoBlockingMe)) return true;
+
+		// 流れてきたNoteがリノートをミュートしてるユーザが行ったもの
+		if (isRenotePacked(note) && !isQuotePacked(note) && this.userIdsWhoMeMutingRenotes.has(note.user.id)) return true;
+
+		return false;
+	}
+
 	constructor(id: string, connection: Connection) {
 		this.id = id;
 		this.connection = connection;
diff --git a/packages/backend/src/server/api/stream/channels/antenna.ts b/packages/backend/src/server/api/stream/channels/antenna.ts
index 135d162e63..4a1d2dd109 100644
--- a/packages/backend/src/server/api/stream/channels/antenna.ts
+++ b/packages/backend/src/server/api/stream/channels/antenna.ts
@@ -4,7 +4,6 @@
  */
 
 import { Injectable } from '@nestjs/common';
-import { isUserRelated } from '@/misc/is-user-related.js';
 import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
 import { bindThis } from '@/decorators.js';
 import type { GlobalEvents } from '@/core/GlobalEventService.js';
@@ -40,12 +39,7 @@ class AntennaChannel extends Channel {
 		if (data.type === 'note') {
 			const note = await this.noteEntityService.pack(data.body.id, this.user, { detail: true });
 
-			// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
-			if (isUserRelated(note, this.userIdsWhoMeMuting)) return;
-			// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
-			if (isUserRelated(note, this.userIdsWhoBlockingMe)) return;
-
-			if (note.renote && !note.text && isUserRelated(note, this.userIdsWhoMeMutingRenotes)) return;
+			if (this.isNoteMutedOrBlocked(note)) return;
 
 			this.connection.cacheNote(note);
 
diff --git a/packages/backend/src/server/api/stream/channels/channel.ts b/packages/backend/src/server/api/stream/channels/channel.ts
index 90ee1ecda5..140dd3dd9b 100644
--- a/packages/backend/src/server/api/stream/channels/channel.ts
+++ b/packages/backend/src/server/api/stream/channels/channel.ts
@@ -4,10 +4,10 @@
  */
 
 import { Injectable } from '@nestjs/common';
-import { isUserRelated } from '@/misc/is-user-related.js';
 import type { Packed } from '@/misc/json-schema.js';
 import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
 import { bindThis } from '@/decorators.js';
+import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
 import Channel, { type MiChannelService } from '../channel.js';
 
 class ChannelChannel extends Channel {
@@ -38,14 +38,9 @@ class ChannelChannel extends Channel {
 	private async onNote(note: Packed<'Note'>) {
 		if (note.channelId !== this.channelId) return;
 
-		// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
-		if (isUserRelated(note, this.userIdsWhoMeMuting)) return;
-		// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
-		if (isUserRelated(note, this.userIdsWhoBlockingMe)) return;
+		if (this.isNoteMutedOrBlocked(note)) return;
 
-		if (note.renote && !note.text && isUserRelated(note, this.userIdsWhoMeMutingRenotes)) return;
-
-		if (this.user && note.renoteId && !note.text) {
+		if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
 			if (note.renote && Object.keys(note.renote.reactions).length > 0) {
 				const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
 				note.renote.myReaction = myRenoteReaction;
diff --git a/packages/backend/src/server/api/stream/channels/global-timeline.ts b/packages/backend/src/server/api/stream/channels/global-timeline.ts
index 723b89c908..17116258d8 100644
--- a/packages/backend/src/server/api/stream/channels/global-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/global-timeline.ts
@@ -4,14 +4,12 @@
  */
 
 import { Injectable } from '@nestjs/common';
-import { checkWordMute } from '@/misc/check-word-mute.js';
-import { isInstanceMuted } from '@/misc/is-instance-muted.js';
-import { isUserRelated } from '@/misc/is-user-related.js';
 import type { Packed } from '@/misc/json-schema.js';
 import { MetaService } from '@/core/MetaService.js';
 import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
 import { bindThis } from '@/decorators.js';
 import { RoleService } from '@/core/RoleService.js';
+import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
 import Channel, { type MiChannelService } from '../channel.js';
 
 class GlobalTimelineChannel extends Channel {
@@ -52,26 +50,11 @@ class GlobalTimelineChannel extends Channel {
 		if (note.visibility !== 'public') return;
 		if (note.channelId != null) return;
 
-		// 関係ない返信は除外
-		if (note.reply && !this.following[note.userId]?.withReplies) {
-			const reply = note.reply;
-			// 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合
-			if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return;
-		}
+		if (isRenotePacked(note) && !isQuotePacked(note) && !this.withRenotes) return;
 
-		if (note.renote && note.text == null && (note.fileIds == null || note.fileIds.length === 0) && !this.withRenotes) return;
+		if (this.isNoteMutedOrBlocked(note)) return;
 
-		// Ignore notes from instances the user has muted
-		if (isInstanceMuted(note, new Set<string>(this.userProfile?.mutedInstances ?? []))) return;
-
-		// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
-		if (isUserRelated(note, this.userIdsWhoMeMuting)) return;
-		// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
-		if (isUserRelated(note, this.userIdsWhoBlockingMe)) return;
-
-		if (note.renote && !note.text && isUserRelated(note, this.userIdsWhoMeMutingRenotes)) return;
-
-		if (this.user && note.renoteId && !note.text) {
+		if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
 			if (note.renote && Object.keys(note.renote.reactions).length > 0) {
 				const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
 				note.renote.myReaction = myRenoteReaction;
diff --git a/packages/backend/src/server/api/stream/channels/hashtag.ts b/packages/backend/src/server/api/stream/channels/hashtag.ts
index 377b1a0162..57bada5d9c 100644
--- a/packages/backend/src/server/api/stream/channels/hashtag.ts
+++ b/packages/backend/src/server/api/stream/channels/hashtag.ts
@@ -5,10 +5,10 @@
 
 import { Injectable } from '@nestjs/common';
 import { normalizeForSearch } from '@/misc/normalize-for-search.js';
-import { isUserRelated } from '@/misc/is-user-related.js';
 import type { Packed } from '@/misc/json-schema.js';
 import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
 import { bindThis } from '@/decorators.js';
+import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
 import Channel, { type MiChannelService } from '../channel.js';
 
 class HashtagChannel extends Channel {
@@ -43,14 +43,9 @@ class HashtagChannel extends Channel {
 		const matched = this.q.some(tags => tags.every(tag => noteTags.includes(normalizeForSearch(tag))));
 		if (!matched) return;
 
-		// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
-		if (isUserRelated(note, this.userIdsWhoMeMuting)) return;
-		// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
-		if (isUserRelated(note, this.userIdsWhoBlockingMe)) return;
+		if (this.isNoteMutedOrBlocked(note)) return;
 
-		if (note.renote && !note.text && isUserRelated(note, this.userIdsWhoMeMutingRenotes)) return;
-
-		if (this.user && note.renoteId && !note.text) {
+		if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
 			if (note.renote && Object.keys(note.renote.reactions).length > 0) {
 				const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
 				note.renote.myReaction = myRenoteReaction;
diff --git a/packages/backend/src/server/api/stream/channels/home-timeline.ts b/packages/backend/src/server/api/stream/channels/home-timeline.ts
index f45bf8622e..878a3180cb 100644
--- a/packages/backend/src/server/api/stream/channels/home-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/home-timeline.ts
@@ -4,12 +4,10 @@
  */
 
 import { Injectable } from '@nestjs/common';
-import { checkWordMute } from '@/misc/check-word-mute.js';
-import { isUserRelated } from '@/misc/is-user-related.js';
-import { isInstanceMuted } from '@/misc/is-instance-muted.js';
 import type { Packed } from '@/misc/json-schema.js';
 import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
 import { bindThis } from '@/decorators.js';
+import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
 import Channel, { type MiChannelService } from '../channel.js';
 
 class HomeTimelineChannel extends Channel {
@@ -51,9 +49,6 @@ class HomeTimelineChannel extends Channel {
 			if (!isMe && !Object.hasOwn(this.following, note.userId)) return;
 		}
 
-		// Ignore notes from instances the user has muted
-		if (isInstanceMuted(note, new Set<string>(this.userProfile!.mutedInstances))) return;
-
 		if (note.visibility === 'followers') {
 			if (!isMe && !Object.hasOwn(this.following, note.userId)) return;
 		} else if (note.visibility === 'specified') {
@@ -72,7 +67,7 @@ class HomeTimelineChannel extends Channel {
 		}
 
 		// 純粋なリノート(引用リノートでないリノート)の場合
-		if (note.renote && note.text == null && (note.fileIds == null || note.fileIds.length === 0) && note.poll == null) {
+		if (isRenotePacked(note) && !isQuotePacked(note) && note.renote) {
 			if (!this.withRenotes) return;
 			if (note.renote.reply) {
 				const reply = note.renote.reply;
@@ -81,14 +76,9 @@ class HomeTimelineChannel extends Channel {
 			}
 		}
 
-		// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
-		if (isUserRelated(note, this.userIdsWhoMeMuting)) return;
-		// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
-		if (isUserRelated(note, this.userIdsWhoBlockingMe)) return;
+		if (this.isNoteMutedOrBlocked(note)) return;
 
-		if (note.renote && !note.text && isUserRelated(note, this.userIdsWhoMeMutingRenotes)) return;
-
-		if (this.user && note.renoteId && !note.text) {
+		if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
 			if (note.renote && Object.keys(note.renote.reactions).length > 0) {
 				const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
 				note.renote.myReaction = myRenoteReaction;
diff --git a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts
index d67da6f565..575d23d53c 100644
--- a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts
@@ -4,14 +4,12 @@
  */
 
 import { Injectable } from '@nestjs/common';
-import { checkWordMute } from '@/misc/check-word-mute.js';
-import { isUserRelated } from '@/misc/is-user-related.js';
-import { isInstanceMuted } from '@/misc/is-instance-muted.js';
 import type { Packed } from '@/misc/json-schema.js';
 import { MetaService } from '@/core/MetaService.js';
 import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
 import { bindThis } from '@/decorators.js';
 import { RoleService } from '@/core/RoleService.js';
+import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
 import Channel, { type MiChannelService } from '../channel.js';
 
 class HybridTimelineChannel extends Channel {
@@ -71,8 +69,7 @@ class HybridTimelineChannel extends Channel {
 			if (!isMe && !note.visibleUserIds!.includes(this.user!.id)) return;
 		}
 
-		// Ignore notes from instances the user has muted
-		if (isInstanceMuted(note, new Set<string>(this.userProfile!.mutedInstances))) return;
+		if (this.isNoteMutedOrBlocked(note)) return;
 
 		if (note.reply) {
 			const reply = note.reply;
@@ -85,14 +82,7 @@ class HybridTimelineChannel extends Channel {
 			}
 		}
 
-		if (note.renote && note.text == null && (note.fileIds == null || note.fileIds.length === 0) && !this.withRenotes) return;
-
-		// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
-		if (isUserRelated(note, this.userIdsWhoMeMuting)) return;
-		// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
-		if (isUserRelated(note, this.userIdsWhoBlockingMe)) return;
-
-		if (note.renote && !note.text && isUserRelated(note, this.userIdsWhoMeMutingRenotes)) return;
+		if (isRenotePacked(note) && !isQuotePacked(note) && !this.withRenotes) return;
 
 		if (this.user && note.renoteId && !note.text) {
 			if (note.renote && Object.keys(note.renote.reactions).length > 0) {
diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts
index 43d26124ef..442d08ae51 100644
--- a/packages/backend/src/server/api/stream/channels/local-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts
@@ -4,13 +4,12 @@
  */
 
 import { Injectable } from '@nestjs/common';
-import { checkWordMute } from '@/misc/check-word-mute.js';
-import { isUserRelated } from '@/misc/is-user-related.js';
 import type { Packed } from '@/misc/json-schema.js';
 import { MetaService } from '@/core/MetaService.js';
 import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
 import { bindThis } from '@/decorators.js';
 import { RoleService } from '@/core/RoleService.js';
+import { isQuotePacked, isRenotePacked } from '@/misc/is-renote.js';
 import Channel, { type MiChannelService } from '../channel.js';
 
 class LocalTimelineChannel extends Channel {
@@ -61,16 +60,11 @@ class LocalTimelineChannel extends Channel {
 			if (reply.userId !== this.user.id && note.userId !== this.user.id && reply.userId !== note.userId) return;
 		}
 
-		if (note.renote && note.text == null && (note.fileIds == null || note.fileIds.length === 0) && !this.withRenotes) return;
+		if (isRenotePacked(note) && !isQuotePacked(note) && !this.withRenotes) return;
 
-		// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
-		if (isUserRelated(note, this.userIdsWhoMeMuting)) return;
-		// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
-		if (isUserRelated(note, this.userIdsWhoBlockingMe)) return;
+		if (this.isNoteMutedOrBlocked(note)) return;
 
-		if (note.renote && !note.text && isUserRelated(note, this.userIdsWhoMeMutingRenotes)) return;
-
-		if (this.user && note.renoteId && !note.text) {
+		if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
 			if (note.renote && Object.keys(note.renote.reactions).length > 0) {
 				const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
 				note.renote.myReaction = myRenoteReaction;
diff --git a/packages/backend/src/server/api/stream/channels/role-timeline.ts b/packages/backend/src/server/api/stream/channels/role-timeline.ts
index 80aab4b35e..6a4ad22460 100644
--- a/packages/backend/src/server/api/stream/channels/role-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/role-timeline.ts
@@ -4,8 +4,6 @@
  */
 
 import { Injectable } from '@nestjs/common';
-import { isUserRelated } from '@/misc/is-user-related.js';
-import type { Packed } from '@/misc/json-schema.js';
 import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
 import { bindThis } from '@/decorators.js';
 import { RoleService } from '@/core/RoleService.js';
@@ -46,12 +44,7 @@ class RoleTimelineChannel extends Channel {
 			}
 			if (note.visibility !== 'public') return;
 
-			// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
-			if (isUserRelated(note, this.userIdsWhoMeMuting)) return;
-			// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
-			if (isUserRelated(note, this.userIdsWhoBlockingMe)) return;
-
-			if (note.renote && !note.text && isUserRelated(note, this.userIdsWhoMeMutingRenotes)) return;
+			if (this.isNoteMutedOrBlocked(note)) return;
 
 			this.send('note', note);
 		} else {
diff --git a/packages/backend/src/server/api/stream/channels/user-list.ts b/packages/backend/src/server/api/stream/channels/user-list.ts
index f7bb106c03..14b30a157c 100644
--- a/packages/backend/src/server/api/stream/channels/user-list.ts
+++ b/packages/backend/src/server/api/stream/channels/user-list.ts
@@ -5,12 +5,11 @@
 
 import { Inject, Injectable } from '@nestjs/common';
 import type { MiUserListMembership, UserListMembershipsRepository, UserListsRepository } from '@/models/_.js';
-import { isUserRelated } from '@/misc/is-user-related.js';
 import type { Packed } from '@/misc/json-schema.js';
 import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
 import { DI } from '@/di-symbols.js';
 import { bindThis } from '@/decorators.js';
-import { isInstanceMuted } from '@/misc/is-instance-muted.js';
+import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
 import Channel, { type MiChannelService } from '../channel.js';
 
 class UserListChannel extends Channel {
@@ -106,25 +105,17 @@ class UserListChannel extends Channel {
 			}
 		}
 
-		if (note.renote && note.text == null && (note.fileIds == null || note.fileIds.length === 0) && !this.withRenotes) return;
+		if (isRenotePacked(note) && !isQuotePacked(note) && !this.withRenotes) return;
 
-		// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
-		if (isUserRelated(note, this.userIdsWhoMeMuting)) return;
-		// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
-		if (isUserRelated(note, this.userIdsWhoBlockingMe)) return;
+		if (this.isNoteMutedOrBlocked(note)) return;
 
-		if (note.renote && !note.text && isUserRelated(note, this.userIdsWhoMeMutingRenotes)) return;
-
-		if (this.user && note.renoteId && !note.text) {
+		if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
 			if (note.renote && Object.keys(note.renote.reactions).length > 0) {
 				const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
 				note.renote.myReaction = myRenoteReaction;
 			}
 		}
 
-		// 流れてきたNoteがミュートしているインスタンスに関わるものだったら無視する
-		if (isInstanceMuted(note, this.userMutedInstances)) return;
-
 		this.connection.cacheNote(note);
 
 		this.send('note', note);
diff --git a/packages/backend/test/e2e/renote-mute.ts b/packages/backend/test/e2e/renote-mute.ts
index 9826068e48..1abbb4f044 100644
--- a/packages/backend/test/e2e/renote-mute.ts
+++ b/packages/backend/test/e2e/renote-mute.ts
@@ -63,6 +63,22 @@ describe('Renote Mute', () => {
 		assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
 	});
 
+	// #12956
+	test('タイムラインにリノートミュートしているユーザーの通常ノートのリノートが含まれる', async () => {
+		const carolNote = await post(carol, { text: 'hi' });
+		const bobRenote = await post(bob, { renoteId: carolNote.id });
+
+		// redisに追加されるのを待つ
+		await sleep(100);
+
+		const res = await api('notes/local-timeline', {}, alice);
+
+		assert.strictEqual(res.status, 200);
+		assert.strictEqual(Array.isArray(res.body), true);
+		assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
+		assert.strictEqual(res.body.some((note: any) => note.id === bobRenote.id), true);
+	});
+
 	test('ストリームにリノートミュートしているユーザーのリノートが流れない', async () => {
 		const bobNote = await post(bob, { text: 'hi' });
 
@@ -86,4 +102,17 @@ describe('Renote Mute', () => {
 
 		assert.strictEqual(fired, true);
 	});
+
+	// #12956
+	test('ストリームにリノートミュートしているユーザーの通常ノートのリノートが流れてくる', async () => {
+		const carolbNote = await post(carol, { text: 'hi' });
+
+		const fired = await waitFire(
+			alice, 'localTimeline',
+			() => api('notes/create', { renoteId: carolbNote.id }, bob),
+			msg => msg.type === 'note' && msg.body.userId === bob.id,
+		);
+
+		assert.strictEqual(fired, true);
+	});
 });
diff --git a/packages/backend/test/e2e/streaming.ts b/packages/backend/test/e2e/streaming.ts
index 26bb68ec6c..b0a70074c6 100644
--- a/packages/backend/test/e2e/streaming.ts
+++ b/packages/backend/test/e2e/streaming.ts
@@ -63,7 +63,7 @@ describe('Streaming', () => {
 			takumiNote = await post(takumi, { text: 'piyo' });
 
 			// Follow: ayano => kyoko
-			await api('following/create', { userId: kyoko.id }, ayano);
+			await api('following/create', { userId: kyoko.id, withReplies: false }, ayano);
 
 			// Follow: ayano => akari
 			await follow(ayano, akari);
@@ -509,6 +509,16 @@ describe('Streaming', () => {
 
 				assert.strictEqual(fired, false);
 			});
+
+			test('withReplies = falseでフォローしてる人によるリプライが流れてくる', async () => {
+				const fired = await waitFire(
+					ayano, 'globalTimeline',		// ayano:Global
+					() => api('notes/create', { text: 'foo', replyId: kanakoNote.id }, kyoko),	// kyoko posts
+					msg => msg.type === 'note' && msg.body.userId === kyoko.id,	// wait kyoko
+				);
+
+				assert.strictEqual(fired, true);
+			});
 		});
 
 		describe('UserList Timeline', () => {

From ea9aa6fdb41d3d5c0611f17fdacedee4861fdd37 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Wed, 17 Apr 2024 18:29:35 +0900
Subject: [PATCH 085/191] =?UTF-8?q?:art:=20=EF=BC=88=E3=83=9A=E3=83=BC?=
 =?UTF-8?q?=E3=82=B8=E8=A1=A8=E7=A4=BA=E9=83=A8=E4=B8=8A=E9=83=A8=E3=81=AE?=
 =?UTF-8?q?=E3=83=9C=E3=82=BF=E3=83=B3=E9=A0=86=E5=BA=8F=E3=82=92=E5=A4=89?=
 =?UTF-8?q?=E6=9B=B4=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Fix https://github.com/misskey-dev/misskey/pull/13724#discussion_r1568179954
---
 packages/frontend/src/pages/page.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/frontend/src/pages/page.vue b/packages/frontend/src/pages/page.vue
index 893c2deebf..e73d032000 100644
--- a/packages/frontend/src/pages/page.vue
+++ b/packages/frontend/src/pages/page.vue
@@ -47,8 +47,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 									<MkAvatar :user="page.user" :class="$style.avatar" indicator link preview/> <MkA :to="`/@${username}`"><MkUserName :user="page.user" :nowrap="false"/></MkA>
 								</div>
 								<div :class="$style.pageBannerTitleSubActions">
-									<button v-tooltip="i18n.ts.share" class="_button" :class="$style.generalActionButton" @click="share"><i class="ti ti-share ti-fw"></i></button>
 									<MkA v-if="page.userId === $i?.id" v-tooltip="i18n.ts._pages.editThisPage" :to="`/pages/edit/${page.id}`" class="_button" :class="$style.generalActionButton"><i class="ti ti-pencil ti-fw"></i></MkA>
+									<button v-tooltip="i18n.ts.share" class="_button" :class="$style.generalActionButton" @click="share"><i class="ti ti-share ti-fw"></i></button>
 								</div>
 							</div>
 						</div>

From cd7f7271ca5595cae95f6fb0280fac9dee77d751 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?=
 <46447427+samunohito@users.noreply.github.com>
Date: Fri, 19 Apr 2024 15:22:23 +0900
Subject: [PATCH 086/191] =?UTF-8?q?enhance:=20=E6=96=B0=E3=81=97=E3=81=84?=
 =?UTF-8?q?=E3=82=B3=E3=83=B3=E3=83=87=E3=82=A3=E3=82=B7=E3=83=A7=E3=83=8A?=
 =?UTF-8?q?=E3=83=AB=E3=83=AD=E3=83=BC=E3=83=AB=E6=9D=A1=E4=BB=B6=E3=81=AE?=
 =?UTF-8?q?=E5=AE=9F=E8=A3=85=20(#13732)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance: 新しいコンディショナルロールの実装

* fix: CHANGELOG.md
---
 CHANGELOG.md                                  |   6 +
 locales/index.d.ts                            |  20 +
 locales/ja-JP.yml                             |   5 +
 packages/backend/src/core/RoleService.ts      |  34 ++
 packages/backend/src/misc/json-schema.ts      |   2 +
 packages/backend/src/models/Role.ts           |  85 +++
 .../backend/src/models/json-schema/role.ts    |  17 +
 packages/backend/test/unit/RoleService.ts     | 512 +++++++++++++++---
 .../src/pages/admin/RolesEditorFormula.vue    |   5 +
 packages/misskey-js/etc/misskey-js.api.md     |   4 +
 packages/misskey-js/src/autogen/models.ts     |   1 +
 packages/misskey-js/src/autogen/types.ts      |   7 +-
 12 files changed, 624 insertions(+), 74 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 36632e5024..c13fa664dd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,12 @@
 - Enhance: アンテナでBotによるノートを除外できるように  
   (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/545)
 - Enhance: クリップのノート数を表示するように
+- Enhance: コンディショナルロールの条件として以下を新たに追加 (#13667)
+  - 猫ユーザーか
+  - botユーザーか
+  - サスペンド済みユーザーか
+  - 鍵アカウントユーザーか
+  - 「アカウントを見つけやすくする」が有効なユーザーか
 - Fix: Play作成時に設定した公開範囲が機能していない問題を修正
 
 ### Client
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 8e31fc8d59..9bcd1979af 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -6592,6 +6592,26 @@ export interface Locale extends ILocale {
              * リモートユーザー
              */
             "isRemote": string;
+            /**
+             * 猫ユーザー
+             */
+            "isCat": string;
+            /**
+             * botユーザー
+             */
+            "isBot": string;
+            /**
+             * サスペンド済みユーザー
+             */
+            "isSuspended": string;
+            /**
+             * 鍵アカウントユーザー
+             */
+            "isLocked": string;
+            /**
+             * 「アカウントを見つけやすくする」が有効なユーザー
+             */
+            "isExplorable": string;
             /**
              * アカウント作成から~以内
              */
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index f598459792..5f7715b210 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1703,6 +1703,11 @@ _role:
     roleAssignedTo: "マニュアルロールにアサイン済み"
     isLocal: "ローカルユーザー"
     isRemote: "リモートユーザー"
+    isCat: "猫ユーザー"
+    isBot: "botユーザー"
+    isSuspended: "サスペンド済みユーザー"
+    isLocked: "鍵アカウントユーザー"
+    isExplorable: "「アカウントを見つけやすくする」が有効なユーザー"
     createdLessThan: "アカウント作成から~以内"
     createdMoreThan: "アカウント作成から~経過"
     followersLessThanOrEq: "フォロワー数が~以下"
diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts
index 09f3097114..70c537f9ab 100644
--- a/packages/backend/src/core/RoleService.ts
+++ b/packages/backend/src/core/RoleService.ts
@@ -205,45 +205,79 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
 	private evalCond(user: MiUser, roles: MiRole[], value: RoleCondFormulaValue): boolean {
 		try {
 			switch (value.type) {
+				// ~かつ~
 				case 'and': {
 					return value.values.every(v => this.evalCond(user, roles, v));
 				}
+				// ~または~
 				case 'or': {
 					return value.values.some(v => this.evalCond(user, roles, v));
 				}
+				// ~ではない
 				case 'not': {
 					return !this.evalCond(user, roles, value.value);
 				}
+				// マニュアルロールがアサインされている
 				case 'roleAssignedTo': {
 					return roles.some(r => r.id === value.roleId);
 				}
+				// ローカルユーザのみ
 				case 'isLocal': {
 					return this.userEntityService.isLocalUser(user);
 				}
+				// リモートユーザのみ
 				case 'isRemote': {
 					return this.userEntityService.isRemoteUser(user);
 				}
+				// サスペンド済みユーザである
+				case 'isSuspended': {
+					return user.isSuspended;
+				}
+				// 鍵アカウントユーザである
+				case 'isLocked': {
+					return user.isLocked;
+				}
+				// botユーザである
+				case 'isBot': {
+					return user.isBot;
+				}
+				// 猫である
+				case 'isCat': {
+					return user.isCat;
+				}
+				// 「ユーザを見つけやすくする」が有効なアカウント
+				case 'isExplorable': {
+					return user.isExplorable;
+				}
+				// ユーザが作成されてから指定期間経過した
 				case 'createdLessThan': {
 					return this.idService.parse(user.id).date.getTime() > (Date.now() - (value.sec * 1000));
 				}
+				// ユーザが作成されてから指定期間経っていない
 				case 'createdMoreThan': {
 					return this.idService.parse(user.id).date.getTime() < (Date.now() - (value.sec * 1000));
 				}
+				// フォロワー数が指定値以下
 				case 'followersLessThanOrEq': {
 					return user.followersCount <= value.value;
 				}
+				// フォロワー数が指定値以上
 				case 'followersMoreThanOrEq': {
 					return user.followersCount >= value.value;
 				}
+				// フォロー数が指定値以下
 				case 'followingLessThanOrEq': {
 					return user.followingCount <= value.value;
 				}
+				// フォロー数が指定値以上
 				case 'followingMoreThanOrEq': {
 					return user.followingCount >= value.value;
 				}
+				// ノート数が指定値以下
 				case 'notesLessThanOrEq': {
 					return user.notesCount <= value.value;
 				}
+				// ノート数が指定値以上
 				case 'notesMoreThanOrEq': {
 					return user.notesCount >= value.value;
 				}
diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts
index 46b0bb2fab..a620d7c94b 100644
--- a/packages/backend/src/misc/json-schema.ts
+++ b/packages/backend/src/misc/json-schema.ts
@@ -48,6 +48,7 @@ import {
 	packedRoleCondFormulaValueCreatedSchema,
 	packedRoleCondFormulaFollowersOrFollowingOrNotesSchema,
 	packedRoleCondFormulaValueSchema,
+	packedRoleCondFormulaValueUserSettingBooleanSchema,
 } from '@/models/json-schema/role.js';
 import { packedAdSchema } from '@/models/json-schema/ad.js';
 import { packedReversiGameLiteSchema, packedReversiGameDetailedSchema } from '@/models/json-schema/reversi-game.js';
@@ -97,6 +98,7 @@ export const refs = {
 	RoleCondFormulaLogics: packedRoleCondFormulaLogicsSchema,
 	RoleCondFormulaValueNot: packedRoleCondFormulaValueNot,
 	RoleCondFormulaValueIsLocalOrRemote: packedRoleCondFormulaValueIsLocalOrRemoteSchema,
+	RoleCondFormulaValueUserSettingBooleanSchema: packedRoleCondFormulaValueUserSettingBooleanSchema,
 	RoleCondFormulaValueAssignedRole: packedRoleCondFormulaValueAssignedRoleSchema,
 	RoleCondFormulaValueCreated: packedRoleCondFormulaValueCreatedSchema,
 	RoleCondFormulaFollowersOrFollowingOrNotes: packedRoleCondFormulaFollowersOrFollowingOrNotesSchema,
diff --git a/packages/backend/src/models/Role.ts b/packages/backend/src/models/Role.ts
index 058abe3118..a173971b2c 100644
--- a/packages/backend/src/models/Role.ts
+++ b/packages/backend/src/models/Role.ts
@@ -6,69 +6,149 @@
 import { Entity, Column, PrimaryColumn } from 'typeorm';
 import { id } from './util/id.js';
 
+/**
+ * ~かつ~
+ * 複数の条件を同時に満たす場合のみ成立とする
+ */
 type CondFormulaValueAnd = {
 	type: 'and';
 	values: RoleCondFormulaValue[];
 };
 
+/**
+ * ~または~
+ * 複数の条件のうち、いずれかを満たす場合のみ成立とする
+ */
 type CondFormulaValueOr = {
 	type: 'or';
 	values: RoleCondFormulaValue[];
 };
 
+/**
+ * ~ではない
+ * 条件を満たさない場合のみ成立とする
+ */
 type CondFormulaValueNot = {
 	type: 'not';
 	value: RoleCondFormulaValue;
 };
 
+/**
+ * ローカルユーザーのみ成立とする
+ */
 type CondFormulaValueIsLocal = {
 	type: 'isLocal';
 };
 
+/**
+ * リモートユーザーのみ成立とする
+ */
 type CondFormulaValueIsRemote = {
 	type: 'isRemote';
 };
 
+/**
+ * 既に指定のマニュアルロールにアサインされている場合のみ成立とする
+ */
 type CondFormulaValueRoleAssignedTo = {
 	type: 'roleAssignedTo';
 	roleId: string;
 };
 
+/**
+ * サスペンド済みアカウントの場合のみ成立とする
+ */
+type CondFormulaValueIsSuspended = {
+	type: 'isSuspended';
+};
+
+/**
+ * 鍵アカウントの場合のみ成立とする
+ */
+type CondFormulaValueIsLocked = {
+	type: 'isLocked';
+};
+
+/**
+ * botアカウントの場合のみ成立とする
+ */
+type CondFormulaValueIsBot = {
+	type: 'isBot';
+};
+
+/**
+ * 猫アカウントの場合のみ成立とする
+ */
+type CondFormulaValueIsCat = {
+	type: 'isCat';
+};
+
+/**
+ * 「ユーザを見つけやすくする」が有効なアカウントの場合のみ成立とする
+ */
+type CondFormulaValueIsExplorable = {
+	type: 'isExplorable';
+};
+
+/**
+ * ユーザが作成されてから指定期間経過した場合のみ成立とする
+ */
 type CondFormulaValueCreatedLessThan = {
 	type: 'createdLessThan';
 	sec: number;
 };
 
+/**
+ * ユーザが作成されてから指定期間経っていない場合のみ成立とする
+ */
 type CondFormulaValueCreatedMoreThan = {
 	type: 'createdMoreThan';
 	sec: number;
 };
 
+/**
+ * フォロワー数が指定値以下の場合のみ成立とする
+ */
 type CondFormulaValueFollowersLessThanOrEq = {
 	type: 'followersLessThanOrEq';
 	value: number;
 };
 
+/**
+ * フォロワー数が指定値以上の場合のみ成立とする
+ */
 type CondFormulaValueFollowersMoreThanOrEq = {
 	type: 'followersMoreThanOrEq';
 	value: number;
 };
 
+/**
+ * フォロー数が指定値以下の場合のみ成立とする
+ */
 type CondFormulaValueFollowingLessThanOrEq = {
 	type: 'followingLessThanOrEq';
 	value: number;
 };
 
+/**
+ * フォロー数が指定値以上の場合のみ成立とする
+ */
 type CondFormulaValueFollowingMoreThanOrEq = {
 	type: 'followingMoreThanOrEq';
 	value: number;
 };
 
+/**
+ * 投稿数が指定値以下の場合のみ成立とする
+ */
 type CondFormulaValueNotesLessThanOrEq = {
 	type: 'notesLessThanOrEq';
 	value: number;
 };
 
+/**
+ * 投稿数が指定値以上の場合のみ成立とする
+ */
 type CondFormulaValueNotesMoreThanOrEq = {
 	type: 'notesMoreThanOrEq';
 	value: number;
@@ -80,6 +160,11 @@ export type RoleCondFormulaValue = { id: string } & (
 	CondFormulaValueNot |
 	CondFormulaValueIsLocal |
 	CondFormulaValueIsRemote |
+	CondFormulaValueIsSuspended |
+	CondFormulaValueIsLocked |
+	CondFormulaValueIsBot |
+	CondFormulaValueIsCat |
+	CondFormulaValueIsExplorable |
 	CondFormulaValueRoleAssignedTo |
 	CondFormulaValueCreatedLessThan |
 	CondFormulaValueCreatedMoreThan |
diff --git a/packages/backend/src/models/json-schema/role.ts b/packages/backend/src/models/json-schema/role.ts
index c770250503..d9987a70c3 100644
--- a/packages/backend/src/models/json-schema/role.ts
+++ b/packages/backend/src/models/json-schema/role.ts
@@ -57,6 +57,20 @@ export const packedRoleCondFormulaValueIsLocalOrRemoteSchema = {
 	},
 } as const;
 
+export const packedRoleCondFormulaValueUserSettingBooleanSchema = {
+	type: 'object',
+	properties: {
+		id: {
+			type: 'string', optional: false,
+		},
+		type: {
+			type: 'string',
+			nullable: false, optional: false,
+			enum: ['isSuspended', 'isLocked', 'isBot', 'isCat', 'isExplorable'],
+		},
+	},
+} as const;
+
 export const packedRoleCondFormulaValueAssignedRoleSchema = {
 	type: 'object',
 	properties: {
@@ -135,6 +149,9 @@ export const packedRoleCondFormulaValueSchema = {
 		{
 			ref: 'RoleCondFormulaValueIsLocalOrRemote',
 		},
+		{
+			ref: 'RoleCondFormulaValueUserSettingBooleanSchema',
+		},
 		{
 			ref: 'RoleCondFormulaValueAssignedRole',
 		},
diff --git a/packages/backend/test/unit/RoleService.ts b/packages/backend/test/unit/RoleService.ts
index 19d03570e0..ec441735d7 100644
--- a/packages/backend/test/unit/RoleService.ts
+++ b/packages/backend/test/unit/RoleService.ts
@@ -3,6 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
+import { UserEntityService } from '@/core/entities/UserEntityService.js';
+
 process.env.NODE_ENV = 'test';
 
 import { jest } from '@jest/globals';
@@ -20,6 +22,7 @@ import { IdService } from '@/core/IdService.js';
 import { GlobalEventService } from '@/core/GlobalEventService.js';
 import { secureRndstr } from '@/misc/secure-rndstr.js';
 import { NotificationService } from '@/core/NotificationService.js';
+import { RoleCondFormulaValue } from '@/models/Role.js';
 import { sleep } from '../utils.js';
 import type { TestingModule } from '@nestjs/testing';
 import type { MockFunctionMetadata } from 'jest-mock';
@@ -52,12 +55,26 @@ describe('RoleService', () => {
 			id: genAidx(Date.now()),
 			updatedAt: new Date(),
 			lastUsedAt: new Date(),
+			name: '',
 			description: '',
 			...data,
 		})
 			.then(x => rolesRepository.findOneByOrFail(x.identifiers[0]));
 	}
 
+	function createConditionalRole(condFormula: RoleCondFormulaValue, data: Partial<MiRole> = {}) {
+		return createRole({
+			name: `[conditional] ${condFormula.type}`,
+			target: 'conditional',
+			condFormula: condFormula,
+			...data,
+		});
+	}
+
+	function aidx() {
+		return genAidx(Date.now());
+	}
+
 	beforeEach(async () => {
 		clock = lolex.install({
 			now: new Date(),
@@ -73,6 +90,7 @@ describe('RoleService', () => {
 				CacheService,
 				IdService,
 				GlobalEventService,
+				UserEntityService,
 				{
 					provide: NotificationService,
 					useFactory: () => ({
@@ -209,79 +227,6 @@ describe('RoleService', () => {
 			expect(result.driveCapacityMb).toBe(100);
 		});
 
-		test('conditional role', async () => {
-			const user1 = await createUser({
-				id: genAidx(Date.now() - (1000 * 60 * 60 * 24 * 365)),
-			});
-			const user2 = await createUser({
-				id: genAidx(Date.now() - (1000 * 60 * 60 * 24 * 365)),
-				followersCount: 10,
-			});
-			await createRole({
-				name: 'a',
-				policies: {
-					canManageCustomEmojis: {
-						useDefault: false,
-						priority: 0,
-						value: true,
-					},
-				},
-				target: 'conditional',
-				condFormula: {
-					id: '232a4221-9816-49a6-a967-ae0fac52ec5e',
-					type: 'and',
-					values: [{
-						id: '2a37ef43-2d93-4c4d-87f6-f2fdb7d9b530',
-						type: 'followersMoreThanOrEq',
-						value: 10,
-					}, {
-						id: '1bd67839-b126-4f92-bad0-4e285dab453b',
-						type: 'createdMoreThan',
-						sec: 60 * 60 * 24 * 7,
-					}],
-				},
-			});
-
-			metaService.fetch.mockResolvedValue({
-				policies: {
-					canManageCustomEmojis: false,
-				},
-			} as any);
-
-			const user1Policies = await roleService.getUserPolicies(user1.id);
-			const user2Policies = await roleService.getUserPolicies(user2.id);
-			expect(user1Policies.canManageCustomEmojis).toBe(false);
-			expect(user2Policies.canManageCustomEmojis).toBe(true);
-		});
-
-		test('コンディショナルロール: マニュアルロールにアサイン済み', async () => {
-			const [user1, user2, role1] = await Promise.all([
-				createUser(),
-				createUser(),
-				createRole({
-					name: 'manual role',
-				}),
-			]);
-			const role2 = await createRole({
-				name: 'conditional role',
-				target: 'conditional',
-				condFormula: {
-					// idはバックエンドのロジックに必要ない?
-					id: 'bdc612bd-9d54-4675-ae83-0499c82ea670',
-					type: 'roleAssignedTo',
-					roleId: role1.id,
-				},
-			});
-			await roleService.assign(user2.id, role1.id);
-
-			const [u1role, u2role] = await Promise.all([
-				roleService.getUserRoles(user1.id),
-				roleService.getUserRoles(user2.id),
-			]);
-			expect(u1role.some(r => r.id === role2.id)).toBe(false);
-			expect(u2role.some(r => r.id === role2.id)).toBe(true);
-		});
-
 		test('expired role', async () => {
 			const user = await createUser();
 			const role = await createRole({
@@ -320,6 +265,427 @@ describe('RoleService', () => {
 		});
 	});
 
+	describe('conditional role', () => {
+		test('~かつ~', async () => {
+			const [user1, user2, user3, user4] = await Promise.all([
+				createUser({ isBot: true, isCat: false, isSuspended: false }),
+				createUser({ isBot: false, isCat: true, isSuspended: false }),
+				createUser({ isBot: true, isCat: true, isSuspended: false }),
+				createUser({ isBot: false, isCat: false, isSuspended: true }),
+			]);
+			const role1 = await createConditionalRole({
+				id: aidx(),
+				type: 'isBot',
+			});
+			const role2 = await createConditionalRole({
+				id: aidx(),
+				type: 'isCat',
+			});
+			const role3 = await createConditionalRole({
+				id: aidx(),
+				type: 'isSuspended',
+			});
+			const role4 = await createConditionalRole({
+				id: aidx(),
+				type: 'and',
+				values: [role1.condFormula, role2.condFormula],
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			const actual3 = await roleService.getUserRoles(user3.id);
+			const actual4 = await roleService.getUserRoles(user4.id);
+			expect(actual1.some(r => r.id === role4.id)).toBe(false);
+			expect(actual2.some(r => r.id === role4.id)).toBe(false);
+			expect(actual3.some(r => r.id === role4.id)).toBe(true);
+			expect(actual4.some(r => r.id === role4.id)).toBe(false);
+		});
+
+		test('~または~', async () => {
+			const [user1, user2, user3, user4] = await Promise.all([
+				createUser({ isBot: true, isCat: false, isSuspended: false }),
+				createUser({ isBot: false, isCat: true, isSuspended: false }),
+				createUser({ isBot: true, isCat: true, isSuspended: false }),
+				createUser({ isBot: false, isCat: false, isSuspended: true }),
+			]);
+			const role1 = await createConditionalRole({
+				id: aidx(),
+				type: 'isBot',
+			});
+			const role2 = await createConditionalRole({
+				id: aidx(),
+				type: 'isCat',
+			});
+			const role3 = await createConditionalRole({
+				id: aidx(),
+				type: 'isSuspended',
+			});
+			const role4 = await createConditionalRole({
+				id: aidx(),
+				type: 'or',
+				values: [role1.condFormula, role2.condFormula],
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			const actual3 = await roleService.getUserRoles(user3.id);
+			const actual4 = await roleService.getUserRoles(user4.id);
+			expect(actual1.some(r => r.id === role4.id)).toBe(true);
+			expect(actual2.some(r => r.id === role4.id)).toBe(true);
+			expect(actual3.some(r => r.id === role4.id)).toBe(true);
+			expect(actual4.some(r => r.id === role4.id)).toBe(false);
+		});
+
+		test('~ではない', async () => {
+			const [user1, user2, user3] = await Promise.all([
+				createUser({ isBot: true, isCat: false, isSuspended: false }),
+				createUser({ isBot: false, isCat: true, isSuspended: false }),
+				createUser({ isBot: true, isCat: true, isSuspended: false }),
+			]);
+			const role1 = await createConditionalRole({
+				id: aidx(),
+				type: 'isBot',
+			});
+			const role2 = await createConditionalRole({
+				id: aidx(),
+				type: 'isCat',
+			});
+			const role4 = await createConditionalRole({
+				id: aidx(),
+				type: 'not',
+				value: role1.condFormula,
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			const actual3 = await roleService.getUserRoles(user3.id);
+			expect(actual1.some(r => r.id === role4.id)).toBe(false);
+			expect(actual2.some(r => r.id === role4.id)).toBe(true);
+			expect(actual3.some(r => r.id === role4.id)).toBe(false);
+		});
+
+		test('マニュアルロールにアサイン済み', async () => {
+			const [user1, user2, role1] = await Promise.all([
+				createUser(),
+				createUser(),
+				createRole({
+					name: 'manual role',
+				}),
+			]);
+			const role2 = await createConditionalRole({
+				id: aidx(),
+				type: 'roleAssignedTo',
+				roleId: role1.id,
+			});
+			await roleService.assign(user2.id, role1.id);
+
+			const [u1role, u2role] = await Promise.all([
+				roleService.getUserRoles(user1.id),
+				roleService.getUserRoles(user2.id),
+			]);
+			expect(u1role.some(r => r.id === role2.id)).toBe(false);
+			expect(u2role.some(r => r.id === role2.id)).toBe(true);
+		});
+
+		test('ローカルユーザのみ', async () => {
+			const [user1, user2] = await Promise.all([
+				createUser({ host: null }),
+				createUser({ host: 'example.com' }),
+			]);
+			const role = await createConditionalRole({
+				id: aidx(),
+				type: 'isLocal',
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			expect(actual1.some(r => r.id === role.id)).toBe(true);
+			expect(actual2.some(r => r.id === role.id)).toBe(false);
+		});
+
+		test('リモートユーザのみ', async () => {
+			const [user1, user2] = await Promise.all([
+				createUser({ host: null }),
+				createUser({ host: 'example.com' }),
+			]);
+			const role = await createConditionalRole({
+				id: aidx(),
+				type: 'isRemote',
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			expect(actual1.some(r => r.id === role.id)).toBe(false);
+			expect(actual2.some(r => r.id === role.id)).toBe(true);
+		});
+
+		test('サスペンド済みユーザである', async () => {
+			const [user1, user2] = await Promise.all([
+				createUser({ isSuspended: false }),
+				createUser({ isSuspended: true }),
+			]);
+			const role = await createConditionalRole({
+				id: aidx(),
+				type: 'isSuspended',
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			expect(actual1.some(r => r.id === role.id)).toBe(false);
+			expect(actual2.some(r => r.id === role.id)).toBe(true);
+		});
+
+		test('鍵アカウントユーザである', async () => {
+			const [user1, user2] = await Promise.all([
+				createUser({ isLocked: false }),
+				createUser({ isLocked: true }),
+			]);
+			const role = await createConditionalRole({
+				id: aidx(),
+				type: 'isLocked',
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			expect(actual1.some(r => r.id === role.id)).toBe(false);
+			expect(actual2.some(r => r.id === role.id)).toBe(true);
+		});
+
+		test('botユーザである', async () => {
+			const [user1, user2] = await Promise.all([
+				createUser({ isBot: false }),
+				createUser({ isBot: true }),
+			]);
+			const role = await createConditionalRole({
+				id: aidx(),
+				type: 'isBot',
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			expect(actual1.some(r => r.id === role.id)).toBe(false);
+			expect(actual2.some(r => r.id === role.id)).toBe(true);
+		});
+
+		test('猫である', async () => {
+			const [user1, user2] = await Promise.all([
+				createUser({ isCat: false }),
+				createUser({ isCat: true }),
+			]);
+			const role = await createConditionalRole({
+				id: aidx(),
+				type: 'isCat',
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			expect(actual1.some(r => r.id === role.id)).toBe(false);
+			expect(actual2.some(r => r.id === role.id)).toBe(true);
+		});
+
+		test('「ユーザを見つけやすくする」が有効なアカウント', async () => {
+			const [user1, user2] = await Promise.all([
+				createUser({ isExplorable: false }),
+				createUser({ isExplorable: true }),
+			]);
+			const role = await createConditionalRole({
+				id: aidx(),
+				type: 'isExplorable',
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			expect(actual1.some(r => r.id === role.id)).toBe(false);
+			expect(actual2.some(r => r.id === role.id)).toBe(true);
+		});
+
+		test('ユーザが作成されてから指定期間経過した', async () => {
+			const base = new Date();
+			base.setMinutes(base.getMinutes() - 5);
+
+			const d1 = new Date(base);
+			const d2 = new Date(base);
+			const d3 = new Date(base);
+			d1.setSeconds(d1.getSeconds() - 1);
+			d3.setSeconds(d3.getSeconds() + 1);
+
+			const [user1, user2, user3] = await Promise.all([
+				// 4:59
+				createUser({ id: genAidx(d1.getTime()) }),
+				// 5:00
+				createUser({ id: genAidx(d2.getTime()) }),
+				// 5:01
+				createUser({ id: genAidx(d3.getTime()) }),
+			]);
+			const role = await createConditionalRole({
+				id: aidx(),
+				type: 'createdLessThan',
+				// 5 minutes
+				sec: 300,
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			const actual3 = await roleService.getUserRoles(user3.id);
+			expect(actual1.some(r => r.id === role.id)).toBe(false);
+			expect(actual2.some(r => r.id === role.id)).toBe(false);
+			expect(actual3.some(r => r.id === role.id)).toBe(true);
+		});
+
+		test('ユーザが作成されてから指定期間経っていない', async () => {
+			const base = new Date();
+			base.setMinutes(base.getMinutes() - 5);
+
+			const d1 = new Date(base);
+			const d2 = new Date(base);
+			const d3 = new Date(base);
+			d1.setSeconds(d1.getSeconds() - 1);
+			d3.setSeconds(d3.getSeconds() + 1);
+
+			const [user1, user2, user3] = await Promise.all([
+				// 4:59
+				createUser({ id: genAidx(d1.getTime()) }),
+				// 5:00
+				createUser({ id: genAidx(d2.getTime()) }),
+				// 5:01
+				createUser({ id: genAidx(d3.getTime()) }),
+			]);
+			const role = await createConditionalRole({
+				id: aidx(),
+				type: 'createdMoreThan',
+				// 5 minutes
+				sec: 300,
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			const actual3 = await roleService.getUserRoles(user3.id);
+			expect(actual1.some(r => r.id === role.id)).toBe(true);
+			expect(actual2.some(r => r.id === role.id)).toBe(false);
+			expect(actual3.some(r => r.id === role.id)).toBe(false);
+		});
+
+		test('フォロワー数が指定値以下', async () => {
+			const [user1, user2, user3] = await Promise.all([
+				createUser({ followersCount: 99 }),
+				createUser({ followersCount: 100 }),
+				createUser({ followersCount: 101 }),
+			]);
+			const role = await createConditionalRole({
+				id: aidx(),
+				type: 'followersLessThanOrEq',
+				value: 100,
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			const actual3 = await roleService.getUserRoles(user3.id);
+			expect(actual1.some(r => r.id === role.id)).toBe(true);
+			expect(actual2.some(r => r.id === role.id)).toBe(true);
+			expect(actual3.some(r => r.id === role.id)).toBe(false);
+		});
+
+		test('フォロワー数が指定値以下', async () => {
+			const [user1, user2, user3] = await Promise.all([
+				createUser({ followersCount: 99 }),
+				createUser({ followersCount: 100 }),
+				createUser({ followersCount: 101 }),
+			]);
+			const role = await createConditionalRole({
+				id: aidx(),
+				type: 'followersMoreThanOrEq',
+				value: 100,
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			const actual3 = await roleService.getUserRoles(user3.id);
+			expect(actual1.some(r => r.id === role.id)).toBe(false);
+			expect(actual2.some(r => r.id === role.id)).toBe(true);
+			expect(actual3.some(r => r.id === role.id)).toBe(true);
+		});
+
+		test('フォロー数が指定値以下', async () => {
+			const [user1, user2, user3] = await Promise.all([
+				createUser({ followingCount: 99 }),
+				createUser({ followingCount: 100 }),
+				createUser({ followingCount: 101 }),
+			]);
+			const role = await createConditionalRole({
+				id: aidx(),
+				type: 'followingLessThanOrEq',
+				value: 100,
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			const actual3 = await roleService.getUserRoles(user3.id);
+			expect(actual1.some(r => r.id === role.id)).toBe(true);
+			expect(actual2.some(r => r.id === role.id)).toBe(true);
+			expect(actual3.some(r => r.id === role.id)).toBe(false);
+		});
+
+		test('フォロー数が指定値以上', async () => {
+			const [user1, user2, user3] = await Promise.all([
+				createUser({ followingCount: 99 }),
+				createUser({ followingCount: 100 }),
+				createUser({ followingCount: 101 }),
+			]);
+			const role = await createConditionalRole({
+				id: aidx(),
+				type: 'followingMoreThanOrEq',
+				value: 100,
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			const actual3 = await roleService.getUserRoles(user3.id);
+			expect(actual1.some(r => r.id === role.id)).toBe(false);
+			expect(actual2.some(r => r.id === role.id)).toBe(true);
+			expect(actual3.some(r => r.id === role.id)).toBe(true);
+		});
+
+		test('ノート数が指定値以下', async () => {
+			const [user1, user2, user3] = await Promise.all([
+				createUser({ notesCount: 9 }),
+				createUser({ notesCount: 10 }),
+				createUser({ notesCount: 11 }),
+			]);
+			const role = await createConditionalRole({
+				id: aidx(),
+				type: 'notesLessThanOrEq',
+				value: 10,
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			const actual3 = await roleService.getUserRoles(user3.id);
+			expect(actual1.some(r => r.id === role.id)).toBe(true);
+			expect(actual2.some(r => r.id === role.id)).toBe(true);
+			expect(actual3.some(r => r.id === role.id)).toBe(false);
+		});
+
+		test('ノート数が指定値以上', async () => {
+			const [user1, user2, user3] = await Promise.all([
+				createUser({ notesCount: 9 }),
+				createUser({ notesCount: 10 }),
+				createUser({ notesCount: 11 }),
+			]);
+			const role = await createConditionalRole({
+				id: aidx(),
+				type: 'notesMoreThanOrEq',
+				value: 10,
+			});
+
+			const actual1 = await roleService.getUserRoles(user1.id);
+			const actual2 = await roleService.getUserRoles(user2.id);
+			const actual3 = await roleService.getUserRoles(user3.id);
+			expect(actual1.some(r => r.id === role.id)).toBe(false);
+			expect(actual2.some(r => r.id === role.id)).toBe(true);
+			expect(actual3.some(r => r.id === role.id)).toBe(true);
+		});
+	});
+
 	describe('assign', () => {
 		test('公開ロールの場合は通知される', async () => {
 			const user = await createUser();
diff --git a/packages/frontend/src/pages/admin/RolesEditorFormula.vue b/packages/frontend/src/pages/admin/RolesEditorFormula.vue
index 2f5b4c47d8..f001a4ac20 100644
--- a/packages/frontend/src/pages/admin/RolesEditorFormula.vue
+++ b/packages/frontend/src/pages/admin/RolesEditorFormula.vue
@@ -9,6 +9,11 @@ SPDX-License-Identifier: AGPL-3.0-only
 		<MkSelect v-model="type" :class="$style.typeSelect">
 			<option value="isLocal">{{ i18n.ts._role._condition.isLocal }}</option>
 			<option value="isRemote">{{ i18n.ts._role._condition.isRemote }}</option>
+			<option value="isSuspended">{{ i18n.ts._role._condition.isSuspended }}</option>
+			<option value="isLocked">{{ i18n.ts._role._condition.isLocked }}</option>
+			<option value="isBot">{{ i18n.ts._role._condition.isBot }}</option>
+			<option value="isCat">{{ i18n.ts._role._condition.isCat }}</option>
+			<option value="isExplorable">{{ i18n.ts._role._condition.isExplorable }}</option>
 			<option value="roleAssignedTo">{{ i18n.ts._role._condition.roleAssignedTo }}</option>
 			<option value="createdLessThan">{{ i18n.ts._role._condition.createdLessThan }}</option>
 			<option value="createdMoreThan">{{ i18n.ts._role._condition.createdMoreThan }}</option>
diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md
index 360724d2a9..9720b04e39 100644
--- a/packages/misskey-js/etc/misskey-js.api.md
+++ b/packages/misskey-js/etc/misskey-js.api.md
@@ -1713,6 +1713,7 @@ declare namespace entities {
         RoleCondFormulaLogics,
         RoleCondFormulaValueNot,
         RoleCondFormulaValueIsLocalOrRemote,
+        RoleCondFormulaValueUserSettingBooleanSchema,
         RoleCondFormulaValueAssignedRole,
         RoleCondFormulaValueCreated,
         RoleCondFormulaFollowersOrFollowingOrNotes,
@@ -2745,6 +2746,9 @@ type RoleCondFormulaValueIsLocalOrRemote = components['schemas']['RoleCondFormul
 // @public (undocumented)
 type RoleCondFormulaValueNot = components['schemas']['RoleCondFormulaValueNot'];
 
+// @public (undocumented)
+type RoleCondFormulaValueUserSettingBooleanSchema = components['schemas']['RoleCondFormulaValueUserSettingBooleanSchema'];
+
 // @public (undocumented)
 type RoleLite = components['schemas']['RoleLite'];
 
diff --git a/packages/misskey-js/src/autogen/models.ts b/packages/misskey-js/src/autogen/models.ts
index 6f61458600..a6e5fbe689 100644
--- a/packages/misskey-js/src/autogen/models.ts
+++ b/packages/misskey-js/src/autogen/models.ts
@@ -38,6 +38,7 @@ export type Signin = components['schemas']['Signin'];
 export type RoleCondFormulaLogics = components['schemas']['RoleCondFormulaLogics'];
 export type RoleCondFormulaValueNot = components['schemas']['RoleCondFormulaValueNot'];
 export type RoleCondFormulaValueIsLocalOrRemote = components['schemas']['RoleCondFormulaValueIsLocalOrRemote'];
+export type RoleCondFormulaValueUserSettingBooleanSchema = components['schemas']['RoleCondFormulaValueUserSettingBooleanSchema'];
 export type RoleCondFormulaValueAssignedRole = components['schemas']['RoleCondFormulaValueAssignedRole'];
 export type RoleCondFormulaValueCreated = components['schemas']['RoleCondFormulaValueCreated'];
 export type RoleCondFormulaFollowersOrFollowingOrNotes = components['schemas']['RoleCondFormulaFollowersOrFollowingOrNotes'];
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index ae001cf874..131d20f09b 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -4586,6 +4586,11 @@ export type components = {
       /** @enum {string} */
       type: 'isLocal' | 'isRemote';
     };
+    RoleCondFormulaValueUserSettingBooleanSchema: {
+      id: string;
+      /** @enum {string} */
+      type: 'isSuspended' | 'isLocked' | 'isBot' | 'isCat' | 'isExplorable';
+    };
     RoleCondFormulaValueAssignedRole: {
       id: string;
       /** @enum {string} */
@@ -4608,7 +4613,7 @@ export type components = {
       type: 'followersLessThanOrEq' | 'followersMoreThanOrEq' | 'followingLessThanOrEq' | 'followingMoreThanOrEq' | 'notesLessThanOrEq' | 'notesMoreThanOrEq';
       value: number;
     };
-    RoleCondFormulaValue: components['schemas']['RoleCondFormulaLogics'] | components['schemas']['RoleCondFormulaValueNot'] | components['schemas']['RoleCondFormulaValueIsLocalOrRemote'] | components['schemas']['RoleCondFormulaValueAssignedRole'] | components['schemas']['RoleCondFormulaValueCreated'] | components['schemas']['RoleCondFormulaFollowersOrFollowingOrNotes'];
+    RoleCondFormulaValue: components['schemas']['RoleCondFormulaLogics'] | components['schemas']['RoleCondFormulaValueNot'] | components['schemas']['RoleCondFormulaValueIsLocalOrRemote'] | components['schemas']['RoleCondFormulaValueUserSettingBooleanSchema'] | components['schemas']['RoleCondFormulaValueAssignedRole'] | components['schemas']['RoleCondFormulaValueCreated'] | components['schemas']['RoleCondFormulaFollowersOrFollowingOrNotes'];
     RoleLite: {
       /**
        * Format: id

From f9aed8f2bf994902386878d1212912caa3a57b0d Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Fri, 19 Apr 2024 19:42:01 +0900
Subject: [PATCH 087/191] =?UTF-8?q?fix:=20=E6=AD=A3=E8=A6=8F=E5=8C=96?=
 =?UTF-8?q?=E3=81=95=E3=82=8C=E3=81=A6=E3=81=84=E3=81=AA=E3=81=84=E7=8A=B6?=
 =?UTF-8?q?=E6=85=8B=E3=81=AEhashtag=E3=81=8C=E9=80=A3=E5=90=88=E3=81=95?=
 =?UTF-8?q?=E3=82=8C=E3=81=A6=E3=81=8D=E3=81=9Fhtml=E3=81=AB=E5=90=AB?=
 =?UTF-8?q?=E3=81=BE=E3=82=8C=E3=81=A6=E3=81=84=E3=82=8B=E3=81=A8hashtag?=
 =?UTF-8?q?=E3=81=8C=E6=AD=A3=E3=81=97=E3=81=8Fhashtag=E3=81=AB=E5=BE=A9?=
 =?UTF-8?q?=E5=85=83=E3=81=95=E3=82=8C=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C?=
 =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3=20(#13733)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 CHANGELOG.md                            | 1 +
 packages/backend/src/core/MfmService.ts | 5 ++++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index c13fa664dd..8c8bcf0ea4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@
   - 鍵アカウントユーザーか
   - 「アカウントを見つけやすくする」が有効なユーザーか
 - Fix: Play作成時に設定した公開範囲が機能していない問題を修正
+- Fix: 正規化されていない状態のhashtagが連合されてきたhtmlに含まれているとhashtagが正しくhashtagに復元されない問題を修正
 
 ### Client
 - Feat: アップロードするファイルの名前をランダム文字列にできるように
diff --git a/packages/backend/src/core/MfmService.ts b/packages/backend/src/core/MfmService.ts
index c62ee5a642..2fb731201b 100644
--- a/packages/backend/src/core/MfmService.ts
+++ b/packages/backend/src/core/MfmService.ts
@@ -10,6 +10,7 @@ import { Window } from 'happy-dom';
 import { DI } from '@/di-symbols.js';
 import type { Config } from '@/config.js';
 import { intersperse } from '@/misc/prelude/array.js';
+import { normalizeForSearch } from '@/misc/normalize-for-search.js';
 import type { IMentionedRemoteUsers } from '@/models/Note.js';
 import { bindThis } from '@/decorators.js';
 import * as TreeAdapter from '../../node_modules/parse5/dist/tree-adapters/default.js';
@@ -33,6 +34,8 @@ export class MfmService {
 		// some AP servers like Pixelfed use br tags as well as newlines
 		html = html.replace(/<br\s?\/?>\r?\n/gi, '\n');
 
+		const normalizedHashtagNames = hashtagNames == null ? undefined : new Set<string>(hashtagNames.map(x => normalizeForSearch(x)));
+
 		const dom = parse5.parseFragment(html);
 
 		let text = '';
@@ -85,7 +88,7 @@ export class MfmService {
 					const href = node.attrs.find(x => x.name === 'href');
 
 					// ハッシュタグ
-					if (hashtagNames && href && hashtagNames.map(x => x.toLowerCase()).includes(txt.toLowerCase())) {
+					if (normalizedHashtagNames && href && normalizedHashtagNames.has(normalizeForSearch(txt))) {
 						text += txt;
 					// メンション
 					} else if (txt.startsWith('@') && !(rel && rel.value.startsWith('me '))) {

From 553ba8479298fa70f4c168b679ae42f8364df17f Mon Sep 17 00:00:00 2001
From: FineArchs <133759614+FineArchs@users.noreply.github.com>
Date: Thu, 25 Apr 2024 10:34:26 +0900
Subject: [PATCH 088/191] =?UTF-8?q?AiScript=E3=81=AE=E3=83=90=E3=83=BC?=
 =?UTF-8?q?=E3=82=B8=E3=83=A7=E3=83=B3=E3=82=920.18.0=E3=81=AB=E4=B8=8A?=
 =?UTF-8?q?=E3=81=92=E3=82=8B=20(#13743)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Update package.json

* Update autogen files

* Update flash-edit.vue

* Update flash-edit.vue

* Update CHANGELOG.md

* revert
---
 CHANGELOG.md                                  |  1 +
 packages/frontend/package.json                |  2 +-
 .../frontend/src/pages/flash/flash-edit.vue   | 34 +++++++++----------
 pnpm-lock.yaml                                | 14 ++++----
 4 files changed, 26 insertions(+), 25 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8c8bcf0ea4..87db026183 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -35,6 +35,7 @@
 - Enhance: リプライにて引用がある場合テキストが空でもノートできるように
   - 引用したいノートのURLをコピーしリプライ投稿画面にペーストして添付することで達成できます
 - Enhance: フォローするかどうかの確認ダイアログを出せるように
+- Chore: AiScriptを0.18.0にバージョンアップ
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
 - Fix: ローカルURLのプレビューポップアップが左上に表示される
diff --git a/packages/frontend/package.json b/packages/frontend/package.json
index cbf4e59592..95980ac0fc 100644
--- a/packages/frontend/package.json
+++ b/packages/frontend/package.json
@@ -24,7 +24,7 @@
 		"@rollup/plugin-json": "6.1.0",
 		"@rollup/plugin-replace": "5.0.5",
 		"@rollup/pluginutils": "5.1.0",
-		"@syuilo/aiscript": "0.17.0",
+		"@syuilo/aiscript": "0.18.0",
 		"@tabler/icons-webfont": "2.44.0",
 		"@twemoji/parser": "15.0.0",
 		"@vitejs/plugin-vue": "5.0.4",
diff --git a/packages/frontend/src/pages/flash/flash-edit.vue b/packages/frontend/src/pages/flash/flash-edit.vue
index 3625bc1164..bff45094a1 100644
--- a/packages/frontend/src/pages/flash/flash-edit.vue
+++ b/packages/frontend/src/pages/flash/flash-edit.vue
@@ -48,7 +48,7 @@ import MkInput from '@/components/MkInput.vue';
 import MkSelect from '@/components/MkSelect.vue';
 import { useRouter } from '@/router/supplier.js';
 
-const PRESET_DEFAULT = `/// @ 0.16.0
+const PRESET_DEFAULT = `/// @ 0.18.0
 
 var name = ""
 
@@ -60,13 +60,13 @@ Ui:render([
 	Ui:C:button({
 		text: "Hello"
 		onClick: @() {
-			Mk:dialog(null \`Hello, {name}!\`)
+			Mk:dialog(null, \`Hello, {name}!\`)
 		}
 	})
 ])
 `;
 
-const PRESET_OMIKUJI = `/// @ 0.16.0
+const PRESET_OMIKUJI = `/// @ 0.18.0
 // ユーザーごとに日替わりのおみくじのプリセット
 
 // 選択肢
@@ -81,11 +81,11 @@ let choices = [
 	"大凶"
 ]
 
-// シードが「ユーザーID+今日の日付」である乱数生成器を用意
-let random = Math:gen_rng(\`{USER_ID}{Date:year()}{Date:month()}{Date:day()}\`)
+// シードが「PlayID+ユーザーID+今日の日付」である乱数生成器を用意
+let random = Math:gen_rng(\`{THIS_ID}{USER_ID}{Date:year()}{Date:month()}{Date:day()}\`)
 
 // ランダムに選択肢を選ぶ
-let chosen = choices[random(0 (choices.len - 1))]
+let chosen = choices[random(0, (choices.len - 1))]
 
 // 結果のテキスト
 let result = \`今日のあなたの運勢は **{chosen}** です。\`
@@ -109,7 +109,7 @@ Ui:render([
 ])
 `;
 
-const PRESET_SHUFFLE = `/// @ 0.16.0
+const PRESET_SHUFFLE = `/// @ 0.18.0
 // 巻き戻し可能な文字シャッフルのプリセット
 
 let string = "ペペロンチーノ"
@@ -123,13 +123,13 @@ var cursor = 0
 
 @do() {
 	if (cursor != 0) {
-		results = results.slice(0 (cursor + 1))
+		results = results.slice(0, (cursor + 1))
 		cursor = 0
 	}
 
 	let chars = []
 	for (let i, length) {
-		let r = Math:rnd(0 (length - 1))
+		let r = Math:rnd(0, (length - 1))
 		chars.push(string.pick(r))
 	}
 	let result = chars.join("")
@@ -188,27 +188,27 @@ var cursor = 0
 do()
 `;
 
-const PRESET_QUIZ = `/// @ 0.16.0
+const PRESET_QUIZ = `/// @ 0.18.0
 let title = '地理クイズ'
 
 let qas = [{
 	q: 'オーストラリアの首都は?'
-	choices: ['シドニー' 'キャンベラ' 'メルボルン']
+	choices: ['シドニー', 'キャンベラ', 'メルボルン']
 	a: 'キャンベラ'
 	aDescription: '最大の都市はシドニーですが首都はキャンベラです。'
 } {
 	q: '国土面積2番目の国は?'
-	choices: ['カナダ' 'アメリカ' '中国']
+	choices: ['カナダ', 'アメリカ', '中国']
 	a: 'カナダ'
 	aDescription: '大きい順にロシア、カナダ、アメリカ、中国です。'
 } {
 	q: '二重内陸国ではないのは?'
-	choices: ['リヒテンシュタイン' 'ウズベキスタン' 'レソト']
+	choices: ['リヒテンシュタイン', 'ウズベキスタン', 'レソト']
 	a: 'レソト'
 	aDescription: 'レソトは(一重)内陸国です。'
 } {
 	q: '閘門がない運河は?'
-	choices: ['キール運河' 'スエズ運河' 'パナマ運河']
+	choices: ['キール運河', 'スエズ運河', 'パナマ運河']
 	a: 'スエズ運河'
 	aDescription: 'スエズ運河は高低差がないので閘門はありません。'
 }]
@@ -296,12 +296,12 @@ qaEls.push(Ui:C:container({
 			onClick: finish
 		})
 	]
-} 'footer'))
+}, 'footer'))
 
 Ui:render(qaEls)
 `;
 
-const PRESET_TIMELINE = `/// @ 0.16.0
+const PRESET_TIMELINE = `/// @ 0.18.0
 // APIリクエストを行いローカルタイムラインを表示するプリセット
 
 @fetch() {
@@ -315,7 +315,7 @@ const PRESET_TIMELINE = `/// @ 0.16.0
 	])
 
 	// タイムライン取得
-	let notes = Mk:api("notes/local-timeline" {})
+	let notes = Mk:api("notes/local-timeline", {})
 
 	// それぞれのノートごとにUI要素作成
 	let noteEls = []
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1dbb172b5d..c7625fd89f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -707,8 +707,8 @@ importers:
         specifier: 5.1.0
         version: 5.1.0(rollup@4.12.0)
       '@syuilo/aiscript':
-        specifier: 0.17.0
-        version: 0.17.0
+        specifier: 0.18.0
+        version: 0.18.0
       '@tabler/icons-webfont':
         specifier: 2.44.0
         version: 2.44.0
@@ -6678,7 +6678,7 @@ packages:
       ts-dedent: 2.2.0
       type-fest: 2.19.0
       vue: 3.4.21(typescript@5.3.3)
-      vue-component-type-helpers: 2.0.10
+      vue-component-type-helpers: 2.0.14
     transitivePeerDependencies:
       - encoding
       - supports-color
@@ -6944,8 +6944,8 @@ packages:
     dev: false
     optional: true
 
-  /@syuilo/aiscript@0.17.0:
-    resolution: {integrity: sha512-3JtQ1rWJHMxQ3153zLCXMUOwrOgjPPYGBl0dPHhR0ohm4tn7okMQRugxMCT0t3YxByemb9FfiM6TUjd0tEGxdA==}
+  /@syuilo/aiscript@0.18.0:
+    resolution: {integrity: sha512-/iY9Vv4LLjtW/KUzId1QwXC4BlpIEPCMcoT7dyRhYdyxtwhS3Hx4b/4j1HYP+n3Pq9XKyW5zvkY72/+DNu4g6Q==}
     dependencies:
       seedrandom: 3.0.5
       stringz: 2.1.0
@@ -19347,8 +19347,8 @@ packages:
     resolution: {integrity: sha512-6bnLkn8O0JJyiFSIF0EfCogzeqNXpnjJ0vW/SZzNHfe6sPx30lTtTXlE5TFs2qhJlAtDFybStVNpL73cPe3OMQ==}
     dev: true
 
-  /vue-component-type-helpers@2.0.10:
-    resolution: {integrity: sha512-FC5fKJjDks3Ue/KRSYBdsiCaZa0kUPQfs8yQpb8W9mlO6BenV8G1z58xobeRMzevnmEcDa09LLwuXDwb4f6NMQ==}
+  /vue-component-type-helpers@2.0.14:
+    resolution: {integrity: sha512-DInfgOyXlMyliyqAAD9frK28tTfch0+tMi4qoWJcZlRxUf+NFAtraJBnAsKLep+FOyLMiajkhfyEb3xLK08i7w==}
     dev: true
 
   /vue-demi@0.14.7(vue@3.4.21):

From 85339ca751401ff856814ca21283c07a7c66f5ce Mon Sep 17 00:00:00 2001
From: Cocoa Hoto <cocoa@hoto.us>
Date: Thu, 25 Apr 2024 11:03:34 +0900
Subject: [PATCH 089/191] feat: improve emoji endpoint (#13742)

---
 packages/backend/src/server/ServerService.ts | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts
index 671dd31eb1..1324cd1361 100644
--- a/packages/backend/src/server/ServerService.ts
+++ b/packages/backend/src/server/ServerService.ts
@@ -120,12 +120,20 @@ export class ServerService implements OnApplicationShutdown {
 				return;
 			}
 
-			const name = path.split('@')[0].replace(/\.webp$/i, '');
-			const host = path.split('@')[1]?.replace(/\.webp$/i, '');
+			const emojiPath = path.replace(/\.webp$/i, '');
+			const pathChunks = emojiPath.split('@');
+
+			if (pathChunks.length > 2) {
+				reply.code(400);
+				return;
+			}
+
+			const name = pathChunks.shift();
+			const host = pathChunks.pop();
 
 			const emoji = await this.emojisRepository.findOneBy({
 				// `@.` is the spec of ReactionService.decodeReaction
-				host: (host == null || host === '.') ? IsNull() : host,
+				host: (host === undefined || host === '.') ? IsNull() : host,
 				name: name,
 			});
 

From 6abb8c49943a0d9002118fb3b50e20940aa1e3ba Mon Sep 17 00:00:00 2001
From: MeiMei <30769358+mei23@users.noreply.github.com>
Date: Sat, 27 Apr 2024 12:57:00 +0900
Subject: [PATCH 090/191] Merge pull request from GHSA-m9qf-3pfj-2r86

* Add Cache-Control to Bull Board

* CHANGELOG

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 CHANGELOG.md                                           | 1 +
 packages/backend/src/server/web/ClientServerService.ts | 4 ++++
 2 files changed, 5 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 87db026183..5933a4383c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -62,6 +62,7 @@
 - Fix: リプライのみの引用リノートと、CWのみの引用リノートが純粋なリノートとして誤って扱われてしまう問題を修正
 - Fix: 登録にメール認証が必須になっている場合、登録されているメールアドレスを削除できないように  
   (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/606)
+- Fix: Add Cache-Control to Bull Board
 - Fix: nginx経由で/files/にRangeリクエストされた場合に正しく応答できないのを修正
 - Fix: 一部のタイムラインのストリーミングでインスタンスミュートが効かない問題を修正
 - Fix: グローバルタイムラインで返信が表示されないことがある問題を修正
diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts
index b1af0c3df6..ba2f8b4324 100644
--- a/packages/backend/src/server/web/ClientServerService.ts
+++ b/packages/backend/src/server/web/ClientServerService.ts
@@ -202,6 +202,10 @@ export class ClientServerService {
 			// %71ueueとかでリクエストされたら困るため
 			const url = decodeURI(request.routeOptions.url);
 			if (url === bullBoardPath || url.startsWith(bullBoardPath + '/')) {
+				if (!url.startsWith(bullBoardPath + '/static/')) {
+					reply.header('Cache-Control', 'private, max-age=0, must-revalidate');
+				}
+
 				const token = request.cookies.token;
 				if (token == null) {
 					reply.code(401).send('Login required');

From f53e22d72c2e67cf4f89dec3c55c7a9a1a970dc8 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Sat, 27 Apr 2024 16:12:00 +0900
Subject: [PATCH 091/191] add comma (#13746)

---
 packages/frontend/src/pages/flash/flash-edit.vue | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/packages/frontend/src/pages/flash/flash-edit.vue b/packages/frontend/src/pages/flash/flash-edit.vue
index bff45094a1..3445da26a2 100644
--- a/packages/frontend/src/pages/flash/flash-edit.vue
+++ b/packages/frontend/src/pages/flash/flash-edit.vue
@@ -163,11 +163,11 @@ var cursor = 0
 						text: "←"
 						disabled: !(results.len > 1 && (results.len - cursor) > 1)
 						onClick: back
-					} {
+					}, {
 						text: "→"
 						disabled: !(results.len > 1 && cursor > 0)
 						onClick: forward
-					} {
+					}, {
 						text: "引き直す"
 						onClick: do
 					}]
@@ -196,17 +196,17 @@ let qas = [{
 	choices: ['シドニー', 'キャンベラ', 'メルボルン']
 	a: 'キャンベラ'
 	aDescription: '最大の都市はシドニーですが首都はキャンベラです。'
-} {
+}, {
 	q: '国土面積2番目の国は?'
 	choices: ['カナダ', 'アメリカ', '中国']
 	a: 'カナダ'
 	aDescription: '大きい順にロシア、カナダ、アメリカ、中国です。'
-} {
+}, {
 	q: '二重内陸国ではないのは?'
 	choices: ['リヒテンシュタイン', 'ウズベキスタン', 'レソト']
 	a: 'レソト'
 	aDescription: 'レソトは(一重)内陸国です。'
-} {
+}, {
 	q: '閘門がない運河は?'
 	choices: ['キール運河', 'スエズ運河', 'パナマ運河']
 	a: 'スエズ運河'
@@ -244,9 +244,9 @@ each (let qa, qas) {
 			})
 			Ui:C:container({
 				children: []
-			} \`{qa.id}:a\`)
+			}, \`{qa.id}:a\`)
 		]
-	} qa.id))
+	}, qa.id))
 }
 
 @finish() {

From 0a31e132c74cc2d8029cdadd103ea66a3ce16b6a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sat, 27 Apr 2024 16:48:04 +0900
Subject: [PATCH 092/191] =?UTF-8?q?fix(frontend):=20Play=E3=81=AEAiScript?=
 =?UTF-8?q?=E3=83=A9=E3=83=B3=E3=82=BF=E3=82=A4=E3=83=A0=E3=81=8C=E5=81=9C?=
 =?UTF-8?q?=E6=AD=A2=E3=81=97=E3=81=9F=E3=81=A8=E3=81=8D=E3=81=AB=E7=94=BB?=
 =?UTF-8?q?=E9=9D=A2=E3=81=8C=E5=88=9D=E6=9C=9F=E5=8C=96=E3=81=95=E3=82=8C?=
 =?UTF-8?q?=E3=81=A6=E3=81=84=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92?=
 =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20(#13747)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(frontend): PlayのAiScriptランタイムが停止したときに画面が初期化されていない問題を修正

* fix

* Update Changelog

* typo
---
 CHANGELOG.md                                |  2 +
 packages/frontend/src/pages/flash/flash.vue | 82 ++++++++++++++++-----
 2 files changed, 66 insertions(+), 18 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5933a4383c..e4605fe746 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -35,6 +35,7 @@
 - Enhance: リプライにて引用がある場合テキストが空でもノートできるように
   - 引用したいノートのURLをコピーしリプライ投稿画面にペーストして添付することで達成できます
 - Enhance: フォローするかどうかの確認ダイアログを出せるように
+- Enhance: Playを手動でリロードできるように
 - Chore: AiScriptを0.18.0にバージョンアップ
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
@@ -50,6 +51,7 @@
 - Fix: ノート詳細ページにおいてCW付き引用リノートのCWボタンのラベルに「引用」が含まれていない問題を修正
 - Fix: ダイアログの入力で字数制限に違反していてもEnterキーが押せてしまう問題を修正
 - Fix: ダイレクト投稿の宛先が保存されない問題を修正
+- Fix: Playのページを離れたときに、Playが正常に初期化されない問題を修正
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
diff --git a/packages/frontend/src/pages/flash/flash.vue b/packages/frontend/src/pages/flash/flash.vue
index 4aa3ce1672..40499fde0e 100644
--- a/packages/frontend/src/pages/flash/flash.vue
+++ b/packages/frontend/src/pages/flash/flash.vue
@@ -15,11 +15,15 @@ SPDX-License-Identifier: AGPL-3.0-only
 							<MkAsUi v-if="root" :component="root" :components="components"/>
 						</div>
 						<div class="actions _panel">
-							<MkButton v-if="flash.isLiked" v-tooltip="i18n.ts.unlike" asLike class="button" rounded primary @click="unlike()"><i class="ti ti-heart"></i><span v-if="flash.likedCount > 0" style="margin-left: 6px;">{{ flash.likedCount }}</span></MkButton>
-							<MkButton v-else v-tooltip="i18n.ts.like" asLike class="button" rounded @click="like()"><i class="ti ti-heart"></i><span v-if="flash.likedCount > 0" style="margin-left: 6px;">{{ flash.likedCount }}</span></MkButton>
-							<MkButton v-tooltip="i18n.ts.shareWithNote" class="button" rounded @click="shareWithNote"><i class="ti ti-repeat ti-fw"></i></MkButton>
-							<MkButton v-tooltip="i18n.ts.copyLink" class="button" rounded @click="copyLink"><i class="ti ti-link ti-fw"></i></MkButton>
-							<MkButton v-if="isSupportShare()" v-tooltip="i18n.ts.share" class="button" rounded @click="share"><i class="ti ti-share ti-fw"></i></MkButton>
+							<div class="items">
+								<MkButton v-tooltip="i18n.ts.reload" class="button" rounded @click="reset"><i class="ti ti-reload"></i></MkButton>
+							</div>
+							<div class="items">
+								<MkButton v-if="flash.isLiked" v-tooltip="i18n.ts.unlike" asLike class="button" rounded primary @click="unlike()"><i class="ti ti-heart"></i><span v-if="flash?.likedCount && flash.likedCount > 0" style="margin-left: 6px;">{{ flash.likedCount }}</span></MkButton>
+								<MkButton v-else v-tooltip="i18n.ts.like" asLike class="button" rounded @click="like()"><i class="ti ti-heart"></i><span v-if="flash?.likedCount && flash.likedCount > 0" style="margin-left: 6px;">{{ flash.likedCount }}</span></MkButton>
+								<MkButton v-tooltip="i18n.ts.copyLink" class="button" rounded @click="copyLink"><i class="ti ti-link ti-fw"></i></MkButton>
+								<MkButton v-tooltip="i18n.ts.share" class="button" rounded @click="share"><i class="ti ti-share ti-fw"></i></MkButton>
+							</div>
 						</div>
 					</div>
 					<div v-else :class="$style.ready">
@@ -49,7 +53,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 				<MkA v-if="$i && $i.id === flash.userId" :to="`/play/${flash.id}/edit`" style="color: var(--accent);">{{ i18n.ts._play.editThisPage }}</MkA>
 				<MkAd :prefer="['horizontal', 'horizontal-big']"/>
 			</div>
-			<MkError v-else-if="error" @retry="fetchPage()"/>
+			<MkError v-else-if="error" @retry="fetchFlash()"/>
 			<MkLoading v-else/>
 		</Transition>
 	</MkSpacer>
@@ -94,12 +98,33 @@ function fetchFlash() {
 	});
 }
 
+function share(ev: MouseEvent) {
+	if (!flash.value) return;
+
+	os.popupMenu([
+		{
+			text: i18n.ts.shareWithNote,
+			icon: 'ti ti-pencil',
+			action: shareWithNote,
+		},
+		...(isSupportShare() ? [{
+			text: i18n.ts.share,
+			icon: 'ti ti-share',
+			action: shareWithNavigator,
+		}] : []),
+	], ev.currentTarget ?? ev.target);
+}
+
 function copyLink() {
+	if (!flash.value) return;
+
 	copyToClipboard(`${url}/play/${flash.value.id}`);
 	os.success();
 }
 
-function share() {
+function shareWithNavigator() {
+	if (!flash.value) return;
+
 	navigator.share({
 		title: flash.value.title,
 		text: flash.value.summary,
@@ -108,21 +133,28 @@ function share() {
 }
 
 function shareWithNote() {
+	if (!flash.value) return;
+
 	os.post({
-		initialText: `${flash.value.title} ${url}/play/${flash.value.id}`,
+		initialText: `${flash.value.title}\n${url}/play/${flash.value.id}`,
+		instant: true,
 	});
 }
 
 function like() {
+	if (!flash.value) return;
+
 	os.apiWithDialog('flash/like', {
 		flashId: flash.value.id,
 	}).then(() => {
-		flash.value.isLiked = true;
-		flash.value.likedCount++;
+		flash.value!.isLiked = true;
+		flash.value!.likedCount++;
 	});
 }
 
 async function unlike() {
+	if (!flash.value) return;
+
 	const confirm = await os.confirm({
 		type: 'warning',
 		text: i18n.ts.unlikeConfirm,
@@ -131,8 +163,8 @@ async function unlike() {
 	os.apiWithDialog('flash/unlike', {
 		flashId: flash.value.id,
 	}).then(() => {
-		flash.value.isLiked = false;
-		flash.value.likedCount--;
+		flash.value!.isLiked = false;
+		flash.value!.likedCount--;
 	});
 }
 
@@ -152,6 +184,7 @@ function start() {
 
 async function run() {
 	if (aiscript.value) aiscript.value.abort();
+	if (!flash.value) return;
 
 	aiscript.value = new Interpreter({
 		...createAiScriptEnv({
@@ -193,12 +226,17 @@ async function run() {
 	}
 }
 
-onDeactivated(() => {
+function reset() {
 	if (aiscript.value) aiscript.value.abort();
+	started.value = false;
+}
+
+onDeactivated(() => {
+	reset();
 });
 
 onUnmounted(() => {
-	if (aiscript.value) aiscript.value.abort();
+	reset();
 });
 
 const headerActions = computed(() => []);
@@ -265,11 +303,19 @@ definePageMetadata(() => ({
 		}
 
 		> .actions {
-			display: flex;
-			justify-content: center;
-			gap: 12px;
 			margin-top: 16px;
-			padding: 16px;
+
+			> .items {
+				display: flex;
+				justify-content: center;
+				gap: 12px;
+				padding: 16px;
+				border-bottom: 1px solid var(--divider);
+
+				&:last-child {
+					border-bottom: none;
+				}
+			}
 		}
 	}
 }

From cb5d8bdcddf76e26b9d0b80855955faa38ec6c36 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sat, 27 Apr 2024 18:53:28 +0900
Subject: [PATCH 093/191] =?UTF-8?q?fix(backend):=20=E3=83=9A=E3=83=BC?=
 =?UTF-8?q?=E3=82=B8=E3=81=AEOGP=20URL=E3=81=8C=E9=81=95=E3=81=86=E3=81=AE?=
 =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3=20(#13749)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(backend): ページのOGP URLが違うのを修正

* Update Changelog

* typo
---
 CHANGELOG.md                                   | 1 +
 packages/backend/src/server/web/views/page.pug | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index e4605fe746..a263680782 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -52,6 +52,7 @@
 - Fix: ダイアログの入力で字数制限に違反していてもEnterキーが押せてしまう問題を修正
 - Fix: ダイレクト投稿の宛先が保存されない問題を修正
 - Fix: Playのページを離れたときに、Playが正常に初期化されない問題を修正
+- Fix: ページのOGP URLが間違っているのを修正
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
diff --git a/packages/backend/src/server/web/views/page.pug b/packages/backend/src/server/web/views/page.pug
index 08bb08ffe7..03c50eca8a 100644
--- a/packages/backend/src/server/web/views/page.pug
+++ b/packages/backend/src/server/web/views/page.pug
@@ -3,7 +3,7 @@ extends ./base
 block vars
 	- const user = page.user;
 	- const title = page.title;
-	- const url = `${config.url}/@${user.username}/${page.name}`;
+	- const url = `${config.url}/@${user.username}/pages/${page.name}`;
 
 block title
 	= `${title} | ${instanceName}`

From 7ce6a9bbaffddc6019ce2eab8b7a06c119ff2f69 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sat, 27 Apr 2024 19:59:30 +0900
Subject: [PATCH 094/191] =?UTF-8?q?fix(frontend):=20=E3=82=B0=E3=83=AB?=
 =?UTF-8?q?=E3=83=BC=E3=83=97=E9=80=9A=E7=9F=A5=E3=81=AE=E4=BA=BA=E6=95=B0?=
 =?UTF-8?q?=E3=82=92=E3=81=A1=E3=82=83=E3=82=93=E3=81=A8=E6=95=B0=E3=81=88?=
 =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=20(#13751)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(frontend): グループ通知の人数をちゃんと数えるように

* Update Changelog
---
 CHANGELOG.md                                        |  1 +
 packages/frontend/src/components/MkNotification.vue | 11 ++++++++---
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index a263680782..1a43649fdb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -53,6 +53,7 @@
 - Fix: ダイレクト投稿の宛先が保存されない問題を修正
 - Fix: Playのページを離れたときに、Playが正常に初期化されない問題を修正
 - Fix: ページのOGP URLが間違っているのを修正
+- Fix: 通知をグループ化している際に、人数が正常に表示されないことがある問題を修正
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue
index 0d3a5c13ba..73cd7cd5b3 100644
--- a/packages/frontend/src/components/MkNotification.vue
+++ b/packages/frontend/src/components/MkNotification.vue
@@ -58,8 +58,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 			<span v-else-if="notification.type === 'achievementEarned'">{{ i18n.ts._notification.achievementEarned }}</span>
 			<span v-else-if="notification.type === 'test'">{{ i18n.ts._notification.testNotification }}</span>
 			<MkA v-else-if="notification.type === 'follow' || notification.type === 'mention' || notification.type === 'reply' || notification.type === 'renote' || notification.type === 'quote' || notification.type === 'reaction' || notification.type === 'receiveFollowRequest' || notification.type === 'followRequestAccepted'" v-user-preview="notification.user.id" :class="$style.headerName" :to="userPage(notification.user)"><MkUserName :user="notification.user"/></MkA>
-			<span v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'">{{ i18n.tsx._notification.likedBySomeUsers({ n: notification.reactions.length }) }}</span>
-			<span v-else-if="notification.type === 'reaction:grouped'">{{ i18n.tsx._notification.reactedBySomeUsers({ n: notification.reactions.length }) }}</span>
+			<span v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'">{{ i18n.tsx._notification.likedBySomeUsers({ n: getActualReactedUsersCount(notification) }) }}</span>
+			<span v-else-if="notification.type === 'reaction:grouped'">{{ i18n.tsx._notification.reactedBySomeUsers({ n: getActualReactedUsersCount(notification) }) }}</span>
 			<span v-else-if="notification.type === 'renote:grouped'">{{ i18n.tsx._notification.renotedBySomeUsers({ n: notification.users.length }) }}</span>
 			<span v-else-if="notification.type === 'app'">{{ notification.header }}</span>
 			<MkTime v-if="withTime" :time="notification.createdAt" :class="$style.headerTime"/>
@@ -72,7 +72,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 			</MkA>
 			<MkA v-else-if="notification.type === 'renote' || notification.type === 'renote:grouped'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note.renote)">
 				<i class="ti ti-quote" :class="$style.quote"></i>
-				<Mfm :text="getNoteSummary(notification.note.renote)" :plain="true" :nowrap="true" :author="notification.note.renote.user"/>
+				<Mfm :text="getNoteSummary(notification.note.renote)" :plain="true" :nowrap="true" :author="notification.note.renote?.user"/>
 				<i class="ti ti-quote" :class="$style.quote"></i>
 			</MkA>
 			<MkA v-else-if="notification.type === 'reply'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
@@ -174,6 +174,11 @@ const rejectFollowRequest = () => {
 	followRequestDone.value = true;
 	misskeyApi('following/requests/reject', { userId: props.notification.user.id });
 };
+
+function getActualReactedUsersCount(notification: Misskey.entities.Notification) {
+	if (notification.type !== 'reaction:grouped') return 0;
+	return new Set(notification.reactions.map((reaction) => reaction.user.id)).size;
+}
 </script>
 
 <style lang="scss" module>

From 78e61c65be76f6f4d8088d6c81efc514db0e8251 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sat, 27 Apr 2024 20:00:57 +0900
Subject: [PATCH 095/191] =?UTF-8?q?fix(frontend=5Freversi):=20=E5=85=B1?=
 =?UTF-8?q?=E6=9C=89=E3=83=9C=E3=82=BF=E3=83=B3=E3=81=AE=E5=AE=9F=E8=A3=85?=
 =?UTF-8?q?=E3=82=92=E6=94=B9=E5=96=84=20(#13750)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(frontend_reversi): 共有ボタンの実装を改善

* Update Changelog

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 CHANGELOG.md                                       | 1 +
 packages/frontend/src/pages/reversi/game.board.vue | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1a43649fdb..bc98ff0b1a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -53,6 +53,7 @@
 - Fix: ダイレクト投稿の宛先が保存されない問題を修正
 - Fix: Playのページを離れたときに、Playが正常に初期化されない問題を修正
 - Fix: ページのOGP URLが間違っているのを修正
+- Fix: リバーシの対局を正しく共有できないことがある問題を修正
 - Fix: 通知をグループ化している際に、人数が正常に表示されないことがある問題を修正
 
 ### Server
diff --git a/packages/frontend/src/pages/reversi/game.board.vue b/packages/frontend/src/pages/reversi/game.board.vue
index 5259dfa29a..175ea62411 100644
--- a/packages/frontend/src/pages/reversi/game.board.vue
+++ b/packages/frontend/src/pages/reversi/game.board.vue
@@ -151,6 +151,7 @@ import MkSwitch from '@/components/MkSwitch.vue';
 import { deepClone } from '@/scripts/clone.js';
 import { useInterval } from '@/scripts/use-interval.js';
 import { signinRequired } from '@/account.js';
+import { url } from '@/config.js';
 import { i18n } from '@/i18n.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { userPage } from '@/filters/user.js';
@@ -442,7 +443,7 @@ function autoplay() {
 
 function share() {
 	os.post({
-		initialText: `#MisskeyReversi ${location.href}`,
+		initialText: `#MisskeyReversi\n${url}/reversi/g/${game.value.id}`,
 		instant: true,
 	});
 }

From 20eb4bc29600975ea9b6d74426204b8f6871bc27 Mon Sep 17 00:00:00 2001
From: ikasoba <57828948+ikasoba@users.noreply.github.com>
Date: Sat, 27 Apr 2024 20:26:55 +0900
Subject: [PATCH 096/191] =?UTF-8?q?Fix(backend):=20ActivityPub=E3=81=A7?=
 =?UTF-8?q?=E3=81=AEHTML=E3=81=B8=E3=81=AE=E3=82=B7=E3=83=AA=E3=82=A2?=
 =?UTF-8?q?=E3=83=A9=E3=82=A4=E3=82=BA=E3=82=92=E4=BF=AE=E6=AD=A3=20(#1375?=
 =?UTF-8?q?2)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* devモードでもActivityPub系エンドポイントへアクセスできるように

* ActivityPubでのHTMLのシリアライズを修正

* ハードコードしていたurlを`httpUrl`へ修正

* テストの追加
---
 packages/backend/src/core/MfmService.ts    |  8 +++++---
 packages/backend/test/unit/MfmService.ts   |  6 ++++++
 packages/frontend/vite.config.local-dev.ts | 16 ++++++++++++++++
 3 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/packages/backend/src/core/MfmService.ts b/packages/backend/src/core/MfmService.ts
index 2fb731201b..9786f8b8bb 100644
--- a/packages/backend/src/core/MfmService.ts
+++ b/packages/backend/src/core/MfmService.ts
@@ -6,7 +6,7 @@
 import { URL } from 'node:url';
 import { Inject, Injectable } from '@nestjs/common';
 import * as parse5 from 'parse5';
-import { Window } from 'happy-dom';
+import { Window, XMLSerializer } from 'happy-dom';
 import { DI } from '@/di-symbols.js';
 import type { Config } from '@/config.js';
 import { intersperse } from '@/misc/prelude/array.js';
@@ -247,6 +247,8 @@ export class MfmService {
 
 		const doc = window.document;
 
+		const body = doc.createElement('p');
+
 		function appendChildren(children: mfm.MfmNode[], targetElement: any): void {
 			if (children) {
 				for (const child of children.map(x => (handlers as any)[x.type](x))) targetElement.appendChild(child);
@@ -457,8 +459,8 @@ export class MfmService {
 			},
 		};
 
-		appendChildren(nodes, doc.body);
+		appendChildren(nodes, body);
 
-		return `<p>${doc.body.innerHTML}</p>`;
+		return new XMLSerializer().serializeToString(body);
 	}
 }
diff --git a/packages/backend/test/unit/MfmService.ts b/packages/backend/test/unit/MfmService.ts
index f613fe9c7c..fd4a03413b 100644
--- a/packages/backend/test/unit/MfmService.ts
+++ b/packages/backend/test/unit/MfmService.ts
@@ -39,6 +39,12 @@ describe('MfmService', () => {
 			const output = '<p>foo <i>bar</i></p>';
 			assert.equal(mfmService.toHtml(mfm.parse(input)), output);
 		});
+
+		test('escape', () => {
+			const input = '```\n<p>Hello, world!</p>\n```';
+			const output = '<p><pre><code>&lt;p&gt;Hello, world!&lt;/p&gt;</code></pre></p>';
+			assert.equal(mfmService.toHtml(mfm.parse(input)), output);
+		});
 	});
 
 	describe('fromHtml', () => {
diff --git a/packages/frontend/vite.config.local-dev.ts b/packages/frontend/vite.config.local-dev.ts
index 460787fd05..f9dff13b15 100644
--- a/packages/frontend/vite.config.local-dev.ts
+++ b/packages/frontend/vite.config.local-dev.ts
@@ -51,6 +51,22 @@ const devConfig = {
 			'/_info_card_': httpUrl,
 			'/bios': httpUrl,
 			'/cli': httpUrl,
+			'/inbox': httpUrl,
+			'/notes': {
+				target: httpUrl,
+				headers: {
+					'Accept': 'application/activity+json',
+				},
+			},
+			'/users': {
+				target: httpUrl,
+				headers: {
+					'Accept': 'application/activity+json',
+				},
+			},
+			'/.well-known': {
+				target: httpUrl,
+			},
 		},
 	},
 	build: {

From fe1172fbb637ad8af3688fae56b10c435b9cf497 Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Sat, 27 Apr 2024 20:41:55 +0900
Subject: [PATCH 097/191] =?UTF-8?q?fix:=20=E3=83=8F=E3=82=A4=E3=83=95?=
 =?UTF-8?q?=E3=83=B3=E3=82=92=E5=90=AB=E3=82=80=E3=83=AA=E3=83=A2=E3=83=BC?=
 =?UTF-8?q?=E3=83=88=E7=B5=B5=E6=96=87=E5=AD=97=E3=81=8C=E6=8F=8F=E7=94=BB?=
 =?UTF-8?q?=E3=81=95=E3=82=8C=E3=81=AA=E3=81=84=20(#13715)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 packages/backend/src/core/CustomEmojiService.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts
index edb9335b6e..1c75566755 100644
--- a/packages/backend/src/core/CustomEmojiService.ts
+++ b/packages/backend/src/core/CustomEmojiService.ts
@@ -20,7 +20,7 @@ import { query } from '@/misc/prelude/url.js';
 import type { Serialized } from '@/types.js';
 import { ModerationLogService } from '@/core/ModerationLogService.js';
 
-const parseEmojiStrRegexp = /^(\w+)(?:@([\w.-]+))?$/;
+const parseEmojiStrRegexp = /^([-\w]+)(?:@([\w.-]+))?$/;
 
 @Injectable()
 export class CustomEmojiService implements OnApplicationShutdown {

From 8e8ee2ac73093b566d0b3905de884e660e67d614 Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Sat, 27 Apr 2024 21:24:39 +0900
Subject: [PATCH 098/191] open links in abuse comment in new window (#13381)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* feat: changing MkA behavior from MkMFM

* chore: open links in abuse comment in new window

* docs(changelog): 通報のコメント内のリンクをクリックした際、ウィンドウで開くように

* chore: use inject instead of prop drilling

* Revert "chore: use inject instead of prop drilling"

This reverts commit b4dd14eacf59c8079676aa6ab019fece67496d79.
---
 CHANGELOG.md                                              | 1 +
 packages/frontend/src/components/MkAbuseReport.vue        | 2 +-
 packages/frontend/src/components/MkLink.vue               | 3 +++
 packages/frontend/src/components/MkMention.vue            | 4 +++-
 packages/frontend/src/components/global/MkA.vue           | 8 +++++++-
 .../src/components/global/MkMisskeyFlavoredMarkdown.ts    | 7 ++++++-
 packages/frontend/src/components/global/MkUrl.vue         | 3 +++
 7 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index bc98ff0b1a..f22cec856f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -36,6 +36,7 @@
   - 引用したいノートのURLをコピーしリプライ投稿画面にペーストして添付することで達成できます
 - Enhance: フォローするかどうかの確認ダイアログを出せるように
 - Enhance: Playを手動でリロードできるように
+- Enhance: 通報のコメント内のリンクをクリックした際、ウィンドウで開くように
 - Chore: AiScriptを0.18.0にバージョンアップ
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
diff --git a/packages/frontend/src/components/MkAbuseReport.vue b/packages/frontend/src/components/MkAbuseReport.vue
index 271b94feaa..ab65ea7ec7 100644
--- a/packages/frontend/src/components/MkAbuseReport.vue
+++ b/packages/frontend/src/components/MkAbuseReport.vue
@@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 	</div>
 	<div class="detail">
 		<div>
-			<Mfm :text="report.comment"/>
+			<Mfm :text="report.comment" :linkBehavior="'window'"/>
 		</div>
 		<hr/>
 		<div>{{ i18n.ts.reporter }}: <MkA :to="`/admin/user/${report.reporter.id}`" class="_link" :behavior="'window'">@{{ report.reporter.username }}</MkA></div>
diff --git a/packages/frontend/src/components/MkLink.vue b/packages/frontend/src/components/MkLink.vue
index ca875242b4..bd1bd0e24a 100644
--- a/packages/frontend/src/components/MkLink.vue
+++ b/packages/frontend/src/components/MkLink.vue
@@ -6,6 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 <template>
 <component
 	:is="self ? 'MkA' : 'a'" ref="el" style="word-break: break-all;" class="_link" :[attr]="self ? url.substring(local.length) : url" :rel="rel ?? 'nofollow noopener'" :target="target"
+	:behavior="props.behavior"
 	:title="url"
 >
 	<slot></slot>
@@ -19,10 +20,12 @@ import { url as local } from '@/config.js';
 import { useTooltip } from '@/scripts/use-tooltip.js';
 import * as os from '@/os.js';
 import { isEnabledUrlPreview } from '@/instance.js';
+import { MkABehavior } from '@/components/global/MkA.vue';
 
 const props = withDefaults(defineProps<{
 	url: string;
 	rel?: null | string;
+	behavior?: MkABehavior;
 }>(), {
 });
 
diff --git a/packages/frontend/src/components/MkMention.vue b/packages/frontend/src/components/MkMention.vue
index e6e8711f67..cbefecf03a 100644
--- a/packages/frontend/src/components/MkMention.vue
+++ b/packages/frontend/src/components/MkMention.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-<MkA v-user-preview="canonical" :class="[$style.root, { [$style.isMe]: isMe }]" :to="url" :style="{ background: bgCss }">
+<MkA v-user-preview="canonical" :class="[$style.root, { [$style.isMe]: isMe }]" :to="url" :style="{ background: bgCss }" :behavior="behavior">
 	<img :class="$style.icon" :src="avatarUrl" alt="">
 	<span>
 		<span>@{{ username }}</span>
@@ -21,10 +21,12 @@ import { host as localHost } from '@/config.js';
 import { $i } from '@/account.js';
 import { defaultStore } from '@/store.js';
 import { getStaticImageUrl } from '@/scripts/media-proxy.js';
+import { MkABehavior } from '@/components/global/MkA.vue';
 
 const props = defineProps<{
 	username: string;
 	host: string;
+	behavior?: MkABehavior;
 }>();
 
 const canonical = props.host === localHost ? `@${props.username}` : `@${props.username}@${toUnicode(props.host)}`;
diff --git a/packages/frontend/src/components/global/MkA.vue b/packages/frontend/src/components/global/MkA.vue
index 1ba7cb2022..b64acacc32 100644
--- a/packages/frontend/src/components/global/MkA.vue
+++ b/packages/frontend/src/components/global/MkA.vue
@@ -9,6 +9,10 @@ SPDX-License-Identifier: AGPL-3.0-only
 </a>
 </template>
 
+<script lang="ts">
+export type MkABehavior = 'window' | 'browser' | null;
+</script>
+
 <script lang="ts" setup>
 import { computed, shallowRef } from 'vue';
 import * as os from '@/os.js';
@@ -20,12 +24,14 @@ import { useRouter } from '@/router/supplier.js';
 const props = withDefaults(defineProps<{
 	to: string;
 	activeClass?: null | string;
-	behavior?: null | 'window' | 'browser';
+	behavior?: MkABehavior;
 }>(), {
 	activeClass: null,
 	behavior: null,
 });
 
+const linkBehaviour = props.behavior;
+
 const el = shallowRef<HTMLElement>();
 
 defineExpose({ $el: el });
diff --git a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
index 4ed76f6bc4..a56d8bcce2 100644
--- a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
+++ b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
@@ -16,7 +16,7 @@ import MkCode from '@/components/MkCode.vue';
 import MkCodeInline from '@/components/MkCodeInline.vue';
 import MkGoogle from '@/components/MkGoogle.vue';
 import MkSparkle from '@/components/MkSparkle.vue';
-import MkA from '@/components/global/MkA.vue';
+import MkA, {MkABehavior} from '@/components/global/MkA.vue';
 import { host } from '@/config.js';
 import { defaultStore } from '@/store.js';
 import { nyaize as doNyaize } from '@/scripts/nyaize.js';
@@ -43,6 +43,7 @@ type MfmProps = {
 	parsedNodes?: mfm.MfmNode[] | null;
 	enableEmojiMenu?: boolean;
 	enableEmojiMenuReaction?: boolean;
+	linkBehavior?: MkABehavior;
 };
 
 type MfmEvents = {
@@ -342,6 +343,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
 					key: Math.random(),
 					url: token.props.url,
 					rel: 'nofollow noopener',
+					behavior: props.linkBehavior,
 				})];
 			}
 
@@ -350,6 +352,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
 					key: Math.random(),
 					url: token.props.url,
 					rel: 'nofollow noopener',
+					behavior: props.linkBehavior,
 				}, genEl(token.children, scale, true))];
 			}
 
@@ -358,6 +361,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
 					key: Math.random(),
 					host: (token.props.host == null && props.author && props.author.host != null ? props.author.host : token.props.host) ?? host,
 					username: token.props.username,
+					behavior: props.linkBehavior,
 				})];
 			}
 
@@ -366,6 +370,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
 					key: Math.random(),
 					to: isNote ? `/tags/${encodeURIComponent(token.props.hashtag)}` : `/user-tags/${encodeURIComponent(token.props.hashtag)}`,
 					style: 'color:var(--hashtag);',
+					behavior: props.linkBehavior,
 				}, `#${token.props.hashtag}`)];
 			}
 
diff --git a/packages/frontend/src/components/global/MkUrl.vue b/packages/frontend/src/components/global/MkUrl.vue
index d2945a78b9..1c2f3ccedb 100644
--- a/packages/frontend/src/components/global/MkUrl.vue
+++ b/packages/frontend/src/components/global/MkUrl.vue
@@ -6,6 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 <template>
 <component
 	:is="self ? 'MkA' : 'a'" ref="el" :class="$style.root" class="_link" :[attr]="self ? props.url.substring(local.length) : props.url" :rel="rel ?? 'nofollow noopener'" :target="target"
+	:behavior = "props.behavior"
 	@contextmenu.stop="() => {}"
 >
 	<template v-if="!self">
@@ -31,11 +32,13 @@ import * as os from '@/os.js';
 import { useTooltip } from '@/scripts/use-tooltip.js';
 import { safeURIDecode } from '@/scripts/safe-uri-decode.js';
 import { isEnabledUrlPreview } from '@/instance.js';
+import { MkABehavior } from '@/components/global/MkA.vue';
 
 const props = withDefaults(defineProps<{
 	url: string;
 	rel?: string;
 	showUrlPreview?: boolean;
+	behavior?: MkABehavior;
 }>(), {
 	showUrlPreview: true,
 });

From c7d7da8fc58ace9be6cf3af1040ed3a4b7309064 Mon Sep 17 00:00:00 2001
From: MeiMei <30769358+mei23@users.noreply.github.com>
Date: Sun, 28 Apr 2024 10:53:33 +0900
Subject: [PATCH 099/191] =?UTF-8?q?AP=20Link=E7=AD=89=E3=81=AF=E6=B7=BB?=
 =?UTF-8?q?=E4=BB=98=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E6=89=B1=E3=81=84?=
 =?UTF-8?q?=E3=81=97=E3=81=AA=E3=81=84=E3=82=88=E3=81=86=E3=81=AB=E3=81=AA?=
 =?UTF-8?q?=E3=81=A9=20(#13754)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Linkは添付ファイルではない

* CHANGELOG
---
 CHANGELOG.md                                  |  1 +
 .../core/activitypub/models/ApImageService.ts | 19 +++++++-------
 .../core/activitypub/models/ApNoteService.ts  | 17 +++++-------
 packages/backend/src/core/activitypub/type.ts | 11 ++++----
 packages/backend/test/unit/activitypub.ts     | 26 ++++++++++++++-----
 5 files changed, 43 insertions(+), 31 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index f22cec856f..68015596bd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -73,6 +73,7 @@
 - Fix: 一部のタイムラインのストリーミングでインスタンスミュートが効かない問題を修正
 - Fix: グローバルタイムラインで返信が表示されないことがある問題を修正
 - Fix: リノートをミュートしたユーザの投稿のリノートがミュートされる問題を修正
+- Fix: AP Link等は添付ファイル扱いしないようになど (#13754)
 
 ## 2024.3.1
 
diff --git a/packages/backend/src/core/activitypub/models/ApImageService.ts b/packages/backend/src/core/activitypub/models/ApImageService.ts
index 89b6ef23d0..3691967270 100644
--- a/packages/backend/src/core/activitypub/models/ApImageService.ts
+++ b/packages/backend/src/core/activitypub/models/ApImageService.ts
@@ -17,7 +17,7 @@ import { bindThis } from '@/decorators.js';
 import { checkHttps } from '@/misc/check-https.js';
 import { ApResolverService } from '../ApResolverService.js';
 import { ApLoggerService } from '../ApLoggerService.js';
-import type { IObject } from '../type.js';
+import { isDocument, type IObject } from '../type.js';
 
 @Injectable()
 export class ApImageService {
@@ -39,7 +39,7 @@ export class ApImageService {
 	 * Imageを作成します。
 	 */
 	@bindThis
-	public async createImage(actor: MiRemoteUser, value: string | IObject): Promise<MiDriveFile> {
+	public async createImage(actor: MiRemoteUser, value: string | IObject): Promise<MiDriveFile | null> {
 		// 投稿者が凍結されていたらスキップ
 		if (actor.isSuspended) {
 			throw new Error('actor has been suspended');
@@ -47,16 +47,18 @@ export class ApImageService {
 
 		const image = await this.apResolverService.createResolver().resolve(value);
 
+		if (!isDocument(image)) return null;
+
 		if (image.url == null) {
-			throw new Error('invalid image: url not provided');
+			return null;
 		}
 
 		if (typeof image.url !== 'string') {
-			throw new Error('invalid image: unexpected type of url: ' + JSON.stringify(image.url, null, 2));
+			return null;
 		}
 
 		if (!checkHttps(image.url)) {
-			throw new Error('invalid image: unexpected schema of url: ' + image.url);
+			return null;
 		}
 
 		this.logger.info(`Creating the Image: ${image.url}`);
@@ -86,12 +88,11 @@ export class ApImageService {
 	/**
 	 * Imageを解決します。
 	 *
-	 * Misskeyに対象のImageが登録されていればそれを返し、そうでなければ
-	 * リモートサーバーからフェッチしてMisskeyに登録しそれを返します。
+	 * ImageをリモートサーバーからフェッチしてMisskeyに登録しそれを返します。
 	 */
 	@bindThis
-	public async resolveImage(actor: MiRemoteUser, value: string | IObject): Promise<MiDriveFile> {
-		// TODO
+	public async resolveImage(actor: MiRemoteUser, value: string | IObject): Promise<MiDriveFile | null> {
+		// TODO: Misskeyに対象のImageが登録されていればそれを返す
 
 		// リモートサーバーからフェッチしてきて登録
 		return await this.createImage(actor, value);
diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts
index 4d64b08e15..05f7879983 100644
--- a/packages/backend/src/core/activitypub/models/ApNoteService.ts
+++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts
@@ -4,7 +4,6 @@
  */
 
 import { forwardRef, Inject, Injectable } from '@nestjs/common';
-import promiseLimit from 'promise-limit';
 import { In } from 'typeorm';
 import { DI } from '@/di-symbols.js';
 import type { PollsRepository, EmojisRepository } from '@/models/_.js';
@@ -209,15 +208,13 @@ export class ApNoteService {
 		}
 
 		// 添付ファイル
-		// TODO: attachmentは必ずしもImageではない
-		// TODO: attachmentは必ずしも配列ではない
-		const limit = promiseLimit<MiDriveFile>(2);
-		const files = (await Promise.all(toArray(note.attachment).map(attach => (
-			limit(() => this.apImageService.resolveImage(actor, {
-				...attach,
-				sensitive: note.sensitive, // Noteがsensitiveなら添付もsensitiveにする
-			}))
-		))));
+		const files: MiDriveFile[] = [];
+
+		for (const attach of toArray(note.attachment)) {
+			attach.sensitive ||= note.sensitive;	// Noteがsensitiveなら添付もsensitiveにする
+			const file = await this.apImageService.resolveImage(actor, attach);
+			if (file) files.push(file);
+		}
 
 		// リプライ
 		const reply: MiNote | null = note.inReplyTo
diff --git a/packages/backend/src/core/activitypub/type.ts b/packages/backend/src/core/activitypub/type.ts
index b43dddad61..09322888d5 100644
--- a/packages/backend/src/core/activitypub/type.ts
+++ b/packages/backend/src/core/activitypub/type.ts
@@ -25,6 +25,7 @@ export interface IObject {
 	endTime?: Date;
 	icon?: any;
 	image?: any;
+	mediaType?: string;
 	url?: ApObject | string;
 	href?: string;
 	tag?: IObject | IObject[];
@@ -240,14 +241,14 @@ export interface IKey extends IObject {
 }
 
 export interface IApDocument extends IObject {
-	type: 'Document';
-	name: string | null;
-	mediaType: string;
+	type: 'Audio' | 'Document' | 'Image' | 'Page' | 'Video';
 }
 
-export interface IApImage extends IObject {
+export const isDocument = (object: IObject): object is IApDocument =>
+	['Audio', 'Document', 'Image', 'Page', 'Video'].includes(getApType(object));
+
+export interface IApImage extends IApDocument {
 	type: 'Image';
-	name: string | null;
 }
 
 export interface ICreate extends IActivity {
diff --git a/packages/backend/test/unit/activitypub.ts b/packages/backend/test/unit/activitypub.ts
index b4b06b06bd..aa3f3a4ff1 100644
--- a/packages/backend/test/unit/activitypub.ts
+++ b/packages/backend/test/unit/activitypub.ts
@@ -17,7 +17,7 @@ import { GlobalModule } from '@/GlobalModule.js';
 import { CoreModule } from '@/core/CoreModule.js';
 import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
 import { LoggerService } from '@/core/LoggerService.js';
-import type { IActor, IApDocument, ICollection, IPost } from '@/core/activitypub/type.js';
+import type { IActor, IApDocument, ICollection, IObject, IPost } from '@/core/activitypub/type.js';
 import { MiMeta, MiNote } from '@/models/_.js';
 import { secureRndstr } from '@/misc/secure-rndstr.js';
 import { DownloadService } from '@/core/DownloadService.js';
@@ -295,7 +295,7 @@ describe('ActivityPub', () => {
 				await createRandomRemoteUser(resolver, personService),
 				imageObject,
 			);
-			assert.ok(!driveFile.isLink);
+			assert.ok(driveFile && !driveFile.isLink);
 
 			const sensitiveImageObject: IApDocument = {
 				type: 'Document',
@@ -308,7 +308,7 @@ describe('ActivityPub', () => {
 				await createRandomRemoteUser(resolver, personService),
 				sensitiveImageObject,
 			);
-			assert.ok(!sensitiveDriveFile.isLink);
+			assert.ok(sensitiveDriveFile && !sensitiveDriveFile.isLink);
 		});
 
 		test('cacheRemoteFiles=false disables caching', async () => {
@@ -324,7 +324,7 @@ describe('ActivityPub', () => {
 				await createRandomRemoteUser(resolver, personService),
 				imageObject,
 			);
-			assert.ok(driveFile.isLink);
+			assert.ok(driveFile && driveFile.isLink);
 
 			const sensitiveImageObject: IApDocument = {
 				type: 'Document',
@@ -337,7 +337,7 @@ describe('ActivityPub', () => {
 				await createRandomRemoteUser(resolver, personService),
 				sensitiveImageObject,
 			);
-			assert.ok(sensitiveDriveFile.isLink);
+			assert.ok(sensitiveDriveFile && sensitiveDriveFile.isLink);
 		});
 
 		test('cacheRemoteSensitiveFiles=false only affects sensitive files', async () => {
@@ -353,7 +353,7 @@ describe('ActivityPub', () => {
 				await createRandomRemoteUser(resolver, personService),
 				imageObject,
 			);
-			assert.ok(!driveFile.isLink);
+			assert.ok(driveFile && !driveFile.isLink);
 
 			const sensitiveImageObject: IApDocument = {
 				type: 'Document',
@@ -366,7 +366,19 @@ describe('ActivityPub', () => {
 				await createRandomRemoteUser(resolver, personService),
 				sensitiveImageObject,
 			);
-			assert.ok(sensitiveDriveFile.isLink);
+			assert.ok(sensitiveDriveFile && sensitiveDriveFile.isLink);
+		});
+
+		test('Link is not an attachment files', async () => {
+			const linkObject: IObject = {
+				type: 'Link',
+				href: 'https://example.com/',
+			};
+			const driveFile = await imageService.createImage(
+				await createRandomRemoteUser(resolver, personService),
+				linkObject,
+			);
+			assert.strictEqual(driveFile, null);
 		});
 	});
 });

From e2ff5f58b2357b2433313b2885e7de7923f65205 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Sun, 28 Apr 2024 10:54:20 +0900
Subject: [PATCH 100/191] lint

---
 .../frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
index a56d8bcce2..6e880fc322 100644
--- a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
+++ b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
@@ -16,7 +16,7 @@ import MkCode from '@/components/MkCode.vue';
 import MkCodeInline from '@/components/MkCodeInline.vue';
 import MkGoogle from '@/components/MkGoogle.vue';
 import MkSparkle from '@/components/MkSparkle.vue';
-import MkA, {MkABehavior} from '@/components/global/MkA.vue';
+import MkA, { MkABehavior } from '@/components/global/MkA.vue';
 import { host } from '@/config.js';
 import { defaultStore } from '@/store.js';
 import { nyaize as doNyaize } from '@/scripts/nyaize.js';

From 2ff90a80d453e33caee2cc39f27149d1d7386ee1 Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Mon, 29 Apr 2024 15:36:01 +0900
Subject: [PATCH 101/191] fix(backend): add detailed schema to `fetch-rss`
 endpoint (#13764)

---
 .../src/server/api/endpoints/fetch-rss.ts     | 179 +++++++++++++++++-
 .../src/ui/_common_/statusbar-rss.vue         |   5 +-
 packages/frontend/src/widgets/WidgetRss.vue   |   7 +-
 .../frontend/src/widgets/WidgetRssTicker.vue  |   7 +-
 packages/misskey-js/src/autogen/types.ts      |  47 ++++-
 5 files changed, 234 insertions(+), 11 deletions(-)

diff --git a/packages/backend/src/server/api/endpoints/fetch-rss.ts b/packages/backend/src/server/api/endpoints/fetch-rss.ts
index 2085b06365..ba48b0119e 100644
--- a/packages/backend/src/server/api/endpoints/fetch-rss.ts
+++ b/packages/backend/src/server/api/endpoints/fetch-rss.ts
@@ -20,13 +20,188 @@ export const meta = {
 	res: {
 		type: 'object',
 		properties: {
+			image: {
+				type: 'object',
+				optional: true,
+				properties: {
+					link: {
+						type: 'string',
+						optional: true,
+					},
+					url: {
+						type: 'string',
+						optional: false,
+					},
+					title: {
+						type: 'string',
+						optional: true,
+					},
+				},
+			},
+			paginationLinks: {
+				type: 'object',
+				optional: true,
+				properties: {
+					self: {
+						type: 'string',
+						optional: true,
+					},
+					first: {
+						type: 'string',
+						optional: true,
+					},
+					next: {
+						type: 'string',
+						optional: true,
+					},
+					last: {
+						type: 'string',
+						optional: true,
+					},
+					prev: {
+						type: 'string',
+						optional: true,
+					},
+				},
+			},
+			link: {
+				type: 'string',
+				optional: true,
+			},
+			title: {
+				type: 'string',
+				optional: true,
+			},
 			items: {
 				type: 'array',
+				optional: false,
 				items: {
 					type: 'object',
+					properties: {
+						link: {
+							type: 'string',
+							optional: true,
+						},
+						guid: {
+							type: 'string',
+							optional: true,
+						},
+						title: {
+							type: 'string',
+							optional: true,
+						},
+						pubDate: {
+							type: 'string',
+							optional: true,
+						},
+						creator: {
+							type: 'string',
+							optional: true,
+						},
+						summary: {
+							type: 'string',
+							optional: true,
+						},
+						content: {
+							type: 'string',
+							optional: true,
+						},
+						isoDate: {
+							type: 'string',
+							optional: true,
+						},
+						categories: {
+							type: 'array',
+							optional: true,
+							items: {
+								type: 'string',
+							},
+						},
+						contentSnippet: {
+							type: 'string',
+							optional: true,
+						},
+						enclosure: {
+							type: 'object',
+							optional: true,
+							properties: {
+								url: {
+									type: 'string',
+									optional: false,
+								},
+								length: {
+									type: 'number',
+									optional: true,
+								},
+								type: {
+									type: 'string',
+									optional: true,
+								},
+							},
+						},
+					},
 				},
-			}
-		}
+			},
+			feedUrl: {
+				type: 'string',
+				optional: true,
+			},
+			description: {
+				type: 'string',
+				optional: true,
+			},
+			itunes: {
+				type: 'object',
+				optional: true,
+				additionalProperties: true,
+				properties: {
+					image: {
+						type: 'string',
+						optional: true,
+					},
+					owner: {
+						type: 'object',
+						optional: true,
+						properties: {
+							name: {
+								type: 'string',
+								optional: true,
+							},
+							email: {
+								type: 'string',
+								optional: true,
+							},
+						},
+					},
+					author: {
+						type: 'string',
+						optional: true,
+					},
+					summary: {
+						type: 'string',
+						optional: true,
+					},
+					explicit: {
+						type: 'string',
+						optional: true,
+					},
+					categories: {
+						type: 'array',
+						optional: true,
+						items: {
+							type: 'string',
+						},
+					},
+					keywords: {
+						type: 'array',
+						optional: true,
+						items: {
+							type: 'string',
+						},
+					},
+				},
+			},
+		},
 	},
 } as const;
 
diff --git a/packages/frontend/src/ui/_common_/statusbar-rss.vue b/packages/frontend/src/ui/_common_/statusbar-rss.vue
index b973a4fd6b..6e1d06eec1 100644
--- a/packages/frontend/src/ui/_common_/statusbar-rss.vue
+++ b/packages/frontend/src/ui/_common_/statusbar-rss.vue
@@ -28,6 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { ref } from 'vue';
+import * as Misskey from 'misskey-js';
 import MarqueeText from '@/components/MkMarquee.vue';
 import { useInterval } from '@/scripts/use-interval.js';
 import { shuffle } from '@/scripts/shuffle.js';
@@ -42,13 +43,13 @@ const props = defineProps<{
 	refreshIntervalSec?: number;
 }>();
 
-const items = ref([]);
+const items = ref<Misskey.entities.FetchRssResponse['items']>([]);
 const fetching = ref(true);
 const key = ref(0);
 
 const tick = () => {
 	window.fetch(`/api/fetch-rss?url=${props.url}`, {}).then(res => {
-		res.json().then(feed => {
+		res.json().then((feed: Misskey.entities.FetchRssResponse) => {
 			if (props.shuffle) {
 				shuffle(feed.items);
 			}
diff --git a/packages/frontend/src/widgets/WidgetRss.vue b/packages/frontend/src/widgets/WidgetRss.vue
index 5d5c1188aa..e5758662cc 100644
--- a/packages/frontend/src/widgets/WidgetRss.vue
+++ b/packages/frontend/src/widgets/WidgetRss.vue
@@ -24,6 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { ref, watch, computed } from 'vue';
+import * as Misskey from 'misskey-js';
 import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
 import { GetFormResultType } from '@/scripts/form.js';
 import MkContainer from '@/components/MkContainer.vue';
@@ -64,7 +65,7 @@ const { widgetProps, configure } = useWidgetPropsManager(name,
 	emit,
 );
 
-const rawItems = ref([]);
+const rawItems = ref<Misskey.entities.FetchRssResponse['items']>([]);
 const items = computed(() => rawItems.value.slice(0, widgetProps.maxEntries));
 const fetching = ref(true);
 const fetchEndpoint = computed(() => {
@@ -79,8 +80,8 @@ const tick = () => {
 
 	window.fetch(fetchEndpoint.value, {})
 		.then(res => res.json())
-		.then(feed => {
-			rawItems.value = feed.items ?? [];
+		.then((feed: Misskey.entities.FetchRssResponse) => {
+			rawItems.value = feed.items;
 			fetching.value = false;
 		});
 };
diff --git a/packages/frontend/src/widgets/WidgetRssTicker.vue b/packages/frontend/src/widgets/WidgetRssTicker.vue
index af220f95e2..16306ef5ba 100644
--- a/packages/frontend/src/widgets/WidgetRssTicker.vue
+++ b/packages/frontend/src/widgets/WidgetRssTicker.vue
@@ -28,6 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { ref, watch, computed } from 'vue';
+import * as Misskey from 'misskey-js';
 import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
 import MarqueeText from '@/components/MkMarquee.vue';
 import { GetFormResultType } from '@/scripts/form.js';
@@ -87,7 +88,7 @@ const { widgetProps, configure } = useWidgetPropsManager(name,
 	emit,
 );
 
-const rawItems = ref([]);
+const rawItems = ref<Misskey.entities.FetchRssResponse['items']>([]);
 const items = computed(() => {
 	const newItems = rawItems.value.slice(0, widgetProps.maxEntries);
 	if (widgetProps.shuffle) {
@@ -110,8 +111,8 @@ const tick = () => {
 
 	window.fetch(fetchEndpoint.value, {})
 		.then(res => res.json())
-		.then(feed => {
-			rawItems.value = feed.items ?? [];
+		.then((feed: Misskey.entities.FetchRssResponse) => {
+			rawItems.value = feed.items;
 			fetching.value = false;
 			key.value++;
 		});
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 131d20f09b..1b9f1304d5 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -26065,7 +26065,52 @@ export type operations = {
       200: {
         content: {
           'application/json': {
-            items: Record<string, never>[];
+            image?: {
+              link?: string;
+              url: string;
+              title?: string;
+            };
+            paginationLinks?: {
+              self?: string;
+              first?: string;
+              next?: string;
+              last?: string;
+              prev?: string;
+            };
+            link?: string;
+            title?: string;
+            items: {
+                link?: string;
+                guid?: string;
+                title?: string;
+                pubDate?: string;
+                creator?: string;
+                summary?: string;
+                content?: string;
+                isoDate?: string;
+                categories?: string[];
+                contentSnippet?: string;
+                enclosure?: {
+                  url: string;
+                  length?: number;
+                  type?: string;
+                };
+              }[];
+            feedUrl?: string;
+            description?: string;
+            itunes?: {
+              image?: string;
+              owner?: {
+                name?: string;
+                email?: string;
+              };
+              author?: string;
+              summary?: string;
+              explicit?: string;
+              categories?: string[];
+              keywords?: string[];
+              [key: string]: unknown;
+            };
           };
         };
       };

From 2017f9114fe281ac86304f3e7956589f43d9ccce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Wed, 1 May 2024 13:51:00 +0900
Subject: [PATCH 102/191] =?UTF-8?q?refactor(frontend):=20=E9=9D=9E?=
 =?UTF-8?q?=E3=83=AD=E3=82=B0=E3=82=A4=E3=83=B3=E7=94=BB=E9=9D=A2=E3=81=A7?=
 =?UTF-8?q?=E3=81=AEmeta=E5=8F=96=E5=BE=97=E3=82=92=E6=B8=9B=E3=82=89?=
 =?UTF-8?q?=E3=81=99=20(#13776)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* refactor(frontend): 非ログイン画面でのmeta取得を減らす

* fix(frontend): サーバー供給のmetaとクライアントフォールバックで取れるmetaの型が違うのを修正

* force fetch meta at welcome.vue

* refactor
---
 .../frontend/src/components/MkFeaturedPhotos.vue     | 12 ++----------
 .../frontend/src/components/MkVisitorDashboard.vue   | 11 +++--------
 packages/frontend/src/instance.ts                    |  8 +++++---
 packages/frontend/src/pages/welcome.entrance.a.vue   |  8 ++------
 packages/frontend/src/pages/welcome.vue              | 12 ++++++------
 packages/frontend/src/ui/visitor.vue                 |  7 -------
 6 files changed, 18 insertions(+), 40 deletions(-)

diff --git a/packages/frontend/src/components/MkFeaturedPhotos.vue b/packages/frontend/src/components/MkFeaturedPhotos.vue
index 8d875790bc..c42c692db0 100644
--- a/packages/frontend/src/components/MkFeaturedPhotos.vue
+++ b/packages/frontend/src/components/MkFeaturedPhotos.vue
@@ -4,19 +4,11 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-<div v-if="meta" :class="$style.root" :style="{ backgroundImage: `url(${ meta.backgroundImageUrl })` }"></div>
+<div v-if="instance" :class="$style.root" :style="{ backgroundImage: `url(${ instance.backgroundImageUrl })` }"></div>
 </template>
 
 <script lang="ts" setup>
-import { ref } from 'vue';
-import * as Misskey from 'misskey-js';
-import { misskeyApi } from '@/scripts/misskey-api.js';
-
-const meta = ref<Misskey.entities.MetaResponse>();
-
-misskeyApi('meta', { detail: true }).then(gotMeta => {
-	meta.value = gotMeta;
-});
+import { instance } from '@/instance.js';
 </script>
 
 <style lang="scss" module>
diff --git a/packages/frontend/src/components/MkVisitorDashboard.vue b/packages/frontend/src/components/MkVisitorDashboard.vue
index be80baa774..611c7be216 100644
--- a/packages/frontend/src/components/MkVisitorDashboard.vue
+++ b/packages/frontend/src/components/MkVisitorDashboard.vue
@@ -4,19 +4,19 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-<div v-if="meta" :class="$style.root">
+<div v-if="instance" :class="$style.root">
 	<div :class="[$style.main, $style.panel]">
 		<img :src="instance.iconUrl || '/favicon.ico'" alt="" :class="$style.mainIcon"/>
 		<button class="_button _acrylic" :class="$style.mainMenu" @click="showMenu"><i class="ti ti-dots"></i></button>
 		<div :class="$style.mainFg">
 			<h1 :class="$style.mainTitle">
 				<!-- 背景色によってはロゴが見えなくなるのでとりあえず無効に -->
-				<!-- <img class="logo" v-if="meta.logoImageUrl" :src="meta.logoImageUrl"><span v-else class="text">{{ instanceName }}</span> -->
+				<!-- <img class="logo" v-if="instance.logoImageUrl" :src="instance.logoImageUrl"><span v-else class="text">{{ instanceName }}</span> -->
 				<span>{{ instanceName }}</span>
 			</h1>
 			<div :class="$style.mainAbout">
 				<!-- eslint-disable-next-line vue/no-v-html -->
-				<div v-html="meta.description || i18n.ts.headlineMisskey"></div>
+				<div v-html="instance.description || i18n.ts.headlineMisskey"></div>
 			</div>
 			<div v-if="instance.disableRegistration" :class="$style.mainWarn">
 				<MkInfo warn>{{ i18n.ts.invitationRequiredToRegister }}</MkInfo>
@@ -66,13 +66,8 @@ import { instance } from '@/instance.js';
 import MkNumber from '@/components/MkNumber.vue';
 import XActiveUsersChart from '@/components/MkVisitorDashboard.ActiveUsersChart.vue';
 
-const meta = ref<Misskey.entities.MetaResponse | null>(null);
 const stats = ref<Misskey.entities.StatsResponse | null>(null);
 
-misskeyApi('meta', { detail: true }).then(_meta => {
-	meta.value = _meta;
-});
-
 misskeyApi('stats', {}).then((res) => {
 	stats.value = res;
 });
diff --git a/packages/frontend/src/instance.ts b/packages/frontend/src/instance.ts
index 22337e7eb9..7df6ec205c 100644
--- a/packages/frontend/src/instance.ts
+++ b/packages/frontend/src/instance.ts
@@ -28,7 +28,7 @@ if (providedAt > cachedAt) {
 
 // TODO: instanceをリアクティブにするかは再考の余地あり
 
-export const instance: Misskey.entities.MetaResponse = reactive(cachedMeta ?? {});
+export const instance: Misskey.entities.MetaDetailed = reactive(cachedMeta ?? {});
 
 export const serverErrorImageUrl = computed(() => instance.serverErrorImageUrl ?? DEFAULT_SERVER_ERROR_IMAGE_URL);
 
@@ -38,7 +38,7 @@ export const notFoundImageUrl = computed(() => instance.notFoundImageUrl ?? DEFA
 
 export const isEnabledUrlPreview = computed(() => instance.enableUrlPreview ?? true);
 
-export async function fetchInstance(force = false): Promise<void> {
+export async function fetchInstance(force = false): Promise<Misskey.entities.MetaDetailed> {
 	if (!force) {
 		const cachedAt = miLocalStorage.getItem('instanceCachedAt') ? parseInt(miLocalStorage.getItem('instanceCachedAt')!) : 0;
 
@@ -48,7 +48,7 @@ export async function fetchInstance(force = false): Promise<void> {
 	}
 
 	const meta = await misskeyApi('meta', {
-		detail: false,
+		detail: true,
 	});
 
 	for (const [k, v] of Object.entries(meta)) {
@@ -57,4 +57,6 @@ export async function fetchInstance(force = false): Promise<void> {
 
 	miLocalStorage.setItem('instance', JSON.stringify(instance));
 	miLocalStorage.setItem('instanceCachedAt', Date.now().toString());
+
+	return instance;
 }
diff --git a/packages/frontend/src/pages/welcome.entrance.a.vue b/packages/frontend/src/pages/welcome.entrance.a.vue
index 6c05aad24f..d6ba397f1b 100644
--- a/packages/frontend/src/pages/welcome.entrance.a.vue
+++ b/packages/frontend/src/pages/welcome.entrance.a.vue
@@ -42,11 +42,11 @@ import XTimeline from './welcome.timeline.vue';
 import MarqueeText from '@/components/MkMarquee.vue';
 import MkFeaturedPhotos from '@/components/MkFeaturedPhotos.vue';
 import misskeysvg from '/client-assets/misskey.svg';
-import { misskeyApi, misskeyApiGet } from '@/scripts/misskey-api.js';
+import { misskeyApiGet } from '@/scripts/misskey-api.js';
 import MkVisitorDashboard from '@/components/MkVisitorDashboard.vue';
 import { getProxiedImageUrl } from '@/scripts/media-proxy.js';
+import { instance as meta } from '@/instance.js';
 
-const meta = ref<Misskey.entities.MetaResponse>();
 const instances = ref<Misskey.entities.FederationInstance[]>();
 
 function getInstanceIcon(instance: Misskey.entities.FederationInstance): string {
@@ -56,10 +56,6 @@ function getInstanceIcon(instance: Misskey.entities.FederationInstance): string
 	return getProxiedImageUrl(instance.iconUrl, 'preview');
 }
 
-misskeyApi('meta', { detail: true }).then(_meta => {
-	meta.value = _meta;
-});
-
 misskeyApiGet('federation/instances', {
 	sort: '+pubSub',
 	limit: 20,
diff --git a/packages/frontend/src/pages/welcome.vue b/packages/frontend/src/pages/welcome.vue
index 9ba6a5885e..915fe35025 100644
--- a/packages/frontend/src/pages/welcome.vue
+++ b/packages/frontend/src/pages/welcome.vue
@@ -4,8 +4,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-<div v-if="meta">
-	<XSetup v-if="meta.requireSetup"/>
+<div v-if="instance">
+	<XSetup v-if="instance.requireSetup"/>
 	<XEntrance v-else/>
 </div>
 </template>
@@ -16,13 +16,13 @@ import * as Misskey from 'misskey-js';
 import XSetup from './welcome.setup.vue';
 import XEntrance from './welcome.entrance.a.vue';
 import { instanceName } from '@/config.js';
-import { misskeyApi } from '@/scripts/misskey-api.js';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
+import { fetchInstance } from '@/instance.js';
 
-const meta = ref<Misskey.entities.MetaResponse | null>(null);
+const instance = ref<Misskey.entities.MetaDetailed | null>(null);
 
-misskeyApi('meta', { detail: true }).then(res => {
-	meta.value = res;
+fetchInstance(true).then((res) => {
+	instance.value = res;
 });
 
 const headerActions = computed(() => []);
diff --git a/packages/frontend/src/ui/visitor.vue b/packages/frontend/src/ui/visitor.vue
index 29b305d9bc..80623083cf 100644
--- a/packages/frontend/src/ui/visitor.vue
+++ b/packages/frontend/src/ui/visitor.vue
@@ -70,11 +70,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { onMounted, provide, ref, computed } from 'vue';
-import * as Misskey from 'misskey-js';
 import XCommon from './_common_/common.vue';
 import { instanceName } from '@/config.js';
 import * as os from '@/os.js';
-import { misskeyApi } from '@/scripts/misskey-api.js';
 import { instance } from '@/instance.js';
 import XSigninDialog from '@/components/MkSigninDialog.vue';
 import XSignupDialog from '@/components/MkSignupDialog.vue';
@@ -114,7 +112,6 @@ const isTimelineAvailable = ref(instance.policies?.ltlAvailable || instance.poli
 const showMenu = ref(false);
 const isDesktop = ref(window.innerWidth >= DESKTOP_THRESHOLD);
 const narrow = ref(window.innerWidth < 1280);
-const meta = ref<Misskey.entities.MetaResponse>();
 
 const keymap = computed(() => {
 	return {
@@ -128,10 +125,6 @@ const keymap = computed(() => {
 	};
 });
 
-misskeyApi('meta', { detail: true }).then(res => {
-	meta.value = res;
-});
-
 function signin() {
 	os.popup(XSigninDialog, {
 		autoSet: true,

From 8c5e5640669c252faaf22ed8742d598ec0e2268f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Wed, 1 May 2024 13:52:59 +0900
Subject: [PATCH 103/191] fix type error

---
 packages/frontend/src/instance.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/frontend/src/instance.ts b/packages/frontend/src/instance.ts
index 7df6ec205c..6847321d6c 100644
--- a/packages/frontend/src/instance.ts
+++ b/packages/frontend/src/instance.ts
@@ -43,7 +43,7 @@ export async function fetchInstance(force = false): Promise<Misskey.entities.Met
 		const cachedAt = miLocalStorage.getItem('instanceCachedAt') ? parseInt(miLocalStorage.getItem('instanceCachedAt')!) : 0;
 
 		if (Date.now() - cachedAt < 1000 * 60 * 60) {
-			return;
+			return instance;
 		}
 	}
 

From ef630df443bdd24cfe0b086b0e2f94d87c4f53b7 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Wed, 1 May 2024 14:12:36 +0900
Subject: [PATCH 104/191] enhance(frontend): add contact page

---
 locales/index.d.ts                            |  4 ++
 locales/ja-JP.yml                             |  1 +
 .../src/components/MkVisitorDashboard.vue     | 39 +------------------
 packages/frontend/src/pages/contact.vue       | 24 ++++++++++++
 packages/frontend/src/router/definition.ts    |  3 ++
 packages/frontend/src/ui/_common_/common.ts   | 11 ++++--
 6 files changed, 42 insertions(+), 40 deletions(-)
 create mode 100644 packages/frontend/src/pages/contact.vue

diff --git a/locales/index.d.ts b/locales/index.d.ts
index 9bcd1979af..779a5d2c3f 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -4952,6 +4952,10 @@ export interface Locale extends ILocale {
      * フォローの際常に確認する
      */
     "alwaysConfirmFollow": string;
+    /**
+     * お問い合わせ
+     */
+    "inquiry": string;
     "_bubbleGame": {
         /**
          * 遊び方
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 5f7715b210..8f17215802 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1234,6 +1234,7 @@ keepOriginalFilename: "オリジナルのファイル名を保持"
 keepOriginalFilenameDescription: "この設定をオフにすると、アップロード時にファイル名が自動でランダム文字列に置き換えられます。"
 noDescription: "説明文はありません"
 alwaysConfirmFollow: "フォローの際常に確認する"
+inquiry: "お問い合わせ"
 
 _bubbleGame:
   howToPlay: "遊び方"
diff --git a/packages/frontend/src/components/MkVisitorDashboard.vue b/packages/frontend/src/components/MkVisitorDashboard.vue
index 611c7be216..f7963f9938 100644
--- a/packages/frontend/src/components/MkVisitorDashboard.vue
+++ b/packages/frontend/src/components/MkVisitorDashboard.vue
@@ -65,6 +65,7 @@ import { i18n } from '@/i18n.js';
 import { instance } from '@/instance.js';
 import MkNumber from '@/components/MkNumber.vue';
 import XActiveUsersChart from '@/components/MkVisitorDashboard.ActiveUsersChart.vue';
+import { openInstanceMenu } from '@/ui/_common_/common';
 
 const stats = ref<Misskey.entities.StatsResponse | null>(null);
 
@@ -85,43 +86,7 @@ function signup() {
 }
 
 function showMenu(ev) {
-	os.popupMenu([{
-		text: i18n.ts.instanceInfo,
-		icon: 'ti ti-info-circle',
-		action: () => {
-			os.pageWindow('/about');
-		},
-	}, {
-		text: i18n.ts.aboutMisskey,
-		icon: 'ti ti-info-circle',
-		action: () => {
-			os.pageWindow('/about-misskey');
-		},
-	}, { type: 'divider' }, (instance.impressumUrl) ? {
-		text: i18n.ts.impressum,
-		icon: 'ti ti-file-invoice',
-		action: () => {
-			window.open(instance.impressumUrl!, '_blank', 'noopener');
-		},
-	} : undefined, (instance.tosUrl) ? {
-		text: i18n.ts.termsOfService,
-		icon: 'ti ti-notebook',
-		action: () => {
-			window.open(instance.tosUrl!, '_blank', 'noopener');
-		},
-	} : undefined, (instance.privacyPolicyUrl) ? {
-		text: i18n.ts.privacyPolicy,
-		icon: 'ti ti-shield-lock',
-		action: () => {
-			window.open(instance.privacyPolicyUrl!, '_blank', 'noopener');
-		},
-	} : undefined, (!instance.impressumUrl && !instance.tosUrl && !instance.privacyPolicyUrl) ? undefined : { type: 'divider' }, {
-		text: i18n.ts.help,
-		icon: 'ti ti-help-circle',
-		action: () => {
-			window.open('https://misskey-hub.net/docs/for-users/', '_blank', 'noopener');
-		},
-	}], ev.currentTarget ?? ev.target);
+	openInstanceMenu(ev);
 }
 
 function exploreOtherServers() {
diff --git a/packages/frontend/src/pages/contact.vue b/packages/frontend/src/pages/contact.vue
new file mode 100644
index 0000000000..3a694a7132
--- /dev/null
+++ b/packages/frontend/src/pages/contact.vue
@@ -0,0 +1,24 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<MkStickyContainer>
+	<template #header><MkPageHeader/></template>
+	<MkSpacer :contentMax="600" :marginMin="20">
+		<div>{{ instance.maintainerEmail }}</div>
+	</MkSpacer>
+</MkStickyContainer>
+</template>
+
+<script lang="ts" setup>
+import { i18n } from '@/i18n.js';
+import { definePageMetadata } from '@/scripts/page-metadata.js';
+import { instance } from '@/instance.js';
+
+definePageMetadata(() => ({
+	title: i18n.ts.inquiry,
+	icon: 'ti ti-help-circle',
+}));
+</script>
diff --git a/packages/frontend/src/router/definition.ts b/packages/frontend/src/router/definition.ts
index c9f03b738f..c5b576f505 100644
--- a/packages/frontend/src/router/definition.ts
+++ b/packages/frontend/src/router/definition.ts
@@ -197,6 +197,9 @@ const routes: RouteDef[] = [{
 	path: '/about',
 	component: page(() => import('@/pages/about.vue')),
 	hash: 'initialTab',
+}, {
+	path: '/contact',
+	component: page(() => import('@/pages/contact.vue')),
 }, {
 	path: '/about-misskey',
 	component: page(() => import('@/pages/about-misskey.vue')),
diff --git a/packages/frontend/src/ui/_common_/common.ts b/packages/frontend/src/ui/_common_/common.ts
index 9b510a6292..839fa5faf8 100644
--- a/packages/frontend/src/ui/_common_/common.ts
+++ b/packages/frontend/src/ui/_common_/common.ts
@@ -79,7 +79,12 @@ export function openInstanceMenu(ev: MouseEvent) {
 		text: i18n.ts.tools,
 		icon: 'ti ti-tool',
 		children: toolsMenuItems(),
-	}, { type: 'divider' }, (instance.impressumUrl) ? {
+	}, { type: 'divider' }, {
+		type: 'link',
+		text: i18n.ts.inquiry,
+		icon: 'ti ti-help-circle',
+		to: '/contact',
+	}, (instance.impressumUrl) ? {
 		text: i18n.ts.impressum,
 		icon: 'ti ti-file-invoice',
 		action: () => {
@@ -98,8 +103,8 @@ export function openInstanceMenu(ev: MouseEvent) {
 			window.open(instance.privacyPolicyUrl, '_blank', 'noopener');
 		},
 	} : undefined, (!instance.impressumUrl && !instance.tosUrl && !instance.privacyPolicyUrl) ? undefined : { type: 'divider' }, {
-		text: i18n.ts.help,
-		icon: 'ti ti-help-circle',
+		text: i18n.ts.document,
+		icon: 'ti ti-bulb',
 		action: () => {
 			window.open('https://misskey-hub.net/docs/for-users/', '_blank', 'noopener');
 		},

From 9f66f229537915f47da8e6e08e92a78be390f454 Mon Sep 17 00:00:00 2001
From: taiy <53635909+taiyme@users.noreply.github.com>
Date: Wed, 1 May 2024 15:29:38 +0900
Subject: [PATCH 105/191] =?UTF-8?q?fix(frontend):=20=E9=80=A3=E5=90=88?=
 =?UTF-8?q?=E3=81=AA=E3=81=97=E3=81=AE=E7=8A=B6=E6=85=8B=E3=81=AE=E8=AA=AD?=
 =?UTF-8?q?=E3=81=BF=E6=9B=B8=E3=81=8D=E3=81=8C=E3=81=A7=E3=81=8D=E3=81=AA?=
 =?UTF-8?q?=E3=81=84=E5=95=8F=E9=A1=8C=20(#13777)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix: 連合なしの状態の読み書きができない問題

* update changelog

* fix types: https://github.com/misskey-dev/misskey/pull/13777#discussion_r1585901601
---
 CHANGELOG.md                                          | 1 +
 packages/frontend/src/components/MkPostForm.vue       | 8 ++++++--
 packages/frontend/src/components/MkPostFormDialog.vue | 6 ++++--
 packages/frontend/src/scripts/get-note-menu.ts        | 5 ++---
 packages/frontend/src/store.ts                        | 4 ++--
 5 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 68015596bd..4b65550daf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -56,6 +56,7 @@
 - Fix: ページのOGP URLが間違っているのを修正
 - Fix: リバーシの対局を正しく共有できないことがある問題を修正
 - Fix: 通知をグループ化している際に、人数が正常に表示されないことがある問題を修正
+- Fix: 連合なしの状態の読み書きができない問題を修正
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index d7efca9de9..7dbc127298 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -156,6 +156,7 @@ const props = withDefaults(defineProps<{
 	initialVisibleUsers: () => [],
 	autofocus: true,
 	mock: false,
+	initialLocalOnly: undefined,
 });
 
 provide('mock', props.mock);
@@ -185,8 +186,8 @@ watch(showPreview, () => defaultStore.set('showPreview', showPreview.value));
 const showAddMfmFunction = ref(defaultStore.state.enableQuickAddMfmFunction);
 watch(showAddMfmFunction, () => defaultStore.set('enableQuickAddMfmFunction', showAddMfmFunction.value));
 const cw = ref<string | null>(props.initialCw ?? null);
-const localOnly = ref<boolean>(props.initialLocalOnly ?? defaultStore.state.rememberNoteVisibility ? defaultStore.state.localOnly : defaultStore.state.defaultNoteLocalOnly);
-const visibility = ref(props.initialVisibility ?? (defaultStore.state.rememberNoteVisibility ? defaultStore.state.visibility : defaultStore.state.defaultNoteVisibility) as typeof Misskey.noteVisibilities[number]);
+const localOnly = ref(props.initialLocalOnly ?? (defaultStore.state.rememberNoteVisibility ? defaultStore.state.localOnly : defaultStore.state.defaultNoteLocalOnly));
+const visibility = ref(props.initialVisibility ?? (defaultStore.state.rememberNoteVisibility ? defaultStore.state.visibility : defaultStore.state.defaultNoteVisibility));
 const visibleUsers = ref<Misskey.entities.UserDetailed[]>([]);
 if (props.initialVisibleUsers) {
 	props.initialVisibleUsers.forEach(pushVisibleUser);
@@ -518,6 +519,9 @@ async function toggleLocalOnly() {
 	}
 
 	localOnly.value = !localOnly.value;
+	if (defaultStore.state.rememberNoteVisibility) {
+		defaultStore.set('localOnly', localOnly.value);
+	}
 }
 
 async function toggleReactionAcceptance() {
diff --git a/packages/frontend/src/components/MkPostFormDialog.vue b/packages/frontend/src/components/MkPostFormDialog.vue
index 6331dfed29..ac37cb31bc 100644
--- a/packages/frontend/src/components/MkPostFormDialog.vue
+++ b/packages/frontend/src/components/MkPostFormDialog.vue
@@ -15,7 +15,7 @@ import * as Misskey from 'misskey-js';
 import MkModal from '@/components/MkModal.vue';
 import MkPostForm from '@/components/MkPostForm.vue';
 
-const props = defineProps<{
+const props = withDefaults(defineProps<{
 	reply?: Misskey.entities.Note;
 	renote?: Misskey.entities.Note;
 	channel?: any; // TODO
@@ -31,7 +31,9 @@ const props = defineProps<{
 	instant?: boolean;
 	fixed?: boolean;
 	autofocus?: boolean;
-}>();
+}>(), {
+	initialLocalOnly: undefined,
+});
 
 const emit = defineEmits<{
 	(ev: 'closed'): void;
diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts
index 87921bc67f..2cd21c1edc 100644
--- a/packages/frontend/src/scripts/get-note-menu.ts
+++ b/packages/frontend/src/scripts/get-note-menu.ts
@@ -492,10 +492,9 @@ export function getNoteMenu(props: {
 	};
 }
 
-type Visibility = 'public' | 'home' | 'followers' | 'specified';
+type Visibility = (typeof Misskey.noteVisibilities)[number];
 
-// defaultStore.state.visibilityがstringなためstringも受け付けている
-function smallerVisibility(a: Visibility | string, b: Visibility | string): Visibility {
+function smallerVisibility(a: Visibility, b: Visibility): Visibility {
 	if (a === 'specified' || b === 'specified') return 'specified';
 	if (a === 'followers' || b === 'followers') return 'followers';
 	if (a === 'home' || b === 'home') return 'home';
diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts
index e6a348b79f..e8eb5a1ed7 100644
--- a/packages/frontend/src/store.ts
+++ b/packages/frontend/src/store.ts
@@ -94,7 +94,7 @@ export const defaultStore = markRaw(new Storage('base', {
 	},
 	defaultNoteVisibility: {
 		where: 'account',
-		default: 'public',
+		default: 'public' as (typeof Misskey.noteVisibilities)[number],
 	},
 	defaultNoteLocalOnly: {
 		where: 'account',
@@ -150,7 +150,7 @@ export const defaultStore = markRaw(new Storage('base', {
 	},
 	visibility: {
 		where: 'deviceAccount',
-		default: 'public' as 'public' | 'home' | 'followers' | 'specified',
+		default: 'public' as (typeof Misskey.noteVisibilities)[number],
 	},
 	localOnly: {
 		where: 'deviceAccount',

From d2a5bb39e344fcb84a24ae60faafe4694b227b88 Mon Sep 17 00:00:00 2001
From: Daiki Mizukami <tesaguriguma@gmail.com>
Date: Wed, 1 May 2024 07:33:58 +0000
Subject: [PATCH 106/191] Merge pull request from GHSA-2vxv-pv3m-3wvj

* fix: normalize incoming signed activities

* Tweak style

* Update CHANGELOG.md

* Log compacted activity as well

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 CHANGELOG.md                                  |  2 +
 packages/backend/src/core/CoreModule.ts       | 12 ++---
 .../src/core/activitypub/ApRendererService.ts | 45 +++----------------
 ...LdSignatureService.ts => JsonLdService.ts} | 32 ++++++++-----
 .../src/core/activitypub/misc/contexts.ts     | 39 +++++++++++++++-
 .../queue/processors/InboxProcessorService.ts | 44 +++++++++++++-----
 packages/backend/test/unit/activitypub.ts     | 42 +++++++++++++++++
 7 files changed, 146 insertions(+), 70 deletions(-)
 rename packages/backend/src/core/activitypub/{LdSignatureService.ts => JsonLdService.ts} (83%)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4b65550daf..4394ab0c55 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
 
 ### Note
 - コントロールパネル内にあるサマリープロキシの設定個所がセキュリティから全般へ変更となります。
+- 悪意のある第三者がリモートユーザーになりすましたアクティビティを受け取れてしまう問題を修正しました。詳しくは[GitHub security advisory](https://github.com/misskey-dev/misskey/security/advisories/GHSA-2vxv-pv3m-3wvj)をご覧ください。
 
 ### General
 - Enhance: URLプレビューの有効化・無効化を設定できるように #13569
@@ -61,6 +62,7 @@
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
 - Enhance: misskey-dev/summaly@5.1.0の取り込み(プレビュー生成処理の効率化)
+- Fix: リモートから配送されたアクティビティにJSON-LD compactionをかける
 - Fix: フォローリクエストを作成する際に既存のものは削除するように  
   (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/440)
 - Fix: エンドポイント`notes/translate`のエラーを改善
diff --git a/packages/backend/src/core/CoreModule.ts b/packages/backend/src/core/CoreModule.ts
index 2c27d33c06..5953155872 100644
--- a/packages/backend/src/core/CoreModule.ts
+++ b/packages/backend/src/core/CoreModule.ts
@@ -127,7 +127,7 @@ import { ApMfmService } from './activitypub/ApMfmService.js';
 import { ApRendererService } from './activitypub/ApRendererService.js';
 import { ApRequestService } from './activitypub/ApRequestService.js';
 import { ApResolverService } from './activitypub/ApResolverService.js';
-import { LdSignatureService } from './activitypub/LdSignatureService.js';
+import { JsonLdService } from './activitypub/JsonLdService.js';
 import { RemoteLoggerService } from './RemoteLoggerService.js';
 import { RemoteUserResolveService } from './RemoteUserResolveService.js';
 import { WebfingerService } from './WebfingerService.js';
@@ -266,7 +266,7 @@ const $ApMfmService: Provider = { provide: 'ApMfmService', useExisting: ApMfmSer
 const $ApRendererService: Provider = { provide: 'ApRendererService', useExisting: ApRendererService };
 const $ApRequestService: Provider = { provide: 'ApRequestService', useExisting: ApRequestService };
 const $ApResolverService: Provider = { provide: 'ApResolverService', useExisting: ApResolverService };
-const $LdSignatureService: Provider = { provide: 'LdSignatureService', useExisting: LdSignatureService };
+const $JsonLdService: Provider = { provide: 'JsonLdService', useExisting: JsonLdService };
 const $RemoteLoggerService: Provider = { provide: 'RemoteLoggerService', useExisting: RemoteLoggerService };
 const $RemoteUserResolveService: Provider = { provide: 'RemoteUserResolveService', useExisting: RemoteUserResolveService };
 const $WebfingerService: Provider = { provide: 'WebfingerService', useExisting: WebfingerService };
@@ -406,7 +406,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
 		ApRendererService,
 		ApRequestService,
 		ApResolverService,
-		LdSignatureService,
+		JsonLdService,
 		RemoteLoggerService,
 		RemoteUserResolveService,
 		WebfingerService,
@@ -542,7 +542,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
 		$ApRendererService,
 		$ApRequestService,
 		$ApResolverService,
-		$LdSignatureService,
+		$JsonLdService,
 		$RemoteLoggerService,
 		$RemoteUserResolveService,
 		$WebfingerService,
@@ -678,7 +678,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
 		ApRendererService,
 		ApRequestService,
 		ApResolverService,
-		LdSignatureService,
+		JsonLdService,
 		RemoteLoggerService,
 		RemoteUserResolveService,
 		WebfingerService,
@@ -813,7 +813,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
 		$ApRendererService,
 		$ApRequestService,
 		$ApResolverService,
-		$LdSignatureService,
+		$JsonLdService,
 		$RemoteLoggerService,
 		$RemoteUserResolveService,
 		$WebfingerService,
diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts
index d7fb977a99..d3553b6f73 100644
--- a/packages/backend/src/core/activitypub/ApRendererService.ts
+++ b/packages/backend/src/core/activitypub/ApRendererService.ts
@@ -28,8 +28,9 @@ import { bindThis } from '@/decorators.js';
 import { CustomEmojiService } from '@/core/CustomEmojiService.js';
 import { isNotNull } from '@/misc/is-not-null.js';
 import { IdService } from '@/core/IdService.js';
-import { LdSignatureService } from './LdSignatureService.js';
+import { JsonLdService } from './JsonLdService.js';
 import { ApMfmService } from './ApMfmService.js';
+import { CONTEXT } from './misc/contexts.js';
 import type { IAccept, IActivity, IAdd, IAnnounce, IApDocument, IApEmoji, IApHashtag, IApImage, IApMention, IBlock, ICreate, IDelete, IFlag, IFollow, IKey, ILike, IMove, IObject, IPost, IQuestion, IReject, IRemove, ITombstone, IUndo, IUpdate } from './type.js';
 
 @Injectable()
@@ -56,7 +57,7 @@ export class ApRendererService {
 		private customEmojiService: CustomEmojiService,
 		private userEntityService: UserEntityService,
 		private driveFileEntityService: DriveFileEntityService,
-		private ldSignatureService: LdSignatureService,
+		private jsonLdService: JsonLdService,
 		private userKeypairService: UserKeypairService,
 		private apMfmService: ApMfmService,
 		private mfmService: MfmService,
@@ -617,48 +618,16 @@ export class ApRendererService {
 			x.id = `${this.config.url}/${randomUUID()}`;
 		}
 
-		return Object.assign({
-			'@context': [
-				'https://www.w3.org/ns/activitystreams',
-				'https://w3id.org/security/v1',
-				{
-					Key: 'sec:Key',
-					// as non-standards
-					manuallyApprovesFollowers: 'as:manuallyApprovesFollowers',
-					sensitive: 'as:sensitive',
-					Hashtag: 'as:Hashtag',
-					quoteUrl: 'as:quoteUrl',
-					// Mastodon
-					toot: 'http://joinmastodon.org/ns#',
-					Emoji: 'toot:Emoji',
-					featured: 'toot:featured',
-					discoverable: 'toot:discoverable',
-					// schema
-					schema: 'http://schema.org#',
-					PropertyValue: 'schema:PropertyValue',
-					value: 'schema:value',
-					// Misskey
-					misskey: 'https://misskey-hub.net/ns#',
-					'_misskey_content': 'misskey:_misskey_content',
-					'_misskey_quote': 'misskey:_misskey_quote',
-					'_misskey_reaction': 'misskey:_misskey_reaction',
-					'_misskey_votes': 'misskey:_misskey_votes',
-					'_misskey_summary': 'misskey:_misskey_summary',
-					'isCat': 'misskey:isCat',
-					// vcard
-					vcard: 'http://www.w3.org/2006/vcard/ns#',
-				},
-			],
-		}, x as T & { id: string });
+		return Object.assign({ '@context': CONTEXT }, x as T & { id: string });
 	}
 
 	@bindThis
 	public async attachLdSignature(activity: any, user: { id: MiUser['id']; host: null; }): Promise<IActivity> {
 		const keypair = await this.userKeypairService.getUserKeypair(user.id);
 
-		const ldSignature = this.ldSignatureService.use();
-		ldSignature.debug = false;
-		activity = await ldSignature.signRsaSignature2017(activity, keypair.privateKey, `${this.config.url}/users/${user.id}#main-key`);
+		const jsonLd = this.jsonLdService.use();
+		jsonLd.debug = false;
+		activity = await jsonLd.signRsaSignature2017(activity, keypair.privateKey, `${this.config.url}/users/${user.id}#main-key`);
 
 		return activity;
 	}
diff --git a/packages/backend/src/core/activitypub/LdSignatureService.ts b/packages/backend/src/core/activitypub/JsonLdService.ts
similarity index 83%
rename from packages/backend/src/core/activitypub/LdSignatureService.ts
rename to packages/backend/src/core/activitypub/JsonLdService.ts
index 9de184336f..100d4fa19f 100644
--- a/packages/backend/src/core/activitypub/LdSignatureService.ts
+++ b/packages/backend/src/core/activitypub/JsonLdService.ts
@@ -7,14 +7,14 @@ import * as crypto from 'node:crypto';
 import { Injectable } from '@nestjs/common';
 import { HttpRequestService } from '@/core/HttpRequestService.js';
 import { bindThis } from '@/decorators.js';
-import { CONTEXTS } from './misc/contexts.js';
+import { CONTEXT, PRELOADED_CONTEXTS } from './misc/contexts.js';
 import { validateContentTypeSetAsJsonLD } from './misc/validator.js';
 import type { JsonLdDocument } from 'jsonld';
-import type { JsonLd, RemoteDocument } from 'jsonld/jsonld-spec.js';
+import type { JsonLd as JsonLdObject, RemoteDocument } from 'jsonld/jsonld-spec.js';
 
-// RsaSignature2017 based from https://github.com/transmute-industries/RsaSignature2017
+// RsaSignature2017 implementation is based on https://github.com/transmute-industries/RsaSignature2017
 
-class LdSignature {
+class JsonLd {
 	public debug = false;
 	public preLoad = true;
 	public loderTimeout = 5000;
@@ -89,10 +89,18 @@ class LdSignature {
 	}
 
 	@bindThis
-	public async normalize(data: JsonLdDocument): Promise<string> {
+	public async compact(data: any, context: any = CONTEXT): Promise<JsonLdDocument> {
 		const customLoader = this.getLoader();
 		// XXX: Importing jsonld dynamically since Jest frequently fails to import it statically
 		// https://github.com/misskey-dev/misskey/pull/9894#discussion_r1103753595
+		return (await import('jsonld')).default.compact(data, context, {
+			documentLoader: customLoader,
+		});
+	}
+
+	@bindThis
+	public async normalize(data: JsonLdDocument): Promise<string> {
+		const customLoader = this.getLoader();
 		return (await import('jsonld')).default.normalize(data, {
 			documentLoader: customLoader,
 		});
@@ -104,11 +112,11 @@ class LdSignature {
 			if (!/^https?:\/\//.test(url)) throw new Error(`Invalid URL ${url}`);
 
 			if (this.preLoad) {
-				if (url in CONTEXTS) {
+				if (url in PRELOADED_CONTEXTS) {
 					if (this.debug) console.debug(`HIT: ${url}`);
 					return {
 						contextUrl: undefined,
-						document: CONTEXTS[url],
+						document: PRELOADED_CONTEXTS[url],
 						documentUrl: url,
 					};
 				}
@@ -125,7 +133,7 @@ class LdSignature {
 	}
 
 	@bindThis
-	private async fetchDocument(url: string): Promise<JsonLd> {
+	private async fetchDocument(url: string): Promise<JsonLdObject> {
 		const json = await this.httpRequestService.send(
 			url,
 			{
@@ -146,7 +154,7 @@ class LdSignature {
 			}
 		});
 
-		return json as JsonLd;
+		return json as JsonLdObject;
 	}
 
 	@bindThis
@@ -158,14 +166,14 @@ class LdSignature {
 }
 
 @Injectable()
-export class LdSignatureService {
+export class JsonLdService {
 	constructor(
 		private httpRequestService: HttpRequestService,
 	) {
 	}
 
 	@bindThis
-	public use(): LdSignature {
-		return new LdSignature(this.httpRequestService);
+	public use(): JsonLd {
+		return new JsonLd(this.httpRequestService);
 	}
 }
diff --git a/packages/backend/src/core/activitypub/misc/contexts.ts b/packages/backend/src/core/activitypub/misc/contexts.ts
index 88afdefcd3..feb8c42c56 100644
--- a/packages/backend/src/core/activitypub/misc/contexts.ts
+++ b/packages/backend/src/core/activitypub/misc/contexts.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import type { JsonLd } from 'jsonld/jsonld-spec.js';
+import type { Context, JsonLd } from 'jsonld/jsonld-spec.js';
 
 /* eslint:disable:quotemark indent */
 const id_v1 = {
@@ -526,7 +526,42 @@ const activitystreams = {
 	},
 } satisfies JsonLd;
 
-export const CONTEXTS: Record<string, JsonLd> = {
+const context_iris = [
+	'https://www.w3.org/ns/activitystreams',
+	'https://w3id.org/security/v1',
+];
+
+const extension_context_definition = {
+	Key: 'sec:Key',
+	// as non-standards
+	manuallyApprovesFollowers: 'as:manuallyApprovesFollowers',
+	sensitive: 'as:sensitive',
+	Hashtag: 'as:Hashtag',
+	quoteUrl: 'as:quoteUrl',
+	// Mastodon
+	toot: 'http://joinmastodon.org/ns#',
+	Emoji: 'toot:Emoji',
+	featured: 'toot:featured',
+	discoverable: 'toot:discoverable',
+	// schema
+	schema: 'http://schema.org#',
+	PropertyValue: 'schema:PropertyValue',
+	value: 'schema:value',
+	// Misskey
+	misskey: 'https://misskey-hub.net/ns#',
+	'_misskey_content': 'misskey:_misskey_content',
+	'_misskey_quote': 'misskey:_misskey_quote',
+	'_misskey_reaction': 'misskey:_misskey_reaction',
+	'_misskey_votes': 'misskey:_misskey_votes',
+	'_misskey_summary': 'misskey:_misskey_summary',
+	'isCat': 'misskey:isCat',
+	// vcard
+	vcard: 'http://www.w3.org/2006/vcard/ns#',
+} satisfies Context;
+
+export const CONTEXT: (string | Context)[] = [...context_iris, extension_context_definition];
+
+export const PRELOADED_CONTEXTS: Record<string, JsonLd> = {
 	'https://w3id.org/identity/v1': id_v1,
 	'https://w3id.org/security/v1': security_v1,
 	'https://www.w3.org/ns/activitystreams': activitystreams,
diff --git a/packages/backend/src/queue/processors/InboxProcessorService.ts b/packages/backend/src/queue/processors/InboxProcessorService.ts
index 3addead058..1d05f4ade1 100644
--- a/packages/backend/src/queue/processors/InboxProcessorService.ts
+++ b/packages/backend/src/queue/processors/InboxProcessorService.ts
@@ -15,13 +15,14 @@ import InstanceChart from '@/core/chart/charts/instance.js';
 import ApRequestChart from '@/core/chart/charts/ap-request.js';
 import FederationChart from '@/core/chart/charts/federation.js';
 import { getApId } from '@/core/activitypub/type.js';
+import type { IActivity } from '@/core/activitypub/type.js';
 import type { MiRemoteUser } from '@/models/User.js';
 import type { MiUserPublickey } from '@/models/UserPublickey.js';
 import { ApDbResolverService } from '@/core/activitypub/ApDbResolverService.js';
 import { StatusError } from '@/misc/status-error.js';
 import { UtilityService } from '@/core/UtilityService.js';
 import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
-import { LdSignatureService } from '@/core/activitypub/LdSignatureService.js';
+import { JsonLdService } from '@/core/activitypub/JsonLdService.js';
 import { ApInboxService } from '@/core/activitypub/ApInboxService.js';
 import { bindThis } from '@/decorators.js';
 import { IdentifiableError } from '@/misc/identifiable-error.js';
@@ -38,7 +39,7 @@ export class InboxProcessorService {
 		private apInboxService: ApInboxService,
 		private federatedInstanceService: FederatedInstanceService,
 		private fetchInstanceMetadataService: FetchInstanceMetadataService,
-		private ldSignatureService: LdSignatureService,
+		private jsonLdService: JsonLdService,
 		private apPersonService: ApPersonService,
 		private apDbResolverService: ApDbResolverService,
 		private instanceChart: InstanceChart,
@@ -52,7 +53,7 @@ export class InboxProcessorService {
 	@bindThis
 	public async process(job: Bull.Job<InboxJobData>): Promise<string> {
 		const signature = job.data.signature;	// HTTP-signature
-		const activity = job.data.activity;
+		let activity = job.data.activity;
 
 		//#region Log
 		const info = Object.assign({}, activity);
@@ -110,20 +111,21 @@ export class InboxProcessorService {
 		// また、signatureのsignerは、activity.actorと一致する必要がある
 		if (!httpSignatureValidated || authUser.user.uri !== activity.actor) {
 			// 一致しなくても、でもLD-Signatureがありそうならそっちも見る
-			if (activity.signature) {
-				if (activity.signature.type !== 'RsaSignature2017') {
-					throw new Bull.UnrecoverableError(`skip: unsupported LD-signature type ${activity.signature.type}`);
+			const ldSignature = activity.signature;
+			if (ldSignature) {
+				if (ldSignature.type !== 'RsaSignature2017') {
+					throw new Bull.UnrecoverableError(`skip: unsupported LD-signature type ${ldSignature.type}`);
 				}
 
-				// activity.signature.creator: https://example.oom/users/user#main-key
+				// ldSignature.creator: https://example.oom/users/user#main-key
 				// みたいになっててUserを引っ張れば公開キーも入ることを期待する
-				if (activity.signature.creator) {
-					const candicate = activity.signature.creator.replace(/#.*/, '');
+				if (ldSignature.creator) {
+					const candicate = ldSignature.creator.replace(/#.*/, '');
 					await this.apPersonService.resolvePerson(candicate).catch(() => null);
 				}
 
 				// keyIdからLD-Signatureのユーザーを取得
-				authUser = await this.apDbResolverService.getAuthUserFromKeyId(activity.signature.creator);
+				authUser = await this.apDbResolverService.getAuthUserFromKeyId(ldSignature.creator);
 				if (authUser == null) {
 					throw new Bull.UnrecoverableError('skip: LD-Signatureのユーザーが取得できませんでした');
 				}
@@ -132,13 +134,31 @@ export class InboxProcessorService {
 					throw new Bull.UnrecoverableError('skip: LD-SignatureのユーザーはpublicKeyを持っていませんでした');
 				}
 
+				const jsonLd = this.jsonLdService.use();
+
 				// LD-Signature検証
-				const ldSignature = this.ldSignatureService.use();
-				const verified = await ldSignature.verifyRsaSignature2017(activity, authUser.key.keyPem).catch(() => false);
+				const verified = await jsonLd.verifyRsaSignature2017(activity, authUser.key.keyPem).catch(() => false);
 				if (!verified) {
 					throw new Bull.UnrecoverableError('skip: LD-Signatureの検証に失敗しました');
 				}
 
+				// アクティビティを正規化
+				delete activity.signature;
+				try {
+					activity = await jsonLd.compact(activity) as IActivity;
+				} catch (e) {
+					throw new Bull.UnrecoverableError(`skip: failed to compact activity: ${e}`);
+				}
+				// TODO: 元のアクティビティと非互換な形に正規化される場合は転送をスキップする
+				// https://github.com/mastodon/mastodon/blob/664b0ca/app/services/activitypub/process_collection_service.rb#L24-L29
+				activity.signature = ldSignature;
+
+				//#region Log
+				const compactedInfo = Object.assign({}, activity);
+				delete compactedInfo['@context'];
+				this.logger.debug(`compacted: ${JSON.stringify(compactedInfo, null, 2)}`);
+				//#endregion
+
 				// もう一度actorチェック
 				if (authUser.user.uri !== activity.actor) {
 					throw new Bull.UnrecoverableError(`skip: LD-Signature user(${authUser.user.uri}) !== activity.actor(${activity.actor})`);
diff --git a/packages/backend/test/unit/activitypub.ts b/packages/backend/test/unit/activitypub.ts
index aa3f3a4ff1..6962608106 100644
--- a/packages/backend/test/unit/activitypub.ts
+++ b/packages/backend/test/unit/activitypub.ts
@@ -13,6 +13,8 @@ import { ApImageService } from '@/core/activitypub/models/ApImageService.js';
 import { ApNoteService } from '@/core/activitypub/models/ApNoteService.js';
 import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
 import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
+import { JsonLdService } from '@/core/activitypub/JsonLdService.js';
+import { CONTEXT } from '@/core/activitypub/misc/contexts.js';
 import { GlobalModule } from '@/GlobalModule.js';
 import { CoreModule } from '@/core/CoreModule.js';
 import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
@@ -88,6 +90,7 @@ describe('ActivityPub', () => {
 	let noteService: ApNoteService;
 	let personService: ApPersonService;
 	let rendererService: ApRendererService;
+	let jsonLdService: JsonLdService;
 	let resolver: MockResolver;
 
 	const metaInitial = {
@@ -128,6 +131,7 @@ describe('ActivityPub', () => {
 		personService = app.get<ApPersonService>(ApPersonService);
 		rendererService = app.get<ApRendererService>(ApRendererService);
 		imageService = app.get<ApImageService>(ApImageService);
+		jsonLdService = app.get<JsonLdService>(JsonLdService);
 		resolver = new MockResolver(await app.resolve<LoggerService>(LoggerService));
 
 		// Prevent ApPersonService from fetching instance, as it causes Jest import-after-test error
@@ -381,4 +385,42 @@ describe('ActivityPub', () => {
 			assert.strictEqual(driveFile, null);
 		});
 	});
+
+	describe('JSON-LD', () =>{
+		test('Compaction', async () => {
+			const jsonLd = jsonLdService.use();
+
+			const object = {
+				'@context': [
+					'https://www.w3.org/ns/activitystreams',
+					{
+						_misskey_quote: 'https://misskey-hub.net/ns#_misskey_quote',
+						unknown: 'https://example.org/ns#unknown',
+						undefined: null,
+					},
+				],
+				id: 'https://example.com/notes/42',
+				type: 'Note',
+				attributedTo: 'https://example.com/users/1',
+				to: ['https://www.w3.org/ns/activitystreams#Public'],
+				content: 'test test foo',
+				_misskey_quote: 'https://example.com/notes/1',
+				unknown: 'test test bar',
+				undefined: 'test test baz',
+			};
+			const compacted = await jsonLd.compact(object);
+
+			assert.deepStrictEqual(compacted, {
+				'@context': CONTEXT,
+				id: 'https://example.com/notes/42',
+				type: 'Note',
+				attributedTo: 'https://example.com/users/1',
+				to: 'as:Public',
+				content: 'test test foo',
+				_misskey_quote: 'https://example.com/notes/1',
+				'https://example.org/ns#unknown': 'test test bar',
+				// undefined: 'test test baz',
+			});
+		});
+	});
 });

From 9c057e6854c22b4bc908485c08364a8a38091167 Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Wed, 1 May 2024 16:39:16 +0900
Subject: [PATCH 107/191] fix(frontend): fix Storybook type errors (#13779)

* fix(frontend): fix Storybook type errors

* fix: `hasReduce` doesn't work in args
---
 packages/frontend/.storybook/fakes.ts         |   10 +-
 packages/frontend/.storybook/generate.tsx     |   26 +-
 packages/frontend/.storybook/main.ts          |    2 +-
 packages/frontend/.storybook/mocks.ts         |    3 +-
 packages/frontend/package.json                |   38 +-
 .../components/MkAccountMoved.stories.impl.ts |   15 +-
 .../MkAnnouncementDialog.stories.impl.ts      |   20 +-
 .../MkSignupDialog.rules.stories.impl.ts      |    6 +
 .../components/global/MkAd.stories.impl.ts    |   22 +-
 .../global/MkAvatar.stories.impl.ts           |    3 +-
 .../global/MkCondensedLine.stories.impl.ts    |    2 +
 .../components/global/MkError.stories.meta.ts |    7 +-
 .../global/MkPageHeader.stories.impl.ts       |    5 +-
 .../components/global/MkPageHeader.tabs.vue   |    1 -
 .../components/global/MkTime.stories.impl.ts  |   14 +-
 .../global/MkUserName.stories.impl.ts         |    2 +-
 pnpm-lock.yaml                                | 1508 +++++++++--------
 17 files changed, 952 insertions(+), 732 deletions(-)

diff --git a/packages/frontend/.storybook/fakes.ts b/packages/frontend/.storybook/fakes.ts
index 48c9e0261d..3a24ccb248 100644
--- a/packages/frontend/.storybook/fakes.ts
+++ b/packages/frontend/.storybook/fakes.ts
@@ -27,7 +27,7 @@ export function galleryPost(isSensitive = false) {
 		id: 'somepostid',
 		createdAt: '2016-12-28T22:49:51.000Z',
 		updatedAt: '2016-12-28T22:49:51.000Z',
-		userid: 'someuserid',
+		userId: 'someuserid',
 		user: userDetailed(),
 		title: 'Some post title',
 		description: 'Some post description',
@@ -75,9 +75,8 @@ export function userDetailed(id = 'someuserid', username = 'miskist', host = 'mi
 		avatarUrl: 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/about-icon.png?raw=true',
 		avatarBlurhash: 'eQFRshof5NWBRi},juayfPju53WB?0ofs;s*a{ofjuay^SoMEJR%ay',
 		avatarDecorations: [],
-		emojis: [],
+		emojis: {},
 		bannerBlurhash: 'eQA^IW^-MH8w9tE8I=S^o{$*R4RikXtSxutRozjEnNR.RQadoyozog',
-		bannerColor: '#000000',
 		bannerUrl: 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true',
 		birthday: '2014-06-20',
 		createdAt: '2016-12-28T22:49:51.000Z',
@@ -118,11 +117,16 @@ export function userDetailed(id = 'someuserid', username = 'miskist', host = 'mi
 		publicReactions: false,
 		securityKeys: false,
 		twoFactorEnabled: false,
+		usePasswordLessLogin: false,
 		twoFactorBackupCodesStock: 'none',
 		updatedAt: null,
+		lastFetchedAt: null,
 		uri: null,
 		url: null,
+		movedTo: null,
+		alsoKnownAs: null,
 		notify: 'none',
+		memo: null
 	};
 }
 
diff --git a/packages/frontend/.storybook/generate.tsx b/packages/frontend/.storybook/generate.tsx
index 1e925aede6..d74c83a500 100644
--- a/packages/frontend/.storybook/generate.tsx
+++ b/packages/frontend/.storybook/generate.tsx
@@ -82,23 +82,16 @@ function h<T extends estree.Node>(
 	return Object.assign(props || {}, { type }) as T;
 }
 
-declare global {
-	namespace JSX {
-		type Element = estree.Node;
-		type ElementClass = never;
-		type ElementAttributesProperty = never;
-		type ElementChildrenAttribute = never;
-		type IntrinsicAttributes = never;
-		type IntrinsicClassAttributes<T> = never;
-		type IntrinsicElements = {
-			[T in keyof typeof generator as ToKebab<SplitCamel<Uncapitalize<T>>>]: {
-				[K in keyof Omit<
-					Parameters<(typeof generator)[T]>[0],
-					'type'
-				>]?: Parameters<(typeof generator)[T]>[0][K];
-			};
+declare namespace h.JSX {
+	type Element = estree.Node;
+	type IntrinsicElements = {
+		[T in keyof typeof generator as ToKebab<SplitCamel<Uncapitalize<T>>>]: {
+			[K in keyof Omit<
+				Parameters<(typeof generator)[T]>[0],
+				'type'
+			>]?: Parameters<(typeof generator)[T]>[0][K];
 		};
-	}
+	};
 }
 
 function toStories(component: string): Promise<string> {
@@ -388,6 +381,7 @@ function toStories(component: string): Promise<string> {
 		'/* eslint-disable @typescript-eslint/explicit-function-return-type */\n' +
 			'/* eslint-disable import/no-default-export */\n' +
 			'/* eslint-disable import/no-duplicates */\n' +
+			'/* eslint-disable import/order */\n' +
 			generate(program, { generator }) +
 			(hasImplStories ? readFileSync(`${implStories}.ts`, 'utf-8') : ''),
 		{
diff --git a/packages/frontend/.storybook/main.ts b/packages/frontend/.storybook/main.ts
index 0a87488573..d3822942cd 100644
--- a/packages/frontend/.storybook/main.ts
+++ b/packages/frontend/.storybook/main.ts
@@ -34,7 +34,7 @@ const config = {
 		disableTelemetry: true,
 	},
 	async viteFinal(config) {
-		const replacePluginForIsChromatic = config.plugins?.findIndex((plugin) => plugin && (plugin as Partial<Plugin>)?.name === 'replace') ?? -1;
+		const replacePluginForIsChromatic = config.plugins?.findIndex((plugin: Plugin) => plugin && plugin.name === 'replace') ?? -1;
 		if (~replacePluginForIsChromatic) {
 			config.plugins?.splice(replacePluginForIsChromatic, 1);
 		}
diff --git a/packages/frontend/.storybook/mocks.ts b/packages/frontend/.storybook/mocks.ts
index 817b0125e7..29cb112ccb 100644
--- a/packages/frontend/.storybook/mocks.ts
+++ b/packages/frontend/.storybook/mocks.ts
@@ -6,7 +6,8 @@
 import { type SharedOptions, http, HttpResponse } from 'msw';
 
 export const onUnhandledRequest = ((req, print) => {
-	if (req.url.hostname !== 'localhost' || /^\/(?:client-assets\/|fluent-emojis?\/|iframe.html$|node_modules\/|src\/|sb-|static-assets\/|vite\/)/.test(req.url.pathname)) {
+	const url = new URL(req.url);
+	if (url.hostname !== 'localhost' || /^\/(?:client-assets\/|fluent-emojis?\/|iframe.html$|node_modules\/|src\/|sb-|static-assets\/|vite\/)/.test(url.pathname)) {
 		return
 	}
 	print.warning()
diff --git a/packages/frontend/package.json b/packages/frontend/package.json
index 95980ac0fc..43a7759fa6 100644
--- a/packages/frontend/package.json
+++ b/packages/frontend/package.json
@@ -78,24 +78,24 @@
 	"devDependencies": {
 		"@misskey-dev/eslint-plugin": "1.0.0",
 		"@misskey-dev/summaly": "5.0.3",
-		"@storybook/addon-actions": "8.0.0-beta.6",
-		"@storybook/addon-essentials": "8.0.0-beta.6",
-		"@storybook/addon-interactions": "8.0.0-beta.6",
-		"@storybook/addon-links": "8.0.0-beta.6",
-		"@storybook/addon-mdx-gfm": "8.0.0-beta.6",
-		"@storybook/addon-storysource": "8.0.0-beta.6",
-		"@storybook/blocks": "8.0.0-beta.6",
-		"@storybook/components": "8.0.0-beta.6",
-		"@storybook/core-events": "8.0.0-beta.6",
-		"@storybook/manager-api": "8.0.0-beta.6",
-		"@storybook/preview-api": "8.0.0-beta.6",
-		"@storybook/react": "8.0.0-beta.6",
-		"@storybook/react-vite": "8.0.0-beta.6",
-		"@storybook/test": "8.0.0-beta.6",
-		"@storybook/theming": "8.0.0-beta.6",
-		"@storybook/types": "8.0.0-beta.6",
-		"@storybook/vue3": "8.0.0-beta.6",
-		"@storybook/vue3-vite": "8.0.0-beta.6",
+		"@storybook/addon-actions": "8.0.9",
+		"@storybook/addon-essentials": "8.0.9",
+		"@storybook/addon-interactions": "8.0.9",
+		"@storybook/addon-links": "8.0.9",
+		"@storybook/addon-mdx-gfm": "8.0.9",
+		"@storybook/addon-storysource": "8.0.9",
+		"@storybook/blocks": "8.0.9",
+		"@storybook/components": "8.0.9",
+		"@storybook/core-events": "8.0.9",
+		"@storybook/manager-api": "8.0.9",
+		"@storybook/preview-api": "8.0.9",
+		"@storybook/react": "8.0.9",
+		"@storybook/react-vite": "8.0.9",
+		"@storybook/test": "8.0.9",
+		"@storybook/theming": "8.0.9",
+		"@storybook/types": "8.0.9",
+		"@storybook/vue3": "8.0.9",
+		"@storybook/vue3-vite": "8.0.9",
 		"@testing-library/vue": "8.0.2",
 		"@types/escape-regexp": "0.0.3",
 		"@types/estree": "1.0.5",
@@ -129,7 +129,7 @@
 		"react": "18.2.0",
 		"react-dom": "18.2.0",
 		"start-server-and-test": "2.0.3",
-		"storybook": "8.0.0-beta.6",
+		"storybook": "8.0.9",
 		"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",
 		"vite-plugin-turbosnap": "1.0.3",
 		"vitest": "0.34.6",
diff --git a/packages/frontend/src/components/MkAccountMoved.stories.impl.ts b/packages/frontend/src/components/MkAccountMoved.stories.impl.ts
index f1cfdc157a..cad26de6e2 100644
--- a/packages/frontend/src/components/MkAccountMoved.stories.impl.ts
+++ b/packages/frontend/src/components/MkAccountMoved.stories.impl.ts
@@ -4,7 +4,10 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
+import { action } from '@storybook/addon-actions';
 import { StoryObj } from '@storybook/vue3';
+import { HttpResponse, http } from 'msw';
+import { commonHandlers } from '../../.storybook/mocks.js';
 import { userDetailed } from '../../.storybook/fakes.js';
 import MkAccountMoved from './MkAccountMoved.vue';
 export const Default = {
@@ -29,10 +32,18 @@ export const Default = {
 		};
 	},
 	args: {
-		username: userDetailed().username,
-		host: userDetailed().host,
+		movedTo: userDetailed().id,
 	},
 	parameters: {
 		layout: 'centered',
+		msw: {
+			handlers: [
+				...commonHandlers,
+				http.post('/api/users/show', async ({ request }) => {
+					action('POST /api/users/show')(await request.json());
+					return HttpResponse.json(userDetailed());
+				}),
+			],
+		},
 	},
 } satisfies StoryObj<typeof MkAccountMoved>;
diff --git a/packages/frontend/src/components/MkAnnouncementDialog.stories.impl.ts b/packages/frontend/src/components/MkAnnouncementDialog.stories.impl.ts
index ffa4e56f5f..bf3ddb935b 100644
--- a/packages/frontend/src/components/MkAnnouncementDialog.stories.impl.ts
+++ b/packages/frontend/src/components/MkAnnouncementDialog.stories.impl.ts
@@ -4,7 +4,10 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
+import { action } from '@storybook/addon-actions';
 import { StoryObj } from '@storybook/vue3';
+import { HttpResponse, http } from 'msw';
+import { commonHandlers } from '../../.storybook/mocks.js';
 import MkAnnouncementDialog from './MkAnnouncementDialog.vue';
 export const Default = {
 	render(args) {
@@ -23,8 +26,13 @@ export const Default = {
 						...this.args,
 					};
 				},
+				events() {
+					return {
+						closed: action('closed'),
+					};
+				},
 			},
-			template: '<MkAnnouncementDialog v-bind="props" />',
+			template: '<MkAnnouncementDialog v-bind="props" v-on="events" />',
 		};
 	},
 	args: {
@@ -38,10 +46,20 @@ export const Default = {
 			imageUrl: null,
 			display: 'dialog',
 			needConfirmationToRead: false,
+			silence: false,
 			forYou: true,
 		},
 	},
 	parameters: {
 		layout: 'centered',
+		msw: {
+			handlers: [
+				...commonHandlers,
+				http.post('/api/i/read-announcement', async ({ request }) => {
+					action('POST /api/i/read-announcement')(await request.json());
+					return HttpResponse.json();
+				}),
+			],
+		},
 	},
 } satisfies StoryObj<typeof MkAnnouncementDialog>;
diff --git a/packages/frontend/src/components/MkSignupDialog.rules.stories.impl.ts b/packages/frontend/src/components/MkSignupDialog.rules.stories.impl.ts
index fcd1ffde3e..9df3ec0c30 100644
--- a/packages/frontend/src/components/MkSignupDialog.rules.stories.impl.ts
+++ b/packages/frontend/src/components/MkSignupDialog.rules.stories.impl.ts
@@ -51,13 +51,16 @@ export const Empty = {
 		expect(buttons.at(-1)).toBeEnabled();
 	},
 	args: {
+		// @ts-expect-error serverRules is for test
 		serverRules: [],
 		tosUrl: null,
 	},
 	decorators: [
 		(_, context) => ({
 			setup() {
+				// @ts-expect-error serverRules is for test
 				instance.serverRules = context.args.serverRules;
+				// @ts-expect-error tosUrl is for test
 				instance.tosUrl = context.args.tosUrl;
 				onBeforeUnmount(() => {
 					// FIXME: 呼び出されない
@@ -76,6 +79,7 @@ export const ServerRulesOnly = {
 	...Empty,
 	args: {
 		...Empty.args,
+		// @ts-expect-error serverRules is for test
 		serverRules: [
 			'ルール',
 		],
@@ -85,6 +89,7 @@ export const TOSOnly = {
 	...Empty,
 	args: {
 		...Empty.args,
+		// @ts-expect-error tosUrl is for test
 		tosUrl: 'https://example.com/tos',
 	},
 } satisfies StoryObj<typeof MkSignupServerRules>;
@@ -92,6 +97,7 @@ export const ServerRulesAndTOS = {
 	...Empty,
 	args: {
 		...Empty.args,
+		// @ts-expect-error serverRules is for test
 		serverRules: ServerRulesOnly.args.serverRules,
 		tosUrl: TOSOnly.args.tosUrl,
 	},
diff --git a/packages/frontend/src/components/global/MkAd.stories.impl.ts b/packages/frontend/src/components/global/MkAd.stories.impl.ts
index f6cdc2bf23..a1d274382f 100644
--- a/packages/frontend/src/components/global/MkAd.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkAd.stories.impl.ts
@@ -4,8 +4,10 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
+import { expect, userEvent, waitFor, within } from '@storybook/test';
 import { StoryObj } from '@storybook/vue3';
 import MkAd from './MkAd.vue';
+import { i18n } from '@/i18n.js';
 
 let lock: Promise<undefined> | undefined;
 
@@ -30,7 +32,6 @@ const common = {
 			template: '<MkAd v-bind="props" />',
 		};
 	},
-	/* FIXME: disabled because it still didn’t pass after applying #11267
 	async play({ canvasElement, args }) {
 		if (lock) {
 			console.warn('This test is unexpectedly running twice in parallel, fix it!');
@@ -44,7 +45,7 @@ const common = {
 		try {
 			const canvas = within(canvasElement);
 			const a = canvas.getByRole<HTMLAnchorElement>('link');
-			await expect(a.href).toMatch(/^https?:\/\/.*#test$/);
+			// await expect(a.href).toMatch(/^https?:\/\/.*#test$/);
 			const img = within(a).getByRole('img');
 			await expect(img).toBeInTheDocument();
 			let buttons = canvas.getAllByRole<HTMLButtonElement>('button');
@@ -52,13 +53,14 @@ const common = {
 			const i = buttons[0];
 			await expect(i).toBeInTheDocument();
 			await userEvent.click(i);
-			await waitFor(() => expect(canvasElement).toHaveTextContent(i18n.ts._ad.back));
+			// await expect(canvasElement).toHaveTextContent(i18n.ts._ad.back);
 			await expect(a).not.toBeInTheDocument();
 			await expect(i).not.toBeInTheDocument();
 			buttons = canvas.getAllByRole<HTMLButtonElement>('button');
-			await expect(buttons).toHaveLength(args.__hasReduce ? 2 : 1);
-			const reduce = args.__hasReduce ? buttons[0] : null;
-			const back = buttons[args.__hasReduce ? 1 : 0];
+			const hasReduceFrequency = args.specify?.ratio !== 0;
+			await expect(buttons).toHaveLength(hasReduceFrequency ? 2 : 1);
+			const reduce = hasReduceFrequency ? buttons[0] : null;
+			const back = buttons[hasReduceFrequency ? 1 : 0];
 			if (reduce) {
 				await expect(reduce).toBeInTheDocument();
 				await expect(reduce).toHaveTextContent(i18n.ts._ad.reduceFrequencyOfThisAd);
@@ -80,15 +82,16 @@ const common = {
 			lock = undefined;
 		}
 	},
-	 */
 	args: {
 		prefer: [],
 		specify: {
 			id: 'someadid',
-			radio: 1,
+			ratio: 1,
 			url: '#test',
+			place: '',
+			imageUrl: '',
+			dayOfWeek: 7,
 		},
-		__hasReduce: true,
 	},
 	parameters: {
 		layout: 'centered',
@@ -138,6 +141,5 @@ export const ZeroRatio = {
 			...Square.args.specify,
 			ratio: 0,
 		},
-		__hasReduce: false,
 	},
 } satisfies StoryObj<typeof MkAd>;
diff --git a/packages/frontend/src/components/global/MkAvatar.stories.impl.ts b/packages/frontend/src/components/global/MkAvatar.stories.impl.ts
index 933754ec4c..9d2de9f0be 100644
--- a/packages/frontend/src/components/global/MkAvatar.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkAvatar.stories.impl.ts
@@ -33,7 +33,7 @@ const common = {
 	},
 	decorators: [
 		(Story, context) => ({
-			// eslint-disable-next-line quotes
+			// @ts-expect-error size is for test
 			template: `<div :style="{ display: 'grid', width: '${context.args.size}px', height: '${context.args.size}px' }"><story/></div>`,
 		}),
 	],
@@ -45,6 +45,7 @@ export const ProfilePage = {
 	...common,
 	args: {
 		...common.args,
+		// @ts-expect-error size is for test
 		size: 120,
 		indicator: true,
 	},
diff --git a/packages/frontend/src/components/global/MkCondensedLine.stories.impl.ts b/packages/frontend/src/components/global/MkCondensedLine.stories.impl.ts
index e4e90cddd5..e15dcba760 100644
--- a/packages/frontend/src/components/global/MkCondensedLine.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkCondensedLine.stories.impl.ts
@@ -28,6 +28,7 @@ export const Default = {
 		};
 	},
 	args: {
+		// @ts-expect-error text is for test
 		text: 'This is a condensed line.',
 	},
 	parameters: {
@@ -41,4 +42,5 @@ export const ContainerIs100px = {
 			template: '<div style="width: 100px;"><story/></div>',
 		}),
 	],
+	// @ts-expect-error text is for test
 } satisfies StoryObj<typeof MkCondensedLine>;
diff --git a/packages/frontend/src/components/global/MkError.stories.meta.ts b/packages/frontend/src/components/global/MkError.stories.meta.ts
index 1abbc56f50..cd7fada189 100644
--- a/packages/frontend/src/components/global/MkError.stories.meta.ts
+++ b/packages/frontend/src/components/global/MkError.stories.meta.ts
@@ -3,8 +3,11 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
+import { Meta } from '@storybook/vue3';
+import MkError from './MkError.vue';
+
 export const argTypes = {
-	retry: {
+	onRetry: {
 		action: 'retry',
 	},
-};
+} satisfies Meta<typeof MkError>['argTypes'];
diff --git a/packages/frontend/src/components/global/MkPageHeader.stories.impl.ts b/packages/frontend/src/components/global/MkPageHeader.stories.impl.ts
index eb74e874dd..1d079edd2c 100644
--- a/packages/frontend/src/components/global/MkPageHeader.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkPageHeader.stories.impl.ts
@@ -33,7 +33,6 @@ export const Empty = {
 		await waitFor(async () => await wait);
 	},
 	args: {
-		static: true,
 		tabs: [],
 	},
 	parameters: {
@@ -71,8 +70,8 @@ export const IconOnly = {
 		...Icon.args,
 		tabs: [
 			{
-				...Icon.args.tabs[0],
-				title: undefined,
+				key: Icon.args.tabs[0].key,
+				icon: Icon.args.tabs[0].icon,
 				iconOnly: true,
 			},
 		],
diff --git a/packages/frontend/src/components/global/MkPageHeader.tabs.vue b/packages/frontend/src/components/global/MkPageHeader.tabs.vue
index e93b09721a..fcc46cc345 100644
--- a/packages/frontend/src/components/global/MkPageHeader.tabs.vue
+++ b/packages/frontend/src/components/global/MkPageHeader.tabs.vue
@@ -38,7 +38,6 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts">
 export type Tab = {
 	key: string;
-	title: string;
 	onClick?: (ev: MouseEvent) => void;
 } & (
 	| {
diff --git a/packages/frontend/src/components/global/MkTime.stories.impl.ts b/packages/frontend/src/components/global/MkTime.stories.impl.ts
index 355c839113..ffd4a849a2 100644
--- a/packages/frontend/src/components/global/MkTime.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkTime.stories.impl.ts
@@ -60,7 +60,7 @@ export const RelativeFuture = {
 export const AbsoluteFuture = {
 	...Empty,
 	async play({ canvasElement, args }) {
-		await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(args.time));
+		await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(typeof args.time === 'string' ? new Date(args.time) : args.time ?? undefined));
 	},
 	args: {
 		...Empty.args,
@@ -97,7 +97,7 @@ export const RelativeNow = {
 export const AbsoluteNow = {
 	...Empty,
 	async play({ canvasElement, args }) {
-		await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(args.time));
+		await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(typeof args.time === 'string' ? new Date(args.time) : args.time ?? undefined));
 	},
 	args: {
 		...Empty.args,
@@ -136,7 +136,7 @@ export const RelativeOneHourAgo = {
 export const AbsoluteOneHourAgo = {
 	...Empty,
 	async play({ canvasElement, args }) {
-		await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(args.time));
+		await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(typeof args.time === 'string' ? new Date(args.time) : args.time ?? undefined));
 	},
 	args: {
 		...Empty.args,
@@ -175,7 +175,7 @@ export const RelativeOneDayAgo = {
 export const AbsoluteOneDayAgo = {
 	...Empty,
 	async play({ canvasElement, args }) {
-		await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(args.time));
+		await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(typeof args.time === 'string' ? new Date(args.time) : args.time ?? undefined));
 	},
 	args: {
 		...Empty.args,
@@ -214,7 +214,7 @@ export const RelativeOneWeekAgo = {
 export const AbsoluteOneWeekAgo = {
 	...Empty,
 	async play({ canvasElement, args }) {
-		await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(args.time));
+		await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(typeof args.time === 'string' ? new Date(args.time) : args.time ?? undefined));
 	},
 	args: {
 		...Empty.args,
@@ -253,7 +253,7 @@ export const RelativeOneMonthAgo = {
 export const AbsoluteOneMonthAgo = {
 	...Empty,
 	async play({ canvasElement, args }) {
-		await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(args.time));
+		await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(typeof args.time === 'string' ? new Date(args.time) : args.time ?? undefined));
 	},
 	args: {
 		...Empty.args,
@@ -292,7 +292,7 @@ export const RelativeOneYearAgo = {
 export const AbsoluteOneYearAgo = {
 	...Empty,
 	async play({ canvasElement, args }) {
-		await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(args.time));
+		await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(typeof args.time === 'string' ? new Date(args.time) : args.time ?? undefined));
 	},
 	args: {
 		...Empty.args,
diff --git a/packages/frontend/src/components/global/MkUserName.stories.impl.ts b/packages/frontend/src/components/global/MkUserName.stories.impl.ts
index 88bf4f4e6c..e39061c291 100644
--- a/packages/frontend/src/components/global/MkUserName.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkUserName.stories.impl.ts
@@ -30,7 +30,7 @@ export const Default = {
 		};
 	},
 	async play({ canvasElement }) {
-		await expect(canvasElement).toHaveTextContent(userDetailed().name);
+		await expect(canvasElement).toHaveTextContent(userDetailed().name as string);
 	},
 	args: {
 		user: userDetailed(),
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c7625fd89f..8e5cc2d699 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -864,59 +864,59 @@ importers:
         specifier: 5.0.3
         version: 5.0.3
       '@storybook/addon-actions':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6
+        specifier: 8.0.9
+        version: 8.0.9
       '@storybook/addon-essentials':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
+        specifier: 8.0.9
+        version: 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
       '@storybook/addon-interactions':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6
+        specifier: 8.0.9
+        version: 8.0.9(vitest@0.34.6)
       '@storybook/addon-links':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6(react@18.2.0)
+        specifier: 8.0.9
+        version: 8.0.9(react@18.2.0)
       '@storybook/addon-mdx-gfm':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6
+        specifier: 8.0.9
+        version: 8.0.9
       '@storybook/addon-storysource':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6
+        specifier: 8.0.9
+        version: 8.0.9
       '@storybook/blocks':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
+        specifier: 8.0.9
+        version: 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
       '@storybook/components':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
+        specifier: 8.0.9
+        version: 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
       '@storybook/core-events':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6
+        specifier: 8.0.9
+        version: 8.0.9
       '@storybook/manager-api':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)
+        specifier: 8.0.9
+        version: 8.0.9(react-dom@18.2.0)(react@18.2.0)
       '@storybook/preview-api':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6
+        specifier: 8.0.9
+        version: 8.0.9
       '@storybook/react':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)
+        specifier: 8.0.9
+        version: 8.0.9(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)
       '@storybook/react-vite':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)(rollup@4.12.0)(typescript@5.3.3)(vite@5.1.4)
+        specifier: 8.0.9
+        version: 8.0.9(react-dom@18.2.0)(react@18.2.0)(rollup@4.12.0)(typescript@5.3.3)(vite@5.1.4)
       '@storybook/test':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6(vitest@0.34.6)
+        specifier: 8.0.9
+        version: 8.0.9(vitest@0.34.6)
       '@storybook/theming':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)
+        specifier: 8.0.9
+        version: 8.0.9(react-dom@18.2.0)(react@18.2.0)
       '@storybook/types':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6
+        specifier: 8.0.9
+        version: 8.0.9
       '@storybook/vue3':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6(vue@3.4.21)
+        specifier: 8.0.9
+        version: 8.0.9(vue@3.4.21)
       '@storybook/vue3-vite':
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)(vite@5.1.4)(vue@3.4.21)
+        specifier: 8.0.9
+        version: 8.0.9(react-dom@18.2.0)(react@18.2.0)(vite@5.1.4)(vue@3.4.21)
       '@testing-library/vue':
         specifier: 8.0.2
         version: 8.0.2(@vue/compiler-sfc@3.4.21)(vue@3.4.21)
@@ -1017,11 +1017,11 @@ importers:
         specifier: 2.0.3
         version: 2.0.3
       storybook:
-        specifier: 8.0.0-beta.6
-        version: 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)
+        specifier: 8.0.9
+        version: 8.0.9(react-dom@18.2.0)(react@18.2.0)
       storybook-addon-misskey-theme:
         specifier: github:misskey-dev/storybook-addon-misskey-theme
-        version: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.0.0-beta.6)(@storybook/components@8.0.0-beta.6)(@storybook/core-events@8.0.0-beta.6)(@storybook/manager-api@8.0.0-beta.6)(@storybook/preview-api@8.0.0-beta.6)(@storybook/theming@8.0.0-beta.6)(@storybook/types@8.0.0-beta.6)(react-dom@18.2.0)(react@18.2.0)
+        version: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.0.9)(@storybook/components@8.0.9)(@storybook/core-events@8.0.9)(@storybook/manager-api@8.0.9)(@storybook/preview-api@8.0.9)(@storybook/theming@8.0.9)(@storybook/types@8.0.9)(react-dom@18.2.0)(react@18.2.0)
       vite-plugin-turbosnap:
         specifier: 1.0.3
         version: 1.0.3
@@ -1964,14 +1964,14 @@ packages:
     resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.23.5
+      '@babel/types': 7.24.0
     dev: true
 
   /@babel/helper-builder-binary-assignment-operator-visitor@7.22.15:
     resolution: {integrity: sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.23.5
+      '@babel/types': 7.24.0
     dev: true
 
   /@babel/helper-compilation-targets@7.22.15:
@@ -1991,48 +1991,48 @@ packages:
     dependencies:
       '@babel/compat-data': 7.23.5
       '@babel/helper-validator-option': 7.23.5
-      browserslist: 4.22.2
+      browserslist: 4.23.0
       lru-cache: 5.1.1
       semver: 6.3.1
     dev: true
 
-  /@babel/helper-create-class-features-plugin@7.23.5(@babel/core@7.23.5):
+  /@babel/helper-create-class-features-plugin@7.23.5(@babel/core@7.24.0):
     resolution: {integrity: sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-annotate-as-pure': 7.22.5
       '@babel/helper-environment-visitor': 7.22.20
       '@babel/helper-function-name': 7.23.0
       '@babel/helper-member-expression-to-functions': 7.23.0
       '@babel/helper-optimise-call-expression': 7.22.5
-      '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.5)
+      '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.0)
       '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
       '@babel/helper-split-export-declaration': 7.22.6
       semver: 6.3.1
     dev: true
 
-  /@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.23.5):
+  /@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.24.0):
     resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-annotate-as-pure': 7.22.5
       regexpu-core: 5.3.2
       semver: 6.3.1
     dev: true
 
-  /@babel/helper-define-polyfill-provider@0.4.3(@babel/core@7.23.5):
+  /@babel/helper-define-polyfill-provider@0.4.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==}
     peerDependencies:
       '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/helper-compilation-targets': 7.22.15
+      '@babel/core': 7.24.0
+      '@babel/helper-compilation-targets': 7.23.6
       '@babel/helper-plugin-utils': 7.22.5
       debug: 4.3.4(supports-color@8.1.1)
       lodash.debounce: 4.0.8
@@ -2065,7 +2065,7 @@ packages:
     resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.23.5
+      '@babel/types': 7.24.0
     dev: true
 
   /@babel/helper-module-imports@7.22.15:
@@ -2107,7 +2107,7 @@ packages:
     resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.23.5
+      '@babel/types': 7.24.0
     dev: true
 
   /@babel/helper-plugin-utils@7.22.5:
@@ -2115,25 +2115,25 @@ packages:
     engines: {node: '>=6.9.0'}
     dev: true
 
-  /@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.23.5):
+  /@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.24.0):
     resolution: {integrity: sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-annotate-as-pure': 7.22.5
       '@babel/helper-environment-visitor': 7.22.20
       '@babel/helper-wrap-function': 7.22.20
     dev: true
 
-  /@babel/helper-replace-supers@7.22.20(@babel/core@7.23.5):
+  /@babel/helper-replace-supers@7.22.20(@babel/core@7.24.0):
     resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-environment-visitor': 7.22.20
       '@babel/helper-member-expression-to-functions': 7.23.0
       '@babel/helper-optimise-call-expression': 7.22.5
@@ -2150,7 +2150,7 @@ packages:
     resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.23.5
+      '@babel/types': 7.24.0
     dev: true
 
   /@babel/helper-split-export-declaration@7.22.6:
@@ -2178,8 +2178,8 @@ packages:
     engines: {node: '>=6.9.0'}
     dependencies:
       '@babel/helper-function-name': 7.23.0
-      '@babel/template': 7.22.15
-      '@babel/types': 7.23.5
+      '@babel/template': 7.24.0
+      '@babel/types': 7.24.0
     dev: true
 
   /@babel/helpers@7.23.5:
@@ -2228,46 +2228,46 @@ packages:
       '@babel/types': 7.24.0
     dev: true
 
-  /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.13.0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
-      '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.5)
+      '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.24.0)
     dev: true
 
-  /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-environment-visitor': 7.22.20
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.5):
+  /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.0):
     resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
     dev: true
 
   /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.5):
@@ -2279,6 +2279,15 @@ packages:
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
+  /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.0):
+    resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.24.0
+      '@babel/helper-plugin-utils': 7.22.5
+    dev: true
+
   /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.5):
     resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}
     peerDependencies:
@@ -2297,61 +2306,70 @@ packages:
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.23.5):
+  /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.0):
+    resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.24.0
+      '@babel/helper-plugin-utils': 7.22.5
+    dev: true
+
+  /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.0):
     resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.23.5):
+  /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.23.5):
+  /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-syntax-flow@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-YZiAIpkJAwQXBJLIQbRFayR5c+gJ35Vcz3bg954k7cd73zqjvhacJuL9RbrzPz8qPmZdgqP6EUKwy0PCNhaaPA==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
@@ -2364,6 +2382,15 @@ packages:
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
+  /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.0):
+    resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.24.0
+      '@babel/helper-plugin-utils': 7.22.5
+    dev: true
+
   /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.5):
     resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
     peerDependencies:
@@ -2373,6 +2400,15 @@ packages:
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
+  /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.0):
+    resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.24.0
+      '@babel/helper-plugin-utils': 7.22.5
+    dev: true
+
   /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.5):
     resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==}
     engines: {node: '>=6.9.0'}
@@ -2383,6 +2419,16 @@ packages:
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
+  /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.24.0):
+    resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.24.0
+      '@babel/helper-plugin-utils': 7.22.5
+    dev: true
+
   /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.5):
     resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
     peerDependencies:
@@ -2392,6 +2438,15 @@ packages:
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
+  /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.0):
+    resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.24.0
+      '@babel/helper-plugin-utils': 7.22.5
+    dev: true
+
   /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.5):
     resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
     peerDependencies:
@@ -2401,6 +2456,15 @@ packages:
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
+  /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.0):
+    resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.24.0
+      '@babel/helper-plugin-utils': 7.22.5
+    dev: true
+
   /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.5):
     resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
     peerDependencies:
@@ -2410,6 +2474,15 @@ packages:
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
+  /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.0):
+    resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.24.0
+      '@babel/helper-plugin-utils': 7.22.5
+    dev: true
+
   /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.5):
     resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
     peerDependencies:
@@ -2419,6 +2492,15 @@ packages:
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
+  /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.0):
+    resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.24.0
+      '@babel/helper-plugin-utils': 7.22.5
+    dev: true
+
   /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.5):
     resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
     peerDependencies:
@@ -2428,6 +2510,15 @@ packages:
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
+  /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.0):
+    resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.24.0
+      '@babel/helper-plugin-utils': 7.22.5
+    dev: true
+
   /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.5):
     resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
     peerDependencies:
@@ -2437,13 +2528,22 @@ packages:
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.23.5):
+  /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.0):
+    resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.24.0
+      '@babel/helper-plugin-utils': 7.22.5
+    dev: true
+
+  /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.0):
     resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
@@ -2457,6 +2557,16 @@ packages:
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
+  /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.0):
+    resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.24.0
+      '@babel/helper-plugin-utils': 7.22.5
+    dev: true
+
   /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.5):
     resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==}
     engines: {node: '>=6.9.0'}
@@ -2467,708 +2577,718 @@ packages:
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.23.5):
+  /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.24.0):
+    resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.24.0
+      '@babel/helper-plugin-utils': 7.22.5
+    dev: true
+
+  /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.0):
     resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5)
+      '@babel/core': 7.24.0
+      '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-async-generator-functions@7.23.4(@babel/core@7.23.5):
+  /@babel/plugin-transform-async-generator-functions@7.23.4(@babel/core@7.24.0):
     resolution: {integrity: sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-environment-visitor': 7.22.20
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.5)
-      '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.5)
+      '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.0)
+      '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.0)
     dev: true
 
-  /@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-module-imports': 7.22.15
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.5)
+      '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.0)
     dev: true
 
-  /@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.23.5):
+  /@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.24.0):
     resolution: {integrity: sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.23.5)
+      '@babel/core': 7.24.0
+      '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.23.5):
+  /@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.24.0):
     resolution: {integrity: sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.12.0
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.23.5)
+      '@babel/core': 7.24.0
+      '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.5)
+      '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.0)
     dev: true
 
-  /@babel/plugin-transform-classes@7.23.5(@babel/core@7.23.5):
+  /@babel/plugin-transform-classes@7.23.5(@babel/core@7.24.0):
     resolution: {integrity: sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-annotate-as-pure': 7.22.5
-      '@babel/helper-compilation-targets': 7.22.15
+      '@babel/helper-compilation-targets': 7.23.6
       '@babel/helper-environment-visitor': 7.22.20
       '@babel/helper-function-name': 7.23.0
       '@babel/helper-optimise-call-expression': 7.22.5
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.5)
+      '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.0)
       '@babel/helper-split-export-declaration': 7.22.6
       globals: 11.12.0
     dev: true
 
-  /@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/template': 7.22.15
+      '@babel/template': 7.24.0
     dev: true
 
-  /@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5)
+      '@babel/core': 7.24.0
+      '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.23.5):
+  /@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.24.0):
     resolution: {integrity: sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.5)
+      '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.0)
     dev: true
 
-  /@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.23.5):
+  /@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.24.0):
     resolution: {integrity: sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.5)
+      '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.0)
     dev: true
 
-  /@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-26/pQTf9nQSNVJCrLB1IkHUKyPxR+lMrH2QDPG89+Znu9rAMbtrybdbWeE9bb7gzjmE5iXHEY+e0HUwM6Co93Q==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.5)
+      '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.24.0)
     dev: true
 
-  /@babel/plugin-transform-for-of@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-for-of@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-function-name@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-function-name@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/helper-compilation-targets': 7.22.15
+      '@babel/core': 7.24.0
+      '@babel/helper-compilation-targets': 7.23.6
       '@babel/helper-function-name': 7.23.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.23.5):
+  /@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.24.0):
     resolution: {integrity: sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.5)
+      '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.0)
     dev: true
 
-  /@babel/plugin-transform-literals@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-literals@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.23.5):
+  /@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.24.0):
     resolution: {integrity: sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.5)
+      '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.0)
     dev: true
 
-  /@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5)
+      '@babel/core': 7.24.0
+      '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5)
+      '@babel/core': 7.24.0
+      '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/helper-simple-access': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-modules-systemjs@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-modules-systemjs@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-hoist-variables': 7.22.5
-      '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5)
+      '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/helper-validator-identifier': 7.22.20
     dev: true
 
-  /@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5)
+      '@babel/core': 7.24.0
+      '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.23.5):
+  /@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.24.0):
     resolution: {integrity: sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5)
+      '@babel/core': 7.24.0
+      '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-new-target@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-new-target@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.23.5):
+  /@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.24.0):
     resolution: {integrity: sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.5)
+      '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.0)
     dev: true
 
-  /@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.23.5):
+  /@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.24.0):
     resolution: {integrity: sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.5)
+      '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.0)
     dev: true
 
-  /@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.23.5):
+  /@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.24.0):
     resolution: {integrity: sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
       '@babel/compat-data': 7.23.5
-      '@babel/core': 7.23.5
-      '@babel/helper-compilation-targets': 7.22.15
+      '@babel/core': 7.24.0
+      '@babel/helper-compilation-targets': 7.23.6
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.5)
+      '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.24.0)
     dev: true
 
-  /@babel/plugin-transform-object-super@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-object-super@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.5)
+      '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.0)
     dev: true
 
-  /@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.23.5):
+  /@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.24.0):
     resolution: {integrity: sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.5)
+      '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.0)
     dev: true
 
-  /@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.23.5):
+  /@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.24.0):
     resolution: {integrity: sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
-      '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.5)
+      '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.0)
     dev: true
 
-  /@babel/plugin-transform-parameters@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-parameters@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.23.5)
+      '@babel/core': 7.24.0
+      '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.23.5):
+  /@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.24.0):
     resolution: {integrity: sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-annotate-as-pure': 7.22.5
-      '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.23.5)
+      '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.5)
+      '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.0)
     dev: true
 
-  /@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       regenerator-transform: 0.15.2
     dev: true
 
-  /@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-spread@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-spread@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-typescript@7.23.5(@babel/core@7.23.5):
+  /@babel/plugin-transform-typescript@7.23.5(@babel/core@7.24.0):
     resolution: {integrity: sha512-2fMkXEJkrmwgu2Bsv1Saxgj30IXZdJ+84lQcKKI7sm719oXs0BBw2ZENKdJdR1PjWndgLCEBNXJOri0fk7RYQA==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-annotate-as-pure': 7.22.5
-      '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.23.5)
+      '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.5)
+      '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.24.0)
     dev: true
 
-  /@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5)
+      '@babel/core': 7.24.0
+      '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5)
+      '@babel/core': 7.24.0
+      '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.23.5):
+  /@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5)
+      '@babel/core': 7.24.0
+      '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/preset-env@7.23.5(@babel/core@7.23.5):
+  /@babel/preset-env@7.23.5(@babel/core@7.24.0):
     resolution: {integrity: sha512-0d/uxVD6tFGWXGDSfyMD1p2otoaKmu6+GD+NfAx0tMaH+dxORnp7T9TaVQ6mKyya7iBtCIVxHjWT7MuzzM9z+A==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
       '@babel/compat-data': 7.23.5
-      '@babel/core': 7.23.5
-      '@babel/helper-compilation-targets': 7.22.15
+      '@babel/core': 7.24.0
+      '@babel/helper-compilation-targets': 7.23.6
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/helper-validator-option': 7.23.5
-      '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.5)
-      '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.5)
-      '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.5)
-      '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.5)
-      '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.5)
-      '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.5)
-      '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.5)
-      '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.5)
-      '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.5)
-      '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.5)
-      '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.5)
-      '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.5)
-      '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.5)
-      '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.5)
-      '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.5)
-      '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.5)
-      '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.23.5)
-      '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-async-generator-functions': 7.23.4(@babel/core@7.23.5)
-      '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-block-scoped-functions': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.23.5)
-      '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.23.5)
-      '@babel/plugin-transform-classes': 7.23.5(@babel/core@7.23.5)
-      '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-duplicate-keys': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-dynamic-import': 7.23.4(@babel/core@7.23.5)
-      '@babel/plugin-transform-exponentiation-operator': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-export-namespace-from': 7.23.4(@babel/core@7.23.5)
-      '@babel/plugin-transform-for-of': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-json-strings': 7.23.4(@babel/core@7.23.5)
-      '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-logical-assignment-operators': 7.23.4(@babel/core@7.23.5)
-      '@babel/plugin-transform-member-expression-literals': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-modules-systemjs': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-modules-umd': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.23.5)
-      '@babel/plugin-transform-new-target': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.23.5)
-      '@babel/plugin-transform-numeric-separator': 7.23.4(@babel/core@7.23.5)
-      '@babel/plugin-transform-object-rest-spread': 7.23.4(@babel/core@7.23.5)
-      '@babel/plugin-transform-object-super': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-optional-catch-binding': 7.23.4(@babel/core@7.23.5)
-      '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.5)
-      '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.23.5)
-      '@babel/plugin-transform-property-literals': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-regenerator': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-reserved-words': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-typeof-symbol': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-unicode-escapes': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-unicode-property-regex': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-unicode-sets-regex': 7.23.3(@babel/core@7.23.5)
-      '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.23.5)
-      babel-plugin-polyfill-corejs2: 0.4.6(@babel/core@7.23.5)
-      babel-plugin-polyfill-corejs3: 0.8.6(@babel/core@7.23.5)
-      babel-plugin-polyfill-regenerator: 0.5.3(@babel/core@7.23.5)
+      '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.0)
+      '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.0)
+      '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.0)
+      '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.0)
+      '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.0)
+      '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.0)
+      '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.0)
+      '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.0)
+      '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.0)
+      '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.0)
+      '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.0)
+      '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.0)
+      '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.0)
+      '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.0)
+      '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.0)
+      '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.0)
+      '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.0)
+      '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-async-generator-functions': 7.23.4(@babel/core@7.24.0)
+      '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-block-scoped-functions': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.24.0)
+      '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.24.0)
+      '@babel/plugin-transform-classes': 7.23.5(@babel/core@7.24.0)
+      '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-duplicate-keys': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-dynamic-import': 7.23.4(@babel/core@7.24.0)
+      '@babel/plugin-transform-exponentiation-operator': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-export-namespace-from': 7.23.4(@babel/core@7.24.0)
+      '@babel/plugin-transform-for-of': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-json-strings': 7.23.4(@babel/core@7.24.0)
+      '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-logical-assignment-operators': 7.23.4(@babel/core@7.24.0)
+      '@babel/plugin-transform-member-expression-literals': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-modules-systemjs': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-modules-umd': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.24.0)
+      '@babel/plugin-transform-new-target': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.24.0)
+      '@babel/plugin-transform-numeric-separator': 7.23.4(@babel/core@7.24.0)
+      '@babel/plugin-transform-object-rest-spread': 7.23.4(@babel/core@7.24.0)
+      '@babel/plugin-transform-object-super': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-optional-catch-binding': 7.23.4(@babel/core@7.24.0)
+      '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.24.0)
+      '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.24.0)
+      '@babel/plugin-transform-property-literals': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-regenerator': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-reserved-words': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-typeof-symbol': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-unicode-escapes': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-unicode-property-regex': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-unicode-sets-regex': 7.23.3(@babel/core@7.24.0)
+      '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.0)
+      babel-plugin-polyfill-corejs2: 0.4.6(@babel/core@7.24.0)
+      babel-plugin-polyfill-corejs3: 0.8.6(@babel/core@7.24.0)
+      babel-plugin-polyfill-regenerator: 0.5.3(@babel/core@7.24.0)
       core-js-compat: 3.33.3
       semver: 6.3.1
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@babel/preset-flow@7.23.3(@babel/core@7.23.5):
+  /@babel/preset-flow@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-7yn6hl8RIv+KNk6iIrGZ+D06VhVY35wLVf23Cz/mMu1zOr7u4MMP4j0nZ9tLf8+4ZFpnib8cFYgB/oYg9hfswA==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/helper-validator-option': 7.23.5
-      '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.23.5)
+      '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.24.0)
     dev: true
 
-  /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.23.5):
+  /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.0):
     resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==}
     peerDependencies:
       '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/types': 7.23.5
+      '@babel/types': 7.24.0
       esutils: 2.0.3
     dev: true
 
-  /@babel/preset-typescript@7.23.3(@babel/core@7.23.5):
+  /@babel/preset-typescript@7.23.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/helper-validator-option': 7.23.5
-      '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-typescript': 7.23.5(@babel/core@7.23.5)
+      '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-typescript': 7.23.5(@babel/core@7.24.0)
     dev: true
 
-  /@babel/register@7.22.15(@babel/core@7.23.5):
+  /@babel/register@7.22.15(@babel/core@7.24.0):
     resolution: {integrity: sha512-V3Q3EqoQdn65RCgTLwauZaTfd1ShhwPmbBv+1dkZV/HpCGMKVyn6oFcRlI7RaKqiDQjX2Qd3AuoEguBgdjIKlg==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       clone-deep: 4.0.1
       find-cache-dir: 2.1.0
       make-dir: 2.1.0
@@ -4557,17 +4677,6 @@ packages:
       - supports-color
     dev: true
 
-  /@jest/types@27.5.1:
-    resolution: {integrity: sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==}
-    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
-    dependencies:
-      '@types/istanbul-lib-coverage': 2.0.4
-      '@types/istanbul-reports': 3.0.1
-      '@types/node': 20.11.22
-      '@types/yargs': 16.0.5
-      chalk: 4.1.2
-    dev: true
-
   /@jest/types@29.6.3:
     resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -5878,10 +5987,10 @@ packages:
     resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==}
     dev: false
 
-  /@storybook/addon-actions@8.0.0-beta.6:
-    resolution: {integrity: sha512-g+X2M6Awg21vkXzRP7hWBYCdbXnxJ3BJWsP7BblYmPo2J7eJDzhQascNyTmSr0pb1/7nv+tworGviXThgvlUgw==}
+  /@storybook/addon-actions@8.0.9:
+    resolution: {integrity: sha512-+I3VTvlKdj8puHeS2tyaOVv9syDiNLneVZbTfqN+UDOK2i42NwvZr8PVwjTzMlEj9eePJdCZgiipz55xwts5bw==}
     dependencies:
-      '@storybook/core-events': 8.0.0-beta.6
+      '@storybook/core-events': 8.0.9
       '@storybook/global': 5.0.0
       '@types/uuid': 9.0.8
       dequal: 2.0.3
@@ -5889,18 +5998,18 @@ packages:
       uuid: 9.0.1
     dev: true
 
-  /@storybook/addon-backgrounds@8.0.0-beta.6:
-    resolution: {integrity: sha512-C8MS635knAOSat5JbkpZXOiAqkDm1bKWvuVqiQfbX2into45/aAuyN3mYxveGIRTRjPJCv/UpostkLSNvfH/NQ==}
+  /@storybook/addon-backgrounds@8.0.9:
+    resolution: {integrity: sha512-pCDecACrVyxPaJKEWS0sHsRb8xw+IPCSxDM1TkjaAQ6zZ468A/dcUnqW+LVK8bSXgQwWzn23wqnqPFSy5yptuQ==}
     dependencies:
       '@storybook/global': 5.0.0
       memoizerific: 1.11.3
       ts-dedent: 2.2.0
     dev: true
 
-  /@storybook/addon-controls@8.0.0-beta.6(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-G96MH7yU/KShq3lTrkgtU1IbNQXLVc3BG7miaLqzQgWFN8SSAivlu3vk1Vffui3+3Dv52WZhMKi3hueNfnM1Xw==}
+  /@storybook/addon-controls@8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0):
+    resolution: {integrity: sha512-wWdmd62UP/sfPm8M7aJjEA+kEXTUIR/QsYi9PoYBhBZcXiikZ4kNan7oD7GfsnzGGKHrBVfwQhO+TqaENGYytA==}
     dependencies:
-      '@storybook/blocks': 8.0.0-beta.6(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/blocks': 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
       lodash: 4.17.21
       ts-dedent: 2.2.0
     transitivePeerDependencies:
@@ -5911,22 +6020,22 @@ packages:
       - supports-color
     dev: true
 
-  /@storybook/addon-docs@8.0.0-beta.6:
-    resolution: {integrity: sha512-VLys4EuL8XVhmu1QxUiUG5keID8v/FsC5L71Y0Wcf5D+ll6ZD8vCqEtbMY3TiJJ9NqqNIcmcG3bG6JVXOYcD8g==}
+  /@storybook/addon-docs@8.0.9:
+    resolution: {integrity: sha512-x7hX7UuzJtClu6XwU3SfpyFhuckVcgqgD6BU6Ihxl0zs+i4xp6iKVXYSnHFMRM1sgoeT8TjPxab35Ke8w8BVRw==}
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
       '@mdx-js/react': 3.0.1(@types/react@18.0.28)(react@18.2.0)
-      '@storybook/blocks': 8.0.0-beta.6(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/client-logger': 8.0.0-beta.6
-      '@storybook/components': 8.0.0-beta.6(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/csf-plugin': 8.0.0-beta.6
-      '@storybook/csf-tools': 8.0.0-beta.6
+      '@storybook/blocks': 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/client-logger': 8.0.9
+      '@storybook/components': 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/csf-plugin': 8.0.9
+      '@storybook/csf-tools': 8.0.9
       '@storybook/global': 5.0.0
-      '@storybook/node-logger': 8.0.0-beta.6
-      '@storybook/preview-api': 8.0.0-beta.6
-      '@storybook/react-dom-shim': 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/theming': 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/types': 8.0.0-beta.6
+      '@storybook/node-logger': 8.0.9
+      '@storybook/preview-api': 8.0.9
+      '@storybook/react-dom-shim': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/theming': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/types': 8.0.9
       '@types/react': 18.0.28
       fs-extra: 11.1.1
       react: 18.2.0
@@ -5939,22 +6048,22 @@ packages:
       - supports-color
     dev: true
 
-  /@storybook/addon-essentials@8.0.0-beta.6(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-6Vjf03c0oIavXqOK9DIN0UeH0iJFmBoVrFt1mTwydMxchyJBSP785MSd9DuFhLdYZPQTMHaR4/JhOIjdDV8mbA==}
+  /@storybook/addon-essentials@8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0):
+    resolution: {integrity: sha512-mwAgdfrOsTuTDcagvM7veBh+iayZIWmKOazzkhrIWbhYcrXOsweigD2UOVeHgAiAzJK49znr4FXTCKcE1hOWcw==}
     dependencies:
-      '@storybook/addon-actions': 8.0.0-beta.6
-      '@storybook/addon-backgrounds': 8.0.0-beta.6
-      '@storybook/addon-controls': 8.0.0-beta.6(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/addon-docs': 8.0.0-beta.6
-      '@storybook/addon-highlight': 8.0.0-beta.6
-      '@storybook/addon-measure': 8.0.0-beta.6
-      '@storybook/addon-outline': 8.0.0-beta.6
-      '@storybook/addon-toolbars': 8.0.0-beta.6
-      '@storybook/addon-viewport': 8.0.0-beta.6
-      '@storybook/core-common': 8.0.0-beta.6
-      '@storybook/manager-api': 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/node-logger': 8.0.0-beta.6
-      '@storybook/preview-api': 8.0.0-beta.6
+      '@storybook/addon-actions': 8.0.9
+      '@storybook/addon-backgrounds': 8.0.9
+      '@storybook/addon-controls': 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/addon-docs': 8.0.9
+      '@storybook/addon-highlight': 8.0.9
+      '@storybook/addon-measure': 8.0.9
+      '@storybook/addon-outline': 8.0.9
+      '@storybook/addon-toolbars': 8.0.9
+      '@storybook/addon-viewport': 8.0.9
+      '@storybook/core-common': 8.0.9
+      '@storybook/manager-api': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/node-logger': 8.0.9
+      '@storybook/preview-api': 8.0.9
       ts-dedent: 2.2.0
     transitivePeerDependencies:
       - '@types/react'
@@ -5964,80 +6073,87 @@ packages:
       - supports-color
     dev: true
 
-  /@storybook/addon-highlight@8.0.0-beta.6:
-    resolution: {integrity: sha512-U+qz4TNLrw24t1eZ2Zmhl2FZKZKiwHbibq4qR5ruAFe9W5/aMHqPuBB0POroaGu3P+tyDP2G46dckMNXVraiWA==}
+  /@storybook/addon-highlight@8.0.9:
+    resolution: {integrity: sha512-vaRHGDbx7dpNpQECAHk5wczlZO3ntstprGlqnZt0o7ylz6xB5+pTQwTuIFty0hwKv+3TPcskzzifATUyEOEmyg==}
     dependencies:
       '@storybook/global': 5.0.0
     dev: true
 
-  /@storybook/addon-interactions@8.0.0-beta.6:
-    resolution: {integrity: sha512-KSigq+7vCA1tnj31MjhM7xaqickR1guZdjyXVRx7gi7qbdhSuCQv52gAkVpDapwlEuvGFCCYxzt7tmcn6dkLZQ==}
+  /@storybook/addon-interactions@8.0.9(vitest@0.34.6):
+    resolution: {integrity: sha512-AMIdNcyM6DDAWvMitBJMqp1iPZND8AXB4QT4VZHGMKG2ngHNKktriEKpTfcRkfKPGTJs9T+71dWfm6/R4tticw==}
     dependencies:
       '@storybook/global': 5.0.0
-      '@storybook/types': 8.0.0-beta.6
-      jest-mock: 27.5.1
+      '@storybook/instrumenter': 8.0.9
+      '@storybook/test': 8.0.9(vitest@0.34.6)
+      '@storybook/types': 8.0.9
       polished: 4.2.2
       ts-dedent: 2.2.0
+    transitivePeerDependencies:
+      - '@jest/globals'
+      - '@types/bun'
+      - '@types/jest'
+      - jest
+      - vitest
     dev: true
 
-  /@storybook/addon-links@8.0.0-beta.6(react@18.2.0):
-    resolution: {integrity: sha512-+5knw5CHEb23n6Bm9Xp9nmoLRqWZ3QVGb1gNI3mGwmkpLwesohFR4fW7OrdRmzYHpS0PyYToZyfTCMYrmjBDvg==}
+  /@storybook/addon-links@8.0.9(react@18.2.0):
+    resolution: {integrity: sha512-FVt+AdW3JFSqbJzkKiqKsMRWqHXqEvCBqFs7lNfk3OW0w0jfv1iREtrxE0dVdJoUFQC9V/2Im/EpJ7UB3C2bNQ==}
     peerDependencies:
       react: ^16.8.0 || ^17.0.0 || ^18.0.0
     peerDependenciesMeta:
       react:
         optional: true
     dependencies:
-      '@storybook/csf': 0.1.2
+      '@storybook/csf': 0.1.6
       '@storybook/global': 5.0.0
       react: 18.2.0
       ts-dedent: 2.2.0
     dev: true
 
-  /@storybook/addon-mdx-gfm@8.0.0-beta.6:
-    resolution: {integrity: sha512-b4pb59rrX+C/oYFeEiHb8jJn0h9WZSkHVkLIgaj0G64Nd9OpyKZXMbGpDxwMq4LTi1w65Wddi1UUQbUVVDNHRw==}
+  /@storybook/addon-mdx-gfm@8.0.9:
+    resolution: {integrity: sha512-AoEx+OGKANtVZgKyWKrQhGpMpDuc2S7PnOlNLUiDYzmj8ABAGPmEJmqeb/VHVgqLQSjhOW1fMsQ4fYsecvMxTQ==}
     dependencies:
-      '@storybook/node-logger': 8.0.0-beta.6
+      '@storybook/node-logger': 8.0.9
       remark-gfm: 4.0.0
       ts-dedent: 2.2.0
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@storybook/addon-measure@8.0.0-beta.6:
-    resolution: {integrity: sha512-D+KzWRULcbwR8/ysD7Qbw4uWBn9gwNm9s3IeVuhupawUb3u+H4XfVCOW2rA5qry/x8aroKOhAmyKd9v4i+l3pg==}
+  /@storybook/addon-measure@8.0.9:
+    resolution: {integrity: sha512-91svOOGEXmGG4USglwXLE3wtlUVgtbKJVxTKX7xRI+AC5JEEaKByVzP17/X8Qn/8HilUL7AfSQ0kCoqtPSJ5cA==}
     dependencies:
       '@storybook/global': 5.0.0
       tiny-invariant: 1.3.1
     dev: true
 
-  /@storybook/addon-outline@8.0.0-beta.6:
-    resolution: {integrity: sha512-U+5TFTj+gtkIiIJCk6h7zbrP588CUipzVVsiDTSLl4pc+H3ylGTGncq3ZGtOyl+DCoBsQCgKxy2YWQtKHrESOw==}
+  /@storybook/addon-outline@8.0.9:
+    resolution: {integrity: sha512-fQ+jm356TgUnz81IxsC99/aOesbLw3N5OQRJpo/A6kqbLMzlq3ybVzuXYCKC3f0ArgQRNh4NoMeJBMRFMtaWRw==}
     dependencies:
       '@storybook/global': 5.0.0
       ts-dedent: 2.2.0
     dev: true
 
-  /@storybook/addon-storysource@8.0.0-beta.6:
-    resolution: {integrity: sha512-J9sCZ5/KQW2hbfKsom8LmgSWJxw+Kp/7LjIHGevFfov/i9DR8i9xbh5htUwC9fx+vWGR87tez03b+oUJbyHPog==}
+  /@storybook/addon-storysource@8.0.9:
+    resolution: {integrity: sha512-5m3K2Rs4fQtKtqwrq4CDS1jK2wzWOlnxhE2ArX5XTWytb1am65CEPxfYTEQkvZH9oPGwX3cXytPCziynqysFMQ==}
     dependencies:
-      '@storybook/source-loader': 8.0.0-beta.6
+      '@storybook/source-loader': 8.0.9
       estraverse: 5.3.0
       tiny-invariant: 1.3.1
     dev: true
 
-  /@storybook/addon-toolbars@8.0.0-beta.6:
-    resolution: {integrity: sha512-ClT5spwh6S1rUvyFEIFQndE3VK6tpwI2cyIW4E20LajtfUmj3dOfJQX/ZbnhEH3sDBsCm97ysZ/mNR0mbBHZrg==}
+  /@storybook/addon-toolbars@8.0.9:
+    resolution: {integrity: sha512-nNSBnnBOhQ+EJwkrIkK4ZBYPcozNmEH770CZ/6NK85SUJ6WEBZapE6ru33jIUokFGEvlOlNCeai0GUc++cQP8w==}
     dev: true
 
-  /@storybook/addon-viewport@8.0.0-beta.6:
-    resolution: {integrity: sha512-KNYGM6nVrz/Ej25W3lcpaxxJDYVXBYeGl60FWN/WlqRnjo4c4Fyufl6Xev2plQ3eI8jIvWEdGNC/Z/NQnDx1+Q==}
+  /@storybook/addon-viewport@8.0.9:
+    resolution: {integrity: sha512-Ao4+D56cO7biaw+iTlMU1FBec1idX0cmdosDeCFZin06MSawcPkeBlRBeruaSQYdLes8TBMdZPFgfuqI5yIk6g==}
     dependencies:
       memoizerific: 1.11.3
     dev: true
 
-  /@storybook/blocks@8.0.0-beta.6(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-QkrWT0BELNv3UGv/dtNuB/ROZn0f9VpERbadhXLE/oNXMJLalyjEbRGM635l0lDeoqjYnWHl+tuM6DTe1Xpk2w==}
+  /@storybook/blocks@8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0):
+    resolution: {integrity: sha512-F2zSrfSwzTFN7qW3zB80tG+EXtmfmCDC6Ird0F7tolszb6tOqJcAcBOwQbE2O0wI63sLu21qxzXgaKBMkiWvJg==}
     peerDependencies:
       react: ^16.8.0 || ^17.0.0 || ^18.0.0
       react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
@@ -6047,18 +6163,18 @@ packages:
       react-dom:
         optional: true
     dependencies:
-      '@storybook/channels': 8.0.0-beta.6
-      '@storybook/client-logger': 8.0.0-beta.6
-      '@storybook/components': 8.0.0-beta.6(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/core-events': 8.0.0-beta.6
-      '@storybook/csf': 0.1.2
-      '@storybook/docs-tools': 8.0.0-beta.6
+      '@storybook/channels': 8.0.9
+      '@storybook/client-logger': 8.0.9
+      '@storybook/components': 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/core-events': 8.0.9
+      '@storybook/csf': 0.1.6
+      '@storybook/docs-tools': 8.0.9
       '@storybook/global': 5.0.0
       '@storybook/icons': 1.2.5(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/manager-api': 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/preview-api': 8.0.0-beta.6
-      '@storybook/theming': 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/types': 8.0.0-beta.6
+      '@storybook/manager-api': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/preview-api': 8.0.9
+      '@storybook/theming': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/types': 8.0.9
       '@types/lodash': 4.14.191
       color-convert: 2.0.1
       dequal: 2.0.3
@@ -6079,18 +6195,18 @@ packages:
       - supports-color
     dev: true
 
-  /@storybook/builder-manager@8.0.0-beta.6:
-    resolution: {integrity: sha512-bB/gSsPIpU22Tc6YTjPZdw1RM6nrsuJJ9aYXGqEJTqA4l4lBUN7fwIZQ1x/pS+5LbeUO0J9lAhGXurS+m8rI2A==}
+  /@storybook/builder-manager@8.0.9:
+    resolution: {integrity: sha512-/PxDwZIfMc/PSRZcasb6SIdGr3azIlenzx7dBF7Imt8i4jLHiAf1t00GvghlfJsvsrn4DNp95rbRbXTDyTj7tQ==}
     dependencies:
       '@fal-works/esbuild-plugin-global-externals': 2.1.2
-      '@storybook/core-common': 8.0.0-beta.6
-      '@storybook/manager': 8.0.0-beta.6
-      '@storybook/node-logger': 8.0.0-beta.6
+      '@storybook/core-common': 8.0.9
+      '@storybook/manager': 8.0.9
+      '@storybook/node-logger': 8.0.9
       '@types/ejs': 3.1.2
-      '@yarnpkg/esbuild-plugin-pnp': 3.0.0-rc.15(esbuild@0.18.20)
+      '@yarnpkg/esbuild-plugin-pnp': 3.0.0-rc.15(esbuild@0.19.11)
       browser-assert: 1.2.1
       ejs: 3.1.9
-      esbuild: 0.18.20
+      esbuild: 0.19.11
       esbuild-plugin-alias: 0.2.1
       express: 4.18.2
       fs-extra: 11.1.1
@@ -6101,8 +6217,8 @@ packages:
       - supports-color
     dev: true
 
-  /@storybook/builder-vite@8.0.0-beta.6(typescript@5.3.3)(vite@5.1.4):
-    resolution: {integrity: sha512-3P5uTZqwwcUW64Hep/VtJXpQYi5vTkmqAjwZvr8gmzr37NYq3YT/PiSGn4CaZswSx5Z/lSYq3In8oIwmj/a1/g==}
+  /@storybook/builder-vite@8.0.9(typescript@5.3.3)(vite@5.1.4):
+    resolution: {integrity: sha512-7hEQFZIIz7VvxdySDpPE96iMvZxQvRZcRdhaNGeE+8Y2pyc3DgYE4WY3sjr+LUoB0a6TYLpAIKqbXwtLz0R+PQ==}
     peerDependencies:
       '@preact/preset-vite': '*'
       typescript: '>= 4.3.x'
@@ -6116,15 +6232,15 @@ packages:
       vite-plugin-glimmerx:
         optional: true
     dependencies:
-      '@storybook/channels': 8.0.0-beta.6
-      '@storybook/client-logger': 8.0.0-beta.6
-      '@storybook/core-common': 8.0.0-beta.6
-      '@storybook/core-events': 8.0.0-beta.6
-      '@storybook/csf-plugin': 8.0.0-beta.6
-      '@storybook/node-logger': 8.0.0-beta.6
-      '@storybook/preview': 8.0.0-beta.6
-      '@storybook/preview-api': 8.0.0-beta.6
-      '@storybook/types': 8.0.0-beta.6
+      '@storybook/channels': 8.0.9
+      '@storybook/client-logger': 8.0.9
+      '@storybook/core-common': 8.0.9
+      '@storybook/core-events': 8.0.9
+      '@storybook/csf-plugin': 8.0.9
+      '@storybook/node-logger': 8.0.9
+      '@storybook/preview': 8.0.9
+      '@storybook/preview-api': 8.0.9
+      '@storybook/types': 8.0.9
       '@types/find-cache-dir': 3.2.1
       browser-assert: 1.2.1
       es-module-lexer: 0.9.3
@@ -6140,32 +6256,31 @@ packages:
       - supports-color
     dev: true
 
-  /@storybook/channels@8.0.0-beta.6:
-    resolution: {integrity: sha512-DjwJhty45gQifo+TvGqddLX+NX1iGTmZyGLxlqPMpdp+x/yq8WwVZ316Q7tLt6z6fyAmsroc3ma5p1iLhqpV7g==}
+  /@storybook/channels@8.0.9:
+    resolution: {integrity: sha512-7Lcfyy5CsLWWGhMPO9WG4jZ/Alzp0AjepFhEreYHRPtQrfttp6qMAjE/g1aHgun0qHCYWxwqIG4NLR/hqDNrXQ==}
     dependencies:
-      '@storybook/client-logger': 8.0.0-beta.6
-      '@storybook/core-events': 8.0.0-beta.6
+      '@storybook/client-logger': 8.0.9
+      '@storybook/core-events': 8.0.9
       '@storybook/global': 5.0.0
-      qs: 6.11.1
       telejson: 7.2.0
       tiny-invariant: 1.3.1
     dev: true
 
-  /@storybook/cli@8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-sREQYnPds2bwQS7FLbRy7oaxGvOmYhPEYVf93pWKyo/qwSWyXEXbqGCGT6bNhSl/xzqXX7VryLDmuOoHmVTh1g==}
+  /@storybook/cli@8.0.9(react-dom@18.2.0)(react@18.2.0):
+    resolution: {integrity: sha512-lilYTKn8F5YOePijqfRYFa5v2mHVIJxPCIgTn+OXAmAFbcizZ6P8P6niU4J/NXulgx68Ln1M7hYhFtTP25hVTw==}
     hasBin: true
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/types': 7.23.5
+      '@babel/core': 7.24.0
+      '@babel/types': 7.24.0
       '@ndelangen/get-tarball': 3.0.7
-      '@storybook/codemod': 8.0.0-beta.6
-      '@storybook/core-common': 8.0.0-beta.6
-      '@storybook/core-events': 8.0.0-beta.6
-      '@storybook/core-server': 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/csf-tools': 8.0.0-beta.6
-      '@storybook/node-logger': 8.0.0-beta.6
-      '@storybook/telemetry': 8.0.0-beta.6
-      '@storybook/types': 8.0.0-beta.6
+      '@storybook/codemod': 8.0.9
+      '@storybook/core-common': 8.0.9
+      '@storybook/core-events': 8.0.9
+      '@storybook/core-server': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/csf-tools': 8.0.9
+      '@storybook/node-logger': 8.0.9
+      '@storybook/telemetry': 8.0.9
+      '@storybook/types': 8.0.9
       '@types/semver': 7.5.8
       '@yarnpkg/fslib': 2.10.3
       '@yarnpkg/libzip': 2.3.0
@@ -6186,7 +6301,7 @@ packages:
       prettier: 3.2.5
       prompts: 2.4.2
       read-pkg-up: 7.0.1
-      semver: 7.5.4
+      semver: 7.6.0
       strip-json-comments: 3.1.1
       tempy: 1.0.1
       tiny-invariant: 1.3.1
@@ -6201,47 +6316,47 @@ packages:
       - utf-8-validate
     dev: true
 
-  /@storybook/client-logger@8.0.0-beta.6:
-    resolution: {integrity: sha512-XX9CSWt9NDO/1K8tTYV+yuj0ur4HznM1Vc5mY5AwT5xh0RP5HtWZ+VoJfrWYXlBoRXaj0gf8si+FO+lSW82DcQ==}
+  /@storybook/client-logger@8.0.9:
+    resolution: {integrity: sha512-LzV/RHkbf07sRc1Jc0ff36RlapKf9Ul7/+9VMvVbI3hshH1CpmrZK4t/tsIdpX/EVOdJ1Gg5cES06PnleOAIPA==}
     dependencies:
       '@storybook/global': 5.0.0
     dev: true
 
-  /@storybook/codemod@8.0.0-beta.6:
-    resolution: {integrity: sha512-ttQYDkhKmtU6Qbg+Kgn4K2XXf8XMpa2euuC6PmYffBD7/qLiGfABfBc4FHKRv4yScnvKK7Ehy7K0lvipfg6tXw==}
+  /@storybook/codemod@8.0.9:
+    resolution: {integrity: sha512-VBeGpSZSQpL6iyLLqceJSNGhdCqcNwv+xC/aWdDFOkmuE1YfbmNNwpa9QYv4ZFJ2QjUsm4iTWG60qK+9NXeSKA==}
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/preset-env': 7.23.5(@babel/core@7.23.5)
-      '@babel/types': 7.23.5
-      '@storybook/csf': 0.1.2
-      '@storybook/csf-tools': 8.0.0-beta.6
-      '@storybook/node-logger': 8.0.0-beta.6
-      '@storybook/types': 8.0.0-beta.6
+      '@babel/core': 7.24.0
+      '@babel/preset-env': 7.23.5(@babel/core@7.24.0)
+      '@babel/types': 7.24.0
+      '@storybook/csf': 0.1.6
+      '@storybook/csf-tools': 8.0.9
+      '@storybook/node-logger': 8.0.9
+      '@storybook/types': 8.0.9
       '@types/cross-spawn': 6.0.2
       cross-spawn: 7.0.3
       globby: 11.1.0
       jscodeshift: 0.15.1(@babel/preset-env@7.23.5)
       lodash: 4.17.21
       prettier: 3.2.5
-      recast: 0.23.4
+      recast: 0.23.6
       tiny-invariant: 1.3.1
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@storybook/components@8.0.0-beta.6(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-J3aJtPgaSco0sefvRMBLFsWbslhKMhaS3U+5baRqlV5bjPLZN+d4P18gP1RMaw/coh6DiKEQJZuHRoPIOdt4CA==}
+  /@storybook/components@8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0):
+    resolution: {integrity: sha512-JcwBGADzIJs0PSzqykrrD2KHzNG9wtexUOKuidt+FSv9szpUhe3qBAXIHpdfBRl7mOJ9TRZ5rt+mukEnfncdzA==}
     peerDependencies:
       react: ^16.8.0 || ^17.0.0 || ^18.0.0
       react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
     dependencies:
       '@radix-ui/react-slot': 1.0.2(@types/react@18.0.28)(react@18.2.0)
-      '@storybook/client-logger': 8.0.0-beta.6
-      '@storybook/csf': 0.1.2
+      '@storybook/client-logger': 8.0.9
+      '@storybook/csf': 0.1.6
       '@storybook/global': 5.0.0
       '@storybook/icons': 1.2.5(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/theming': 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/types': 8.0.0-beta.6
+      '@storybook/theming': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/types': 8.0.9
       memoizerific: 1.11.3
       react: 18.2.0
       react-dom: 18.2.0(react@18.2.0)
@@ -6250,19 +6365,19 @@ packages:
       - '@types/react'
     dev: true
 
-  /@storybook/core-common@8.0.0-beta.6:
-    resolution: {integrity: sha512-Mah4Kx/VBNhHaX6neYHTiVwfD93yf3LVVfLTS9WcJFOpek74EAAqbARV3vzOn/utOI75N7yu2PCVoKi5KkDoVw==}
+  /@storybook/core-common@8.0.9:
+    resolution: {integrity: sha512-Jmue+sfHFb4GTYBzyWYw1MygoJiQSfISIrKmNIzAmZ+oR9EOr+jpu/i/bH+uetZ2Hqg1AGhj1VB7OtJp9HQyWw==}
     dependencies:
-      '@storybook/core-events': 8.0.0-beta.6
-      '@storybook/csf-tools': 8.0.0-beta.6
-      '@storybook/node-logger': 8.0.0-beta.6
-      '@storybook/types': 8.0.0-beta.6
+      '@storybook/core-events': 8.0.9
+      '@storybook/csf-tools': 8.0.9
+      '@storybook/node-logger': 8.0.9
+      '@storybook/types': 8.0.9
       '@yarnpkg/fslib': 2.10.3
       '@yarnpkg/libzip': 2.3.0
       chalk: 4.1.2
       cross-spawn: 7.0.3
-      esbuild: 0.18.20
-      esbuild-register: 3.5.0(esbuild@0.18.20)
+      esbuild: 0.19.11
+      esbuild-register: 3.5.0(esbuild@0.19.11)
       execa: 5.1.1
       file-system-cache: 2.3.0
       find-cache-dir: 3.3.2
@@ -6276,7 +6391,7 @@ packages:
       pkg-dir: 5.0.0
       pretty-hrtime: 1.0.3
       resolve-from: 5.0.0
-      semver: 7.5.4
+      semver: 7.6.0
       tempy: 1.0.1
       tiny-invariant: 1.3.1
       ts-dedent: 2.2.0
@@ -6286,32 +6401,32 @@ packages:
       - supports-color
     dev: true
 
-  /@storybook/core-events@8.0.0-beta.6:
-    resolution: {integrity: sha512-ZyEVkOJ5gGGTfHjyasyeZgNGoeVJwVkLFRpV6cUl8hzOT29R5iDsf5PbJdrpF1x2pm1oLumeRckYQ7sYhr+R/w==}
+  /@storybook/core-events@8.0.9:
+    resolution: {integrity: sha512-DxSUx7wG9Qe3OFUBnv3OrYq48J8UWNo2DUR5/JecJCtp3n++L4fAEW3J0IF5FfxpQDMQSp1yTNjZ2PaWCMd2ag==}
     dependencies:
       ts-dedent: 2.2.0
     dev: true
 
-  /@storybook/core-server@8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-0ciJTWZs+mCnQOUzB3WuSfkhwXKpO033M5iYK92PKu9A6KSrwdc/WCwIJHeBNnIpmxC0GEh9j6/CgIsWehwJvg==}
+  /@storybook/core-server@8.0.9(react-dom@18.2.0)(react@18.2.0):
+    resolution: {integrity: sha512-BIe1T5YUBl0GYxEjRoTQsvXD2pyuzL8rPTUD41zlzSQM0R8U6Iant9SzRms4u0+rKUm2mGxxKuODlUo5ewqaGA==}
     dependencies:
       '@aw-web-design/x-default-browser': 1.4.126
       '@babel/core': 7.24.0
       '@discoveryjs/json-ext': 0.5.7
-      '@storybook/builder-manager': 8.0.0-beta.6
-      '@storybook/channels': 8.0.0-beta.6
-      '@storybook/core-common': 8.0.0-beta.6
-      '@storybook/core-events': 8.0.0-beta.6
-      '@storybook/csf': 0.1.2
-      '@storybook/csf-tools': 8.0.0-beta.6
+      '@storybook/builder-manager': 8.0.9
+      '@storybook/channels': 8.0.9
+      '@storybook/core-common': 8.0.9
+      '@storybook/core-events': 8.0.9
+      '@storybook/csf': 0.1.6
+      '@storybook/csf-tools': 8.0.9
       '@storybook/docs-mdx': 3.0.0
       '@storybook/global': 5.0.0
-      '@storybook/manager': 8.0.0-beta.6
-      '@storybook/manager-api': 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/node-logger': 8.0.0-beta.6
-      '@storybook/preview-api': 8.0.0-beta.6
-      '@storybook/telemetry': 8.0.0-beta.6
-      '@storybook/types': 8.0.0-beta.6
+      '@storybook/manager': 8.0.9
+      '@storybook/manager-api': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/node-logger': 8.0.9
+      '@storybook/preview-api': 8.0.9
+      '@storybook/telemetry': 8.0.9
+      '@storybook/types': 8.0.9
       '@types/detect-port': 1.3.2
       '@types/node': 18.17.15
       '@types/pretty-hrtime': 1.0.1
@@ -6330,7 +6445,7 @@ packages:
       pretty-hrtime: 1.0.3
       prompts: 2.4.2
       read-pkg-up: 7.0.1
-      semver: 7.5.4
+      semver: 7.6.0
       telejson: 7.2.0
       tiny-invariant: 1.3.1
       ts-dedent: 2.2.0
@@ -6347,33 +6462,33 @@ packages:
       - utf-8-validate
     dev: true
 
-  /@storybook/csf-plugin@8.0.0-beta.6:
-    resolution: {integrity: sha512-cYI/4OndODf0utV0DxJs8AOKbmjCG+pEgxQGcmPtGnkSmEuieUwpQpN7v+fEIN7IPUQLYvs0wspR0njZQAIzyA==}
+  /@storybook/csf-plugin@8.0.9:
+    resolution: {integrity: sha512-pXaNCNi++kxKsqSWwvx215fPx8cNqvepLVxQ7B69qXLHj80DHn0Q3DFBO3sLXNiQMJ2JK4OYcTxMfuOiyzszKw==}
     dependencies:
-      '@storybook/csf-tools': 8.0.0-beta.6
+      '@storybook/csf-tools': 8.0.9
       unplugin: 1.4.0
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@storybook/csf-tools@8.0.0-beta.6:
-    resolution: {integrity: sha512-wwzbE6f8ykrvIeZlXYTba0IA8D5GPSyZ4L0+PqRAYHm3ozu0DXqtm4USDHKrjYAzuD+W+fG/6qIOQmsWYbNmpA==}
+  /@storybook/csf-tools@8.0.9:
+    resolution: {integrity: sha512-PiNMhL97giLytTdQwuhsZ92buVk4gy9H/8DtrDhUc45/1OmF95gogm6T2Yap729SIFwgpOcuq/U3aVo6d6swVQ==}
     dependencies:
-      '@babel/generator': 7.23.5
-      '@babel/parser': 7.23.9
-      '@babel/traverse': 7.23.5
-      '@babel/types': 7.23.5
-      '@storybook/csf': 0.1.2
-      '@storybook/types': 8.0.0-beta.6
+      '@babel/generator': 7.23.6
+      '@babel/parser': 7.24.0
+      '@babel/traverse': 7.24.0
+      '@babel/types': 7.24.0
+      '@storybook/csf': 0.1.6
+      '@storybook/types': 8.0.9
       fs-extra: 11.1.1
-      recast: 0.23.4
+      recast: 0.23.6
       ts-dedent: 2.2.0
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@storybook/csf@0.1.2:
-    resolution: {integrity: sha512-ePrvE/pS1vsKR9Xr+o+YwdqNgHUyXvg+1Xjx0h9LrVx7Zq4zNe06pd63F5EvzTbCbJsHj7GHr9tkiaqm7U8WRA==}
+  /@storybook/csf@0.1.6:
+    resolution: {integrity: sha512-JjWnBptVhBYJ14yq+cHs66BXjykRUWQ5TlD1RhPxMOtavynYyV/Q+QR98/N+XB+mcPtFMm5I2DvNkpj0/Dk8Mw==}
     dependencies:
       type-fest: 2.19.0
     dev: true
@@ -6382,12 +6497,13 @@ packages:
     resolution: {integrity: sha512-NmiGXl2HU33zpwTv1XORe9XG9H+dRUC1Jl11u92L4xr062pZtrShLmD4VKIsOQujxhhOrbxpwhNOt+6TdhyIdQ==}
     dev: true
 
-  /@storybook/docs-tools@8.0.0-beta.6:
-    resolution: {integrity: sha512-fSKXEu0vegzqC2HT1RaOKqi0+W/vIn+qa5D+dZHkj2BnceYxWAGYsX9ZZPHW6DUvvwp0WZp1vz57nPUhsLvcQg==}
+  /@storybook/docs-tools@8.0.9:
+    resolution: {integrity: sha512-OzogAeOmeHea/MxSPKRBWtOQVNSpoq+OOpimO9YRA5h5GBRJ2TUOGT44Gny6QT4ll5AvQA8fIiq9KezKcLekAg==}
     dependencies:
-      '@storybook/core-common': 8.0.0-beta.6
-      '@storybook/preview-api': 8.0.0-beta.6
-      '@storybook/types': 8.0.0-beta.6
+      '@storybook/core-common': 8.0.9
+      '@storybook/core-events': 8.0.9
+      '@storybook/preview-api': 8.0.9
+      '@storybook/types': 8.0.9
       '@types/doctrine': 0.0.3
       assert: 2.1.0
       doctrine: 3.0.0
@@ -6412,29 +6528,30 @@ packages:
       react-dom: 18.2.0(react@18.2.0)
     dev: true
 
-  /@storybook/instrumenter@8.0.0-beta.6:
-    resolution: {integrity: sha512-xJ3qkvj8dce7nJEa6hmp4PDDZJMBuP5UlSKPidiMAfEsB0MeUbDulTFNDb0t1DwcH9ywinDl8TilSzG4+r1kDA==}
+  /@storybook/instrumenter@8.0.9:
+    resolution: {integrity: sha512-Gw74dgpTU/2p7FG0s7DuVdqCbJ2MEcSuRJjDo7HcXRYcvWp7I6Ly+C0v7N5VaoS+kbBVerAhLKIHZgG/LZf1og==}
     dependencies:
-      '@storybook/channels': 8.0.0-beta.6
-      '@storybook/client-logger': 8.0.0-beta.6
-      '@storybook/core-events': 8.0.0-beta.6
+      '@storybook/channels': 8.0.9
+      '@storybook/client-logger': 8.0.9
+      '@storybook/core-events': 8.0.9
       '@storybook/global': 5.0.0
-      '@storybook/preview-api': 8.0.0-beta.6
-      '@vitest/utils': 0.34.6
+      '@storybook/preview-api': 8.0.9
+      '@vitest/utils': 1.5.3
       util: 0.12.5
     dev: true
 
-  /@storybook/manager-api@8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-kOGOT/yGFgKzld9IL1HREouFwZ0LpFuXZZOHBih5ydK8XT+bkWF6e3SiqthB3qtqpd0eVLAbNiPfY9R8t3qfWg==}
+  /@storybook/manager-api@8.0.9(react-dom@18.2.0)(react@18.2.0):
+    resolution: {integrity: sha512-99b3yKArDSvfabXL7QE3nA95e4DdW/5H/ZCcr6/E2qCQJayZ6G1v/WWamKXbiaTpkndulFmcb/+ZmnDXcweIIQ==}
     dependencies:
-      '@storybook/channels': 8.0.0-beta.6
-      '@storybook/client-logger': 8.0.0-beta.6
-      '@storybook/core-events': 8.0.0-beta.6
-      '@storybook/csf': 0.1.2
+      '@storybook/channels': 8.0.9
+      '@storybook/client-logger': 8.0.9
+      '@storybook/core-events': 8.0.9
+      '@storybook/csf': 0.1.6
       '@storybook/global': 5.0.0
-      '@storybook/router': 8.0.0-beta.6
-      '@storybook/theming': 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/types': 8.0.0-beta.6
+      '@storybook/icons': 1.2.5(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/router': 8.0.9
+      '@storybook/theming': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/types': 8.0.9
       dequal: 2.0.3
       lodash: 4.17.21
       memoizerific: 1.11.3
@@ -6446,23 +6563,23 @@ packages:
       - react-dom
     dev: true
 
-  /@storybook/manager@8.0.0-beta.6:
-    resolution: {integrity: sha512-FeQ2/CIasSOgcTMEE3QYMFa92KeMnfEMyUVO4hHEmPh3SqPsz6OOv8p0bQvN0SWWBgZarbhFR0dKC3W10yYrXg==}
+  /@storybook/manager@8.0.9:
+    resolution: {integrity: sha512-+NnRo+5JQFGNqveKrLtC0b+Z08Tae4m44iq292bPeZMpr9OkFsIkU0PBPsHTHPkrqC/zZXRNsCsTEgvu3p2OIA==}
     dev: true
 
-  /@storybook/node-logger@8.0.0-beta.6:
-    resolution: {integrity: sha512-nmBlmZ8wzJiU1/ubhUmFeWQaJPBv6l6s0Cndk04omPSjROa+O1whoPhDTVGvWC28zm17tmAYVcQRujkdoi+YBA==}
+  /@storybook/node-logger@8.0.9:
+    resolution: {integrity: sha512-5ajMdZFrYrjGLJOVDq7dlEQNFsgeLHymt4dCK9MulL/ciXykmXUZXE3Bye0wFy+I2qqDVvrvR8uzCvSFvm5MAQ==}
     dev: true
 
-  /@storybook/preview-api@8.0.0-beta.6:
-    resolution: {integrity: sha512-V07MF1ArjBGi2EPSjrEW8pjCoW/TIwxNDilcO9cD12LHrDQGXuo/iKyR47TGUYmcJ/u1I2Eu9cjyVj9DVyppag==}
+  /@storybook/preview-api@8.0.9:
+    resolution: {integrity: sha512-zHfX34bkAMzzmE7vbDzaqFwSW6ExiBD0HiO1L/IsHF55f0f7xV7IH8uJyFRrDTvAoW3ReSxZDMvvPpeydFPKGA==}
     dependencies:
-      '@storybook/channels': 8.0.0-beta.6
-      '@storybook/client-logger': 8.0.0-beta.6
-      '@storybook/core-events': 8.0.0-beta.6
-      '@storybook/csf': 0.1.2
+      '@storybook/channels': 8.0.9
+      '@storybook/client-logger': 8.0.9
+      '@storybook/core-events': 8.0.9
+      '@storybook/csf': 0.1.6
       '@storybook/global': 5.0.0
-      '@storybook/types': 8.0.0-beta.6
+      '@storybook/types': 8.0.9
       '@types/qs': 6.9.7
       dequal: 2.0.3
       lodash: 4.17.21
@@ -6473,12 +6590,12 @@ packages:
       util-deprecate: 1.0.2
     dev: true
 
-  /@storybook/preview@8.0.0-beta.6:
-    resolution: {integrity: sha512-tp3Wyvjsbf5r5RhbCQSafArQWJAir1bmIJWGG2S4o2E3YT6TlHFpR078tNJtgXqsPyG0yhF9vhRRkDczrPX/Gw==}
+  /@storybook/preview@8.0.9:
+    resolution: {integrity: sha512-tFsR8xc8AYBZZrZw8enklFbSQt7ZAV+rv20BoxwDhd3q7fjXyK7O4moGPqUwBZ7rukTG13nPoISxr+VXAk/HYA==}
     dev: true
 
-  /@storybook/react-dom-shim@8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-l14oDKAW2jyrXynHKP6SoNGal78gXcWCgj0zLwSDWpKgAFWC7SuIneuxLv6weU1D4+f9Y9FBrz+K3CCaMgMtOA==}
+  /@storybook/react-dom-shim@8.0.9(react-dom@18.2.0)(react@18.2.0):
+    resolution: {integrity: sha512-8011KlRuG3obr5pZZ7bcEyYYNWF3tR596YadoMd267NPoHKvwAbKL1L/DNgb6kiYjZDUf9QfaKSCWW31k0kcRQ==}
     peerDependencies:
       react: ^16.8.0 || ^17.0.0 || ^18.0.0
       react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
@@ -6487,8 +6604,8 @@ packages:
       react-dom: 18.2.0(react@18.2.0)
     dev: true
 
-  /@storybook/react-vite@8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)(rollup@4.12.0)(typescript@5.3.3)(vite@5.1.4):
-    resolution: {integrity: sha512-Tvz25pTXmhncDxprjIYsnXc68Lfa9idDybpRTRRbtvjsJyVpZogUdgz2/kddGNTuX3mqz6vmTMWiLiIVh+ytQA==}
+  /@storybook/react-vite@8.0.9(react-dom@18.2.0)(react@18.2.0)(rollup@4.12.0)(typescript@5.3.3)(vite@5.1.4):
+    resolution: {integrity: sha512-FT5KeulUH6grfzOJOxJCxpv9+81UVDrT9UPcgiFhQT9rKtsgmltezThwbHknByZNw3WWnf+ieidMLEis9hd73A==}
     engines: {node: '>=18.0.0'}
     peerDependencies:
       react: ^16.8.0 || ^17.0.0 || ^18.0.0
@@ -6497,12 +6614,16 @@ packages:
     dependencies:
       '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.3.3)(vite@5.1.4)
       '@rollup/pluginutils': 5.1.0(rollup@4.12.0)
-      '@storybook/builder-vite': 8.0.0-beta.6(typescript@5.3.3)(vite@5.1.4)
-      '@storybook/react': 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)
+      '@storybook/builder-vite': 8.0.9(typescript@5.3.3)(vite@5.1.4)
+      '@storybook/node-logger': 8.0.9
+      '@storybook/react': 8.0.9(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)
+      find-up: 5.0.0
       magic-string: 0.30.7
       react: 18.2.0
       react-docgen: 7.0.1
       react-dom: 18.2.0(react@18.2.0)
+      resolve: 1.22.8
+      tsconfig-paths: 4.2.0
       vite: 5.1.4(@types/node@20.11.22)(sass@1.71.1)(terser@5.28.1)
     transitivePeerDependencies:
       - '@preact/preset-vite'
@@ -6513,8 +6634,8 @@ packages:
       - vite-plugin-glimmerx
     dev: true
 
-  /@storybook/react@8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3):
-    resolution: {integrity: sha512-69B0c08HDYHEgZRRnkB+3z4dY/HO/GMSiRzRCNpzI0SBQzk1YwDzG9MOtkNgGqzdLK3e3DveSXb5Uyy1cB0ZiQ==}
+  /@storybook/react@8.0.9(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3):
+    resolution: {integrity: sha512-NeQ6suZG3HKikwe3Tx9cAIaRx7uP8FKCmlVvIiBg4LTTI5orCt94PPakvuZukZcbkqvcCnEBkebAzwUpn8PiJw==}
     engines: {node: '>=18.0.0'}
     peerDependencies:
       react: ^16.8.0 || ^17.0.0 || ^18.0.0
@@ -6524,12 +6645,12 @@ packages:
       typescript:
         optional: true
     dependencies:
-      '@storybook/client-logger': 8.0.0-beta.6
-      '@storybook/docs-tools': 8.0.0-beta.6
+      '@storybook/client-logger': 8.0.9
+      '@storybook/docs-tools': 8.0.9
       '@storybook/global': 5.0.0
-      '@storybook/preview-api': 8.0.0-beta.6
-      '@storybook/react-dom-shim': 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/types': 8.0.0-beta.6
+      '@storybook/preview-api': 8.0.9
+      '@storybook/react-dom-shim': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/types': 8.0.9
       '@types/escodegen': 0.0.6
       '@types/estree': 0.0.51
       '@types/node': 18.17.15
@@ -6543,7 +6664,7 @@ packages:
       react: 18.2.0
       react-dom: 18.2.0(react@18.2.0)
       react-element-to-jsx-string: 15.0.0(react-dom@18.2.0)(react@18.2.0)
-      semver: 7.5.4
+      semver: 7.6.0
       ts-dedent: 2.2.0
       type-fest: 2.19.0
       typescript: 5.3.3
@@ -6553,30 +6674,30 @@ packages:
       - supports-color
     dev: true
 
-  /@storybook/router@8.0.0-beta.6:
-    resolution: {integrity: sha512-JjLyDaVzCH3kmNsOkuJ8/U2bPIoReZZ/QsgHJdfvm22T2wKNjQ+lfNrQptBgNybfi1o/Tmn9VbCdRqurSlh9Dw==}
+  /@storybook/router@8.0.9:
+    resolution: {integrity: sha512-aAOWxbM9J4mt+cp4o88T2PB29mgBBTOzU37/pUsTHYnKnR9XI4npXEXdN8Gv+ryqM0kj0AbBpz/llFlnR2MNNA==}
     dependencies:
-      '@storybook/client-logger': 8.0.0-beta.6
+      '@storybook/client-logger': 8.0.9
       memoizerific: 1.11.3
       qs: 6.11.1
     dev: true
 
-  /@storybook/source-loader@8.0.0-beta.6:
-    resolution: {integrity: sha512-cYtjnuJZgm8MS9SsNsbuhuFz2d7j6BKRLZByBUqELrK+ftup0qqOWM+78w26qn3nPgA8myZXWxGa+V/Pjxio5w==}
+  /@storybook/source-loader@8.0.9:
+    resolution: {integrity: sha512-FDnpxIGE5nIYT15pvYe6rz95TSBrdLcDll7lOHNyZisWt19MI3wZU3YkVsFNRBuFrebo+FjVU3wHyoV81ur1Qw==}
     dependencies:
-      '@storybook/csf': 0.1.2
-      '@storybook/types': 8.0.0-beta.6
+      '@storybook/csf': 0.1.6
+      '@storybook/types': 8.0.9
       estraverse: 5.3.0
       lodash: 4.17.21
       prettier: 3.2.5
     dev: true
 
-  /@storybook/telemetry@8.0.0-beta.6:
-    resolution: {integrity: sha512-3CU5Sdj8eVm0tb35GriMkDrxJyTpdGcfU/hgUnsuw+I4eHYdZsc4Boh9uXWTVNsaBaoqbD/MP1aqbfxkElqPxQ==}
+  /@storybook/telemetry@8.0.9:
+    resolution: {integrity: sha512-AGGfcup06t+wxhBIkHd0iybieOh9PDVZQJ9oPct5JGB39+ni9wvs0WOD+MYlHbsjp8id7+aGkh6mYuYOvfck+Q==}
     dependencies:
-      '@storybook/client-logger': 8.0.0-beta.6
-      '@storybook/core-common': 8.0.0-beta.6
-      '@storybook/csf-tools': 8.0.0-beta.6
+      '@storybook/client-logger': 8.0.9
+      '@storybook/core-common': 8.0.9
+      '@storybook/csf-tools': 8.0.9
       chalk: 4.1.2
       detect-package-manager: 2.0.1
       fetch-retry: 5.0.4
@@ -6587,19 +6708,18 @@ packages:
       - supports-color
     dev: true
 
-  /@storybook/test@8.0.0-beta.6(vitest@0.34.6):
-    resolution: {integrity: sha512-GcV76EX3U77G+k8+0V+jAa/sJQZEuNb/4W+g/RaqGLRCEG73UADzkgRuFm60UQUBGtltvvRZU9sIPVbFTJFxuA==}
+  /@storybook/test@8.0.9(vitest@0.34.6):
+    resolution: {integrity: sha512-bRd5tBJnPzR6UKbDXONWnFWtdkNOY99HMLDUWe5fTRo50GwkrpFBVqPflhdkruEeof0kAbBUbnoN2CIYgtnAFw==}
     dependencies:
-      '@storybook/client-logger': 8.0.0-beta.6
-      '@storybook/core-events': 8.0.0-beta.6
-      '@storybook/instrumenter': 8.0.0-beta.6
-      '@storybook/preview-api': 8.0.0-beta.6
-      '@testing-library/dom': 9.3.3
+      '@storybook/client-logger': 8.0.9
+      '@storybook/core-events': 8.0.9
+      '@storybook/instrumenter': 8.0.9
+      '@storybook/preview-api': 8.0.9
+      '@testing-library/dom': 9.3.4
       '@testing-library/jest-dom': 6.4.2(vitest@0.34.6)
-      '@testing-library/user-event': 14.5.2(@testing-library/dom@9.3.3)
-      '@vitest/expect': 1.1.3
-      '@vitest/spy': 1.2.2
-      chai: 4.3.10
+      '@testing-library/user-event': 14.5.2(@testing-library/dom@9.3.4)
+      '@vitest/expect': 1.3.1
+      '@vitest/spy': 1.5.3
       util: 0.12.5
     transitivePeerDependencies:
       - '@jest/globals'
@@ -6609,8 +6729,8 @@ packages:
       - vitest
     dev: true
 
-  /@storybook/theming@8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-WXvDbV257fKbHM5jHd7hOHefRSBnyZec08NGpcVOG6muJjLu8nPjazcYgISqFc97MkFmxvEDPFfX8CvBEeefzA==}
+  /@storybook/theming@8.0.9(react-dom@18.2.0)(react@18.2.0):
+    resolution: {integrity: sha512-jgfDuYoiNMMirQiASN3Eg0hGDXsEtpdAcMxyShqYGwu9elxgD9yUnYC2nSckYsM74a3ZQ3JaViZ9ZFSe2FHmeQ==}
     peerDependencies:
       react: ^16.8.0 || ^17.0.0 || ^18.0.0
       react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
@@ -6621,35 +6741,35 @@ packages:
         optional: true
     dependencies:
       '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.2.0)
-      '@storybook/client-logger': 8.0.0-beta.6
+      '@storybook/client-logger': 8.0.9
       '@storybook/global': 5.0.0
       memoizerific: 1.11.3
       react: 18.2.0
       react-dom: 18.2.0(react@18.2.0)
     dev: true
 
-  /@storybook/types@8.0.0-beta.6:
-    resolution: {integrity: sha512-w3jq8mBcxir4P0RK3gQePeUJ0rXbnUbCKg91YBOKeitmU0+4jSr4e1EwTWOYgsyz7KtikzSNr8JXtMQn2TJD5A==}
+  /@storybook/types@8.0.9:
+    resolution: {integrity: sha512-ew0EXzk9k4B557P1qIWYrnvUcgaE0WWA5qQS0AU8l+fRTp5nvl9O3SP/zNIB0SN1qDFO7dXr3idTNTyIikTcEQ==}
     dependencies:
-      '@storybook/channels': 8.0.0-beta.6
+      '@storybook/channels': 8.0.9
       '@types/express': 4.17.17
       file-system-cache: 2.3.0
     dev: true
 
-  /@storybook/vue3-vite@8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)(vite@5.1.4)(vue@3.4.21):
-    resolution: {integrity: sha512-Pf9W7hcHjx1FE3JmhY1iSxGq9k/Tp5n/obOCd4FJGUdIttPYFclG9km49DrCJtNfhK7M6+d2QTZ6Uds4ORWZPg==}
+  /@storybook/vue3-vite@8.0.9(react-dom@18.2.0)(react@18.2.0)(vite@5.1.4)(vue@3.4.21):
+    resolution: {integrity: sha512-IkzYsEyCo5HIvLWbJeGrBu/VIN4u+LvdIAz7vcFqVVXBtTUhy+9/8caLx8fdnM0FWgKcBRQs8HnjBB2V0lOFcg==}
     engines: {node: '>=18.0.0'}
     peerDependencies:
       vite: ^4.0.0 || ^5.0.0
     dependencies:
-      '@storybook/builder-vite': 8.0.0-beta.6(typescript@5.3.3)(vite@5.1.4)
-      '@storybook/core-server': 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/vue3': 8.0.0-beta.6(vue@3.4.21)
+      '@storybook/builder-vite': 8.0.9(typescript@5.3.3)(vite@5.1.4)
+      '@storybook/core-server': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/vue3': 8.0.9(vue@3.4.21)
       find-package-json: 1.2.0
       magic-string: 0.30.7
       typescript: 5.3.3
       vite: 5.1.4(@types/node@20.11.22)(sass@1.71.1)(terser@5.28.1)
-      vue-component-meta: 1.8.27(typescript@5.3.3)
+      vue-component-meta: 2.0.16(typescript@5.3.3)
       vue-docgen-api: 4.75.1(vue@3.4.21)
     transitivePeerDependencies:
       - '@preact/preset-vite'
@@ -6663,22 +6783,22 @@ packages:
       - vue
     dev: true
 
-  /@storybook/vue3@8.0.0-beta.6(vue@3.4.21):
-    resolution: {integrity: sha512-027KDM1f6y0XzMK1yE5W4JKY/VsbGpr1kj0mvEKxaPUYgBJV9wTHADWgmluiJS/e/MWrCCZql5mE+D9lVJUjoA==}
+  /@storybook/vue3@8.0.9(vue@3.4.21):
+    resolution: {integrity: sha512-EqVdS62YbOCAE0wJrQKW0sHpM90be8N8Mvmj+HzB0QYhJNtFqP9ehwbcTfwEKtaVGudisHgGBOzNoSKDlxFaag==}
     engines: {node: '>=18.0.0'}
     peerDependencies:
       vue: ^3.0.0
     dependencies:
-      '@storybook/docs-tools': 8.0.0-beta.6
+      '@storybook/docs-tools': 8.0.9
       '@storybook/global': 5.0.0
-      '@storybook/preview-api': 8.0.0-beta.6
-      '@storybook/types': 8.0.0-beta.6
-      '@vue/compiler-core': 3.4.18
+      '@storybook/preview-api': 8.0.9
+      '@storybook/types': 8.0.9
+      '@vue/compiler-core': 3.4.21
       lodash: 4.17.21
       ts-dedent: 2.2.0
       type-fest: 2.19.0
       vue: 3.4.21(typescript@5.3.3)
-      vue-component-type-helpers: 2.0.14
+      vue-component-type-helpers: 2.0.16
     transitivePeerDependencies:
       - encoding
       - supports-color
@@ -7108,6 +7228,20 @@ packages:
       pretty-format: 27.5.1
     dev: true
 
+  /@testing-library/dom@9.3.4:
+    resolution: {integrity: sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==}
+    engines: {node: '>=14'}
+    dependencies:
+      '@babel/code-frame': 7.23.5
+      '@babel/runtime': 7.23.4
+      '@types/aria-query': 5.0.1
+      aria-query: 5.1.3
+      chalk: 4.1.2
+      dom-accessibility-api: 0.5.16
+      lz-string: 1.5.0
+      pretty-format: 27.5.1
+    dev: true
+
   /@testing-library/jest-dom@6.4.2(vitest@0.34.6):
     resolution: {integrity: sha512-CzqH0AFymEMG48CpzXFriYYkOjk6ZGPCLMhW9e9jg3KMCn5OfJecF8GtGW7yGfR/IgCe3SX8BSwjdzI6BBbZLw==}
     engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
@@ -7140,13 +7274,13 @@ packages:
       vitest: 0.34.6(happy-dom@13.6.2)(sass@1.71.1)(terser@5.28.1)
     dev: true
 
-  /@testing-library/user-event@14.5.2(@testing-library/dom@9.3.3):
+  /@testing-library/user-event@14.5.2(@testing-library/dom@9.3.4):
     resolution: {integrity: sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==}
     engines: {node: '>=12', npm: '>=6'}
     peerDependencies:
       '@testing-library/dom': '>=7.21.4'
     dependencies:
-      '@testing-library/dom': 9.3.3
+      '@testing-library/dom': 9.3.4
     dev: true
 
   /@testing-library/vue@8.0.2(@vue/compiler-sfc@3.4.21)(vue@3.4.21):
@@ -7296,7 +7430,7 @@ packages:
   /@types/cross-spawn@6.0.2:
     resolution: {integrity: sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==}
     dependencies:
-      '@types/node': 20.11.22
+      '@types/node': 20.11.28
     dev: true
 
   /@types/debug@4.1.12:
@@ -7382,13 +7516,13 @@ packages:
     resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
     dependencies:
       '@types/minimatch': 5.1.2
-      '@types/node': 20.11.22
+      '@types/node': 20.11.28
     dev: true
 
   /@types/graceful-fs@4.1.6:
     resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==}
     dependencies:
-      '@types/node': 20.11.22
+      '@types/node': 20.11.28
     dev: true
 
   /@types/hast@3.0.4:
@@ -7793,12 +7927,6 @@ packages:
     resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==}
     dev: true
 
-  /@types/yargs@16.0.5:
-    resolution: {integrity: sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==}
-    dependencies:
-      '@types/yargs-parser': 21.0.0
-    dev: true
-
   /@types/yargs@17.0.19:
     resolution: {integrity: sha512-cAx3qamwaYX9R0fzOIZAlFpo4A+1uBVCxqpKz9D26uTF4srRXaGTTsikQmaotCtNdbhzyUH7ft6p9ktz9s6UNQ==}
     dependencies:
@@ -8120,11 +8248,11 @@ packages:
       chai: 4.3.10
     dev: true
 
-  /@vitest/expect@1.1.3:
-    resolution: {integrity: sha512-MnJqsKc1Ko04lksF9XoRJza0bGGwTtqfbyrsYv5on4rcEkdo+QgUdITenBQBUltKzdxW7K3rWh+nXRULwsdaVg==}
+  /@vitest/expect@1.3.1:
+    resolution: {integrity: sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==}
     dependencies:
-      '@vitest/spy': 1.1.3
-      '@vitest/utils': 1.1.3
+      '@vitest/spy': 1.3.1
+      '@vitest/utils': 1.3.1
       chai: 4.3.10
     dev: true
 
@@ -8150,14 +8278,14 @@ packages:
       tinyspy: 2.2.0
     dev: true
 
-  /@vitest/spy@1.1.3:
-    resolution: {integrity: sha512-Ec0qWyGS5LhATFQtldvChPTAHv08yHIOZfiNcjwRQbFPHpkih0md9KAbs7TfeIfL7OFKoe7B/6ukBTqByubXkQ==}
+  /@vitest/spy@1.3.1:
+    resolution: {integrity: sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==}
     dependencies:
       tinyspy: 2.2.0
     dev: true
 
-  /@vitest/spy@1.2.2:
-    resolution: {integrity: sha512-k9Gcahssw8d7X3pSLq3e3XEu/0L78mUkCjivUqCQeXJm9clfXR/Td8+AP+VC1O6fKPIDLcHDTAmBOINVuv6+7g==}
+  /@vitest/spy@1.5.3:
+    resolution: {integrity: sha512-Llj7Jgs6lbnL55WoshJUUacdJfjU2honvGcAJBxhra5TPEzTJH8ZuhI3p/JwqqfnTr4PmP7nDmOXP53MS7GJlg==}
     dependencies:
       tinyspy: 2.2.0
     dev: true
@@ -8170,8 +8298,17 @@ packages:
       pretty-format: 29.7.0
     dev: true
 
-  /@vitest/utils@1.1.3:
-    resolution: {integrity: sha512-Dyt3UMcdElTll2H75vhxfpZu03uFpXRCHxWnzcrFjZxT1kTbq8ALUYIeBgGolo1gldVdI0YSlQRacsqxTwNqwg==}
+  /@vitest/utils@1.3.1:
+    resolution: {integrity: sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==}
+    dependencies:
+      diff-sequences: 29.6.3
+      estree-walker: 3.0.3
+      loupe: 2.3.7
+      pretty-format: 29.7.0
+    dev: true
+
+  /@vitest/utils@1.5.3:
+    resolution: {integrity: sha512-rE9DTN1BRhzkzqNQO+kw8ZgfeEBCLXiHJwetk668shmNBpSagQxneT5eSqEBLP+cqSiAeecvQmbpFfdMyLcIQA==}
     dependencies:
       diff-sequences: 29.6.3
       estree-walker: 3.0.3
@@ -8185,12 +8322,24 @@ packages:
       '@volar/source-map': 1.11.1
     dev: true
 
+  /@volar/language-core@2.2.0:
+    resolution: {integrity: sha512-a8WG9+4OdeNDW4ywABZIM6S6UN7em8uIlM/BZ2pWQUYrVmX+m8sj/X+QadvO+Li/t/LjAqbWJQtVgxdpEWLALQ==}
+    dependencies:
+      '@volar/source-map': 2.2.0
+    dev: true
+
   /@volar/source-map@1.11.1:
     resolution: {integrity: sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==}
     dependencies:
       muggle-string: 0.3.1
     dev: true
 
+  /@volar/source-map@2.2.0:
+    resolution: {integrity: sha512-HQlPRlHOVqCCHK8wI76ZldHkEwKsjp7E6idUc36Ekni+KJDNrqgSqPvyHQixybXPHNU7CI9Uxd9/IkxO7LuNBw==}
+    dependencies:
+      muggle-string: 0.4.1
+    dev: true
+
   /@volar/typescript@1.11.1:
     resolution: {integrity: sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==}
     dependencies:
@@ -8198,6 +8347,13 @@ packages:
       path-browserify: 1.0.1
     dev: true
 
+  /@volar/typescript@2.2.0:
+    resolution: {integrity: sha512-wC6l4zLiiCLxF+FGaHCbWlQYf4vMsnRxYhcI6WgvaNppOD6r1g+Ef1RKRJUApALWU46Yy/JDU/TbdV6w/X6Liw==}
+    dependencies:
+      '@volar/language-core': 2.2.0
+      path-browserify: 1.0.1
+    dev: true
+
   /@vue/compiler-core@3.4.18:
     resolution: {integrity: sha512-F7YK8lMK0iv6b9/Gdk15A67wM0KKZvxDxed0RR60C1z9tIJTKta+urs4j0RTN5XqHISzI3etN3mX0uHhjmoqjQ==}
     dependencies:
@@ -8269,6 +8425,24 @@ packages:
       vue-template-compiler: 2.7.14
     dev: true
 
+  /@vue/language-core@2.0.16(typescript@5.3.3):
+    resolution: {integrity: sha512-Bc2sexRH99pznOph8mLw2BlRZ9edm7tW51kcBXgx8adAoOcZUWJj3UNSsdQ6H9Y8meGz7BoazVrVo/jUukIsPw==}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+    dependencies:
+      '@volar/language-core': 2.2.0
+      '@vue/compiler-dom': 3.4.21
+      '@vue/shared': 3.4.21
+      computeds: 0.0.1
+      minimatch: 9.0.3
+      path-browserify: 1.0.1
+      typescript: 5.3.3
+      vue-template-compiler: 2.7.14
+    dev: true
+
   /@vue/reactivity@3.4.21:
     resolution: {integrity: sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==}
     dependencies:
@@ -8326,13 +8500,13 @@ packages:
     requiresBuild: true
     dev: false
 
-  /@yarnpkg/esbuild-plugin-pnp@3.0.0-rc.15(esbuild@0.18.20):
+  /@yarnpkg/esbuild-plugin-pnp@3.0.0-rc.15(esbuild@0.19.11):
     resolution: {integrity: sha512-kYzDJO5CA9sy+on/s2aIW0411AklfCi8Ck/4QDivOqsMKpStZA2SsR+X27VTggGwpStWaLrjJcDcdDMowtG8MA==}
     engines: {node: '>=14.15.0'}
     peerDependencies:
       esbuild: '>=0.10.0'
     dependencies:
-      esbuild: 0.18.20
+      esbuild: 0.19.11
       tslib: 2.6.2
     dev: true
 
@@ -8847,12 +9021,12 @@ packages:
     resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==}
     dev: false
 
-  /babel-core@7.0.0-bridge.0(@babel/core@7.23.5):
+  /babel-core@7.0.0-bridge.0(@babel/core@7.24.0):
     resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.5
+      '@babel/core': 7.24.0
     dev: true
 
   /babel-jest@29.7.0(@babel/core@7.23.5):
@@ -8896,38 +9070,38 @@ packages:
       '@types/babel__traverse': 7.20.0
     dev: true
 
-  /babel-plugin-polyfill-corejs2@0.4.6(@babel/core@7.23.5):
+  /babel-plugin-polyfill-corejs2@0.4.6(@babel/core@7.24.0):
     resolution: {integrity: sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==}
     peerDependencies:
       '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
     dependencies:
       '@babel/compat-data': 7.23.5
-      '@babel/core': 7.23.5
-      '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.23.5)
+      '@babel/core': 7.24.0
+      '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.24.0)
       semver: 6.3.1
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /babel-plugin-polyfill-corejs3@0.8.6(@babel/core@7.23.5):
+  /babel-plugin-polyfill-corejs3@0.8.6(@babel/core@7.24.0):
     resolution: {integrity: sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==}
     peerDependencies:
       '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.23.5)
+      '@babel/core': 7.24.0
+      '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.24.0)
       core-js-compat: 3.33.3
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /babel-plugin-polyfill-regenerator@0.5.3(@babel/core@7.23.5):
+  /babel-plugin-polyfill-regenerator@0.5.3(@babel/core@7.24.0):
     resolution: {integrity: sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==}
     peerDependencies:
       '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.23.5)
+      '@babel/core': 7.24.0
+      '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.24.0)
     transitivePeerDependencies:
       - supports-color
     dev: true
@@ -9167,7 +9341,6 @@ packages:
       electron-to-chromium: 1.4.686
       node-releases: 2.0.14
       update-browserslist-db: 1.0.13(browserslist@4.23.0)
-    dev: false
 
   /bser@2.1.1:
     resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
@@ -9363,7 +9536,6 @@ packages:
 
   /caniuse-lite@1.0.30001591:
     resolution: {integrity: sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==}
-    dev: false
 
   /canonicalize@1.0.8:
     resolution: {integrity: sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==}
@@ -9887,7 +10059,7 @@ packages:
   /core-js-compat@3.33.3:
     resolution: {integrity: sha512-cNzGqFsh3Ot+529GIXacjTJ7kegdt5fPXxCBVS1G0iaZpuo/tBz399ymceLJveQhFFZ8qThHiP3fzuoQjKN2ow==}
     dependencies:
-      browserslist: 4.22.2
+      browserslist: 4.23.0
     dev: true
 
   /core-js@3.29.1:
@@ -10614,7 +10786,6 @@ packages:
 
   /electron-to-chromium@1.4.686:
     resolution: {integrity: sha512-3avY1B+vUzNxEgkBDpKOP8WarvUAEwpRaiCL0He5OKWEFxzaOFiq4WoZEZe7qh0ReS7DiWoHMnYoQCKxNZNzSg==}
-    dev: false
 
   /emittery@0.13.1:
     resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
@@ -10789,13 +10960,13 @@ packages:
     resolution: {integrity: sha512-jyfL/pwPqaFXyKnj8lP8iLk6Z0m099uXR45aSN8Av1XD4vhvQutxxPzgA2bTcAwQpa1zCXDcWOlhFgyP3GKqhQ==}
     dev: true
 
-  /esbuild-register@3.5.0(esbuild@0.18.20):
+  /esbuild-register@3.5.0(esbuild@0.19.11):
     resolution: {integrity: sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==}
     peerDependencies:
       esbuild: '>=0.12 <1'
     dependencies:
       debug: 4.3.4(supports-color@8.1.1)
-      esbuild: 0.18.20
+      esbuild: 0.19.11
     transitivePeerDependencies:
       - supports-color
     dev: true
@@ -13392,14 +13563,6 @@ packages:
       stack-utils: 2.0.6
     dev: true
 
-  /jest-mock@27.5.1:
-    resolution: {integrity: sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==}
-    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
-    dependencies:
-      '@jest/types': 27.5.1
-      '@types/node': 20.11.22
-    dev: true
-
   /jest-mock@29.7.0:
     resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==}
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -13688,18 +13851,18 @@ packages:
       '@babel/preset-env':
         optional: true
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/parser': 7.23.9
-      '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.5)
-      '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.23.5)
-      '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.5)
-      '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.5)
-      '@babel/preset-env': 7.23.5(@babel/core@7.23.5)
-      '@babel/preset-flow': 7.23.3(@babel/core@7.23.5)
-      '@babel/preset-typescript': 7.23.3(@babel/core@7.23.5)
-      '@babel/register': 7.22.15(@babel/core@7.23.5)
-      babel-core: 7.0.0-bridge.0(@babel/core@7.23.5)
+      '@babel/core': 7.24.0
+      '@babel/parser': 7.24.0
+      '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.24.0)
+      '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.24.0)
+      '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.24.0)
+      '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.24.0)
+      '@babel/preset-env': 7.23.5(@babel/core@7.24.0)
+      '@babel/preset-flow': 7.23.3(@babel/core@7.24.0)
+      '@babel/preset-typescript': 7.23.3(@babel/core@7.24.0)
+      '@babel/register': 7.22.15(@babel/core@7.24.0)
+      babel-core: 7.0.0-bridge.0(@babel/core@7.24.0)
       chalk: 4.1.2
       flow-parser: 0.202.0
       graceful-fs: 4.2.11
@@ -14995,6 +15158,10 @@ packages:
     resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==}
     dev: true
 
+  /muggle-string@0.4.1:
+    resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
+    dev: true
+
   /multer@1.4.4-lts.1:
     resolution: {integrity: sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==}
     engines: {node: '>= 6.0.0'}
@@ -16819,9 +16986,9 @@ packages:
     resolution: {integrity: sha512-rCz0HBIT0LWbIM+///LfRrJoTKftIzzwsYDf0ns5KwaEjejMHQRtphcns+IXFHDNY9pnz6G8l/JbbI6pD4EAIA==}
     engines: {node: '>=16.14.0'}
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/traverse': 7.23.5
-      '@babel/types': 7.23.5
+      '@babel/core': 7.24.0
+      '@babel/traverse': 7.24.0
+      '@babel/types': 7.24.0
       '@types/babel__core': 7.20.0
       '@types/babel__traverse': 7.20.0
       '@types/doctrine': 0.0.9
@@ -16971,6 +17138,17 @@ packages:
       tslib: 2.6.2
     dev: true
 
+  /recast@0.23.6:
+    resolution: {integrity: sha512-9FHoNjX1yjuesMwuthAmPKabxYQdOgihFYmT5ebXfYGBcnqXZf3WOVz+5foEZ8Y83P4ZY6yQD5GMmtV+pgCCAQ==}
+    engines: {node: '>= 4'}
+    dependencies:
+      ast-types: 0.16.1
+      esprima: 4.0.1
+      source-map: 0.6.1
+      tiny-invariant: 1.3.3
+      tslib: 2.6.2
+    dev: true
+
   /reconnecting-websocket@4.4.0:
     resolution: {integrity: sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==}
     dev: false
@@ -17972,11 +18150,11 @@ packages:
     resolution: {integrity: sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==}
     dev: true
 
-  /storybook@8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-8d9gpKPDY9Ix64f0560rXIifmnuoswDdvSdTz4NXHGvPt7WrKNmaDTvWGyt1/fbTbv2dvvVp7bsWPgq1KGbrcg==}
+  /storybook@8.0.9(react-dom@18.2.0)(react@18.2.0):
+    resolution: {integrity: sha512-/Mvij0Br5bUwJpCvqAUZMEDIWmdRxEyllvVj8Ukw5lIWJePxfpSsz4px5jg9+R6B9tO8sQSqjg4HJvQ/pZk8Tg==}
     hasBin: true
     dependencies:
-      '@storybook/cli': 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/cli': 8.0.9(react-dom@18.2.0)(react@18.2.0)
     transitivePeerDependencies:
       - '@babel/preset-env'
       - bufferutil
@@ -18429,6 +18607,10 @@ packages:
     resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==}
     dev: true
 
+  /tiny-invariant@1.3.3:
+    resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
+    dev: true
+
   /tiny-lru@10.0.1:
     resolution: {integrity: sha512-Vst+6kEsWvb17Zpz14sRJV/f8bUWKhqm6Dc+v08iShmIJ/WxqWytHzCTd6m88pS33rE2zpX34TRmOpAJPloNCA==}
     engines: {node: '>=6'}
@@ -18612,7 +18794,6 @@ packages:
       json5: 2.2.3
       minimist: 1.2.8
       strip-bom: 3.0.0
-    dev: false
 
   /tsd@0.30.7:
     resolution: {integrity: sha512-oTiJ28D6B/KXoU3ww/Eji+xqHJojiuPVMwA12g4KYX1O72N93Nb6P3P3h2OAhhf92Xl8NIhb/xFmBZd5zw/xUw==}
@@ -19027,7 +19208,6 @@ packages:
       browserslist: 4.23.0
       escalade: 3.1.1
       picocolors: 1.0.0
-    dev: false
 
   /uri-js@4.4.1:
     resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
@@ -19324,19 +19504,19 @@ packages:
       vscode-languageserver-protocol: 3.17.5
     dev: false
 
-  /vue-component-meta@1.8.27(typescript@5.3.3):
-    resolution: {integrity: sha512-j3WJsyQHP4TDlvnjHc/eseo0/eVkf0FaCpkqGwez5zD+Tj31onBzWZEXTnWKs8xRj0n3dMNYdy3SpiS6NubSvg==}
+  /vue-component-meta@2.0.16(typescript@5.3.3):
+    resolution: {integrity: sha512-IyIMClUMYcKxAL34GqdPbR4V45MUeHXqQiZlHxeYMV5Qcqp4M+CEmtGpF//XBSS138heDkYkceHAtJQjLUB1Lw==}
     peerDependencies:
       typescript: '*'
     peerDependenciesMeta:
       typescript:
         optional: true
     dependencies:
-      '@volar/typescript': 1.11.1
-      '@vue/language-core': 1.8.27(typescript@5.3.3)
+      '@volar/typescript': 2.2.0
+      '@vue/language-core': 2.0.16(typescript@5.3.3)
       path-browserify: 1.0.1
       typescript: 5.3.3
-      vue-component-type-helpers: 1.8.27
+      vue-component-type-helpers: 2.0.16
     dev: true
 
   /vue-component-type-helpers@1.8.27:
@@ -19347,8 +19527,8 @@ packages:
     resolution: {integrity: sha512-6bnLkn8O0JJyiFSIF0EfCogzeqNXpnjJ0vW/SZzNHfe6sPx30lTtTXlE5TFs2qhJlAtDFybStVNpL73cPe3OMQ==}
     dev: true
 
-  /vue-component-type-helpers@2.0.14:
-    resolution: {integrity: sha512-DInfgOyXlMyliyqAAD9frK28tTfch0+tMi4qoWJcZlRxUf+NFAtraJBnAsKLep+FOyLMiajkhfyEb3xLK08i7w==}
+  /vue-component-type-helpers@2.0.16:
+    resolution: {integrity: sha512-qisL/iAfdO++7w+SsfYQJVPj6QKvxp4i1MMxvsNO41z/8zu3KuAw9LkhKUfP/kcOWGDxESp+pQObWppXusejCA==}
     dev: true
 
   /vue-demi@0.14.7(vue@3.4.21):
@@ -19371,9 +19551,9 @@ packages:
     peerDependencies:
       vue: '>=2'
     dependencies:
-      '@babel/parser': 7.23.9
-      '@babel/types': 7.23.5
-      '@vue/compiler-dom': 3.4.18
+      '@babel/parser': 7.24.0
+      '@babel/types': 7.24.0
+      '@vue/compiler-dom': 3.4.21
       '@vue/compiler-sfc': 3.4.21
       ast-types: 0.16.1
       hash-sum: 2.0.0
@@ -19893,7 +20073,7 @@ packages:
       vscode-languageclient: 9.0.1
     dev: false
 
-  github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.0.0-beta.6)(@storybook/components@8.0.0-beta.6)(@storybook/core-events@8.0.0-beta.6)(@storybook/manager-api@8.0.0-beta.6)(@storybook/preview-api@8.0.0-beta.6)(@storybook/theming@8.0.0-beta.6)(@storybook/types@8.0.0-beta.6)(react-dom@18.2.0)(react@18.2.0):
+  github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.0.9)(@storybook/components@8.0.9)(@storybook/core-events@8.0.9)(@storybook/manager-api@8.0.9)(@storybook/preview-api@8.0.9)(@storybook/theming@8.0.9)(@storybook/types@8.0.9)(react-dom@18.2.0)(react@18.2.0):
     resolution: {tarball: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640}
     id: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640
     name: storybook-addon-misskey-theme
@@ -19914,13 +20094,13 @@ packages:
       react-dom:
         optional: true
     dependencies:
-      '@storybook/blocks': 8.0.0-beta.6(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/components': 8.0.0-beta.6(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/core-events': 8.0.0-beta.6
-      '@storybook/manager-api': 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/preview-api': 8.0.0-beta.6
-      '@storybook/theming': 8.0.0-beta.6(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/types': 8.0.0-beta.6
+      '@storybook/blocks': 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/components': 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/core-events': 8.0.9
+      '@storybook/manager-api': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/preview-api': 8.0.9
+      '@storybook/theming': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/types': 8.0.9
       react: 18.2.0
       react-dom: 18.2.0(react@18.2.0)
     dev: true

From c530a46e547791b22ecf12fe1b9e952f7df0a58c Mon Sep 17 00:00:00 2001
From: Kisaragi <48310258+KisaragiEffective@users.noreply.github.com>
Date: Wed, 1 May 2024 17:13:20 +0900
Subject: [PATCH 108/191] =?UTF-8?q?enhance(backend):=20=E3=83=89=E3=83=A9?=
 =?UTF-8?q?=E3=82=A4=E3=83=96=E3=81=AE=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB?=
 =?UTF-8?q?=E3=81=8CNSFW=E3=81=8B=E3=81=A9=E3=81=86=E3=81=8B=E5=80=8B?=
 =?UTF-8?q?=E5=88=A5=E3=81=AB=E9=80=A3=E5=90=88=E3=81=95=E3=82=8C=E3=82=8B?=
 =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB=20(#13756)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(backend): ノートのattachmentにおいて、attach.sensitiveが元から存在する場合はそれを尊重する

* docs: update changelog (per misskey-dev#13756)

* feat(backend,apub): renderDocumentがsensitiveを連合するようにする
per https://github.com/misskey-dev/misskey/issues/13755#issuecomment-2081303014

* chore(backend): 追加したコメントを削除

* docs: changelogをより丁寧にする

* docs: changelogの項目名をPRに合わせる

* docs: tweak

apply suggestion from mei23
---
 CHANGELOG.md                                                  | 2 ++
 packages/backend/src/core/activitypub/ApRendererService.ts    | 1 +
 packages/backend/src/core/activitypub/models/ApNoteService.ts | 2 +-
 3 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4394ab0c55..1f3ae412ef 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -77,6 +77,8 @@
 - Fix: グローバルタイムラインで返信が表示されないことがある問題を修正
 - Fix: リノートをミュートしたユーザの投稿のリノートがミュートされる問題を修正
 - Fix: AP Link等は添付ファイル扱いしないようになど (#13754)
+- Enhance: ドライブのファイルがNSFWかどうか個別に連合されるように (#13756)
+  - 可能な場合、ノートの添付ファイルのセンシティブ判定がファイル単位になります
 
 ## 2024.3.1
 
diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts
index d3553b6f73..4fc724b548 100644
--- a/packages/backend/src/core/activitypub/ApRendererService.ts
+++ b/packages/backend/src/core/activitypub/ApRendererService.ts
@@ -167,6 +167,7 @@ export class ApRendererService {
 			mediaType: file.webpublicType ?? file.type,
 			url: this.driveFileEntityService.getPublicUrl(file),
 			name: file.comment,
+			sensitive: file.isSensitive,
 		};
 	}
 
diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts
index 05f7879983..4e361b57bc 100644
--- a/packages/backend/src/core/activitypub/models/ApNoteService.ts
+++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts
@@ -211,7 +211,7 @@ export class ApNoteService {
 		const files: MiDriveFile[] = [];
 
 		for (const attach of toArray(note.attachment)) {
-			attach.sensitive ||= note.sensitive;	// Noteがsensitiveなら添付もsensitiveにする
+			attach.sensitive ??= note.sensitive;
 			const file = await this.apImageService.resolveImage(actor, attach);
 			if (file) files.push(file);
 		}

From 053e7626e41a7001a49287b2d51933151efaf4c5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sat, 4 May 2024 13:21:40 +0900
Subject: [PATCH 109/191] =?UTF-8?q?enhance(frontend=5Fais):=20PostForm?=
 =?UTF-8?q?=E7=B3=BB=E3=81=AE=E8=A8=AD=E5=AE=9A=E9=A0=85=E7=9B=AE=E3=82=92?=
 =?UTF-8?q?=E8=BF=BD=E5=8A=A0=20(#13788)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance(frontend_ais): PostForm系の設定項目を追加

* Update Changelog
---
 CHANGELOG.md                                 |  1 +
 packages/frontend/src/components/MkAsUi.vue  |  4 ++
 packages/frontend/src/scripts/aiscript/ui.ts | 62 ++++++++++----------
 3 files changed, 35 insertions(+), 32 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1f3ae412ef..c54fa6ed78 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -38,6 +38,7 @@
 - Enhance: フォローするかどうかの確認ダイアログを出せるように
 - Enhance: Playを手動でリロードできるように
 - Enhance: 通報のコメント内のリンクをクリックした際、ウィンドウで開くように
+- Enhance: `Ui:C:postForm` および `Ui:C:postFormButton` に `localOnly` と `visibility` を設定できるように
 - Chore: AiScriptを0.18.0にバージョンアップ
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
diff --git a/packages/frontend/src/components/MkAsUi.vue b/packages/frontend/src/components/MkAsUi.vue
index 5eb77740be..18e8e7542e 100644
--- a/packages/frontend/src/components/MkAsUi.vue
+++ b/packages/frontend/src/components/MkAsUi.vue
@@ -44,6 +44,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 			:instant="true"
 			:initialText="c.form?.text"
 			:initialCw="c.form?.cw"
+			:initialVisibility="c.form?.visibility"
+			:initialLocalOnly="c.form?.localOnly"
 		/>
 	</div>
 	<MkFolder v-else-if="c.type === 'folder'" :defaultOpen="c.opened">
@@ -111,6 +113,8 @@ function openPostForm() {
 	os.post({
 		initialText: form.text,
 		initialCw: form.cw,
+		initialVisibility: form.visibility,
+		initialLocalOnly: form.localOnly,
 		instant: true,
 	});
 }
diff --git a/packages/frontend/src/scripts/aiscript/ui.ts b/packages/frontend/src/scripts/aiscript/ui.ts
index f2493264d3..fa3fcac2e7 100644
--- a/packages/frontend/src/scripts/aiscript/ui.ts
+++ b/packages/frontend/src/scripts/aiscript/ui.ts
@@ -6,6 +6,7 @@
 import { utils, values } from '@syuilo/aiscript';
 import { v4 as uuid } from 'uuid';
 import { ref, Ref } from 'vue';
+import * as Misskey from 'misskey-js';
 
 export type AsUiComponentBase = {
 	id: string;
@@ -115,23 +116,24 @@ export type AsUiFolder = AsUiComponentBase & {
 	opened?: boolean;
 };
 
+type PostFormPropsForAsUi = {
+	text: string;
+	cw?: string;
+	visibility?: (typeof Misskey.noteVisibilities)[number];
+	localOnly?: boolean;
+};
+
 export type AsUiPostFormButton = AsUiComponentBase & {
 	type: 'postFormButton';
 	text?: string;
 	primary?: boolean;
 	rounded?: boolean;
-	form?: {
-		text: string;
-		cw?: string;
-	};
+	form?: PostFormPropsForAsUi;
 };
 
 export type AsUiPostForm = AsUiComponentBase & {
 	type: 'postForm';
-	form?: {
-		text: string;
-		cw?: string;
-	};
+	form?: PostFormPropsForAsUi;
 };
 
 export type AsUiComponent = AsUiRoot | AsUiContainer | AsUiText | AsUiMfm | AsUiButton | AsUiButtons | AsUiSwitch | AsUiTextarea | AsUiTextInput | AsUiNumberInput | AsUiSelect | AsUiFolder | AsUiPostFormButton | AsUiPostForm;
@@ -447,6 +449,24 @@ function getFolderOptions(def: values.Value | undefined): Omit<AsUiFolder, 'id'
 	};
 }
 
+function getPostFormProps(form: values.VObj): PostFormPropsForAsUi {
+	const text = form.value.get('text');
+	utils.assertString(text);
+	const cw = form.value.get('cw');
+	if (cw) utils.assertString(cw);
+	const visibility = form.value.get('visibility');
+	if (visibility) utils.assertString(visibility);
+	const localOnly = form.value.get('localOnly');
+	if (localOnly) utils.assertBoolean(localOnly);
+
+	return {
+		text: text.value,
+		cw: cw?.value,
+		visibility: (visibility?.value && (Misskey.noteVisibilities as readonly string[]).includes(visibility.value)) ? visibility.value as typeof Misskey.noteVisibilities[number] : undefined,
+		localOnly: localOnly?.value,
+	};
+}
+
 function getPostFormButtonOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Omit<AsUiPostFormButton, 'id' | 'type'> {
 	utils.assertObject(def);
 
@@ -459,22 +479,11 @@ function getPostFormButtonOptions(def: values.Value | undefined, call: (fn: valu
 	const form = def.value.get('form');
 	if (form) utils.assertObject(form);
 
-	const getForm = () => {
-		const text = form!.value.get('text');
-		utils.assertString(text);
-		const cw = form!.value.get('cw');
-		if (cw) utils.assertString(cw);
-		return {
-			text: text.value,
-			cw: cw?.value,
-		};
-	};
-
 	return {
 		text: text?.value,
 		primary: primary?.value,
 		rounded: rounded?.value,
-		form: form ? getForm() : {
+		form: form ? getPostFormProps(form) : {
 			text: '',
 		},
 	};
@@ -486,19 +495,8 @@ function getPostFormOptions(def: values.Value | undefined, call: (fn: values.VFn
 	const form = def.value.get('form');
 	if (form) utils.assertObject(form);
 
-	const getForm = () => {
-		const text = form!.value.get('text');
-		utils.assertString(text);
-		const cw = form!.value.get('cw');
-		if (cw) utils.assertString(cw);
-		return {
-			text: text.value,
-			cw: cw?.value,
-		};
-	};
-
 	return {
-		form: form ? getForm() : {
+		form: form ? getPostFormProps(form) : {
 			text: '',
 		},
 	};

From eef7fcdd45b12556c07c0cff31ee7c37a0e9d12f Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Sat, 4 May 2024 19:40:17 +0900
Subject: [PATCH 110/191] chore(frontend): ui tweak

---
 packages/frontend/src/pages/admin-user.vue       | 2 +-
 packages/frontend/src/pages/admin/roles.role.vue | 2 +-
 packages/frontend/src/scripts/get-user-menu.ts   | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue
index 2cef55df6c..f57aa51b5b 100644
--- a/packages/frontend/src/pages/admin-user.vue
+++ b/packages/frontend/src/pages/admin-user.vue
@@ -416,7 +416,7 @@ async function assignRole() {
 	if (canceled) return;
 
 	const { canceled: canceled2, result: period } = await os.select({
-		title: i18n.ts.period,
+		title: i18n.ts.period + ': ' + roles.find(r => r.id === roleId)!.name,
 		items: [{
 			value: 'indefinitely', text: i18n.ts.indefinitely,
 		}, {
diff --git a/packages/frontend/src/pages/admin/roles.role.vue b/packages/frontend/src/pages/admin/roles.role.vue
index ab8005045b..8b3c906d8a 100644
--- a/packages/frontend/src/pages/admin/roles.role.vue
+++ b/packages/frontend/src/pages/admin/roles.role.vue
@@ -119,7 +119,7 @@ async function assign() {
 	const user = await os.selectUser({ includeSelf: true });
 
 	const { canceled: canceled2, result: period } = await os.select({
-		title: i18n.ts.period,
+		title: i18n.ts.period + ': ' + role.name,
 		items: [{
 			value: 'indefinitely', text: i18n.ts.indefinitely,
 		}, {
diff --git a/packages/frontend/src/scripts/get-user-menu.ts b/packages/frontend/src/scripts/get-user-menu.ts
index c14f75f382..3e031d232f 100644
--- a/packages/frontend/src/scripts/get-user-menu.ts
+++ b/packages/frontend/src/scripts/get-user-menu.ts
@@ -272,7 +272,7 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
 						text: r.name,
 						action: async () => {
 							const { canceled, result: period } = await os.select({
-								title: i18n.ts.period,
+								title: i18n.ts.period + ': ' + r.name,
 								items: [{
 									value: 'indefinitely', text: i18n.ts.indefinitely,
 								}, {

From 2b21c1936212b6e1288d545b71544888e84ce8ab Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Sat, 4 May 2024 20:56:14 +0900
Subject: [PATCH 111/191] update deps (#13624)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* update deps

* Update package.json

* update deps

* build: pass --strip-leading-paths to restore 0.2.x behavior (#13684)

* :v:

* :v:

* pureimageの代わりに@napi-rs/canvasを使う (#13748)

* pureimageの代わりに@napi-rs/canvasを使う

* remove writestream

* remove createtemp

* wip

* Update ClientServerService.ts

* update pnpm to 9.x

* update deps

* re: update pnpm to 9.x

* update node

* :v:

---------

Co-authored-by: anatawa12 <anatawa12@icloud.com>
Co-authored-by: tamaina <tamaina@hotmail.co.jp>
---
 .devcontainer/devcontainer.json               |     2 +-
 .../workflows/check-misskey-js-autogen.yml    |     2 +-
 .github/workflows/get-api-diff.yml            |     4 +-
 .github/workflows/lint.yml                    |     6 +-
 .github/workflows/on-release-created.yml      |     4 +-
 .github/workflows/storybook.yml               |     2 +-
 .github/workflows/test-backend.yml            |     8 +-
 .github/workflows/test-frontend.yml           |     8 +-
 .github/workflows/test-misskey-js.yml         |     2 +-
 .github/workflows/test-production.yml         |     4 +-
 .github/workflows/validate-api-json.yml       |     4 +-
 .node-version                                 |     2 +-
 Dockerfile                                    |     2 +-
 package.json                                  |    24 +-
 packages/backend/package.json                 |   114 +-
 packages/backend/src/core/WebAuthnService.ts  |    22 +-
 packages/backend/src/misc/gen-identicon.ts    |     9 +-
 packages/backend/src/server/ServerService.ts  |     5 +-
 .../server/api/endpoints/i/2fa/key-done.ts    |     6 +-
 .../src/server/web/ClientServerService.ts     |     5 +
 .../backend/src/server/web/views/base.pug     |     2 +-
 .../frontend/.storybook/preview-head.html     |     2 +-
 packages/frontend/package.json                |    64 +-
 packages/frontend/src/_dev_boot_.ts           |     2 +-
 packages/misskey-js/package.json              |    14 +-
 packages/sw/package.json                      |     6 +-
 pnpm-lock.yaml                                | 24074 +++++++++-------
 scripts/build-assets.mjs                      |     2 +-
 28 files changed, 13923 insertions(+), 10478 deletions(-)

diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index f8d9905ecd..182ee2fbb2 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -8,7 +8,7 @@
 			"version": "8.9.2"
 		},
 		"ghcr.io/devcontainers/features/node:1": {
-			"version": "20.10.0"
+			"version": "20.12.2"
 		}
 	},
 	"forwardPorts": [3000],
diff --git a/.github/workflows/check-misskey-js-autogen.yml b/.github/workflows/check-misskey-js-autogen.yml
index 4aa0646b7b..9052b2e372 100644
--- a/.github/workflows/check-misskey-js-autogen.yml
+++ b/.github/workflows/check-misskey-js-autogen.yml
@@ -26,7 +26,7 @@ jobs:
       - name: setup pnpm
         uses: pnpm/action-setup@v3
         with:
-          version: 8
+          version: 9
 
       - name: setup node
         id: setup-node
diff --git a/.github/workflows/get-api-diff.yml b/.github/workflows/get-api-diff.yml
index e737b89b42..146e0686e5 100644
--- a/.github/workflows/get-api-diff.yml
+++ b/.github/workflows/get-api-diff.yml
@@ -18,7 +18,7 @@ jobs:
 
     strategy:
       matrix:
-        node-version: [20.10.0]
+        node-version: [20.12.2]
         api-json-name: [api-base.json, api-head.json]
         include:
           - api-json-name: api-base.json
@@ -34,7 +34,7 @@ jobs:
     - name: Install pnpm
       uses: pnpm/action-setup@v3
       with:
-        version: 8
+        version: 9
         run_install: false
     - name: Use Node.js ${{ matrix.node-version }}
       uses: actions/setup-node@v4.0.2
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 9b3f85fe1d..9a269014ab 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -29,7 +29,7 @@ jobs:
         submodules: true
     - uses: pnpm/action-setup@v3
       with:
-        version: 8
+        version: 9
         run_install: false
     - uses: actions/setup-node@v4.0.2
       with:
@@ -56,7 +56,7 @@ jobs:
         submodules: true
     - uses: pnpm/action-setup@v3
       with:
-        version: 7
+        version: 9
         run_install: false
     - uses: actions/setup-node@v4.0.2
       with:
@@ -82,7 +82,7 @@ jobs:
         submodules: true
     - uses: pnpm/action-setup@v3
       with:
-        version: 7
+        version: 9
         run_install: false
     - uses: actions/setup-node@v4.0.2
       with:
diff --git a/.github/workflows/on-release-created.yml b/.github/workflows/on-release-created.yml
index 069534bd53..52463d7542 100644
--- a/.github/workflows/on-release-created.yml
+++ b/.github/workflows/on-release-created.yml
@@ -17,7 +17,7 @@ jobs:
 
     strategy:
       matrix:
-        node-version: [20.10.0]
+        node-version: [20.12.2]
 
     steps:
       - uses: actions/checkout@v4.1.1
@@ -26,7 +26,7 @@ jobs:
       - name: Install pnpm
         uses: pnpm/action-setup@v3
         with:
-          version: 8
+          version: 9
           run_install: false
       - name: Use Node.js ${{ matrix.node-version }}
         uses: actions/setup-node@v4.0.2
diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml
index ca82f4bcf3..3bc354b331 100644
--- a/.github/workflows/storybook.yml
+++ b/.github/workflows/storybook.yml
@@ -36,7 +36,7 @@ jobs:
     - name: Install pnpm
       uses: pnpm/action-setup@v3
       with:
-        version: 8
+        version: 9
         run_install: false
     - name: Use Node.js 20.x
       uses: actions/setup-node@v4.0.2
diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml
index a803db4508..525cd0916b 100644
--- a/.github/workflows/test-backend.yml
+++ b/.github/workflows/test-backend.yml
@@ -21,7 +21,7 @@ jobs:
 
     strategy:
       matrix:
-        node-version: [20.10.0]
+        node-version: [20.12.2]
 
     services:
       postgres:
@@ -43,7 +43,7 @@ jobs:
     - name: Install pnpm
       uses: pnpm/action-setup@v3
       with:
-        version: 8
+        version: 9
         run_install: false
     - name: Install FFmpeg
       uses: FedericoCarboni/setup-ffmpeg@v3
@@ -73,7 +73,7 @@ jobs:
 
     strategy:
       matrix:
-        node-version: [20.10.0]
+        node-version: [20.12.2]
 
     services:
       postgres:
@@ -95,7 +95,7 @@ jobs:
       - name: Install pnpm
         uses: pnpm/action-setup@v3
         with:
-          version: 8
+          version: 9
           run_install: false
       - name: Use Node.js ${{ matrix.node-version }}
         uses: actions/setup-node@v4.0.2
diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml
index 1e020b7368..9df3c98393 100644
--- a/.github/workflows/test-frontend.yml
+++ b/.github/workflows/test-frontend.yml
@@ -26,7 +26,7 @@ jobs:
 
     strategy:
       matrix:
-        node-version: [20.10.0]
+        node-version: [20.12.2]
 
     steps:
     - uses: actions/checkout@v4.1.1
@@ -35,7 +35,7 @@ jobs:
     - name: Install pnpm
       uses: pnpm/action-setup@v3
       with:
-        version: 8
+        version: 9
         run_install: false
     - name: Use Node.js ${{ matrix.node-version }}
       uses: actions/setup-node@v4.0.2
@@ -64,7 +64,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        node-version: [20.10.0]
+        node-version: [20.12.2]
         browser: [chrome]
 
     services:
@@ -93,7 +93,7 @@ jobs:
     - name: Install pnpm
       uses: pnpm/action-setup@v3
       with:
-        version: 7
+        version: 9
         run_install: false
     - name: Use Node.js ${{ matrix.node-version }}
       uses: actions/setup-node@v4.0.2
diff --git a/.github/workflows/test-misskey-js.yml b/.github/workflows/test-misskey-js.yml
index f73bd0b08f..2589d908b8 100644
--- a/.github/workflows/test-misskey-js.yml
+++ b/.github/workflows/test-misskey-js.yml
@@ -20,7 +20,7 @@ jobs:
 
     strategy:
       matrix:
-        node-version: [20.10.0]
+        node-version: [20.12.2]
         # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
 
     steps:
diff --git a/.github/workflows/test-production.yml b/.github/workflows/test-production.yml
index 77af08b6fe..24a530e073 100644
--- a/.github/workflows/test-production.yml
+++ b/.github/workflows/test-production.yml
@@ -16,7 +16,7 @@ jobs:
 
     strategy:
       matrix:
-        node-version: [20.10.0]
+        node-version: [20.12.2]
 
     steps:
     - uses: actions/checkout@v4.1.1
@@ -25,7 +25,7 @@ jobs:
     - name: Install pnpm
       uses: pnpm/action-setup@v3
       with:
-        version: 8
+        version: 9
         run_install: false
     - name: Use Node.js ${{ matrix.node-version }}
       uses: actions/setup-node@v4.0.2
diff --git a/.github/workflows/validate-api-json.yml b/.github/workflows/validate-api-json.yml
index 36ed8d273f..229c447893 100644
--- a/.github/workflows/validate-api-json.yml
+++ b/.github/workflows/validate-api-json.yml
@@ -17,7 +17,7 @@ jobs:
 
     strategy:
       matrix:
-        node-version: [20.10.0]
+        node-version: [20.12.2]
 
     steps:
     - uses: actions/checkout@v4.1.1
@@ -26,7 +26,7 @@ jobs:
     - name: Install pnpm
       uses: pnpm/action-setup@v3
       with:
-        version: 8
+        version: 9
         run_install: false
     - name: Use Node.js ${{ matrix.node-version }}
       uses: actions/setup-node@v4.0.2
diff --git a/.node-version b/.node-version
index d5a159609d..87834047a6 100644
--- a/.node-version
+++ b/.node-version
@@ -1 +1 @@
-20.10.0
+20.12.2
diff --git a/Dockerfile b/Dockerfile
index ee3a30a3c1..9fc2d611cd 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,6 @@
 # syntax = docker/dockerfile:1.4
 
-ARG NODE_VERSION=20.10.0-bullseye
+ARG NODE_VERSION=20.12.2-bullseye
 
 # build assets & compile TypeScript
 
diff --git a/package.json b/package.json
index 84d6db5124..23e0ea0ee5 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
 		"type": "git",
 		"url": "https://github.com/misskey-dev/misskey.git"
 	},
-	"packageManager": "pnpm@8.15.4",
+	"packageManager": "pnpm@9.0.6",
 	"workspaces": [
 		"packages/frontend",
 		"packages/backend",
@@ -48,24 +48,24 @@
 		"lodash": "4.17.21"
 	},
 	"dependencies": {
-		"cssnano": "6.0.5",
+		"cssnano": "6.1.2",
 		"execa": "8.0.1",
 		"fast-glob": "3.3.2",
 		"ignore-walk": "6.0.4",
 		"js-yaml": "4.1.0",
-		"postcss": "8.4.35",
-		"tar": "6.2.0",
-		"terser": "5.28.1",
-		"typescript": "5.3.3",
-		"esbuild": "0.19.11",
-		"glob": "10.3.10"
+		"postcss": "8.4.38",
+		"tar": "6.2.1",
+		"terser": "5.30.3",
+		"typescript": "5.4.5",
+		"esbuild": "0.20.2",
+		"glob": "10.3.12"
 	},
 	"devDependencies": {
-		"@types/node": "^20.11.28",
-		"@typescript-eslint/eslint-plugin": "7.1.0",
-		"@typescript-eslint/parser": "7.1.0",
+		"@types/node": "20.12.7",
+		"@typescript-eslint/eslint-plugin": "7.7.1",
+		"@typescript-eslint/parser": "7.7.1",
 		"cross-env": "7.0.3",
-		"cypress": "13.6.6",
+		"cypress": "13.7.3",
 		"eslint": "8.57.0",
 		"ncp": "2.0.0",
 		"start-server-and-test": "2.0.3"
diff --git a/packages/backend/package.json b/packages/backend/package.json
index 7f70ae0c97..23b3bfdb8b 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -12,9 +12,9 @@
 		"migrate": "pnpm typeorm migration:run -d ormconfig.js",
 		"revert": "pnpm typeorm migration:revert -d ormconfig.js",
 		"check:connect": "node ./scripts/check_connect.js",
-		"build": "swc src -d built -D",
-		"build:test": "swc test-server -d built-test -D --config-file test-server/.swcrc",
-		"watch:swc": "swc src -d built -D -w",
+		"build": "swc src -d built -D --strip-leading-paths",
+		"build:test": "swc test-server -d built-test -D --config-file test-server/.swcrc --strip-leading-paths",
+		"watch:swc": "swc src -d built -D -w --strip-leading-paths",
 		"build:tsc": "tsc -p tsconfig.json && tsc-alias -p tsconfig.json",
 		"watch": "node ./scripts/watch.mjs",
 		"restart": "pnpm build && pnpm start",
@@ -67,38 +67,39 @@
 	"dependencies": {
 		"@aws-sdk/client-s3": "3.412.0",
 		"@aws-sdk/lib-storage": "3.412.0",
-		"@bull-board/api": "5.14.2",
-		"@bull-board/fastify": "5.14.2",
-		"@bull-board/ui": "5.14.2",
-		"@discordapp/twemoji": "15.0.2",
+		"@bull-board/api": "5.17.0",
+		"@bull-board/fastify": "5.17.0",
+		"@bull-board/ui": "5.17.0",
+		"@discordapp/twemoji": "15.0.3",
 		"@fastify/accepts": "4.3.0",
 		"@fastify/cookie": "9.3.1",
-		"@fastify/cors": "8.5.0",
-		"@fastify/express": "2.3.0",
-		"@fastify/http-proxy": "9.3.0",
-		"@fastify/multipart": "8.1.0",
-		"@fastify/static": "6.12.0",
-		"@fastify/view": "8.2.0",
+		"@fastify/cors": "9.0.1",
+		"@fastify/express": "3.0.0",
+		"@fastify/http-proxy": "9.5.0",
+		"@fastify/multipart": "8.2.0",
+		"@fastify/static": "7.0.3",
+		"@fastify/view": "9.1.0",
 		"@misskey-dev/sharp-read-bmp": "1.2.0",
 		"@misskey-dev/summaly": "5.1.0",
-		"@nestjs/common": "10.3.3",
-		"@nestjs/core": "10.3.3",
-		"@nestjs/testing": "10.3.3",
+		"@napi-rs/canvas": "^0.1.52",
+		"@nestjs/common": "10.3.8",
+		"@nestjs/core": "10.3.8",
+		"@nestjs/testing": "10.3.8",
 		"@peertube/http-signature": "1.7.0",
-		"@simplewebauthn/server": "9.0.3",
+		"@simplewebauthn/server": "10.0.0",
 		"@sinonjs/fake-timers": "11.2.2",
-		"@smithy/node-http-handler": "2.1.10",
-		"@swc/cli": "0.1.63",
-		"@swc/core": "1.3.107",
-		"@twemoji/parser": "15.0.0",
+		"@smithy/node-http-handler": "2.5.0",
+		"@swc/cli": "0.3.12",
+		"@swc/core": "1.4.17",
+		"@twemoji/parser": "15.1.1",
 		"accepts": "1.3.8",
-		"ajv": "8.12.0",
-		"archiver": "6.0.1",
-		"async-mutex": "0.4.1",
+		"ajv": "8.13.0",
+		"archiver": "7.0.1",
+		"async-mutex": "0.5.0",
 		"bcryptjs": "2.4.3",
 		"blurhash": "2.0.5",
 		"body-parser": "1.20.2",
-		"bullmq": "5.4.0",
+		"bullmq": "5.7.8",
 		"cacheable-lookup": "7.0.0",
 		"cbor": "9.0.2",
 		"chalk": "5.3.0",
@@ -109,85 +110,84 @@
 		"content-disposition": "0.5.4",
 		"date-fns": "2.30.0",
 		"deep-email-validator": "0.1.21",
-		"fastify": "4.25.2",
+		"fastify": "4.26.2",
 		"fastify-raw-body": "4.3.0",
 		"feed": "4.2.2",
 		"file-type": "19.0.0",
 		"fluent-ffmpeg": "2.1.2",
 		"form-data": "4.0.0",
-		"got": "14.2.0",
-		"happy-dom": "10.0.3",
+		"got": "14.2.1",
+		"happy-dom": "14.7.1",
 		"hpagent": "1.2.0",
 		"htmlescape": "1.1.1",
-		"http-link-header": "1.1.2",
-		"ioredis": "5.3.2",
+		"http-link-header": "1.1.3",
+		"ioredis": "5.4.1",
 		"ip-cidr": "3.1.0",
-		"ipaddr.js": "2.1.0",
+		"ipaddr.js": "2.2.0",
 		"is-svg": "5.0.0",
 		"js-yaml": "4.1.0",
-		"jsdom": "23.2.0",
+		"jsdom": "24.0.0",
 		"json5": "2.2.3",
 		"jsonld": "8.3.2",
 		"jsrsasign": "11.1.0",
-		"meilisearch": "0.37.0",
+		"meilisearch": "0.38.0",
 		"mfm-js": "0.24.0",
 		"microformats-parser": "2.0.2",
 		"mime-types": "2.1.35",
 		"misskey-js": "workspace:*",
 		"misskey-reversi": "workspace:*",
 		"ms": "3.0.0-canary.1",
-		"nanoid": "5.0.6",
+		"nanoid": "5.0.7",
 		"nested-property": "4.0.0",
 		"node-fetch": "3.3.2",
-		"nodemailer": "6.9.10",
+		"nodemailer": "6.9.13",
 		"nsfwjs": "2.4.2",
 		"oauth": "0.10.0",
 		"oauth2orize": "1.12.0",
 		"oauth2orize-pkce": "0.1.2",
 		"os-utils": "0.0.14",
-		"otpauth": "9.2.2",
+		"otpauth": "9.2.3",
 		"parse5": "7.1.2",
-		"pg": "8.11.3",
+		"pg": "8.11.5",
 		"pkce-challenge": "4.1.0",
 		"probe-image-size": "7.2.3",
 		"promise-limit": "2.7.0",
 		"pug": "3.0.2",
 		"punycode": "2.3.1",
-		"pureimage": "0.3.17",
 		"qrcode": "1.5.3",
 		"random-seed": "0.3.0",
 		"ratelimiter": "3.4.1",
-		"re2": "1.20.9",
+		"re2": "1.20.10",
 		"redis-lock": "0.1.4",
-		"reflect-metadata": "0.2.1",
+		"reflect-metadata": "0.2.2",
 		"rename": "1.0.4",
 		"rss-parser": "3.13.0",
 		"rxjs": "7.8.1",
-		"sanitize-html": "2.12.1",
+		"sanitize-html": "2.13.0",
 		"secure-json-parse": "2.7.0",
-		"sharp": "0.33.2",
+		"sharp": "0.33.3",
 		"slacc": "0.0.10",
 		"strict-event-emitter-types": "2.0.0",
 		"stringz": "2.1.0",
-		"systeminformation": "5.22.0",
+		"systeminformation": "5.22.7",
 		"tinycolor2": "1.6.0",
-		"tmp": "0.2.2",
+		"tmp": "0.2.3",
 		"tsc-alias": "1.8.8",
 		"tsconfig-paths": "4.2.0",
 		"typeorm": "0.3.20",
-		"typescript": "5.3.3",
+		"typescript": "5.4.5",
 		"ulid": "2.3.0",
 		"vary": "1.1.2",
 		"web-push": "3.6.7",
-		"ws": "8.16.0",
+		"ws": "8.17.0",
 		"xev": "3.0.2"
 	},
 	"devDependencies": {
 		"@jest/globals": "29.7.0",
 		"@misskey-dev/eslint-plugin": "1.0.0",
-		"@nestjs/platform-express": "10.3.3",
-		"@simplewebauthn/types": "9.0.1",
-		"@swc/jest": "0.2.31",
+		"@nestjs/platform-express": "10.3.8",
+		"@simplewebauthn/types": "10.0.0",
+		"@swc/jest": "0.2.36",
 		"@types/accepts": "1.3.7",
 		"@types/archiver": "6.0.2",
 		"@types/bcryptjs": "2.4.6",
@@ -197,20 +197,20 @@
 		"@types/fluent-ffmpeg": "2.1.24",
 		"@types/htmlescape": "^1.1.3",
 		"@types/http-link-header": "1.0.5",
-		"@types/jest": "29.5.11",
+		"@types/jest": "29.5.12",
 		"@types/js-yaml": "4.0.9",
 		"@types/jsdom": "21.1.6",
 		"@types/jsonld": "1.5.13",
-		"@types/jsrsasign": "10.5.12",
+		"@types/jsrsasign": "10.5.14",
 		"@types/mime-types": "2.1.4",
 		"@types/ms": "0.7.34",
-		"@types/node": "20.11.22",
+		"@types/node": "20.12.7",
 		"@types/node-fetch": "3.0.3",
-		"@types/nodemailer": "6.4.14",
+		"@types/nodemailer": "6.4.15",
 		"@types/oauth": "0.9.4",
-		"@types/oauth2orize": "1.11.3",
+		"@types/oauth2orize": "1.11.5",
 		"@types/oauth2orize-pkce": "0.1.2",
-		"@types/pg": "8.11.2",
+		"@types/pg": "8.11.5",
 		"@types/pug": "2.0.10",
 		"@types/punycode": "2.1.4",
 		"@types/qrcode": "1.5.5",
@@ -226,8 +226,8 @@
 		"@types/vary": "1.1.3",
 		"@types/web-push": "3.6.3",
 		"@types/ws": "8.5.10",
-		"@typescript-eslint/eslint-plugin": "7.1.0",
-		"@typescript-eslint/parser": "7.1.0",
+		"@typescript-eslint/eslint-plugin": "7.7.1",
+		"@typescript-eslint/parser": "7.7.1",
 		"aws-sdk-client-mock": "3.0.1",
 		"cross-env": "7.0.3",
 		"eslint": "8.57.0",
diff --git a/packages/backend/src/core/WebAuthnService.ts b/packages/backend/src/core/WebAuthnService.ts
index 42fbed2110..ec9f4484a4 100644
--- a/packages/backend/src/core/WebAuthnService.ts
+++ b/packages/backend/src/core/WebAuthnService.ts
@@ -10,7 +10,7 @@ import {
 	generateRegistrationOptions, verifyAuthenticationResponse,
 	verifyRegistrationResponse,
 } from '@simplewebauthn/server';
-import { AttestationFormat, isoCBOR } from '@simplewebauthn/server/helpers';
+import { AttestationFormat, isoCBOR, isoUint8Array } from '@simplewebauthn/server/helpers';
 import { DI } from '@/di-symbols.js';
 import type { UserSecurityKeysRepository } from '@/models/_.js';
 import type { Config } from '@/config.js';
@@ -49,7 +49,7 @@ export class WebAuthnService {
 		const instance = await this.metaService.fetch();
 		return {
 			origin: this.config.url,
-			rpId: this.config.host,
+			rpId: this.config.hostname,
 			rpName: instance.name ?? this.config.host,
 			rpIcon: instance.iconUrl ?? undefined,
 		};
@@ -65,13 +65,12 @@ export class WebAuthnService {
 		const registrationOptions = await generateRegistrationOptions({
 			rpName: relyingParty.rpName,
 			rpID: relyingParty.rpId,
-			userID: userId,
+			userID: isoUint8Array.fromUTF8String(userId),
 			userName: userName,
 			userDisplayName: userDisplayName,
 			attestationType: 'indirect',
-			excludeCredentials: keys.map(key => (<PublicKeyCredentialDescriptorFuture>{
-				id: Buffer.from(key.id, 'base64url'),
-				type: 'public-key',
+			excludeCredentials: keys.map(key => (<{ id: string; transports?: AuthenticatorTransportFuture[]; }>{
+				id: key.id,
 				transports: key.transports ?? undefined,
 			})),
 			authenticatorSelection: {
@@ -87,7 +86,7 @@ export class WebAuthnService {
 
 	@bindThis
 	public async verifyRegistration(userId: MiUser['id'], response: RegistrationResponseJSON): Promise<{
-		credentialID: Uint8Array;
+		credentialID: string;
 		credentialPublicKey: Uint8Array;
 		attestationObject: Uint8Array;
 		fmt: AttestationFormat;
@@ -144,6 +143,7 @@ export class WebAuthnService {
 
 	@bindThis
 	public async initiateAuthentication(userId: MiUser['id']): Promise<PublicKeyCredentialRequestOptionsJSON> {
+		const relyingParty = await this.getRelyingParty();
 		const keys = await this.userSecurityKeysRepository.findBy({
 			userId: userId,
 		});
@@ -153,9 +153,9 @@ export class WebAuthnService {
 		}
 
 		const authenticationOptions = await generateAuthenticationOptions({
-			allowCredentials: keys.map(key => (<PublicKeyCredentialDescriptorFuture>{
-				id: Buffer.from(key.id, 'base64url'),
-				type: 'public-key',
+			rpID: relyingParty.rpId,
+			allowCredentials: keys.map(key => (<{ id: string; transports?: AuthenticatorTransportFuture[]; }>{
+				id: key.id,
 				transports: key.transports ?? undefined,
 			})),
 			userVerification: 'preferred',
@@ -219,7 +219,7 @@ export class WebAuthnService {
 				expectedOrigin: relyingParty.origin,
 				expectedRPID: relyingParty.rpId,
 				authenticator: {
-					credentialID: Buffer.from(key.id, 'base64url'),
+					credentialID: key.id,
 					credentialPublicKey: Buffer.from(key.publicKey, 'base64url'),
 					counter: key.counter,
 					transports: key.transports ? key.transports as AuthenticatorTransportFuture[] : undefined,
diff --git a/packages/backend/src/misc/gen-identicon.ts b/packages/backend/src/misc/gen-identicon.ts
index 62a8ab8ace..342e0f8602 100644
--- a/packages/backend/src/misc/gen-identicon.ts
+++ b/packages/backend/src/misc/gen-identicon.ts
@@ -8,9 +8,8 @@
  * https://en.wikipedia.org/wiki/Identicon
  */
 
-import * as p from 'pureimage';
+import { createCanvas } from '@napi-rs/canvas';
 import gen from 'random-seed';
-import type { WriteStream } from 'node:fs';
 
 const size = 128; // px
 const n = 5; // resolution
@@ -45,9 +44,9 @@ const sideN = Math.floor(n / 2);
 /**
  * Generate buffer of an identicon by seed
  */
-export function genIdenticon(seed: string, stream: WriteStream): Promise<void> {
+export async function genIdenticon(seed: string): Promise<Buffer> {
 	const rand = gen.create(seed);
-	const canvas = p.make(size, size, undefined);
+	const canvas = createCanvas(size, size);
 	const ctx = canvas.getContext('2d');
 
 	const bgColors = colors[rand(colors.length)];
@@ -101,5 +100,5 @@ export function genIdenticon(seed: string, stream: WriteStream): Promise<void> {
 		}
 	}
 
-	return p.encodePNGToStream(canvas, stream);
+	return await canvas.encode('png');
 }
diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts
index 1324cd1361..da17a88e03 100644
--- a/packages/backend/src/server/ServerService.ts
+++ b/packages/backend/src/server/ServerService.ts
@@ -18,7 +18,6 @@ import { DI } from '@/di-symbols.js';
 import type Logger from '@/logger.js';
 import * as Acct from '@/misc/acct.js';
 import { genIdenticon } from '@/misc/gen-identicon.js';
-import { createTemp } from '@/misc/create-temp.js';
 import { UserEntityService } from '@/core/entities/UserEntityService.js';
 import { LoggerService } from '@/core/LoggerService.js';
 import { bindThis } from '@/decorators.js';
@@ -192,9 +191,7 @@ export class ServerService implements OnApplicationShutdown {
 			reply.header('Cache-Control', 'public, max-age=86400');
 
 			if ((await this.metaService.fetch()).enableIdenticonGeneration) {
-				const [temp, cleanup] = await createTemp();
-				await genIdenticon(request.params.x, fs.createWriteStream(temp));
-				return fs.createReadStream(temp).on('close', () => cleanup());
+				return await genIdenticon(request.params.x);
 			} else {
 				return reply.redirect('/static-assets/avatar.png');
 			}
diff --git a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts
index 5f738420f2..65eece5b97 100644
--- a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts
+++ b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts
@@ -96,10 +96,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 			}
 
 			const keyInfo = await this.webAuthnService.verifyRegistration(me.id, ps.credential);
+			const keyId = keyInfo.credentialID;
 
-			const credentialId = Buffer.from(keyInfo.credentialID).toString('base64url');
 			await this.userSecurityKeysRepository.insert({
-				id: credentialId,
+				id: keyId,
 				userId: me.id,
 				name: ps.name,
 				publicKey: Buffer.from(keyInfo.credentialPublicKey).toString('base64url'),
@@ -116,7 +116,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 			}));
 
 			return {
-				id: credentialId,
+				id: keyId,
 				name: ps.name,
 			};
 		});
diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts
index ba2f8b4324..1394616752 100644
--- a/packages/backend/src/server/web/ClientServerService.ts
+++ b/packages/backend/src/server/web/ClientServerService.ts
@@ -199,6 +199,11 @@ export class ClientServerService {
 
 		// Authenticate
 		fastify.addHook('onRequest', async (request, reply) => {
+			if (request.routeOptions.url == null) {
+				reply.code(404).send('Not found');
+				return;
+			}
+
 			// %71ueueとかでリクエストされたら困るため
 			const url = decodeURI(request.routeOptions.url);
 			if (url === bullBoardPath || url.startsWith(bullBoardPath + '/')) {
diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug
index 123336809b..1d9146e22a 100644
--- a/packages/backend/src/server/web/views/base.pug
+++ b/packages/backend/src/server/web/views/base.pug
@@ -36,7 +36,7 @@ html
 		link(rel='prefetch' href=infoImageUrl)
 		link(rel='prefetch' href=notFoundImageUrl)
 		//- https://github.com/misskey-dev/misskey/issues/9842
-		link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.min.css?v2.44.0')
+		link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.min.css?v3.3.0')
 		link(rel='modulepreload' href=`/vite/${clientEntry.file}`)
 
 		if !config.clientManifestExists
diff --git a/packages/frontend/.storybook/preview-head.html b/packages/frontend/.storybook/preview-head.html
index e50c488243..4722fe7f5f 100644
--- a/packages/frontend/.storybook/preview-head.html
+++ b/packages/frontend/.storybook/preview-head.html
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <link rel="preload" href="https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/about-icon.png?raw=true" as="image" type="image/png" crossorigin="anonymous">
 <link rel="preload" href="https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true" as="image" type="image/jpeg" crossorigin="anonymous">
-<link rel="stylesheet" href="https://unpkg.com/@tabler/icons-webfont@2.44.0/tabler-icons.min.css">
+<link rel="stylesheet" href="https://unpkg.com/@tabler/icons-webfont@3.3.0/tabler-icons.min.css">
 <link rel="stylesheet" href="https://unpkg.com/@fontsource/m-plus-rounded-1c/index.css">
 <style>
 	html {
diff --git a/packages/frontend/package.json b/packages/frontend/package.json
index 43a7759fa6..a482373200 100644
--- a/packages/frontend/package.json
+++ b/packages/frontend/package.json
@@ -17,7 +17,7 @@
 		"lint": "pnpm typecheck && pnpm eslint"
 	},
 	"dependencies": {
-		"@discordapp/twemoji": "15.0.2",
+		"@discordapp/twemoji": "15.0.3",
 		"@github/webauthn-json": "2.1.1",
 		"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
 		"@misskey-dev/browser-image-resizer": "2024.1.0",
@@ -25,23 +25,23 @@
 		"@rollup/plugin-replace": "5.0.5",
 		"@rollup/pluginutils": "5.1.0",
 		"@syuilo/aiscript": "0.18.0",
-		"@tabler/icons-webfont": "2.44.0",
-		"@twemoji/parser": "15.0.0",
+		"@tabler/icons-webfont": "3.3.0",
+		"@twemoji/parser": "15.1.1",
 		"@vitejs/plugin-vue": "5.0.4",
-		"@vue/compiler-sfc": "3.4.21",
+		"@vue/compiler-sfc": "3.4.26",
 		"aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.4",
 		"astring": "1.8.6",
 		"broadcast-channel": "7.0.0",
 		"buraha": "0.0.1",
-		"canvas-confetti": "1.9.2",
+		"canvas-confetti": "1.9.3",
 		"chart.js": "4.4.2",
 		"chartjs-adapter-date-fns": "3.0.0",
 		"chartjs-chart-matrix": "2.0.1",
 		"chartjs-plugin-gradient": "0.6.1",
 		"chartjs-plugin-zoom": "2.0.1",
-		"chromatic": "11.0.0",
+		"chromatic": "11.3.0",
 		"compare-versions": "6.1.0",
-		"cropperjs": "2.0.0-beta.4",
+		"cropperjs": "2.0.0-beta.5",
 		"date-fns": "2.30.0",
 		"escape-regexp": "0.0.1",
 		"estree-walker": "3.0.3",
@@ -57,27 +57,27 @@
 		"misskey-reversi": "workspace:*",
 		"photoswipe": "5.4.3",
 		"punycode": "2.3.1",
-		"rollup": "4.12.0",
-		"sanitize-html": "2.12.1",
-		"sass": "1.71.1",
-		"shiki": "1.2.0",
+		"rollup": "4.17.2",
+		"sanitize-html": "2.13.0",
+		"sass": "1.76.0",
+		"shiki": "1.4.0",
 		"strict-event-emitter-types": "2.0.0",
 		"textarea-caret": "3.1.0",
-		"three": "0.162.0",
+		"three": "0.164.1",
 		"throttle-debounce": "5.0.0",
 		"tinycolor2": "1.6.0",
 		"tsc-alias": "1.8.8",
 		"tsconfig-paths": "4.2.0",
-		"typescript": "5.3.3",
+		"typescript": "5.4.5",
 		"uuid": "9.0.1",
-		"v-code-diff": "1.9.0",
-		"vite": "5.1.4",
-		"vue": "3.4.21",
+		"v-code-diff": "1.11.0",
+		"vite": "5.2.11",
+		"vue": "3.4.26",
 		"vuedraggable": "next"
 	},
 	"devDependencies": {
 		"@misskey-dev/eslint-plugin": "1.0.0",
-		"@misskey-dev/summaly": "5.0.3",
+		"@misskey-dev/summaly": "5.1.0",
 		"@storybook/addon-actions": "8.0.9",
 		"@storybook/addon-essentials": "8.0.9",
 		"@storybook/addon-interactions": "8.0.9",
@@ -96,46 +96,46 @@
 		"@storybook/types": "8.0.9",
 		"@storybook/vue3": "8.0.9",
 		"@storybook/vue3-vite": "8.0.9",
-		"@testing-library/vue": "8.0.2",
+		"@testing-library/vue": "8.0.3",
 		"@types/escape-regexp": "0.0.3",
 		"@types/estree": "1.0.5",
 		"@types/matter-js": "0.19.6",
-		"@types/micromatch": "4.0.6",
-		"@types/node": "20.11.22",
+		"@types/micromatch": "4.0.7",
+		"@types/node": "20.12.7",
 		"@types/punycode": "2.1.4",
 		"@types/sanitize-html": "2.11.0",
 		"@types/throttle-debounce": "5.0.2",
 		"@types/tinycolor2": "1.4.6",
 		"@types/uuid": "9.0.8",
 		"@types/ws": "8.5.10",
-		"@typescript-eslint/eslint-plugin": "7.1.0",
-		"@typescript-eslint/parser": "7.1.0",
+		"@typescript-eslint/eslint-plugin": "7.7.1",
+		"@typescript-eslint/parser": "7.7.1",
 		"@vitest/coverage-v8": "0.34.6",
-		"@vue/runtime-core": "3.4.21",
+		"@vue/runtime-core": "3.4.26",
 		"acorn": "8.11.3",
 		"cross-env": "7.0.3",
-		"cypress": "13.6.6",
+		"cypress": "13.8.1",
 		"eslint": "8.57.0",
 		"eslint-plugin-import": "2.29.1",
-		"eslint-plugin-vue": "9.22.0",
+		"eslint-plugin-vue": "9.25.0",
 		"fast-glob": "3.3.2",
-		"happy-dom": "13.6.2",
+		"happy-dom": "14.7.1",
 		"intersection-observer": "0.12.2",
 		"micromatch": "4.0.5",
-		"msw": "2.1.7",
-		"msw-storybook-addon": "2.0.0-beta.1",
+		"msw": "2.2.14",
+		"msw-storybook-addon": "2.0.1",
 		"nodemon": "3.1.0",
 		"prettier": "3.2.5",
-		"react": "18.2.0",
-		"react-dom": "18.2.0",
+		"react": "18.3.1",
+		"react-dom": "18.3.1",
 		"start-server-and-test": "2.0.3",
 		"storybook": "8.0.9",
 		"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",
 		"vite-plugin-turbosnap": "1.0.3",
 		"vitest": "0.34.6",
 		"vitest-fetch-mock": "0.2.2",
-		"vue-component-type-helpers": "1.8.27",
+		"vue-component-type-helpers": "2.0.16",
 		"vue-eslint-parser": "9.4.2",
-		"vue-tsc": "1.8.27"
+		"vue-tsc": "2.0.16"
 	}
 }
diff --git a/packages/frontend/src/_dev_boot_.ts b/packages/frontend/src/_dev_boot_.ts
index eceec76c51..7c6e537fbc 100644
--- a/packages/frontend/src/_dev_boot_.ts
+++ b/packages/frontend/src/_dev_boot_.ts
@@ -6,7 +6,7 @@
 // devモードで起動される際(index.htmlを使うとき)はrouterが暴発してしまってうまく読み込めない。
 // よって、devモードとして起動されるときはビルド時に組み込む形としておく。
 // (pnpm start時はpugファイルの中で静的リソースとして読み込むようになっており、この問題は起こっていない)
-import '@tabler/icons-webfont/tabler-icons.scss';
+import '@tabler/icons-webfont/dist/tabler-icons.scss';
 
 await main();
 
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index a9c75c95c2..6badc7f3ee 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -33,13 +33,13 @@
 		"url": "git+https://github.com/misskey-dev/misskey.js.git"
 	},
 	"devDependencies": {
-		"@microsoft/api-extractor": "7.39.1",
+		"@microsoft/api-extractor": "7.43.1",
 		"@misskey-dev/eslint-plugin": "1.0.0",
-		"@swc/jest": "0.2.31",
+		"@swc/jest": "0.2.36",
 		"@types/jest": "29.5.12",
-		"@types/node": "20.11.22",
-		"@typescript-eslint/eslint-plugin": "7.1.0",
-		"@typescript-eslint/parser": "7.1.0",
+		"@types/node": "20.12.7",
+		"@typescript-eslint/eslint-plugin": "7.7.1",
+		"@typescript-eslint/parser": "7.7.1",
 		"eslint": "8.57.0",
 		"jest": "29.7.0",
 		"jest-fetch-mock": "3.0.3",
@@ -49,9 +49,9 @@
 		"nodemon": "3.1.0",
 		"execa": "8.0.1",
 		"tsd": "0.30.7",
-		"typescript": "5.3.3",
+		"typescript": "5.4.5",
 		"esbuild": "0.19.11",
-		"glob": "10.3.10"
+		"glob": "10.3.12"
 	},
 	"files": [
 		"built"
diff --git a/packages/sw/package.json b/packages/sw/package.json
index bac0cc1ff5..cb59a70238 100644
--- a/packages/sw/package.json
+++ b/packages/sw/package.json
@@ -9,18 +9,18 @@
 		"lint": "pnpm typecheck && pnpm eslint"
 	},
 	"dependencies": {
-		"esbuild": "0.19.11",
+		"esbuild": "0.20.2",
 		"idb-keyval": "6.2.1",
 		"misskey-js": "workspace:*"
 	},
 	"devDependencies": {
 		"@misskey-dev/eslint-plugin": "1.0.0",
-		"@typescript-eslint/parser": "7.1.0",
+		"@typescript-eslint/parser": "7.7.1",
 		"@typescript/lib-webworker": "npm:@types/serviceworker@0.0.67",
 		"eslint": "8.57.0",
 		"eslint-plugin-import": "2.29.1",
 		"nodemon": "3.1.0",
-		"typescript": "5.3.3"
+		"typescript": "5.4.5"
 	},
 	"type": "module"
 }
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8e5cc2d699..9ddc1f1160 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1,4 +1,4 @@
-lockfileVersion: '6.0'
+lockfileVersion: '9.0'
 
 settings:
   autoInstallPeers: true
@@ -13,11 +13,11 @@ importers:
   .:
     dependencies:
       cssnano:
-        specifier: 6.0.5
-        version: 6.0.5(postcss@8.4.35)
+        specifier: 6.1.2
+        version: 6.1.2(postcss@8.4.38)
       esbuild:
-        specifier: 0.19.11
-        version: 0.19.11
+        specifier: 0.20.2
+        version: 0.20.2
       execa:
         specifier: 8.0.1
         version: 8.0.1
@@ -25,8 +25,8 @@ importers:
         specifier: 3.3.2
         version: 3.3.2
       glob:
-        specifier: 10.3.10
-        version: 10.3.10
+        specifier: 10.3.12
+        version: 10.3.12
       ignore-walk:
         specifier: 6.0.4
         version: 6.0.4
@@ -34,37 +34,37 @@ importers:
         specifier: 4.1.0
         version: 4.1.0
       postcss:
-        specifier: 8.4.35
-        version: 8.4.35
+        specifier: 8.4.38
+        version: 8.4.38
       tar:
-        specifier: 6.2.0
-        version: 6.2.0
+        specifier: 6.2.1
+        version: 6.2.1
       terser:
-        specifier: 5.28.1
-        version: 5.28.1
+        specifier: 5.30.3
+        version: 5.30.3
       typescript:
-        specifier: 5.3.3
-        version: 5.3.3
+        specifier: 5.4.5
+        version: 5.4.5
     optionalDependencies:
       '@tensorflow/tfjs-core':
         specifier: 4.4.0
-        version: 4.4.0
+        version: 4.4.0(encoding@0.1.13)
     devDependencies:
       '@types/node':
-        specifier: ^20.11.28
-        version: 20.11.28
+        specifier: 20.12.7
+        version: 20.12.7
       '@typescript-eslint/eslint-plugin':
-        specifier: 7.1.0
-        version: 7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3)
+        specifier: 7.7.1
+        version: 7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
       '@typescript-eslint/parser':
-        specifier: 7.1.0
-        version: 7.1.0(eslint@8.57.0)(typescript@5.3.3)
+        specifier: 7.7.1
+        version: 7.7.1(eslint@8.57.0)(typescript@5.4.5)
       cross-env:
         specifier: 7.0.3
         version: 7.0.3
       cypress:
-        specifier: 13.6.6
-        version: 13.6.6
+        specifier: 13.7.3
+        version: 13.7.3
       eslint:
         specifier: 8.57.0
         version: 8.57.0
@@ -84,17 +84,17 @@ importers:
         specifier: 3.412.0
         version: 3.412.0(@aws-sdk/client-s3@3.412.0)
       '@bull-board/api':
-        specifier: 5.14.2
-        version: 5.14.2(@bull-board/ui@5.14.2)
+        specifier: 5.17.0
+        version: 5.17.0(@bull-board/ui@5.17.0)
       '@bull-board/fastify':
-        specifier: 5.14.2
-        version: 5.14.2
+        specifier: 5.17.0
+        version: 5.17.0
       '@bull-board/ui':
-        specifier: 5.14.2
-        version: 5.14.2
+        specifier: 5.17.0
+        version: 5.17.0
       '@discordapp/twemoji':
-        specifier: 15.0.2
-        version: 15.0.2
+        specifier: 15.0.3
+        version: 15.0.3
       '@fastify/accepts':
         specifier: 4.3.0
         version: 4.3.0
@@ -102,71 +102,74 @@ importers:
         specifier: 9.3.1
         version: 9.3.1
       '@fastify/cors':
-        specifier: 8.5.0
-        version: 8.5.0
+        specifier: 9.0.1
+        version: 9.0.1
       '@fastify/express':
-        specifier: 2.3.0
-        version: 2.3.0
+        specifier: 3.0.0
+        version: 3.0.0
       '@fastify/http-proxy':
-        specifier: 9.3.0
-        version: 9.3.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
+        specifier: 9.5.0
+        version: 9.5.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
       '@fastify/multipart':
-        specifier: 8.1.0
-        version: 8.1.0
-      '@fastify/static':
-        specifier: 6.12.0
-        version: 6.12.0
-      '@fastify/view':
         specifier: 8.2.0
         version: 8.2.0
+      '@fastify/static':
+        specifier: 7.0.3
+        version: 7.0.3
+      '@fastify/view':
+        specifier: 9.1.0
+        version: 9.1.0
       '@misskey-dev/sharp-read-bmp':
         specifier: 1.2.0
         version: 1.2.0
       '@misskey-dev/summaly':
         specifier: 5.1.0
         version: 5.1.0
+      '@napi-rs/canvas':
+        specifier: ^0.1.52
+        version: 0.1.52
       '@nestjs/common':
-        specifier: 10.3.3
-        version: 10.3.3(reflect-metadata@0.2.1)(rxjs@7.8.1)
+        specifier: 10.3.8
+        version: 10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1)
       '@nestjs/core':
-        specifier: 10.3.3
-        version: 10.3.3(@nestjs/common@10.3.3)(@nestjs/platform-express@10.3.3)(reflect-metadata@0.2.1)(rxjs@7.8.1)
+        specifier: 10.3.8
+        version: 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)
       '@nestjs/testing':
-        specifier: 10.3.3
-        version: 10.3.3(@nestjs/common@10.3.3)(@nestjs/core@10.3.3)(@nestjs/platform-express@10.3.3)
+        specifier: 10.3.8
+        version: 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8))
       '@peertube/http-signature':
         specifier: 1.7.0
         version: 1.7.0
       '@simplewebauthn/server':
-        specifier: 9.0.3
-        version: 9.0.3
+        specifier: 10.0.0
+        version: 10.0.0(encoding@0.1.13)
       '@sinonjs/fake-timers':
         specifier: 11.2.2
         version: 11.2.2
       '@smithy/node-http-handler':
-        specifier: 2.1.10
-        version: 2.1.10
+        specifier: 2.5.0
+        version: 2.5.0
       '@swc/cli':
-        specifier: 0.1.63
-        version: 0.1.63(@swc/core@1.3.107)(chokidar@3.5.3)
+        specifier: 0.3.12
+        version: 0.3.12(@swc/core@1.4.17)(chokidar@3.5.3)
       '@swc/core':
-        specifier: 1.3.107
-        version: 1.3.107
+        specifier: 1.4.17
+        version: 1.4.17
       '@twemoji/parser':
-        specifier: 15.0.0
-        version: 15.0.0
+        specifier: 15.1.1
+        version: 15.1.1
       accepts:
         specifier: 1.3.8
         version: 1.3.8
       ajv:
-        specifier: 8.12.0
-        version: 8.12.0
+        specifier: 8.13.0
+        version: 8.13.0
       archiver:
-        specifier: 6.0.1
-        version: 6.0.1
+        specifier: 7.0.1
+        version: 7.0.1
       async-mutex:
-        specifier: 0.4.1
-        version: 0.4.1
+        specifier: 0.5.0
+        version: 0.5.0
       bcryptjs:
         specifier: 2.4.3
         version: 2.4.3
@@ -177,8 +180,8 @@ importers:
         specifier: 1.20.2
         version: 1.20.2
       bullmq:
-        specifier: 5.4.0
-        version: 5.4.0
+        specifier: 5.7.8
+        version: 5.7.8
       cacheable-lookup:
         specifier: 7.0.0
         version: 7.0.0
@@ -210,8 +213,8 @@ importers:
         specifier: 0.1.21
         version: 0.1.21
       fastify:
-        specifier: 4.25.2
-        version: 4.25.2
+        specifier: 4.26.2
+        version: 4.26.2
       fastify-raw-body:
         specifier: 4.3.0
         version: 4.3.0
@@ -228,11 +231,11 @@ importers:
         specifier: 4.0.0
         version: 4.0.0
       got:
-        specifier: 14.2.0
-        version: 14.2.0
+        specifier: 14.2.1
+        version: 14.2.1
       happy-dom:
-        specifier: 10.0.3
-        version: 10.0.3
+        specifier: 14.7.1
+        version: 14.7.1
       hpagent:
         specifier: 1.2.0
         version: 1.2.0
@@ -240,17 +243,17 @@ importers:
         specifier: 1.1.1
         version: 1.1.1
       http-link-header:
-        specifier: 1.1.2
-        version: 1.1.2
+        specifier: 1.1.3
+        version: 1.1.3
       ioredis:
-        specifier: 5.3.2
-        version: 5.3.2
+        specifier: 5.4.1
+        version: 5.4.1
       ip-cidr:
         specifier: 3.1.0
         version: 3.1.0
       ipaddr.js:
-        specifier: 2.1.0
-        version: 2.1.0
+        specifier: 2.2.0
+        version: 2.2.0
       is-svg:
         specifier: 5.0.0
         version: 5.0.0
@@ -258,20 +261,20 @@ importers:
         specifier: 4.1.0
         version: 4.1.0
       jsdom:
-        specifier: 23.2.0
-        version: 23.2.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
+        specifier: 24.0.0
+        version: 24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
       json5:
         specifier: 2.2.3
         version: 2.2.3
       jsonld:
         specifier: 8.3.2
-        version: 8.3.2
+        version: 8.3.2(web-streams-polyfill@3.2.1)
       jsrsasign:
         specifier: 11.1.0
         version: 11.1.0
       meilisearch:
-        specifier: 0.37.0
-        version: 0.37.0
+        specifier: 0.38.0
+        version: 0.38.0(encoding@0.1.13)
       mfm-js:
         specifier: 0.24.0
         version: 0.24.0
@@ -291,8 +294,8 @@ importers:
         specifier: 3.0.0-canary.1
         version: 3.0.0-canary.1
       nanoid:
-        specifier: 5.0.6
-        version: 5.0.6
+        specifier: 5.0.7
+        version: 5.0.7
       nested-property:
         specifier: 4.0.0
         version: 4.0.0
@@ -300,11 +303,11 @@ importers:
         specifier: 3.3.2
         version: 3.3.2
       nodemailer:
-        specifier: 6.9.10
-        version: 6.9.10
+        specifier: 6.9.13
+        version: 6.9.13
       nsfwjs:
         specifier: 2.4.2
-        version: 2.4.2(@tensorflow/tfjs@4.4.0)
+        version: 2.4.2(@tensorflow/tfjs@4.4.0(encoding@0.1.13)(seedrandom@3.0.5))
       oauth:
         specifier: 0.10.0
         version: 0.10.0
@@ -318,14 +321,14 @@ importers:
         specifier: 0.0.14
         version: 0.0.14
       otpauth:
-        specifier: 9.2.2
-        version: 9.2.2
+        specifier: 9.2.3
+        version: 9.2.3
       parse5:
         specifier: 7.1.2
         version: 7.1.2
       pg:
-        specifier: 8.11.3
-        version: 8.11.3
+        specifier: 8.11.5
+        version: 8.11.5
       pkce-challenge:
         specifier: 4.1.0
         version: 4.1.0
@@ -341,9 +344,6 @@ importers:
       punycode:
         specifier: 2.3.1
         version: 2.3.1
-      pureimage:
-        specifier: 0.3.17
-        version: 0.3.17
       qrcode:
         specifier: 1.5.3
         version: 1.5.3
@@ -354,14 +354,14 @@ importers:
         specifier: 3.4.1
         version: 3.4.1
       re2:
-        specifier: 1.20.9
-        version: 1.20.9
+        specifier: 1.20.10
+        version: 1.20.10
       redis-lock:
         specifier: 0.1.4
         version: 0.1.4
       reflect-metadata:
-        specifier: 0.2.1
-        version: 0.2.1
+        specifier: 0.2.2
+        version: 0.2.2
       rename:
         specifier: 1.0.4
         version: 1.0.4
@@ -372,14 +372,14 @@ importers:
         specifier: 7.8.1
         version: 7.8.1
       sanitize-html:
-        specifier: 2.12.1
-        version: 2.12.1
+        specifier: 2.13.0
+        version: 2.13.0
       secure-json-parse:
         specifier: 2.7.0
         version: 2.7.0
       sharp:
-        specifier: 0.33.2
-        version: 0.33.2
+        specifier: 0.33.3
+        version: 0.33.3
       slacc:
         specifier: 0.0.10
         version: 0.0.10
@@ -390,14 +390,14 @@ importers:
         specifier: 2.1.0
         version: 2.1.0
       systeminformation:
-        specifier: 5.22.0
-        version: 5.22.0
+        specifier: 5.22.7
+        version: 5.22.7
       tinycolor2:
         specifier: 1.6.0
         version: 1.6.0
       tmp:
-        specifier: 0.2.2
-        version: 0.2.2
+        specifier: 0.2.3
+        version: 0.2.3
       tsc-alias:
         specifier: 1.8.8
         version: 1.8.8
@@ -406,10 +406,10 @@ importers:
         version: 4.2.0
       typeorm:
         specifier: 0.3.20
-        version: 0.3.20(ioredis@5.3.2)(pg@8.11.3)
+        version: 0.3.20(ioredis@5.4.1)(pg@8.11.5)
       typescript:
-        specifier: 5.3.3
-        version: 5.3.3
+        specifier: 5.4.5
+        version: 5.4.5
       ulid:
         specifier: 2.3.0
         version: 2.3.0
@@ -420,8 +420,8 @@ importers:
         specifier: 3.6.7
         version: 3.6.7
       ws:
-        specifier: 8.16.0
-        version: 8.16.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
+        specifier: 8.17.0
+        version: 8.17.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
       xev:
         specifier: 3.0.2
         version: 3.0.2
@@ -464,10 +464,10 @@ importers:
         version: 1.3.56
       '@tensorflow/tfjs':
         specifier: 4.4.0
-        version: 4.4.0(seedrandom@3.0.5)
+        version: 4.4.0(encoding@0.1.13)(seedrandom@3.0.5)
       '@tensorflow/tfjs-node':
         specifier: 4.4.0
-        version: 4.4.0(seedrandom@3.0.5)
+        version: 4.4.0(encoding@0.1.13)(seedrandom@3.0.5)
       bufferutil:
         specifier: 4.0.7
         version: 4.0.7
@@ -519,16 +519,16 @@ importers:
         version: 29.7.0
       '@misskey-dev/eslint-plugin':
         specifier: 1.0.0
-        version: 1.0.0(@typescript-eslint/eslint-plugin@7.1.0)(@typescript-eslint/parser@7.1.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
+        version: 1.0.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0)
       '@nestjs/platform-express':
-        specifier: 10.3.3
-        version: 10.3.3(@nestjs/common@10.3.3)(@nestjs/core@10.3.3)
+        specifier: 10.3.8
+        version: 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)
       '@simplewebauthn/types':
-        specifier: 9.0.1
-        version: 9.0.1
+        specifier: 10.0.0
+        version: 10.0.0
       '@swc/jest':
-        specifier: 0.2.31
-        version: 0.2.31(@swc/core@1.3.107)
+        specifier: 0.2.36
+        version: 0.2.36(@swc/core@1.4.17)
       '@types/accepts':
         specifier: 1.3.7
         version: 1.3.7
@@ -557,8 +557,8 @@ importers:
         specifier: 1.0.5
         version: 1.0.5
       '@types/jest':
-        specifier: 29.5.11
-        version: 29.5.11
+        specifier: 29.5.12
+        version: 29.5.12
       '@types/js-yaml':
         specifier: 4.0.9
         version: 4.0.9
@@ -569,8 +569,8 @@ importers:
         specifier: 1.5.13
         version: 1.5.13
       '@types/jsrsasign':
-        specifier: 10.5.12
-        version: 10.5.12
+        specifier: 10.5.14
+        version: 10.5.14
       '@types/mime-types':
         specifier: 2.1.4
         version: 2.1.4
@@ -578,26 +578,26 @@ importers:
         specifier: 0.7.34
         version: 0.7.34
       '@types/node':
-        specifier: 20.11.22
-        version: 20.11.22
+        specifier: 20.12.7
+        version: 20.12.7
       '@types/node-fetch':
         specifier: 3.0.3
         version: 3.0.3
       '@types/nodemailer':
-        specifier: 6.4.14
-        version: 6.4.14
+        specifier: 6.4.15
+        version: 6.4.15
       '@types/oauth':
         specifier: 0.9.4
         version: 0.9.4
       '@types/oauth2orize':
-        specifier: 1.11.3
-        version: 1.11.3
+        specifier: 1.11.5
+        version: 1.11.5
       '@types/oauth2orize-pkce':
         specifier: 0.1.2
         version: 0.1.2
       '@types/pg':
-        specifier: 8.11.2
-        version: 8.11.2
+        specifier: 8.11.5
+        version: 8.11.5
       '@types/pug':
         specifier: 2.0.10
         version: 2.0.10
@@ -644,11 +644,11 @@ importers:
         specifier: 8.5.10
         version: 8.5.10
       '@typescript-eslint/eslint-plugin':
-        specifier: 7.1.0
-        version: 7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3)
+        specifier: 7.7.1
+        version: 7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
       '@typescript-eslint/parser':
-        specifier: 7.1.0
-        version: 7.1.0(eslint@8.57.0)(typescript@5.3.3)
+        specifier: 7.7.1
+        version: 7.7.1(eslint@8.57.0)(typescript@5.4.5)
       aws-sdk-client-mock:
         specifier: 3.0.1
         version: 3.0.1
@@ -660,7 +660,7 @@ importers:
         version: 8.57.0
       eslint-plugin-import:
         specifier: 2.29.1
-        version: 2.29.1(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)
+        version: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)
       execa:
         specifier: 8.0.1
         version: 8.0.1
@@ -669,7 +669,7 @@ importers:
         version: 9.0.0
       jest:
         specifier: 29.7.0
-        version: 29.7.0(@types/node@20.11.22)
+        version: 29.7.0(@types/node@20.12.7)
       jest-mock:
         specifier: 29.7.0
         version: 29.7.0
@@ -686,8 +686,8 @@ importers:
   packages/frontend:
     dependencies:
       '@discordapp/twemoji':
-        specifier: 15.0.2
-        version: 15.0.2
+        specifier: 15.0.3
+        version: 15.0.3
       '@github/webauthn-json':
         specifier: 2.1.1
         version: 2.1.1
@@ -699,31 +699,31 @@ importers:
         version: 2024.1.0
       '@rollup/plugin-json':
         specifier: 6.1.0
-        version: 6.1.0(rollup@4.12.0)
+        version: 6.1.0(rollup@4.17.2)
       '@rollup/plugin-replace':
         specifier: 5.0.5
-        version: 5.0.5(rollup@4.12.0)
+        version: 5.0.5(rollup@4.17.2)
       '@rollup/pluginutils':
         specifier: 5.1.0
-        version: 5.1.0(rollup@4.12.0)
+        version: 5.1.0(rollup@4.17.2)
       '@syuilo/aiscript':
         specifier: 0.18.0
         version: 0.18.0
       '@tabler/icons-webfont':
-        specifier: 2.44.0
-        version: 2.44.0
+        specifier: 3.3.0
+        version: 3.3.0
       '@twemoji/parser':
-        specifier: 15.0.0
-        version: 15.0.0
+        specifier: 15.1.1
+        version: 15.1.1
       '@vitejs/plugin-vue':
         specifier: 5.0.4
-        version: 5.0.4(vite@5.1.4)(vue@3.4.21)
+        version: 5.0.4(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))(vue@3.4.26(typescript@5.4.5))
       '@vue/compiler-sfc':
-        specifier: 3.4.21
-        version: 3.4.21
+        specifier: 3.4.26
+        version: 3.4.26
       aiscript-vscode:
         specifier: github:aiscript-dev/aiscript-vscode#v0.1.4
-        version: github.com/aiscript-dev/aiscript-vscode/3f79d6f0550369267220aa67702287948d885424
+        version: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/3f79d6f0550369267220aa67702287948d885424
       astring:
         specifier: 1.8.6
         version: 1.8.6
@@ -734,8 +734,8 @@ importers:
         specifier: 0.0.1
         version: 0.0.1
       canvas-confetti:
-        specifier: 1.9.2
-        version: 1.9.2
+        specifier: 1.9.3
+        version: 1.9.3
       chart.js:
         specifier: 4.4.2
         version: 4.4.2
@@ -752,14 +752,14 @@ importers:
         specifier: 2.0.1
         version: 2.0.1(chart.js@4.4.2)
       chromatic:
-        specifier: 11.0.0
-        version: 11.0.0
+        specifier: 11.3.0
+        version: 11.3.0
       compare-versions:
         specifier: 6.1.0
         version: 6.1.0
       cropperjs:
-        specifier: 2.0.0-beta.4
-        version: 2.0.0-beta.4
+        specifier: 2.0.0-beta.5
+        version: 2.0.0-beta.5
       date-fns:
         specifier: 2.30.0
         version: 2.30.0
@@ -806,17 +806,17 @@ importers:
         specifier: 2.3.1
         version: 2.3.1
       rollup:
-        specifier: 4.12.0
-        version: 4.12.0
+        specifier: 4.17.2
+        version: 4.17.2
       sanitize-html:
-        specifier: 2.12.1
-        version: 2.12.1
+        specifier: 2.13.0
+        version: 2.13.0
       sass:
-        specifier: 1.71.1
-        version: 1.71.1
+        specifier: 1.76.0
+        version: 1.76.0
       shiki:
-        specifier: 1.2.0
-        version: 1.2.0
+        specifier: 1.4.0
+        version: 1.4.0
       strict-event-emitter-types:
         specifier: 2.0.0
         version: 2.0.0
@@ -824,8 +824,8 @@ importers:
         specifier: 3.1.0
         version: 3.1.0
       three:
-        specifier: 0.162.0
-        version: 0.162.0
+        specifier: 0.164.1
+        version: 0.164.1
       throttle-debounce:
         specifier: 5.0.0
         version: 5.0.0
@@ -839,42 +839,42 @@ importers:
         specifier: 4.2.0
         version: 4.2.0
       typescript:
-        specifier: 5.3.3
-        version: 5.3.3
+        specifier: 5.4.5
+        version: 5.4.5
       uuid:
         specifier: 9.0.1
         version: 9.0.1
       v-code-diff:
-        specifier: 1.9.0
-        version: 1.9.0(vue@3.4.21)
+        specifier: 1.11.0
+        version: 1.11.0(vue@3.4.26(typescript@5.4.5))
       vite:
-        specifier: 5.1.4
-        version: 5.1.4(@types/node@20.11.22)(sass@1.71.1)(terser@5.28.1)
+        specifier: 5.2.11
+        version: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
       vue:
-        specifier: 3.4.21
-        version: 3.4.21(typescript@5.3.3)
+        specifier: 3.4.26
+        version: 3.4.26(typescript@5.4.5)
       vuedraggable:
         specifier: next
-        version: 4.1.0(vue@3.4.21)
+        version: 4.1.0(vue@3.4.26(typescript@5.4.5))
     devDependencies:
       '@misskey-dev/eslint-plugin':
         specifier: 1.0.0
-        version: 1.0.0(@typescript-eslint/eslint-plugin@7.1.0)(@typescript-eslint/parser@7.1.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
+        version: 1.0.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0)
       '@misskey-dev/summaly':
-        specifier: 5.0.3
-        version: 5.0.3
+        specifier: 5.1.0
+        version: 5.1.0
       '@storybook/addon-actions':
         specifier: 8.0.9
         version: 8.0.9
       '@storybook/addon-essentials':
         specifier: 8.0.9
-        version: 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
+        version: 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/addon-interactions':
         specifier: 8.0.9
-        version: 8.0.9(vitest@0.34.6)
+        version: 8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
       '@storybook/addon-links':
         specifier: 8.0.9
-        version: 8.0.9(react@18.2.0)
+        version: 8.0.9(react@18.3.1)
       '@storybook/addon-mdx-gfm':
         specifier: 8.0.9
         version: 8.0.9
@@ -883,43 +883,43 @@ importers:
         version: 8.0.9
       '@storybook/blocks':
         specifier: 8.0.9
-        version: 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
+        version: 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/components':
         specifier: 8.0.9
-        version: 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
+        version: 8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/core-events':
         specifier: 8.0.9
         version: 8.0.9
       '@storybook/manager-api':
         specifier: 8.0.9
-        version: 8.0.9(react-dom@18.2.0)(react@18.2.0)
+        version: 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/preview-api':
         specifier: 8.0.9
         version: 8.0.9
       '@storybook/react':
         specifier: 8.0.9
-        version: 8.0.9(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)
+        version: 8.0.9(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
       '@storybook/react-vite':
         specifier: 8.0.9
-        version: 8.0.9(react-dom@18.2.0)(react@18.2.0)(rollup@4.12.0)(typescript@5.3.3)(vite@5.1.4)
+        version: 8.0.9(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.17.2)(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))
       '@storybook/test':
         specifier: 8.0.9
-        version: 8.0.9(vitest@0.34.6)
+        version: 8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
       '@storybook/theming':
         specifier: 8.0.9
-        version: 8.0.9(react-dom@18.2.0)(react@18.2.0)
+        version: 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/types':
         specifier: 8.0.9
         version: 8.0.9
       '@storybook/vue3':
         specifier: 8.0.9
-        version: 8.0.9(vue@3.4.21)
+        version: 8.0.9(encoding@0.1.13)(vue@3.4.26(typescript@5.4.5))
       '@storybook/vue3-vite':
         specifier: 8.0.9
-        version: 8.0.9(react-dom@18.2.0)(react@18.2.0)(vite@5.1.4)(vue@3.4.21)
+        version: 8.0.9(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))(vue@3.4.26(typescript@5.4.5))
       '@testing-library/vue':
-        specifier: 8.0.2
-        version: 8.0.2(@vue/compiler-sfc@3.4.21)(vue@3.4.21)
+        specifier: 8.0.3
+        version: 8.0.3(@vue/compiler-sfc@3.4.26)(@vue/server-renderer@3.4.25(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))
       '@types/escape-regexp':
         specifier: 0.0.3
         version: 0.0.3
@@ -930,11 +930,11 @@ importers:
         specifier: 0.19.6
         version: 0.19.6
       '@types/micromatch':
-        specifier: 4.0.6
-        version: 4.0.6
+        specifier: 4.0.7
+        version: 4.0.7
       '@types/node':
-        specifier: 20.11.22
-        version: 20.11.22
+        specifier: 20.12.7
+        version: 20.12.7
       '@types/punycode':
         specifier: 2.1.4
         version: 2.1.4
@@ -954,17 +954,17 @@ importers:
         specifier: 8.5.10
         version: 8.5.10
       '@typescript-eslint/eslint-plugin':
-        specifier: 7.1.0
-        version: 7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3)
+        specifier: 7.7.1
+        version: 7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
       '@typescript-eslint/parser':
-        specifier: 7.1.0
-        version: 7.1.0(eslint@8.57.0)(typescript@5.3.3)
+        specifier: 7.7.1
+        version: 7.7.1(eslint@8.57.0)(typescript@5.4.5)
       '@vitest/coverage-v8':
         specifier: 0.34.6
-        version: 0.34.6(vitest@0.34.6)
+        version: 0.34.6(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
       '@vue/runtime-core':
-        specifier: 3.4.21
-        version: 3.4.21
+        specifier: 3.4.26
+        version: 3.4.26
       acorn:
         specifier: 8.11.3
         version: 8.11.3
@@ -972,23 +972,23 @@ importers:
         specifier: 7.0.3
         version: 7.0.3
       cypress:
-        specifier: 13.6.6
-        version: 13.6.6
+        specifier: 13.8.1
+        version: 13.8.1
       eslint:
         specifier: 8.57.0
         version: 8.57.0
       eslint-plugin-import:
         specifier: 2.29.1
-        version: 2.29.1(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)
+        version: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)
       eslint-plugin-vue:
-        specifier: 9.22.0
-        version: 9.22.0(eslint@8.57.0)
+        specifier: 9.25.0
+        version: 9.25.0(eslint@8.57.0)
       fast-glob:
         specifier: 3.3.2
         version: 3.3.2
       happy-dom:
-        specifier: 13.6.2
-        version: 13.6.2
+        specifier: 14.7.1
+        version: 14.7.1
       intersection-observer:
         specifier: 0.12.2
         version: 0.12.2
@@ -996,11 +996,11 @@ importers:
         specifier: 4.0.5
         version: 4.0.5
       msw:
-        specifier: 2.1.7
-        version: 2.1.7(typescript@5.3.3)
+        specifier: 2.2.14
+        version: 2.2.14(typescript@5.4.5)
       msw-storybook-addon:
-        specifier: 2.0.0-beta.1
-        version: 2.0.0-beta.1(msw@2.1.7)
+        specifier: 2.0.1
+        version: 2.0.1(msw@2.2.14(typescript@5.4.5))
       nodemon:
         specifier: 3.1.0
         version: 3.1.0
@@ -1008,38 +1008,38 @@ importers:
         specifier: 3.2.5
         version: 3.2.5
       react:
-        specifier: 18.2.0
-        version: 18.2.0
+        specifier: 18.3.1
+        version: 18.3.1
       react-dom:
-        specifier: 18.2.0
-        version: 18.2.0(react@18.2.0)
+        specifier: 18.3.1
+        version: 18.3.1(react@18.3.1)
       start-server-and-test:
         specifier: 2.0.3
         version: 2.0.3
       storybook:
         specifier: 8.0.9
-        version: 8.0.9(react-dom@18.2.0)(react@18.2.0)
+        version: 8.0.9(@babel/preset-env@7.23.5(@babel/core@7.24.0))(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)
       storybook-addon-misskey-theme:
         specifier: github:misskey-dev/storybook-addon-misskey-theme
-        version: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.0.9)(@storybook/components@8.0.9)(@storybook/core-events@8.0.9)(@storybook/manager-api@8.0.9)(@storybook/preview-api@8.0.9)(@storybook/theming@8.0.9)(@storybook/types@8.0.9)(react-dom@18.2.0)(react@18.2.0)
+        version: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/components@8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/core-events@8.0.9)(@storybook/manager-api@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/preview-api@8.0.9)(@storybook/theming@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/types@8.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       vite-plugin-turbosnap:
         specifier: 1.0.3
         version: 1.0.3
       vitest:
         specifier: 0.34.6
-        version: 0.34.6(happy-dom@13.6.2)(sass@1.71.1)(terser@5.28.1)
+        version: 0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)
       vitest-fetch-mock:
         specifier: 0.2.2
-        version: 0.2.2(vitest@0.34.6)
+        version: 0.2.2(encoding@0.1.13)(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
       vue-component-type-helpers:
-        specifier: 1.8.27
-        version: 1.8.27
+        specifier: 2.0.16
+        version: 2.0.16
       vue-eslint-parser:
         specifier: 9.4.2
         version: 9.4.2(eslint@8.57.0)
       vue-tsc:
-        specifier: 1.8.27
-        version: 1.8.27(typescript@5.3.3)
+        specifier: 2.0.16
+        version: 2.0.16(typescript@5.4.5)
 
   packages/misskey-bubble-game:
     dependencies:
@@ -1055,7 +1055,7 @@ importers:
     devDependencies:
       '@misskey-dev/eslint-plugin':
         specifier: 1.0.0
-        version: 1.0.0(@typescript-eslint/eslint-plugin@7.1.0)(@typescript-eslint/parser@7.1.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
+        version: 1.0.0(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0))(eslint@8.57.0)
       '@types/matter-js':
         specifier: 0.19.6
         version: 0.19.6
@@ -1067,7 +1067,7 @@ importers:
         version: 3.0.8
       '@typescript-eslint/eslint-plugin':
         specifier: 7.1.0
-        version: 7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3)
+        version: 7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3)
       '@typescript-eslint/parser':
         specifier: 7.1.0
         version: 7.1.0(eslint@8.57.0)(typescript@5.3.3)
@@ -1100,26 +1100,26 @@ importers:
         version: 4.4.0
     devDependencies:
       '@microsoft/api-extractor':
-        specifier: 7.39.1
-        version: 7.39.1(@types/node@20.11.22)
+        specifier: 7.43.1
+        version: 7.43.1(@types/node@20.12.7)
       '@misskey-dev/eslint-plugin':
         specifier: 1.0.0
-        version: 1.0.0(@typescript-eslint/eslint-plugin@7.1.0)(@typescript-eslint/parser@7.1.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
+        version: 1.0.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0)
       '@swc/jest':
-        specifier: 0.2.31
-        version: 0.2.31(@swc/core@1.3.107)
+        specifier: 0.2.36
+        version: 0.2.36(@swc/core@1.4.17)
       '@types/jest':
         specifier: 29.5.12
         version: 29.5.12
       '@types/node':
-        specifier: 20.11.22
-        version: 20.11.22
+        specifier: 20.12.7
+        version: 20.12.7
       '@typescript-eslint/eslint-plugin':
-        specifier: 7.1.0
-        version: 7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3)
+        specifier: 7.7.1
+        version: 7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
       '@typescript-eslint/parser':
-        specifier: 7.1.0
-        version: 7.1.0(eslint@8.57.0)(typescript@5.3.3)
+        specifier: 7.7.1
+        version: 7.7.1(eslint@8.57.0)(typescript@5.4.5)
       esbuild:
         specifier: 0.19.11
         version: 0.19.11
@@ -1130,14 +1130,14 @@ importers:
         specifier: 8.0.1
         version: 8.0.1
       glob:
-        specifier: 10.3.10
-        version: 10.3.10
+        specifier: 10.3.12
+        version: 10.3.12
       jest:
         specifier: 29.7.0
-        version: 29.7.0(@types/node@20.11.22)
+        version: 29.7.0(@types/node@20.12.7)
       jest-fetch-mock:
         specifier: 3.0.3
-        version: 3.0.3
+        version: 3.0.3(encoding@0.1.13)
       jest-websocket-mock:
         specifier: 2.5.0
         version: 2.5.0
@@ -1154,14 +1154,14 @@ importers:
         specifier: 0.30.7
         version: 0.30.7
       typescript:
-        specifier: 5.3.3
-        version: 5.3.3
+        specifier: 5.4.5
+        version: 5.4.5
 
   packages/misskey-js/generator:
     devDependencies:
       '@misskey-dev/eslint-plugin':
         specifier: ^1.0.0
-        version: 1.0.0(@typescript-eslint/eslint-plugin@6.11.0)(@typescript-eslint/parser@6.11.0)(eslint-plugin-import@2.29.1)(eslint@8.53.0)
+        version: 1.0.0(@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0)(typescript@5.3.3))(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0))(eslint@8.53.0)
       '@readme/openapi-parser':
         specifier: 2.5.0
         version: 2.5.0(openapi-types@12.1.3)
@@ -1170,7 +1170,7 @@ importers:
         version: 20.9.1
       '@typescript-eslint/eslint-plugin':
         specifier: 6.11.0
-        version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.3)
+        version: 6.11.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0)(typescript@5.3.3)
       '@typescript-eslint/parser':
         specifier: 6.11.0
         version: 6.11.0(eslint@8.53.0)(typescript@5.3.3)
@@ -1201,13 +1201,13 @@ importers:
     devDependencies:
       '@misskey-dev/eslint-plugin':
         specifier: 1.0.0
-        version: 1.0.0(@typescript-eslint/eslint-plugin@7.1.0)(@typescript-eslint/parser@7.1.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
+        version: 1.0.0(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0))(eslint@8.57.0)
       '@types/node':
         specifier: 20.11.5
         version: 20.11.5
       '@typescript-eslint/eslint-plugin':
         specifier: 7.1.0
-        version: 7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3)
+        version: 7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3)
       '@typescript-eslint/parser':
         specifier: 7.1.0
         version: 7.1.0(eslint@8.57.0)(typescript@5.3.3)
@@ -1233,8 +1233,8 @@ importers:
   packages/sw:
     dependencies:
       esbuild:
-        specifier: 0.19.11
-        version: 0.19.11
+        specifier: 0.20.2
+        version: 0.20.2
       idb-keyval:
         specifier: 6.2.1
         version: 6.2.1
@@ -1244,93 +1244,9966 @@ importers:
     devDependencies:
       '@misskey-dev/eslint-plugin':
         specifier: 1.0.0
-        version: 1.0.0(@typescript-eslint/eslint-plugin@7.1.0)(@typescript-eslint/parser@7.1.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
+        version: 1.0.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0)
       '@typescript-eslint/parser':
-        specifier: 7.1.0
-        version: 7.1.0(eslint@8.57.0)(typescript@5.3.3)
+        specifier: 7.7.1
+        version: 7.7.1(eslint@8.57.0)(typescript@5.4.5)
       '@typescript/lib-webworker':
         specifier: npm:@types/serviceworker@0.0.67
-        version: /@types/serviceworker@0.0.67
+        version: '@types/serviceworker@0.0.67'
       eslint:
         specifier: 8.57.0
         version: 8.57.0
       eslint-plugin-import:
         specifier: 2.29.1
-        version: 2.29.1(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)
+        version: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)
       nodemon:
         specifier: 3.1.0
         version: 3.1.0
       typescript:
-        specifier: 5.3.3
-        version: 5.3.3
+        specifier: 5.4.5
+        version: 5.4.5
 
 packages:
 
-  /@aashutoshrathi/word-wrap@1.2.6:
+  '@aashutoshrathi/word-wrap@1.2.6':
     resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
     engines: {node: '>=0.10.0'}
-    dev: true
 
-  /@adobe/css-tools@4.3.3:
+  '@adobe/css-tools@4.3.3':
     resolution: {integrity: sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==}
-    dev: true
 
-  /@ampproject/remapping@2.2.1:
+  '@aiscript-dev/aiscript-languageserver@https://github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz':
+    resolution: {tarball: https://github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz}
+    version: 0.1.6
+    hasBin: true
+
+  '@ampproject/remapping@2.2.1':
     resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==}
     engines: {node: '>=6.0.0'}
+
+  '@apidevtools/openapi-schemas@2.1.0':
+    resolution: {integrity: sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==}
+    engines: {node: '>=10'}
+
+  '@apidevtools/swagger-methods@3.0.2':
+    resolution: {integrity: sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==}
+
+  '@aw-web-design/x-default-browser@1.4.126':
+    resolution: {integrity: sha512-Xk1sIhyNC/esHGGVjL/niHLowM0csl/kFO5uawBy4IrWwy0o1G8LGt3jP6nmWGz+USxeeqbihAmp/oVZju6wug==}
+    hasBin: true
+
+  '@aws-crypto/crc32@3.0.0':
+    resolution: {integrity: sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==}
+
+  '@aws-crypto/crc32c@3.0.0':
+    resolution: {integrity: sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w==}
+
+  '@aws-crypto/ie11-detection@3.0.0':
+    resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==}
+
+  '@aws-crypto/sha1-browser@3.0.0':
+    resolution: {integrity: sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw==}
+
+  '@aws-crypto/sha256-browser@3.0.0':
+    resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==}
+
+  '@aws-crypto/sha256-js@3.0.0':
+    resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==}
+
+  '@aws-crypto/supports-web-crypto@3.0.0':
+    resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==}
+
+  '@aws-crypto/util@3.0.0':
+    resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==}
+
+  '@aws-sdk/client-s3@3.412.0':
+    resolution: {integrity: sha512-sNrlx9sSBmFUCqMgTznwk9Fee3PJat0nZ3RIDR5Crhsld/eexxrqb6TYKsxzFfBfXTL/oPh+/S5driRV2xsB8A==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/client-sso@3.410.0':
+    resolution: {integrity: sha512-MC9GrgwtlOuSL2WS3DRM3dQ/5y+49KSMMJRH6JiEcU5vE0dX/OtEcX+VfEwpi73x5pSfIjm7xnzjzOFx+sQBIg==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/client-sts@3.410.0':
+    resolution: {integrity: sha512-e6VMrBJtnTxxUXwDmkADGIvyppmDMFf4+cGGA68tVCUm1cFNlCI6M/67bVSIPN/WVKAAfhEL5O2vVXCM7aatYg==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/credential-provider-env@3.410.0':
+    resolution: {integrity: sha512-c7TB9LbN0PkFOsXI0lcRJnqPNOmc4VBvrHf8jP/BkTDg4YUoKQKOFd4d0SqzODmlZiAyoMQVZTR4ISZo95Zj4Q==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/credential-provider-ini@3.410.0':
+    resolution: {integrity: sha512-D8rcr5bRCFD0f42MPQ7K6TWZq5d3pfqrKINL1/bpfkK5BJbvq1BGYmR88UC6CLpTRtZ1LHY2HgYG0fp/2zjjww==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/credential-provider-node@3.410.0':
+    resolution: {integrity: sha512-0wmVm33T/j1FS7MZ/j+WsPlgSc0YnCXnpbWSov1Mn6R86SHI2b2JhdIPRRE4XbGfyW2QGNUl2CwoZVaqhXeF5g==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/credential-provider-process@3.410.0':
+    resolution: {integrity: sha512-BMju1hlDCDNkkSZpKF5SQ8G0WCLRj6/Jvw9QmudLHJuVwYJXEW1r2AsVMg98OZ3hB9G+MAvHruHZIbMiNmUMXQ==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/credential-provider-sso@3.410.0':
+    resolution: {integrity: sha512-zEaoY/sY+KYTlQUkp9dvveAHf175b8RIt0DsQkDrRPtrg/RBHR00r5rFvz9+nrwsR8546RaBU7h/zzTaQGhmcA==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/credential-provider-web-identity@3.410.0':
+    resolution: {integrity: sha512-cE0l8LmEHdWbDkdPNgrfdYSgp4/cIVXrjUKI1QCATA729CrHZ/OQjB/maOBOrMHO9YTiggko887NkslVvwVB7w==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/lib-storage@3.412.0':
+    resolution: {integrity: sha512-uAdVtNuip06rJOs28zVrYXLNeHfKraxvJRTzTA+DW1dXkzh70GTKqDKHWH9IJkW/xMTE6wGSM+fDs8jsMOn/yA==}
+    engines: {node: '>=14.0.0'}
+    peerDependencies:
+      '@aws-sdk/client-s3': ^3.0.0
+
+  '@aws-sdk/middleware-bucket-endpoint@3.410.0':
+    resolution: {integrity: sha512-pUGrpFgCKf9fDHu01JJhhw+MUImheS0HFlZwNG37OMubkxUAbCdmYGewGxfTCUvWyZJtx9bVjrSu6gG7w+RARg==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/middleware-expect-continue@3.410.0':
+    resolution: {integrity: sha512-e5YqGCNmW99GZjEPPujJ02RlEZql19U40oORysBhVF7mKz8BBvF3s8l37tvu37oxebDEkh1u/2cm2+ggOXxLjQ==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/middleware-flexible-checksums@3.410.0':
+    resolution: {integrity: sha512-IK7KlvEKtrQVBfmAp/MmGd0wbWLuN2GZwwfAmsU0qFb0f5vOVUbKDsu6tudtDKCBG9uXyTEsx3/QGvoK2zDy+g==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/middleware-host-header@3.410.0':
+    resolution: {integrity: sha512-ED/OVcyITln5rrxnajZP+V0PN1nug+gSDHJDqdDo/oLy7eiDr/ZWn3nlWW7WcMplQ1/Jnb+hK0UetBp/25XooA==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/middleware-location-constraint@3.410.0':
+    resolution: {integrity: sha512-jAftSpOpw/5AdpOJ/cGiXCb+Vv22KXR5QZmxmllUDsnlm18672tpRaI2plmu/1d98CVvqhY61eSklFMrIf2c4w==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/middleware-logger@3.410.0':
+    resolution: {integrity: sha512-YtmKYCVtBfScq3/UFJk+aSZOktKJBNZL9DaSc2aPcy/goCVsYDOkGwtHk0jIkC1JRSNCkVTqL7ya60sSr8zaQQ==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/middleware-recursion-detection@3.410.0':
+    resolution: {integrity: sha512-KWaes5FLzRqj28vaIEE4Bimpga2E596WdPF2HaH6zsVMJddoRDsc3ZX9ZhLOGrXzIO1RqBd0QxbLrM0S/B2aOQ==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/middleware-sdk-s3@3.410.0':
+    resolution: {integrity: sha512-K2sG2V1ZkezYMCIy3uMt0MwtflcfIwLptwm0iFLaYitiINZQ1tcslk9ggAjyTHg0rslDSI4/zjkhy8VHFOV7HA==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/middleware-sdk-sts@3.410.0':
+    resolution: {integrity: sha512-YfBpctDocRR4CcROoDueJA7D+aMLBV8nTFfmVNdLLLgyuLZ/AUR11VQSu1lf9gQZKl8IpKE/BLf2fRE/qV1ZuA==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/middleware-signing@3.410.0':
+    resolution: {integrity: sha512-KBAZ/eoAJUSJv5us2HsKwK2OszG2s9FEyKpEhgnHLcbbKzW873zHBH5GcOGEQu4AWArTy2ndzJu3FF+9/J9hJQ==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/middleware-ssec@3.410.0':
+    resolution: {integrity: sha512-DNsjVTXoxIh+PuW9o45CFaMiconbuZRm19MC3NA1yNCaCj3ZxD5OdXAutq6UjQdrx8UG4EjUlCJEEvBKmboITw==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/middleware-user-agent@3.410.0':
+    resolution: {integrity: sha512-ZayDtLfvCZUohSxQc/49BfoU/y6bDHLfLdyyUJbJ54Sv8zQcrmdyKvCBFUZwE6tHQgAmv9/ZT18xECMl+xiONA==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/signature-v4-multi-region@3.412.0':
+    resolution: {integrity: sha512-ijxOeYpNDuk2T940S9HYcZ1C+wTP9vqp1Cw37zw9whVY2mKV3Vr7i+44D4FQ5HhWULgdwhjD7IctbNxPIPzUZQ==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/token-providers@3.410.0':
+    resolution: {integrity: sha512-d5Nc0xydkH/X0LA1HDyhGY5sEv4LuADFk+QpDtT8ogLilcre+b1jpdY8Sih/gd1KoGS1H+d1tz2hSGwUHAbUbw==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/types@3.410.0':
+    resolution: {integrity: sha512-D7iaUCszv/v04NDaZUmCmekamy6VD/lKozm/3gS9+dkfU6cC2CsNoUfPV8BlV6dPdw0oWgF91am3I1stdvfVrQ==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/types@3.413.0':
+    resolution: {integrity: sha512-j1xib0f/TazIFc5ySIKOlT1ujntRbaoG4LJFeEezz4ji03/wSJMI8Vi4KjzpBp8J1tTu0oRDnsxRIGixsUBeYQ==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/util-arn-parser@3.310.0':
+    resolution: {integrity: sha512-jL8509owp/xB9+Or0pvn3Fe+b94qfklc2yPowZZIFAkFcCSIdkIglz18cPDWnYAcy9JGewpMS1COXKIUhZkJsA==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/util-endpoints@3.410.0':
+    resolution: {integrity: sha512-iNiqJyC7N3+8zFwnXUqcWSxrZecVZLToo1iTQQdeYL2af1IcOtRgb7n8jpAI/hmXhBSx2+3RI+Y7pxyFo1vu+w==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/util-locate-window@3.208.0':
+    resolution: {integrity: sha512-iua1A2+P7JJEDHVgvXrRJSvsnzG7stYSGQnBVphIUlemwl6nN5D+QrgbjECtrbxRz8asYFHSzhdhECqN+tFiBg==}
+    engines: {node: '>=14.0.0'}
+
+  '@aws-sdk/util-user-agent-browser@3.410.0':
+    resolution: {integrity: sha512-i1G/XGpXGMRT2zEiAhi1xucJsfCWk8nNYjk/LbC0sA+7B9Huri96YAzVib12wkHPsJQvZxZC6CpQDIHWm4lXMA==}
+
+  '@aws-sdk/util-user-agent-node@3.410.0':
+    resolution: {integrity: sha512-bK70t1jHRl8HrJXd4hEIwc5PBZ7U0w+81AKFnanIVKZwZedd6nLibUXDTK14z/Jp2GFcBqd4zkt2YLGkRt/U4A==}
+    engines: {node: '>=14.0.0'}
+    peerDependencies:
+      aws-crt: '>=1.0.0'
+    peerDependenciesMeta:
+      aws-crt:
+        optional: true
+
+  '@aws-sdk/util-utf8-browser@3.259.0':
+    resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==}
+
+  '@aws-sdk/xml-builder@3.310.0':
+    resolution: {integrity: sha512-TqELu4mOuSIKQCqj63fGVs86Yh+vBx5nHRpWKNUNhB2nPTpfbziTs5c1X358be3peVWA4wPxW7Nt53KIg1tnNw==}
+    engines: {node: '>=14.0.0'}
+
+  '@babel/code-frame@7.23.5':
+    resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/compat-data@7.23.5':
+    resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/core@7.23.5':
+    resolution: {integrity: sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/core@7.24.0':
+    resolution: {integrity: sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/generator@7.23.5':
+    resolution: {integrity: sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/generator@7.23.6':
+    resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-annotate-as-pure@7.22.5':
+    resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-builder-binary-assignment-operator-visitor@7.22.15':
+    resolution: {integrity: sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-compilation-targets@7.22.15':
+    resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-compilation-targets@7.23.6':
+    resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-create-class-features-plugin@7.23.5':
+    resolution: {integrity: sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  '@babel/helper-create-regexp-features-plugin@7.22.15':
+    resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  '@babel/helper-define-polyfill-provider@0.4.3':
+    resolution: {integrity: sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==}
+    peerDependencies:
+      '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
+
+  '@babel/helper-environment-visitor@7.22.20':
+    resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-function-name@7.23.0':
+    resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-hoist-variables@7.22.5':
+    resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-member-expression-to-functions@7.23.0':
+    resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-module-imports@7.22.15':
+    resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-module-transforms@7.23.3':
+    resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  '@babel/helper-optimise-call-expression@7.22.5':
+    resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-plugin-utils@7.22.5':
+    resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-remap-async-to-generator@7.22.20':
+    resolution: {integrity: sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  '@babel/helper-replace-supers@7.22.20':
+    resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  '@babel/helper-simple-access@7.22.5':
+    resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-skip-transparent-expression-wrappers@7.22.5':
+    resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-split-export-declaration@7.22.6':
+    resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-string-parser@7.23.4':
+    resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-validator-identifier@7.22.20':
+    resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-validator-option@7.23.5':
+    resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-wrap-function@7.22.20':
+    resolution: {integrity: sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helpers@7.23.5':
+    resolution: {integrity: sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helpers@7.24.0':
+    resolution: {integrity: sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/highlight@7.23.4':
+    resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/parser@7.23.9':
+    resolution: {integrity: sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==}
+    engines: {node: '>=6.0.0'}
+    hasBin: true
+
+  '@babel/parser@7.24.0':
+    resolution: {integrity: sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==}
+    engines: {node: '>=6.0.0'}
+    hasBin: true
+
+  '@babel/parser@7.24.5':
+    resolution: {integrity: sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==}
+    engines: {node: '>=6.0.0'}
+    hasBin: true
+
+  '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3':
+    resolution: {integrity: sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3':
+    resolution: {integrity: sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.13.0
+
+  '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.3':
+    resolution: {integrity: sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2':
+    resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-async-generators@7.8.4':
+    resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-bigint@7.8.3':
+    resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-class-properties@7.12.13':
+    resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-class-static-block@7.14.5':
+    resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-dynamic-import@7.8.3':
+    resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-export-namespace-from@7.8.3':
+    resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-flow@7.23.3':
+    resolution: {integrity: sha512-YZiAIpkJAwQXBJLIQbRFayR5c+gJ35Vcz3bg954k7cd73zqjvhacJuL9RbrzPz8qPmZdgqP6EUKwy0PCNhaaPA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-import-assertions@7.23.3':
+    resolution: {integrity: sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-import-attributes@7.23.3':
+    resolution: {integrity: sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-import-meta@7.10.4':
+    resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-json-strings@7.8.3':
+    resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-jsx@7.23.3':
+    resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-logical-assignment-operators@7.10.4':
+    resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3':
+    resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-numeric-separator@7.10.4':
+    resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-object-rest-spread@7.8.3':
+    resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-optional-catch-binding@7.8.3':
+    resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-optional-chaining@7.8.3':
+    resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-private-property-in-object@7.14.5':
+    resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-top-level-await@7.14.5':
+    resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-typescript@7.23.3':
+    resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-unicode-sets-regex@7.18.6':
+    resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  '@babel/plugin-transform-arrow-functions@7.23.3':
+    resolution: {integrity: sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-async-generator-functions@7.23.4':
+    resolution: {integrity: sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-async-to-generator@7.23.3':
+    resolution: {integrity: sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-block-scoped-functions@7.23.3':
+    resolution: {integrity: sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-block-scoping@7.23.4':
+    resolution: {integrity: sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-class-properties@7.23.3':
+    resolution: {integrity: sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-class-static-block@7.23.4':
+    resolution: {integrity: sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.12.0
+
+  '@babel/plugin-transform-classes@7.23.5':
+    resolution: {integrity: sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-computed-properties@7.23.3':
+    resolution: {integrity: sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-destructuring@7.23.3':
+    resolution: {integrity: sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-dotall-regex@7.23.3':
+    resolution: {integrity: sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-duplicate-keys@7.23.3':
+    resolution: {integrity: sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-dynamic-import@7.23.4':
+    resolution: {integrity: sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-exponentiation-operator@7.23.3':
+    resolution: {integrity: sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-export-namespace-from@7.23.4':
+    resolution: {integrity: sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-flow-strip-types@7.23.3':
+    resolution: {integrity: sha512-26/pQTf9nQSNVJCrLB1IkHUKyPxR+lMrH2QDPG89+Znu9rAMbtrybdbWeE9bb7gzjmE5iXHEY+e0HUwM6Co93Q==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-for-of@7.23.3':
+    resolution: {integrity: sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-function-name@7.23.3':
+    resolution: {integrity: sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-json-strings@7.23.4':
+    resolution: {integrity: sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-literals@7.23.3':
+    resolution: {integrity: sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-logical-assignment-operators@7.23.4':
+    resolution: {integrity: sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-member-expression-literals@7.23.3':
+    resolution: {integrity: sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-modules-amd@7.23.3':
+    resolution: {integrity: sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-modules-commonjs@7.23.3':
+    resolution: {integrity: sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-modules-systemjs@7.23.3':
+    resolution: {integrity: sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-modules-umd@7.23.3':
+    resolution: {integrity: sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-named-capturing-groups-regex@7.22.5':
+    resolution: {integrity: sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  '@babel/plugin-transform-new-target@7.23.3':
+    resolution: {integrity: sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-nullish-coalescing-operator@7.23.4':
+    resolution: {integrity: sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-numeric-separator@7.23.4':
+    resolution: {integrity: sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-object-rest-spread@7.23.4':
+    resolution: {integrity: sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-object-super@7.23.3':
+    resolution: {integrity: sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-optional-catch-binding@7.23.4':
+    resolution: {integrity: sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-optional-chaining@7.23.4':
+    resolution: {integrity: sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-parameters@7.23.3':
+    resolution: {integrity: sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-private-methods@7.23.3':
+    resolution: {integrity: sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-private-property-in-object@7.23.4':
+    resolution: {integrity: sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-property-literals@7.23.3':
+    resolution: {integrity: sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-regenerator@7.23.3':
+    resolution: {integrity: sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-reserved-words@7.23.3':
+    resolution: {integrity: sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-shorthand-properties@7.23.3':
+    resolution: {integrity: sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-spread@7.23.3':
+    resolution: {integrity: sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-sticky-regex@7.23.3':
+    resolution: {integrity: sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-template-literals@7.23.3':
+    resolution: {integrity: sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-typeof-symbol@7.23.3':
+    resolution: {integrity: sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-typescript@7.23.5':
+    resolution: {integrity: sha512-2fMkXEJkrmwgu2Bsv1Saxgj30IXZdJ+84lQcKKI7sm719oXs0BBw2ZENKdJdR1PjWndgLCEBNXJOri0fk7RYQA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-unicode-escapes@7.23.3':
+    resolution: {integrity: sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-unicode-property-regex@7.23.3':
+    resolution: {integrity: sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-unicode-regex@7.23.3':
+    resolution: {integrity: sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-unicode-sets-regex@7.23.3':
+    resolution: {integrity: sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  '@babel/preset-env@7.23.5':
+    resolution: {integrity: sha512-0d/uxVD6tFGWXGDSfyMD1p2otoaKmu6+GD+NfAx0tMaH+dxORnp7T9TaVQ6mKyya7iBtCIVxHjWT7MuzzM9z+A==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/preset-flow@7.23.3':
+    resolution: {integrity: sha512-7yn6hl8RIv+KNk6iIrGZ+D06VhVY35wLVf23Cz/mMu1zOr7u4MMP4j0nZ9tLf8+4ZFpnib8cFYgB/oYg9hfswA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/preset-modules@0.1.6-no-external-plugins':
+    resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0
+
+  '@babel/preset-typescript@7.23.3':
+    resolution: {integrity: sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/register@7.22.15':
+    resolution: {integrity: sha512-V3Q3EqoQdn65RCgTLwauZaTfd1ShhwPmbBv+1dkZV/HpCGMKVyn6oFcRlI7RaKqiDQjX2Qd3AuoEguBgdjIKlg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/regjsgen@0.8.0':
+    resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==}
+
+  '@babel/runtime@7.23.4':
+    resolution: {integrity: sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/template@7.22.15':
+    resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/template@7.24.0':
+    resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/traverse@7.23.5':
+    resolution: {integrity: sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/traverse@7.24.0':
+    resolution: {integrity: sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/types@7.23.5':
+    resolution: {integrity: sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/types@7.24.0':
+    resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==}
+    engines: {node: '>=6.9.0'}
+
+  '@base2/pretty-print-object@1.0.1':
+    resolution: {integrity: sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==}
+
+  '@bcoe/v8-coverage@0.2.3':
+    resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
+
+  '@bull-board/api@5.17.0':
+    resolution: {integrity: sha512-qU+AiZIaYa//rkt1x7jDowtYa8u7/dLsDfEWgenZMkgvUszZ1kxJszdCtGapsDTVyPmnXgTRxpOWcR6sAYwSNQ==}
+    peerDependencies:
+      '@bull-board/ui': 5.17.0
+
+  '@bull-board/fastify@5.17.0':
+    resolution: {integrity: sha512-73YrPc7ERTWSOQRgBP6a7BPscWfcHd8U+Zq0auMdL/KkjPhG9GxapbfnovGZDDahJL/p/4YQb6ULu03zdtOrEA==}
+
+  '@bull-board/ui@5.17.0':
+    resolution: {integrity: sha512-Vj+yWPjrjx3Iqh2N/ZBDhK2d2yJD44dfvIxm+SnXQb4ne312j117TpViInceysxGtbbAOlAW6hq6JvsDoRl7KQ==}
+
+  '@bundled-es-modules/cookie@2.0.0':
+    resolution: {integrity: sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==}
+
+  '@bundled-es-modules/statuses@1.0.1':
+    resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==}
+
+  '@canvas/image-data@1.0.0':
+    resolution: {integrity: sha512-BxOqI5LgsIQP1odU5KMwV9yoijleOPzHL18/YvNqF9KFSGF2K/DLlYAbDQsWqd/1nbaFuSkYD/191dpMtNh4vw==}
+
+  '@colors/colors@1.5.0':
+    resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
+    engines: {node: '>=0.1.90'}
+
+  '@cropper/element-canvas@2.0.0-beta.5':
+    resolution: {integrity: sha512-TS+NTVQAyLKBFLIjzFcaFK6V5GaNCNSp8FBjApTD/AosV/dPRlNCsgmdJ/BugwJTJUSowVnLrPmulI35z4npAg==}
+
+  '@cropper/element-crosshair@2.0.0-beta.5':
+    resolution: {integrity: sha512-en3EjiqS/O/uVPVLUanx2ZxvE2n3J5VxGABvBTwQimX4c3kNixq8TUVlsaLdcG7jbehxFpT3S19+tiuZudHqxg==}
+
+  '@cropper/element-grid@2.0.0-beta.5':
+    resolution: {integrity: sha512-uKQExNTOMOGo5d6Tv1NJDbjJHRR/0NgqeROUSt2J8g9ymPP+/MoFdCCf+Nj/KM5pk7/fBEV3HhzUnO8jh1hZfQ==}
+
+  '@cropper/element-handle@2.0.0-beta.5':
+    resolution: {integrity: sha512-SlaV5/qbEBQLHnuaGD8J0EqSp797m/MMB8V10EUZpv6cznSRxg/SXOj6ROE0ePzo5+0i96Dw+8ZukLilDgc1Xw==}
+
+  '@cropper/element-image@2.0.0-beta.5':
+    resolution: {integrity: sha512-369ztVaoRS2DN8SaiHZ/bRCz0Snw9ss7PZrX1OQK86fwVhCoeRqCHj48ayfLMdchx+J3RbM5f2g8ePf7ejwOKw==}
+
+  '@cropper/element-selection@2.0.0-beta.5':
+    resolution: {integrity: sha512-l8DvOBAZYytTarpkfhCglhxD+zDQ2acVwIzGwp5r9xR+ERleJHxr2rHYVhowRHT/JZRd94DJBlye91c1uO/XGg==}
+
+  '@cropper/element-shade@2.0.0-beta.5':
+    resolution: {integrity: sha512-LGSVLAD1lasFrS+Pd7JnQSJRCMSNnc40UCcjLhscDuRcRHK/ViMglnwCfFxeGnS26kugbDLF5IbYDCLCbykUog==}
+
+  '@cropper/element-viewer@2.0.0-beta.5':
+    resolution: {integrity: sha512-i4cc+L+j8Gq1L8g1BQWfQ842QxH5T9v2EkIeGuW66SVSBglafxu8gxmSOyRD3hDAMHM3wbJ+XVmFwBHZzlYCvQ==}
+
+  '@cropper/element@2.0.0-beta.5':
+    resolution: {integrity: sha512-+pHX/iYw+Y/HxgpcjvSPBc3+hvJaycznbZdWifnChmDkpLStd6Xu9gO2ful9sSL0uGSjQxUYV4xPyikYJOnfug==}
+
+  '@cropper/elements@2.0.0-beta.5':
+    resolution: {integrity: sha512-KWa5/dmJpLcKDJpNlbEQzO9Shz+f4aB0I3y97CqqTf8JSGS6CEKOd9uLywd1eow1r4O0Hwo65ktXPwAEhMWDZg==}
+
+  '@cropper/utils@2.0.0-beta.5':
+    resolution: {integrity: sha512-xE7Klel/4WSjhLUeldfROwbWqV/1A3YKrQLqTrs5/X0ath7B05Fmvhr3TNFvN51v2KSx46Ug6xDJzmbg772m1g==}
+
+  '@cypress/request@3.0.0':
+    resolution: {integrity: sha512-GKFCqwZwMYmL3IBoNeR2MM1SnxRIGERsQOTWeQKoYBt2JLqcqiy7JXqO894FLrpjZYqGxW92MNwRH2BN56obdQ==}
+    engines: {node: '>= 6'}
+
+  '@cypress/xvfb@1.2.4':
+    resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==}
+
+  '@digitalbazaar/http-client@3.4.1':
+    resolution: {integrity: sha512-Ahk1N+s7urkgj7WvvUND5f8GiWEPfUw0D41hdElaqLgu8wZScI8gdI0q+qWw5N1d35x7GCRH2uk9mi+Uzo9M3g==}
+    engines: {node: '>=14.0'}
+
+  '@discordapp/twemoji@15.0.3':
+    resolution: {integrity: sha512-5t0LLrNaSqViG0cSaomWwfR0+3fWqok+xLq40M8hJHxNX7s8gIoyNZYybQJo+s5/rGMjgdldpt8Ox8MapGvBUA==}
+
+  '@discoveryjs/json-ext@0.5.7':
+    resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==}
+    engines: {node: '>=10.0.0'}
+
+  '@emnapi/runtime@1.1.1':
+    resolution: {integrity: sha512-3bfqkzuR1KLx57nZfjr2NLnFOobvyS0aTszaEGCGqmYMVDRaGvgIZbjGSV/MHSSmLgQ/b9JFHQ5xm5WRZYd+XQ==}
+
+  '@emotion/use-insertion-effect-with-fallbacks@1.0.1':
+    resolution: {integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==}
+    peerDependencies:
+      react: '>=16.8.0'
+
+  '@esbuild/aix-ppc64@0.19.11':
+    resolution: {integrity: sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==}
+    engines: {node: '>=12'}
+    cpu: [ppc64]
+    os: [aix]
+
+  '@esbuild/aix-ppc64@0.20.2':
+    resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==}
+    engines: {node: '>=12'}
+    cpu: [ppc64]
+    os: [aix]
+
+  '@esbuild/android-arm64@0.18.20':
+    resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [android]
+
+  '@esbuild/android-arm64@0.19.11':
+    resolution: {integrity: sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [android]
+
+  '@esbuild/android-arm64@0.20.2':
+    resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [android]
+
+  '@esbuild/android-arm@0.18.20':
+    resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==}
+    engines: {node: '>=12'}
+    cpu: [arm]
+    os: [android]
+
+  '@esbuild/android-arm@0.19.11':
+    resolution: {integrity: sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==}
+    engines: {node: '>=12'}
+    cpu: [arm]
+    os: [android]
+
+  '@esbuild/android-arm@0.20.2':
+    resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==}
+    engines: {node: '>=12'}
+    cpu: [arm]
+    os: [android]
+
+  '@esbuild/android-x64@0.18.20':
+    resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [android]
+
+  '@esbuild/android-x64@0.19.11':
+    resolution: {integrity: sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [android]
+
+  '@esbuild/android-x64@0.20.2':
+    resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [android]
+
+  '@esbuild/darwin-arm64@0.18.20':
+    resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@esbuild/darwin-arm64@0.19.11':
+    resolution: {integrity: sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@esbuild/darwin-arm64@0.20.2':
+    resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@esbuild/darwin-x64@0.18.20':
+    resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@esbuild/darwin-x64@0.19.11':
+    resolution: {integrity: sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@esbuild/darwin-x64@0.20.2':
+    resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@esbuild/freebsd-arm64@0.18.20':
+    resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [freebsd]
+
+  '@esbuild/freebsd-arm64@0.19.11':
+    resolution: {integrity: sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [freebsd]
+
+  '@esbuild/freebsd-arm64@0.20.2':
+    resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [freebsd]
+
+  '@esbuild/freebsd-x64@0.18.20':
+    resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@esbuild/freebsd-x64@0.19.11':
+    resolution: {integrity: sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@esbuild/freebsd-x64@0.20.2':
+    resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@esbuild/linux-arm64@0.18.20':
+    resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@esbuild/linux-arm64@0.19.11':
+    resolution: {integrity: sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@esbuild/linux-arm64@0.20.2':
+    resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@esbuild/linux-arm@0.18.20':
+    resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==}
+    engines: {node: '>=12'}
+    cpu: [arm]
+    os: [linux]
+
+  '@esbuild/linux-arm@0.19.11':
+    resolution: {integrity: sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==}
+    engines: {node: '>=12'}
+    cpu: [arm]
+    os: [linux]
+
+  '@esbuild/linux-arm@0.20.2':
+    resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==}
+    engines: {node: '>=12'}
+    cpu: [arm]
+    os: [linux]
+
+  '@esbuild/linux-ia32@0.18.20':
+    resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [linux]
+
+  '@esbuild/linux-ia32@0.19.11':
+    resolution: {integrity: sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [linux]
+
+  '@esbuild/linux-ia32@0.20.2':
+    resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [linux]
+
+  '@esbuild/linux-loong64@0.18.20':
+    resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==}
+    engines: {node: '>=12'}
+    cpu: [loong64]
+    os: [linux]
+
+  '@esbuild/linux-loong64@0.19.11':
+    resolution: {integrity: sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==}
+    engines: {node: '>=12'}
+    cpu: [loong64]
+    os: [linux]
+
+  '@esbuild/linux-loong64@0.20.2':
+    resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==}
+    engines: {node: '>=12'}
+    cpu: [loong64]
+    os: [linux]
+
+  '@esbuild/linux-mips64el@0.18.20':
+    resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==}
+    engines: {node: '>=12'}
+    cpu: [mips64el]
+    os: [linux]
+
+  '@esbuild/linux-mips64el@0.19.11':
+    resolution: {integrity: sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==}
+    engines: {node: '>=12'}
+    cpu: [mips64el]
+    os: [linux]
+
+  '@esbuild/linux-mips64el@0.20.2':
+    resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==}
+    engines: {node: '>=12'}
+    cpu: [mips64el]
+    os: [linux]
+
+  '@esbuild/linux-ppc64@0.18.20':
+    resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==}
+    engines: {node: '>=12'}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@esbuild/linux-ppc64@0.19.11':
+    resolution: {integrity: sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==}
+    engines: {node: '>=12'}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@esbuild/linux-ppc64@0.20.2':
+    resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==}
+    engines: {node: '>=12'}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@esbuild/linux-riscv64@0.18.20':
+    resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==}
+    engines: {node: '>=12'}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@esbuild/linux-riscv64@0.19.11':
+    resolution: {integrity: sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==}
+    engines: {node: '>=12'}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@esbuild/linux-riscv64@0.20.2':
+    resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==}
+    engines: {node: '>=12'}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@esbuild/linux-s390x@0.18.20':
+    resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==}
+    engines: {node: '>=12'}
+    cpu: [s390x]
+    os: [linux]
+
+  '@esbuild/linux-s390x@0.19.11':
+    resolution: {integrity: sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==}
+    engines: {node: '>=12'}
+    cpu: [s390x]
+    os: [linux]
+
+  '@esbuild/linux-s390x@0.20.2':
+    resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==}
+    engines: {node: '>=12'}
+    cpu: [s390x]
+    os: [linux]
+
+  '@esbuild/linux-x64@0.18.20':
+    resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [linux]
+
+  '@esbuild/linux-x64@0.19.11':
+    resolution: {integrity: sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [linux]
+
+  '@esbuild/linux-x64@0.20.2':
+    resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [linux]
+
+  '@esbuild/netbsd-x64@0.18.20':
+    resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [netbsd]
+
+  '@esbuild/netbsd-x64@0.19.11':
+    resolution: {integrity: sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [netbsd]
+
+  '@esbuild/netbsd-x64@0.20.2':
+    resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [netbsd]
+
+  '@esbuild/openbsd-x64@0.18.20':
+    resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [openbsd]
+
+  '@esbuild/openbsd-x64@0.19.11':
+    resolution: {integrity: sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [openbsd]
+
+  '@esbuild/openbsd-x64@0.20.2':
+    resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [openbsd]
+
+  '@esbuild/sunos-x64@0.18.20':
+    resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [sunos]
+
+  '@esbuild/sunos-x64@0.19.11':
+    resolution: {integrity: sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [sunos]
+
+  '@esbuild/sunos-x64@0.20.2':
+    resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [sunos]
+
+  '@esbuild/win32-arm64@0.18.20':
+    resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@esbuild/win32-arm64@0.19.11':
+    resolution: {integrity: sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@esbuild/win32-arm64@0.20.2':
+    resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@esbuild/win32-ia32@0.18.20':
+    resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [win32]
+
+  '@esbuild/win32-ia32@0.19.11':
+    resolution: {integrity: sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [win32]
+
+  '@esbuild/win32-ia32@0.20.2':
+    resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [win32]
+
+  '@esbuild/win32-x64@0.18.20':
+    resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [win32]
+
+  '@esbuild/win32-x64@0.19.11':
+    resolution: {integrity: sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [win32]
+
+  '@esbuild/win32-x64@0.20.2':
+    resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [win32]
+
+  '@eslint-community/eslint-utils@4.4.0':
+    resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+
+  '@eslint-community/regexpp@4.10.0':
+    resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==}
+    engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+
+  '@eslint-community/regexpp@4.6.2':
+    resolution: {integrity: sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==}
+    engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+
+  '@eslint/eslintrc@2.1.4':
+    resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  '@eslint/js@8.53.0':
+    resolution: {integrity: sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  '@eslint/js@8.57.0':
+    resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  '@fal-works/esbuild-plugin-global-externals@2.1.2':
+    resolution: {integrity: sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==}
+
+  '@fastify/accept-negotiator@1.0.0':
+    resolution: {integrity: sha512-4R/N2KfYeld7A5LGkai+iUFMahXcxxYbDp+XS2B1yuL3cdmZLJ9TlCnNzT3q5xFTqsYm0GPpinLUwfSwjcVjyA==}
+    engines: {node: '>=14'}
+
+  '@fastify/accepts@4.3.0':
+    resolution: {integrity: sha512-QK4FoqXdwwPmaPOLL6NrxsyaXVvdviYVoS6ltHyOLdFlUyREIaMykHQIp+x0aJz9hB3B3n/Ht6QRdvBeGkptGQ==}
+
+  '@fastify/ajv-compiler@3.5.0':
+    resolution: {integrity: sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==}
+
+  '@fastify/busboy@2.1.0':
+    resolution: {integrity: sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==}
+    engines: {node: '>=14'}
+
+  '@fastify/cookie@9.3.1':
+    resolution: {integrity: sha512-h1NAEhB266+ZbZ0e9qUE6NnNR07i7DnNXWG9VbbZ8uC6O/hxHpl+Zoe5sw1yfdZ2U6XhToUGDnzQtWJdCaPwfg==}
+
+  '@fastify/cors@9.0.1':
+    resolution: {integrity: sha512-YY9Ho3ovI+QHIL2hW+9X4XqQjXLjJqsU+sMV/xFsxZkE8p3GNnYVFpoOxF7SsP5ZL76gwvbo3V9L+FIekBGU4Q==}
+
+  '@fastify/deepmerge@1.3.0':
+    resolution: {integrity: sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A==}
+
+  '@fastify/error@3.4.0':
+    resolution: {integrity: sha512-e/mafFwbK3MNqxUcFBLgHhgxsF8UT1m8aj0dAlqEa2nJEgPsRtpHTZ3ObgrgkZ2M1eJHPTwgyUl/tXkvabsZdQ==}
+
+  '@fastify/express@3.0.0':
+    resolution: {integrity: sha512-Ug6aulXCUiHgMyrHVYQqnQbGdsAV0aTad6nZxbOr6w3QjKn1mdQS3Kyzvc+I0xMjZ9yIyMUWHSooHgZ0l7nOng==}
+
+  '@fastify/fast-json-stringify-compiler@4.3.0':
+    resolution: {integrity: sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==}
+
+  '@fastify/http-proxy@9.5.0':
+    resolution: {integrity: sha512-1iqIdV10d5k9YtfHq9ylX5zt1NiM50fG+rIX40qt00R694sqWso3ukyTFZVk33SDoSiBW8roB7n11RUVUoN+Ag==}
+
+  '@fastify/multipart@8.2.0':
+    resolution: {integrity: sha512-OZ8nsyyoS2TV7Yeu3ZdrdDGsKUTAbfjrKC9jSxGgT2qdgek+BxpWX31ZubTrWMNZyU5xwk4ox6AvTjAbYWjrWg==}
+
+  '@fastify/reply-from@9.0.1':
+    resolution: {integrity: sha512-q9vFNUiXZTY1x8omDPe59os2MYq+3y7KgO/kZoXpZlnud+45Nd8Ot/svEvrUATzjkizIggfS4K8LR9zXDyZZKg==}
+
+  '@fastify/send@2.0.1':
+    resolution: {integrity: sha512-8jdouu0o5d0FMq1+zCKeKXc1tmOQ5tTGYdQP3MpyF9+WWrZT1KCBdh6hvoEYxOm3oJG/akdE9BpehLiJgYRvGw==}
+
+  '@fastify/static@6.12.0':
+    resolution: {integrity: sha512-KK1B84E6QD/FcQWxDI2aiUCwHxMJBI1KeCUzm1BwYpPY1b742+jeKruGHP2uOluuM6OkBPI8CIANrXcCRtC2oQ==}
+
+  '@fastify/static@7.0.3':
+    resolution: {integrity: sha512-2tmTdF+uFCykasutaO6k4/wOt7eXyi7m3dGuCPo5micXzv0qt6ttb/nWnDYL/BlXjYGfp1JI4a1gyluTIylvQA==}
+
+  '@fastify/view@8.2.0':
+    resolution: {integrity: sha512-hBSiBofCnJNlPHEMZWpO1SL84eqOaqujJ1hR3jntFyZZCkweH5jMs12DKYyGesjVll7SJFRRxPUBB8kmUmneRQ==}
+
+  '@fastify/view@9.1.0':
+    resolution: {integrity: sha512-jRTGDljs/uB2p8bf6c1x4stGjP7H84VQkhbtDgCx55Mxf9Fplud5UZIHubvL4BTTX8jNYEzP1FpNAOBi7vibxg==}
+
+  '@github/webauthn-json@2.1.1':
+    resolution: {integrity: sha512-XrftRn4z75SnaJOmZQbt7Mk+IIjqVHw+glDGOxuHwXkZBZh/MBoRS7MHjSZMDaLhT4RjN2VqiEU7EOYleuJWSQ==}
+    hasBin: true
+
+  '@hapi/boom@10.0.1':
+    resolution: {integrity: sha512-ERcCZaEjdH3OgSJlyjVk8pHIFeus91CjKP3v+MpgBNp5IvGzP2l/bRiD78nqYcKPaZdbKkK5vDBVPd2ohHBlsA==}
+
+  '@hapi/bourne@3.0.0':
+    resolution: {integrity: sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==}
+
+  '@hapi/hoek@10.0.1':
+    resolution: {integrity: sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==}
+
+  '@hapi/hoek@11.0.2':
+    resolution: {integrity: sha512-aKmlCO57XFZ26wso4rJsW4oTUnrgTFw2jh3io7CAtO9w4UltBNwRXvXIVzzyfkaaLRo3nluP/19msA8vDUUuKw==}
+
+  '@hapi/hoek@9.3.0':
+    resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==}
+
+  '@hapi/topo@5.1.0':
+    resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==}
+
+  '@hapi/wreck@18.0.1':
+    resolution: {integrity: sha512-OLHER70+rZxvDl75xq3xXOfd3e8XIvz8fWY0dqg92UvhZ29zo24vQgfqgHSYhB5ZiuFpSLeriOisAlxAo/1jWg==}
+
+  '@hexagon/base64@1.1.27':
+    resolution: {integrity: sha512-PdUmzpvcUM3Rh39kvz9RdbPVYhMjBjdV7Suw7ZduP7urRLsZR8l5tzgSWKm7TExwBYDFwTnYrZbnE0rQ3N5NLQ==}
+
+  '@humanwhocodes/config-array@0.11.13':
+    resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==}
+    engines: {node: '>=10.10.0'}
+
+  '@humanwhocodes/config-array@0.11.14':
+    resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
+    engines: {node: '>=10.10.0'}
+
+  '@humanwhocodes/module-importer@1.0.1':
+    resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+    engines: {node: '>=12.22'}
+
+  '@humanwhocodes/momoa@2.0.4':
+    resolution: {integrity: sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==}
+    engines: {node: '>=10.10.0'}
+
+  '@humanwhocodes/object-schema@2.0.1':
+    resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
+
+  '@humanwhocodes/object-schema@2.0.2':
+    resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==}
+
+  '@img/sharp-darwin-arm64@0.33.3':
+    resolution: {integrity: sha512-FaNiGX1MrOuJ3hxuNzWgsT/mg5OHG/Izh59WW2mk1UwYHUwtfbhk5QNKYZgxf0pLOhx9ctGiGa2OykD71vOnSw==}
+    engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@img/sharp-darwin-x64@0.33.3':
+    resolution: {integrity: sha512-2QeSl7QDK9ru//YBT4sQkoq7L0EAJZA3rtV+v9p8xTKl4U1bUqTIaCnoC7Ctx2kCjQgwFXDasOtPTCT8eCTXvw==}
+    engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@img/sharp-libvips-darwin-arm64@1.0.2':
+    resolution: {integrity: sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==}
+    engines: {macos: '>=11', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@img/sharp-libvips-darwin-x64@1.0.2':
+    resolution: {integrity: sha512-Ofw+7oaWa0HiiMiKWqqaZbaYV3/UGL2wAPeLuJTx+9cXpCRdvQhCLG0IH8YGwM0yGWGLpsF4Su9vM1o6aer+Fw==}
+    engines: {macos: '>=10.13', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@img/sharp-libvips-linux-arm64@1.0.2':
+    resolution: {integrity: sha512-x7kCt3N00ofFmmkkdshwj3vGPCnmiDh7Gwnd4nUwZln2YjqPxV1NlTyZOvoDWdKQVDL911487HOueBvrpflagw==}
+    engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@img/sharp-libvips-linux-arm@1.0.2':
+    resolution: {integrity: sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==}
+    engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [arm]
+    os: [linux]
+
+  '@img/sharp-libvips-linux-s390x@1.0.2':
+    resolution: {integrity: sha512-cmhQ1J4qVhfmS6szYW7RT+gLJq9dH2i4maq+qyXayUSn9/3iY2ZeWpbAgSpSVbV2E1JUL2Gg7pwnYQ1h8rQIog==}
+    engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [s390x]
+    os: [linux]
+
+  '@img/sharp-libvips-linux-x64@1.0.2':
+    resolution: {integrity: sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==}
+    engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [x64]
+    os: [linux]
+
+  '@img/sharp-libvips-linuxmusl-arm64@1.0.2':
+    resolution: {integrity: sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==}
+    engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@img/sharp-libvips-linuxmusl-x64@1.0.2':
+    resolution: {integrity: sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==}
+    engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [x64]
+    os: [linux]
+
+  '@img/sharp-linux-arm64@0.33.3':
+    resolution: {integrity: sha512-Zf+sF1jHZJKA6Gor9hoYG2ljr4wo9cY4twaxgFDvlG0Xz9V7sinsPp8pFd1XtlhTzYo0IhDbl3rK7P6MzHpnYA==}
+    engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@img/sharp-linux-arm@0.33.3':
+    resolution: {integrity: sha512-Q7Ee3fFSC9P7vUSqVEF0zccJsZ8GiiCJYGWDdhEjdlOeS9/jdkyJ6sUSPj+bL8VuOYFSbofrW0t/86ceVhx32w==}
+    engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [arm]
+    os: [linux]
+
+  '@img/sharp-linux-s390x@0.33.3':
+    resolution: {integrity: sha512-vFk441DKRFepjhTEH20oBlFrHcLjPfI8B0pMIxGm3+yilKyYeHEVvrZhYFdqIseSclIqbQ3SnZMwEMWonY5XFA==}
+    engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [s390x]
+    os: [linux]
+
+  '@img/sharp-linux-x64@0.33.3':
+    resolution: {integrity: sha512-Q4I++herIJxJi+qmbySd072oDPRkCg/SClLEIDh5IL9h1zjhqjv82H0Seupd+q2m0yOfD+/fJnjSoDFtKiHu2g==}
+    engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [x64]
+    os: [linux]
+
+  '@img/sharp-linuxmusl-arm64@0.33.3':
+    resolution: {integrity: sha512-qnDccehRDXadhM9PM5hLvcPRYqyFCBN31kq+ErBSZtZlsAc1U4Z85xf/RXv1qolkdu+ibw64fUDaRdktxTNP9A==}
+    engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@img/sharp-linuxmusl-x64@0.33.3':
+    resolution: {integrity: sha512-Jhchim8kHWIU/GZ+9poHMWRcefeaxFIs9EBqf9KtcC14Ojk6qua7ghKiPs0sbeLbLj/2IGBtDcxHyjCdYWkk2w==}
+    engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [x64]
+    os: [linux]
+
+  '@img/sharp-wasm32@0.33.3':
+    resolution: {integrity: sha512-68zivsdJ0koE96stdUfM+gmyaK/NcoSZK5dV5CAjES0FUXS9lchYt8LAB5rTbM7nlWtxaU/2GON0HVN6/ZYJAQ==}
+    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [wasm32]
+
+  '@img/sharp-win32-ia32@0.33.3':
+    resolution: {integrity: sha512-CyimAduT2whQD8ER4Ux7exKrtfoaUiVr7HG0zZvO0XTFn2idUWljjxv58GxNTkFb8/J9Ub9AqITGkJD6ZginxQ==}
+    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [ia32]
+    os: [win32]
+
+  '@img/sharp-win32-x64@0.33.3':
+    resolution: {integrity: sha512-viT4fUIDKnli3IfOephGnolMzhz5VaTvDRkYqtZxOMIoMQ4MrAziO7pT1nVnOt2FAm7qW5aa+CCc13aEY6Le0g==}
+    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+    cpu: [x64]
+    os: [win32]
+
+  '@inquirer/confirm@3.1.6':
+    resolution: {integrity: sha512-Mj4TU29g6Uy+37UtpA8UpEOI2icBfpCwSW1QDtfx60wRhUy90s/kHPif2OXSSvuwDQT1lhAYRWUfkNf9Tecxvg==}
+    engines: {node: '>=18'}
+
+  '@inquirer/core@8.1.0':
+    resolution: {integrity: sha512-kfx0SU9nWgGe1f03ao/uXc85SFH1v2w3vQVH7QDGjKxdtJz+7vPitFtG++BTyJMYyYgH8MpXigutcXJeiQwVRw==}
+    engines: {node: '>=18'}
+
+  '@inquirer/figures@1.0.1':
+    resolution: {integrity: sha512-mtup3wVKia3ZwULPHcbs4Mor8Voi+iIXEWD7wCNbIO6lYR62oPCTQyrddi5OMYVXHzeCSoneZwJuS8sBvlEwDw==}
+    engines: {node: '>=18'}
+
+  '@inquirer/type@1.3.1':
+    resolution: {integrity: sha512-Pe3PFccjPVJV1vtlfVvm9OnlbxqdnP5QcscFEFEnK5quChf1ufZtM0r8mR5ToWHMxZOh0s8o/qp9ANGRTo/DAw==}
+    engines: {node: '>=18'}
+
+  '@intlify/core-base@9.13.1':
+    resolution: {integrity: sha512-+bcQRkJO9pcX8d0gel9ZNfrzU22sZFSA0WVhfXrf5jdJOS24a+Bp8pozuS9sBI9Hk/tGz83pgKfmqcn/Ci7/8w==}
+    engines: {node: '>= 16'}
+
+  '@intlify/message-compiler@9.13.1':
+    resolution: {integrity: sha512-SKsVa4ajYGBVm7sHMXd5qX70O2XXjm55zdZB3VeMFCvQyvLew/dLvq3MqnaIsTMF1VkkOb9Ttr6tHcMlyPDL9w==}
+    engines: {node: '>= 16'}
+
+  '@intlify/shared@9.13.1':
+    resolution: {integrity: sha512-u3b6BKGhE6j/JeRU6C/RL2FgyJfy6LakbtfeVF8fJXURpZZTzfh3e05J0bu0XPw447Q6/WUp3C4ajv4TMS4YsQ==}
+    engines: {node: '>= 16'}
+
+  '@ioredis/commands@1.2.0':
+    resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==}
+
+  '@isaacs/cliui@8.0.2':
+    resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
+    engines: {node: '>=12'}
+
+  '@istanbuljs/load-nyc-config@1.1.0':
+    resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
+    engines: {node: '>=8'}
+
+  '@istanbuljs/schema@0.1.3':
+    resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
+    engines: {node: '>=8'}
+
+  '@jest/console@29.7.0':
+    resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  '@jest/core@29.7.0':
+    resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+    peerDependencies:
+      node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+    peerDependenciesMeta:
+      node-notifier:
+        optional: true
+
+  '@jest/create-cache-key-function@29.7.0':
+    resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  '@jest/environment@29.7.0':
+    resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  '@jest/expect-utils@29.7.0':
+    resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  '@jest/expect@29.7.0':
+    resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  '@jest/fake-timers@29.7.0':
+    resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  '@jest/globals@29.7.0':
+    resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  '@jest/reporters@29.7.0':
+    resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+    peerDependencies:
+      node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+    peerDependenciesMeta:
+      node-notifier:
+        optional: true
+
+  '@jest/schemas@29.6.3':
+    resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  '@jest/source-map@29.6.3':
+    resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  '@jest/test-result@29.7.0':
+    resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  '@jest/test-sequencer@29.7.0':
+    resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  '@jest/transform@29.7.0':
+    resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  '@jest/types@29.6.3':
+    resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  '@joshwooding/vite-plugin-react-docgen-typescript@0.3.0':
+    resolution: {integrity: sha512-2D6y7fNvFmsLmRt6UCOFJPvFoPMJGT0Uh1Wg0RaigUp7kdQPs6yYn8Dmx6GZkOH/NW0yMTwRz/p0SRMMRo50vA==}
+    peerDependencies:
+      typescript: '>= 4.3.x'
+      vite: ^3.0.0 || ^4.0.0 || ^5.0.0
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@jridgewell/gen-mapping@0.3.2':
+    resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==}
+    engines: {node: '>=6.0.0'}
+
+  '@jridgewell/resolve-uri@3.1.0':
+    resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
+    engines: {node: '>=6.0.0'}
+
+  '@jridgewell/set-array@1.1.2':
+    resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
+    engines: {node: '>=6.0.0'}
+
+  '@jridgewell/source-map@0.3.5':
+    resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==}
+
+  '@jridgewell/sourcemap-codec@1.4.14':
+    resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==}
+
+  '@jridgewell/sourcemap-codec@1.4.15':
+    resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
+
+  '@jridgewell/trace-mapping@0.3.18':
+    resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==}
+
+  '@jsdevtools/ono@7.1.3':
+    resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==}
+
+  '@kurkle/color@0.3.2':
+    resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==}
+
+  '@levischuck/tiny-cbor@0.2.2':
+    resolution: {integrity: sha512-f5CnPw997Y2GQ8FAvtuVVC19FX8mwNNC+1XJcIi16n/LTJifKO6QBgGLgN3YEmqtGMk17SKSuoWES3imJVxAVw==}
+
+  '@lukeed/csprng@1.0.1':
+    resolution: {integrity: sha512-uSvJdwQU5nK+Vdf6zxcWAY2A8r7uqe+gePwLWzJ+fsQehq18pc0I2hJKwypZ2aLM90+Er9u1xn4iLJPZ+xlL4g==}
+    engines: {node: '>=8'}
+
+  '@lukeed/ms@2.0.1':
+    resolution: {integrity: sha512-Xs/4RZltsAL7pkvaNStUQt7netTkyxrS0K+RILcVr3TRMS/ToOg4I6uNfhB9SlGsnWBym4U+EaXq0f0cEMNkHA==}
+    engines: {node: '>=8'}
+
+  '@mapbox/node-pre-gyp@1.0.9':
+    resolution: {integrity: sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==}
+    hasBin: true
+
+  '@mcaptcha/core-glue@0.1.0-alpha-5':
+    resolution: {integrity: sha512-16qWm5O5X0Y9LXULULaAks8Vf9FNlUUBcR5KDt49aWhFhG5++JzxNmCwQM9EJSHNU7y0U+FdyAWcGmjfKlkRLA==}
+
+  '@mcaptcha/vanilla-glue@0.1.0-alpha-3':
+    resolution: {integrity: sha512-GT6TJBgmViGXcXiT5VOr+h/6iOnThSlZuCoOWncubyTZU9R3cgU5vWPkF7G6Ob6ee2CBe3yqBxxk24CFVGTVXw==}
+
+  '@mdx-js/react@3.0.1':
+    resolution: {integrity: sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==}
+    peerDependencies:
+      '@types/react': '>=16'
+      react: '>=16'
+
+  '@microsoft/api-extractor-model@7.28.14':
+    resolution: {integrity: sha512-Bery/c8A8SsKPSvA82cTTuy/+OcxZbLRmKhPkk91/AJOQzxZsShcrmHFAGeiEqSIrv1nPZ3tKq9kfMLdCHmsqg==}
+
+  '@microsoft/api-extractor@7.43.1':
+    resolution: {integrity: sha512-ohg40SsvFFgzHFAtYq5wKJc8ZDyY46bphjtnSvhSSlXpPTG7GHwyyXkn48UZiUCBwr2WC7TRC1Jfwz7nreuiyQ==}
+    hasBin: true
+
+  '@microsoft/tsdoc-config@0.16.2':
+    resolution: {integrity: sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==}
+
+  '@microsoft/tsdoc@0.14.2':
+    resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==}
+
+  '@misskey-dev/browser-image-resizer@2024.1.0':
+    resolution: {integrity: sha512-4EnO0zLW5NDtng3Gaz5MuT761uiuoOuplwX18wBqgj8w56LTU5BjLn/vbHwDIIe0j2gwqDYhMb7bDjmr1/Fomg==}
+
+  '@misskey-dev/eslint-plugin@1.0.0':
+    resolution: {integrity: sha512-dh6UbcrNDVg5DD8k8Qh4ab30OPpuEYIlJCqaBV/lkIV8wNN/AfCJ2V7iTP8V8KjryM4t+sf5IqzQLQnT0mWI4A==}
+    peerDependencies:
+      '@typescript-eslint/eslint-plugin': '>= 6'
+      '@typescript-eslint/parser': '>= 6'
+      eslint: '>= 3'
+      eslint-plugin-import: '>= 2'
+
+  '@misskey-dev/sharp-read-bmp@1.2.0':
+    resolution: {integrity: sha512-er4pRakXzHYfEgOFAFfQagqDouG+wLm+kwNq1I30oSdIHDa0wM3KjFpfIGQ25Fks4GcmOl1s7Zh6xoQu5dNjTw==}
+
+  '@misskey-dev/summaly@5.1.0':
+    resolution: {integrity: sha512-WAUrgX3/z4h4aI8Y/WVwmJcJ6Fa1Zf2LJCSS651t9MHoWVGABLsQ2KCXRGmlpk4i+cMDNIwweObUroosE7j8rg==}
+
+  '@mole-inc/bin-wrapper@8.0.1':
+    resolution: {integrity: sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+  '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2':
+    resolution: {integrity: sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.2':
+    resolution: {integrity: sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==}
+    cpu: [x64]
+    os: [darwin]
+
+  '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.2':
+    resolution: {integrity: sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==}
+    cpu: [arm64]
+    os: [linux]
+
+  '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.2':
+    resolution: {integrity: sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==}
+    cpu: [arm]
+    os: [linux]
+
+  '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.2':
+    resolution: {integrity: sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==}
+    cpu: [x64]
+    os: [linux]
+
+  '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.2':
+    resolution: {integrity: sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==}
+    cpu: [x64]
+    os: [win32]
+
+  '@mswjs/cookies@1.1.0':
+    resolution: {integrity: sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw==}
+    engines: {node: '>=18'}
+
+  '@mswjs/interceptors@0.26.15':
+    resolution: {integrity: sha512-HM47Lu1YFmnYHKMBynFfjCp0U/yRskHj/8QEJW0CBEPOlw8Gkmjfll+S9b8M7V5CNDw2/ciRxjjnWeaCiblSIQ==}
+    engines: {node: '>=18'}
+
+  '@napi-rs/canvas-android-arm64@0.1.52':
+    resolution: {integrity: sha512-x/K471KbASPVh5mfBUxokza66J0FNIlOgMNANWAf5C8HiATb487KecEhSkUQvvTS3WLYC9uSqIPHFgwF+tir3w==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [android]
+
+  '@napi-rs/canvas-darwin-arm64@0.1.52':
+    resolution: {integrity: sha512-4OgVRD7TW02q5Q7lWLLjT+pYJ9ZHkQUTBOuXbPQ5wB0Wnh3RIq/aMY6thoXDZDzdR5vV3a5TUtbZUJ0aqLq3NA==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@napi-rs/canvas-darwin-x64@0.1.52':
+    resolution: {integrity: sha512-3fgeGJ3j2X6Mtmn0QYf3iA+A6y1ePnsayakc2emEokzf03ErrPczONw3vjnTQo53JLPMzEnfPGAffdktU/ssPA==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@napi-rs/canvas-linux-arm-gnueabihf@0.1.52':
+    resolution: {integrity: sha512-aaDEEK5XwHUrPt0q4SR8l7Va0vtn50KmSs+itxP+o7RNk3Nuch8fINHOXyhMyhwNYgv1tfiJVyHsJhD0E6lXGA==}
+    engines: {node: '>= 10'}
+    cpu: [arm]
+    os: [linux]
+
+  '@napi-rs/canvas-linux-arm64-gnu@0.1.52':
+    resolution: {integrity: sha512-tzuwM7Amt5mkrp4csQjYWkFzwFdiCm7RNdJ5usX8syzKSXmozqWzLHjzo/2ozdSQNUy6wyzRrxkG4Rh6g0OpOA==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@napi-rs/canvas-linux-arm64-musl@0.1.52':
+    resolution: {integrity: sha512-HQCtJlDT0dFp3uUZVzZOZ1VLMO7lbLRc548MjMxPpojit2ZdGopFzJ8jDSr4iszHrTO1SM1AxPaCM3pRvCAtjw==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@napi-rs/canvas-linux-x64-gnu@0.1.52':
+    resolution: {integrity: sha512-z5sBEw0PVWPH/MIQL8hOR8C3YYVlu8lqtRUcYajigMfXAhbMiNqDWTjuIWGMz3nIydDjZmn8KTxw/D4a0HFPqQ==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [linux]
+
+  '@napi-rs/canvas-linux-x64-musl@0.1.52':
+    resolution: {integrity: sha512-G1+JdWFhHLyHhULJS51xTEhB7EL0ZiAUQwQaRi4/w75OOYDQ91O+o4miaxDHiV0hZuxBhHtZU6ftV2Zl3RMguw==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [linux]
+
+  '@napi-rs/canvas-win32-x64-msvc@0.1.52':
+    resolution: {integrity: sha512-hMI626VsCC/wv29qHF78N7TSG+auatOp08DHln0Zdif5y1NJ14NU/rNUhzlTW8Zc6ssw+AMDJ3KKYYWYYg1aoA==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [win32]
+
+  '@napi-rs/canvas@0.1.52':
+    resolution: {integrity: sha512-xeW9EghZLDPZuqWJ4l1+eG3ld0i9J7SpV2zlgi34MPt/FE9K2XWGCfnLr0gHGOBkcI3YOVhI13I0HqRAkMPdVw==}
+    engines: {node: '>= 10'}
+
+  '@ndelangen/get-tarball@3.0.7':
+    resolution: {integrity: sha512-NqGfTZIZpRFef1GoVaShSSRwDC3vde3ThtTeqFdcYd6ipKqnfEVhjK2hUeHjCQUcptyZr2TONqcloFXM+5QBrQ==}
+
+  '@nestjs/common@10.3.8':
+    resolution: {integrity: sha512-P+vPEIvqx2e+fonsYVlFXKvoChyJ8Tq+lfpqdVFqblovHbFr3kZ/nYX0cPs+XuW6bnRT8tz0SSR9XBGU43kJhw==}
+    peerDependencies:
+      class-transformer: '*'
+      class-validator: '*'
+      reflect-metadata: ^0.1.12 || ^0.2.0
+      rxjs: ^7.1.0
+    peerDependenciesMeta:
+      class-transformer:
+        optional: true
+      class-validator:
+        optional: true
+
+  '@nestjs/core@10.3.8':
+    resolution: {integrity: sha512-AxF4tpYLDNn5Wfb3C4bNaaHJ4pREH5FJrSisR2A5zkYpQFORFs0Tc36lOFPMwBTy8Iv2wUwWLUVc5ftBnxEv4w==}
+    peerDependencies:
+      '@nestjs/common': ^10.0.0
+      '@nestjs/microservices': ^10.0.0
+      '@nestjs/platform-express': ^10.0.0
+      '@nestjs/websockets': ^10.0.0
+      reflect-metadata: ^0.1.12 || ^0.2.0
+      rxjs: ^7.1.0
+    peerDependenciesMeta:
+      '@nestjs/microservices':
+        optional: true
+      '@nestjs/platform-express':
+        optional: true
+      '@nestjs/websockets':
+        optional: true
+
+  '@nestjs/platform-express@10.3.8':
+    resolution: {integrity: sha512-sifLoxgEJvAgbim1UuW6wyScMfkS9SVQRH+lN33N/9ZvZSjO6NSDLOe+wxqsnZkia+QrjFC0qy0ITRAsggfqbg==}
+    peerDependencies:
+      '@nestjs/common': ^10.0.0
+      '@nestjs/core': ^10.0.0
+
+  '@nestjs/testing@10.3.8':
+    resolution: {integrity: sha512-hpX9das2TdFTKQ4/2ojhjI6YgXtCfXRKui3A4Qaj54VVzc5+mtK502Jj18Vzji98o9MVS6skmYu+S/UvW3U6Fw==}
+    peerDependencies:
+      '@nestjs/common': ^10.0.0
+      '@nestjs/core': ^10.0.0
+      '@nestjs/microservices': ^10.0.0
+      '@nestjs/platform-express': ^10.0.0
+    peerDependenciesMeta:
+      '@nestjs/microservices':
+        optional: true
+      '@nestjs/platform-express':
+        optional: true
+
+  '@nodelib/fs.scandir@2.1.5':
+    resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+    engines: {node: '>= 8'}
+
+  '@nodelib/fs.stat@2.0.5':
+    resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+    engines: {node: '>= 8'}
+
+  '@nodelib/fs.walk@1.2.8':
+    resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+    engines: {node: '>= 8'}
+
+  '@npmcli/agent@2.2.0':
+    resolution: {integrity: sha512-2yThA1Es98orMkpSLVqlDZAMPK3jHJhifP2gnNUdk1754uZ8yI5c+ulCoVG+WlntQA6MzhrURMXjSd9Z7dJ2/Q==}
+    engines: {node: ^16.14.0 || >=18.0.0}
+
+  '@npmcli/fs@3.1.0':
+    resolution: {integrity: sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
+  '@nsfw-filter/gif-frames@1.0.2':
+    resolution: {integrity: sha512-XZrbJWEN8YfVla5i+PD4Wj51rRlJ8OgnXiPjjOt/OsrbsCR9GZRD4jr953oNWcwiRaoIcOCFWQNMQukO7Yb1dA==}
+
+  '@nsfw-filter/save-pixels@2.3.4':
+    resolution: {integrity: sha512-dRZXwrXadMvxwJYKChrDBqC6GNvxVqlmdkyvZJO5DV65qyBsHZw8bPg9CnX7EgpxGl6+4ba/MAdHDLxs2XoD0Q==}
+
+  '@nuxtjs/opencollective@0.3.2':
+    resolution: {integrity: sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==}
+    engines: {node: '>=8.0.0', npm: '>=5.0.0'}
+    hasBin: true
+
+  '@one-ini/wasm@0.1.1':
+    resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==}
+
+  '@open-draft/deferred-promise@2.2.0':
+    resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==}
+
+  '@open-draft/logger@0.3.0':
+    resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==}
+
+  '@open-draft/until@2.1.0':
+    resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==}
+
+  '@peculiar/asn1-android@2.3.10':
+    resolution: {integrity: sha512-z9Rx9cFJv7UUablZISe7uksNbFJCq13hO0yEAOoIpAymALTLlvUOSLnGiQS7okPaM5dP42oTLhezH6XDXRXjGw==}
+
+  '@peculiar/asn1-ecc@2.3.8':
+    resolution: {integrity: sha512-Ah/Q15y3A/CtxbPibiLM/LKcMbnLTdUdLHUgdpB5f60sSvGkXzxJCu5ezGTFHogZXWNX3KSmYqilCrfdmBc6pQ==}
+
+  '@peculiar/asn1-rsa@2.3.8':
+    resolution: {integrity: sha512-ES/RVEHu8VMYXgrg3gjb1m/XG0KJWnV4qyZZ7mAg7rrF3VTmRbLxO8mk+uy0Hme7geSMebp+Wvi2U6RLLEs12Q==}
+
+  '@peculiar/asn1-schema@2.3.8':
+    resolution: {integrity: sha512-ULB1XqHKx1WBU/tTFIA+uARuRoBVZ4pNdOA878RDrRbBfBGcSzi5HBkdScC6ZbHn8z7L8gmKCgPC1LHRrP46tA==}
+
+  '@peculiar/asn1-x509@2.3.8':
+    resolution: {integrity: sha512-voKxGfDU1c6r9mKiN5ZUsZWh3Dy1BABvTM3cimf0tztNwyMJPhiXY94eRTgsMQe6ViLfT6EoXxkWVzcm3mFAFw==}
+
+  '@peertube/http-signature@1.7.0':
+    resolution: {integrity: sha512-aGQIwo6/sWtyyqhVK4e1MtxYz4N1X8CNt6SOtCc+Wnczs5S5ONaLHDDR8LYaGn0MgOwvGgXyuZ5sJIfd7iyoUw==}
+    engines: {node: '>=0.10'}
+
+  '@pkgjs/parseargs@0.11.0':
+    resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
+    engines: {node: '>=14'}
+
+  '@radix-ui/react-compose-refs@1.0.1':
+    resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==}
+    peerDependencies:
+      '@types/react': '*'
+      react: ^16.8 || ^17.0 || ^18.0
+    peerDependenciesMeta:
+      '@types/react':
+        optional: true
+
+  '@radix-ui/react-slot@1.0.2':
+    resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==}
+    peerDependencies:
+      '@types/react': '*'
+      react: ^16.8 || ^17.0 || ^18.0
+    peerDependenciesMeta:
+      '@types/react':
+        optional: true
+
+  '@readme/better-ajv-errors@1.6.0':
+    resolution: {integrity: sha512-9gO9rld84Jgu13kcbKRU+WHseNhaVt76wYMeRDGsUGYxwJtI3RmEJ9LY9dZCYQGI8eUZLuxb5qDja0nqklpFjQ==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      ajv: 4.11.8 - 8
+
+  '@readme/json-schema-ref-parser@1.2.0':
+    resolution: {integrity: sha512-Bt3QVovFSua4QmHa65EHUmh2xS0XJ3rgTEUPH998f4OW4VVJke3BuS16f+kM0ZLOGdvIrzrPRqwihuv5BAjtrA==}
+
+  '@readme/openapi-parser@2.5.0':
+    resolution: {integrity: sha512-IbymbOqRuUzoIgxfAAR7XJt2FWl6n2yqN09fF5adacGm7W03siA3bj1Emql0X9D2T+RpBYz3x9zDsMhuoMP62A==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      openapi-types: '>=7'
+
+  '@rollup/plugin-json@6.1.0':
+    resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==}
+    engines: {node: '>=14.0.0'}
+    peerDependencies:
+      rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+    peerDependenciesMeta:
+      rollup:
+        optional: true
+
+  '@rollup/plugin-replace@5.0.5':
+    resolution: {integrity: sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==}
+    engines: {node: '>=14.0.0'}
+    peerDependencies:
+      rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+    peerDependenciesMeta:
+      rollup:
+        optional: true
+
+  '@rollup/pluginutils@5.1.0':
+    resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==}
+    engines: {node: '>=14.0.0'}
+    peerDependencies:
+      rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+    peerDependenciesMeta:
+      rollup:
+        optional: true
+
+  '@rollup/rollup-android-arm-eabi@4.17.2':
+    resolution: {integrity: sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==}
+    cpu: [arm]
+    os: [android]
+
+  '@rollup/rollup-android-arm64@4.17.2':
+    resolution: {integrity: sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==}
+    cpu: [arm64]
+    os: [android]
+
+  '@rollup/rollup-darwin-arm64@4.17.2':
+    resolution: {integrity: sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@rollup/rollup-darwin-x64@4.17.2':
+    resolution: {integrity: sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==}
+    cpu: [x64]
+    os: [darwin]
+
+  '@rollup/rollup-linux-arm-gnueabihf@4.17.2':
+    resolution: {integrity: sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==}
+    cpu: [arm]
+    os: [linux]
+
+  '@rollup/rollup-linux-arm-musleabihf@4.17.2':
+    resolution: {integrity: sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==}
+    cpu: [arm]
+    os: [linux]
+
+  '@rollup/rollup-linux-arm64-gnu@4.17.2':
+    resolution: {integrity: sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==}
+    cpu: [arm64]
+    os: [linux]
+
+  '@rollup/rollup-linux-arm64-musl@4.17.2':
+    resolution: {integrity: sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==}
+    cpu: [arm64]
+    os: [linux]
+
+  '@rollup/rollup-linux-powerpc64le-gnu@4.17.2':
+    resolution: {integrity: sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@rollup/rollup-linux-riscv64-gnu@4.17.2':
+    resolution: {integrity: sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@rollup/rollup-linux-s390x-gnu@4.17.2':
+    resolution: {integrity: sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==}
+    cpu: [s390x]
+    os: [linux]
+
+  '@rollup/rollup-linux-x64-gnu@4.17.2':
+    resolution: {integrity: sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==}
+    cpu: [x64]
+    os: [linux]
+
+  '@rollup/rollup-linux-x64-musl@4.17.2':
+    resolution: {integrity: sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==}
+    cpu: [x64]
+    os: [linux]
+
+  '@rollup/rollup-win32-arm64-msvc@4.17.2':
+    resolution: {integrity: sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==}
+    cpu: [arm64]
+    os: [win32]
+
+  '@rollup/rollup-win32-ia32-msvc@4.17.2':
+    resolution: {integrity: sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==}
+    cpu: [ia32]
+    os: [win32]
+
+  '@rollup/rollup-win32-x64-msvc@4.17.2':
+    resolution: {integrity: sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==}
+    cpu: [x64]
+    os: [win32]
+
+  '@rushstack/node-core-library@4.1.0':
+    resolution: {integrity: sha512-qz4JFBZJCf1YN5cAXa1dP6Mki/HrsQxc/oYGAGx29dF2cwF2YMxHoly0FBhMw3IEnxo5fMj0boVfoHVBkpkx/w==}
+    peerDependencies:
+      '@types/node': '*'
+    peerDependenciesMeta:
+      '@types/node':
+        optional: true
+
+  '@rushstack/rig-package@0.5.2':
+    resolution: {integrity: sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==}
+
+  '@rushstack/terminal@0.10.1':
+    resolution: {integrity: sha512-C6Vi/m/84IYJTkfzmXr1+W8Wi3MmBjVF/q3za91Gb3VYjKbpALHVxY6FgH625AnDe5Z0Kh4MHKWA3Z7bqgAezA==}
+    peerDependencies:
+      '@types/node': '*'
+    peerDependenciesMeta:
+      '@types/node':
+        optional: true
+
+  '@rushstack/ts-command-line@4.19.2':
+    resolution: {integrity: sha512-cqmXXmBEBlzo9WtyUrHtF9e6kl0LvBY7aTSVX4jfnBfXWZQWnPq9JTFPlQZ+L/ZwjZ4HrNwQsOVvhe9oOucZkw==}
+
+  '@shikijs/core@1.4.0':
+    resolution: {integrity: sha512-CxpKLntAi64h3j+TwWqVIQObPTED0FyXLHTTh3MKXtqiQNn2JGcMQQ362LftDbc9kYbDtrksNMNoVmVXzKFYUQ==}
+
+  '@sideway/address@4.1.4':
+    resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==}
+
+  '@sideway/formula@3.0.1':
+    resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==}
+
+  '@sideway/pinpoint@2.0.0':
+    resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==}
+
+  '@simplewebauthn/server@10.0.0':
+    resolution: {integrity: sha512-w5eIoiF7ltg1sgggjY5Tx654j+DBuyEx2B3869jjmPp0xl2Z4BUP4kJ3yJ6DnZIv+ZYYntT3E6nZXNjPOQbrtw==}
+    engines: {node: '>=20.0.0'}
+
+  '@simplewebauthn/types@10.0.0':
+    resolution: {integrity: sha512-SFXke7xkgPRowY2E+8djKbdEznTVnD5R6GO7GPTthpHrokLvNKw8C3lFZypTxLI7KkCfGPfhtqB3d7OVGGa9jQ==}
+
+  '@sinclair/typebox@0.27.8':
+    resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
+
+  '@sindresorhus/is@4.6.0':
+    resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
+    engines: {node: '>=10'}
+
+  '@sindresorhus/is@5.3.0':
+    resolution: {integrity: sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==}
+    engines: {node: '>=14.16'}
+
+  '@sindresorhus/is@6.1.0':
+    resolution: {integrity: sha512-BuvU07zq3tQ/2SIgBsEuxKYDyDjC0n7Zir52bpHy2xnBbW81+po43aLFPLbeV3HRAheFbGud1qgcqSYfhtHMAg==}
+    engines: {node: '>=16'}
+
+  '@sinonjs/commons@2.0.0':
+    resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==}
+
+  '@sinonjs/commons@3.0.0':
+    resolution: {integrity: sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==}
+
+  '@sinonjs/fake-timers@10.3.0':
+    resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==}
+
+  '@sinonjs/fake-timers@11.2.2':
+    resolution: {integrity: sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==}
+
+  '@sinonjs/samsam@8.0.0':
+    resolution: {integrity: sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==}
+
+  '@sinonjs/text-encoding@0.7.2':
+    resolution: {integrity: sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==}
+
+  '@smithy/abort-controller@2.0.14':
+    resolution: {integrity: sha512-zXtteuYLWbSXnzI3O6xq3FYvigYZFW8mdytGibfarLL2lxHto9L3ILtGVnVGmFZa7SDh62l39EnU5hesLN87Fw==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/abort-controller@2.2.0':
+    resolution: {integrity: sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/chunked-blob-reader-native@2.0.0':
+    resolution: {integrity: sha512-HM8V2Rp1y8+1343tkZUKZllFhEQPNmpNdgFAncbTsxkZ18/gqjk23XXv3qGyXWp412f3o43ZZ1UZHVcHrpRnCQ==}
+
+  '@smithy/chunked-blob-reader@2.0.0':
+    resolution: {integrity: sha512-k+J4GHJsMSAIQPChGBrjEmGS+WbPonCXesoqP9fynIqjn7rdOThdH8FAeCmokP9mxTYKQAKoHCLPzNlm6gh7Wg==}
+
+  '@smithy/config-resolver@2.0.9':
+    resolution: {integrity: sha512-QBkGPLUqyPmis9Erz8v4q5lo/ErnF7+GD5WZHa6JZiXopUPfaaM+B21n8gzS5xCkIXZmnwzNQhObP9xQPu8oqQ==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/credential-provider-imds@2.0.11':
+    resolution: {integrity: sha512-uJJs8dnM5iXkn8a2GaKvlKMhcOJ+oJPYqY9gY3CM/EieCVObIDjxUtR/g8lU/k/A+OauA78GzScAfulmFjPOYA==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/eventstream-codec@2.0.8':
+    resolution: {integrity: sha512-onO4to8ujCKn4m5XagReT9Nc6FlNG5vveuvjp1H7AtaG7njdet1LOl6/jmUOkskF2C/w+9jNw3r9Ak+ghOvN0A==}
+
+  '@smithy/eventstream-serde-browser@2.0.8':
+    resolution: {integrity: sha512-/RGlkKUnC0sd+xKBKH/2APSBRmVMZTeLOKZMhrZmrO+ONoU+DwyMr/RLJ6WnmBKN+2ebjffM4pcIJTKLNNDD8g==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/eventstream-serde-config-resolver@2.0.8':
+    resolution: {integrity: sha512-EyAEj258eMUv9zcMvBbqrInh2eHRYuiwQAjXDMxZFCyP+JePzQB6O++3wFwjQeRKMFFgZipNgnEXfReII4+NAw==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/eventstream-serde-node@2.0.8':
+    resolution: {integrity: sha512-FMBatSUSKwh6aguKVJokXfJaV8nqsuCkCZHb9MP9zah0ZF+ohbTLeeed7DQGeTVBueVIVWEzIsShPxtxBv7MMQ==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/eventstream-serde-universal@2.0.8':
+    resolution: {integrity: sha512-6InMXH8BUKoEDa6CAuxR4Gn8Gf2vBfVtjA9A6zDKZClYHT+ANUJS+2EtOBc5wECJJGk4KLn5ajQyrt9MBv5lcw==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/fetch-http-handler@2.1.4':
+    resolution: {integrity: sha512-SL24M9W5ERByoXaVicRx+bj9GJVujDnPn+QO7GY7adhY0mPGa6DSF58pVKsgIh4r5Tx/k3SWCPlH4BxxSxA/fQ==}
+
+  '@smithy/hash-blob-browser@2.0.8':
+    resolution: {integrity: sha512-IgvRlBMfg/qLg321a59T1yTdEEbaizLrEVsU3DHj65DAO4lFRMF5f+l7vuV+je6m1G9wSD5GQXLturX8qlGb4g==}
+
+  '@smithy/hash-node@2.0.8':
+    resolution: {integrity: sha512-yZL/nmxZzjZV5/QX5JWSgXlt0HxuMTwFO89CS++jOMMPiCMZngf6VYmtNdccs8IIIAMmfQeTzwu07XgUE/Zd3Q==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/hash-stream-node@2.0.8':
+    resolution: {integrity: sha512-82zC6I9ZJycbEZH8TVyXyBx9c2ZIPQDgBvM0x5AFPUl/i1AxwKKX+lwYRnzgkF//cYhIIoJaCfJ9mjSMPRGvCQ==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/invalid-dependency@2.0.8':
+    resolution: {integrity: sha512-88VOS7W3KzUz/bNRc+Sl/F/CDIasFspEE4G39YZRHIh9YmsXF7GUyVaAKURfMNulTie62ayk6BHC9O0nOBAVgQ==}
+
+  '@smithy/is-array-buffer@2.0.0':
+    resolution: {integrity: sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/md5-js@2.0.8':
+    resolution: {integrity: sha512-1VVECXEiuJvjXv+mudiaUFKYwgDLOWz5MTTy8RzbrPiU3GiOb3/o5/urdkYpqmgoMfxdvxxOw/Adjv2dV2q2Yg==}
+
+  '@smithy/middleware-content-length@2.0.10':
+    resolution: {integrity: sha512-EGSbysyA4jH0p3xI6G0jdXoj9Iz9GUnAta6aEaHtXm3wVWtenRf80y2TeVvNkVSr5jwKOdSCjKIRI2l1A/oZLA==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/middleware-endpoint@2.0.8':
+    resolution: {integrity: sha512-yOpogfG2d2V0cbJdAJ6GLAWkNOc9pVsL5hZUfXcxJu408N3CUCsXzIAFF6+70ZKSE+lCfG3GFErcSXv/UfUbjw==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/middleware-retry@2.0.11':
+    resolution: {integrity: sha512-pknfokumZ+wvBERSuKAI2vVr+aK3ZgPiWRg6+0ZG4kKJogBRpPmDGWw+Jht0izS9ZaEbIobNzueIb4wD33JJVg==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/middleware-serde@2.0.8':
+    resolution: {integrity: sha512-Is0sm+LiNlgsc0QpstDzifugzL9ehno1wXp109GgBgpnKTK3j+KphiparBDI4hWTtH9/7OUsxuspNqai2yyhcg==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/middleware-stack@2.0.1':
+    resolution: {integrity: sha512-UexsfY6/oQZRjTQL56s9AKtMcR60tBNibSgNYX1I2WXaUaXg97W9JCkFyth85TzBWKDBTyhLfenrukS/kyu54A==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/node-config-provider@2.0.11':
+    resolution: {integrity: sha512-CaR1dciSSGKttjhcefpytYjsfI/Yd5mqL8am4wfmyFCDxSiPsvnEWHl8UjM/RbcAjX0klt+CeIKPSHEc0wGvJA==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/node-http-handler@2.5.0':
+    resolution: {integrity: sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/property-provider@2.0.9':
+    resolution: {integrity: sha512-25pPZ8f8DeRwYI5wbPRZaoMoR+3vrw8DwbA0TjP+GsdiB2KxScndr4HQehiJ5+WJ0giOTWhLz0bd+7Djv1qpUQ==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/protocol-http@3.0.10':
+    resolution: {integrity: sha512-6+tjNk7rXW7YTeGo9qwxXj/2BFpJTe37kTj3EnZCoX/nH+NP/WLA7O83fz8XhkGqsaAhLUPo/bB12vvd47nsmg==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/protocol-http@3.3.0':
+    resolution: {integrity: sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/querystring-builder@2.0.14':
+    resolution: {integrity: sha512-lQ4pm9vTv9nIhl5jt6uVMPludr6syE2FyJmHsIJJuOD7QPIJnrf9HhUGf1iHh9KJ4CUv21tpOU3X6s0rB6uJ0g==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/querystring-builder@2.2.0':
+    resolution: {integrity: sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/querystring-parser@2.0.8':
+    resolution: {integrity: sha512-ArbanNuR7O/MmTd90ZqhDqGOPPDYmxx3huHxD+R3cuCnazcK/1tGQA+SnnR5307T7ZRb5WTpB6qBggERuibVSA==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/service-error-classification@2.0.1':
+    resolution: {integrity: sha512-QHa9+t+v4s0cMuDCcbjIJN67mNZ42/+fc3jKe8P6ZMPXZl5ksKk6a8vhZ/m494GZng5eFTc3OePv+NF9cG83yg==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/shared-ini-file-loader@2.0.10':
+    resolution: {integrity: sha512-jWASteSezRKohJ7GdA7pHDvmr7Q7tw3b5mu3xLHIkZy/ICftJ+O7aqNaF8wklhI7UNFoQ7flFRM3Rd0KA+1BbQ==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/signature-v4@2.0.5':
+    resolution: {integrity: sha512-ABIzXmUDXK4n2c9cXjQLELgH2RdtABpYKT+U131e2I6RbCypFZmxIHmIBufJzU2kdMCQ3+thBGDWorAITFW04A==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/smithy-client@2.1.5':
+    resolution: {integrity: sha512-7S865uKzsxApM8W8Q6zkij7tcUFgaG8PuADMFdMt1yL/ku3d0+s6Zwrg3N7iXCPM08Gu/mf0BIfTXIu/9i450Q==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/types@2.12.0':
+    resolution: {integrity: sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/types@2.6.0':
+    resolution: {integrity: sha512-PgqxJq2IcdMF9iAasxcqZqqoOXBHufEfmbEUdN1pmJrJltT42b0Sc8UiYSWWzKkciIp9/mZDpzYi4qYG1qqg6g==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/url-parser@2.0.8':
+    resolution: {integrity: sha512-wQw7j004ScCrBRJ+oNPXlLE9mtofxyadSZ9D8ov/rHkyurS7z1HTNuyaGRj6OvKsEk0SVQsuY0C9+EfM75XTkw==}
+
+  '@smithy/util-base64@2.0.0':
+    resolution: {integrity: sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/util-body-length-browser@2.0.0':
+    resolution: {integrity: sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==}
+
+  '@smithy/util-body-length-node@2.1.0':
+    resolution: {integrity: sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/util-buffer-from@2.0.0':
+    resolution: {integrity: sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/util-config-provider@2.0.0':
+    resolution: {integrity: sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/util-defaults-mode-browser@2.0.9':
+    resolution: {integrity: sha512-JONLJVQWT8165XoSV36ERn3SVlZLJJ4D6IeGsCSePv65Uxa93pzSLE0UMSR9Jwm4zix7rst9AS8W5QIypZWP8Q==}
+    engines: {node: '>= 10.0.0'}
+
+  '@smithy/util-defaults-mode-node@2.0.11':
+    resolution: {integrity: sha512-tmqjNsfj+bgZN6jXBe6efZnukzILA7BUytHkzqikuRLNtR+0VVchQHvawD0w6vManh76rO81ydhioe7i4oBzuA==}
+    engines: {node: '>= 10.0.0'}
+
+  '@smithy/util-hex-encoding@2.0.0':
+    resolution: {integrity: sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/util-middleware@2.0.1':
+    resolution: {integrity: sha512-LnsBMi0Mg3gfz/TpNGLv2Jjcz2ra1OX5HR/4IaCepIYmtPQzqMWDdhX/XTW1LS8OZ0xbQuyQPcHkQ+2XkhWOVQ==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/util-retry@2.0.1':
+    resolution: {integrity: sha512-naj4X0IafJ9yJnVJ58QgSMkCNLjyQOnyrnKh/T0f+0UOUxJiT8vuFn/hS7B/pNqbo2STY7PyJ4J4f+5YqxwNtA==}
+    engines: {node: '>= 14.0.0'}
+
+  '@smithy/util-stream@2.0.11':
+    resolution: {integrity: sha512-2MeWfqSpZKdmEJ+tH8CJQSgzLWhH5cmdE24X7JB0hiamXrOmswWGGuPvyj/9sQCTclo57pNxLR2p7KrP8Ahiyg==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/util-uri-escape@2.0.0':
+    resolution: {integrity: sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/util-uri-escape@2.2.0':
+    resolution: {integrity: sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/util-utf8@2.0.0':
+    resolution: {integrity: sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/util-waiter@2.0.8':
+    resolution: {integrity: sha512-t9yaoofNhdEhNlyDeV5al/JJEFJ62HIQBGktgCUE63MvKn6imnbkh1qISsYMyMYVLwhWCpZ3Xa3R1LA+SnWcng==}
+    engines: {node: '>=14.0.0'}
+
+  '@sqltools/formatter@1.2.5':
+    resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==}
+
+  '@storybook/addon-actions@8.0.9':
+    resolution: {integrity: sha512-+I3VTvlKdj8puHeS2tyaOVv9syDiNLneVZbTfqN+UDOK2i42NwvZr8PVwjTzMlEj9eePJdCZgiipz55xwts5bw==}
+
+  '@storybook/addon-backgrounds@8.0.9':
+    resolution: {integrity: sha512-pCDecACrVyxPaJKEWS0sHsRb8xw+IPCSxDM1TkjaAQ6zZ468A/dcUnqW+LVK8bSXgQwWzn23wqnqPFSy5yptuQ==}
+
+  '@storybook/addon-controls@8.0.9':
+    resolution: {integrity: sha512-wWdmd62UP/sfPm8M7aJjEA+kEXTUIR/QsYi9PoYBhBZcXiikZ4kNan7oD7GfsnzGGKHrBVfwQhO+TqaENGYytA==}
+
+  '@storybook/addon-docs@8.0.9':
+    resolution: {integrity: sha512-x7hX7UuzJtClu6XwU3SfpyFhuckVcgqgD6BU6Ihxl0zs+i4xp6iKVXYSnHFMRM1sgoeT8TjPxab35Ke8w8BVRw==}
+
+  '@storybook/addon-essentials@8.0.9':
+    resolution: {integrity: sha512-mwAgdfrOsTuTDcagvM7veBh+iayZIWmKOazzkhrIWbhYcrXOsweigD2UOVeHgAiAzJK49znr4FXTCKcE1hOWcw==}
+
+  '@storybook/addon-highlight@8.0.9':
+    resolution: {integrity: sha512-vaRHGDbx7dpNpQECAHk5wczlZO3ntstprGlqnZt0o7ylz6xB5+pTQwTuIFty0hwKv+3TPcskzzifATUyEOEmyg==}
+
+  '@storybook/addon-interactions@8.0.9':
+    resolution: {integrity: sha512-AMIdNcyM6DDAWvMitBJMqp1iPZND8AXB4QT4VZHGMKG2ngHNKktriEKpTfcRkfKPGTJs9T+71dWfm6/R4tticw==}
+
+  '@storybook/addon-links@8.0.9':
+    resolution: {integrity: sha512-FVt+AdW3JFSqbJzkKiqKsMRWqHXqEvCBqFs7lNfk3OW0w0jfv1iREtrxE0dVdJoUFQC9V/2Im/EpJ7UB3C2bNQ==}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+    peerDependenciesMeta:
+      react:
+        optional: true
+
+  '@storybook/addon-mdx-gfm@8.0.9':
+    resolution: {integrity: sha512-AoEx+OGKANtVZgKyWKrQhGpMpDuc2S7PnOlNLUiDYzmj8ABAGPmEJmqeb/VHVgqLQSjhOW1fMsQ4fYsecvMxTQ==}
+
+  '@storybook/addon-measure@8.0.9':
+    resolution: {integrity: sha512-91svOOGEXmGG4USglwXLE3wtlUVgtbKJVxTKX7xRI+AC5JEEaKByVzP17/X8Qn/8HilUL7AfSQ0kCoqtPSJ5cA==}
+
+  '@storybook/addon-outline@8.0.9':
+    resolution: {integrity: sha512-fQ+jm356TgUnz81IxsC99/aOesbLw3N5OQRJpo/A6kqbLMzlq3ybVzuXYCKC3f0ArgQRNh4NoMeJBMRFMtaWRw==}
+
+  '@storybook/addon-storysource@8.0.9':
+    resolution: {integrity: sha512-5m3K2Rs4fQtKtqwrq4CDS1jK2wzWOlnxhE2ArX5XTWytb1am65CEPxfYTEQkvZH9oPGwX3cXytPCziynqysFMQ==}
+
+  '@storybook/addon-toolbars@8.0.9':
+    resolution: {integrity: sha512-nNSBnnBOhQ+EJwkrIkK4ZBYPcozNmEH770CZ/6NK85SUJ6WEBZapE6ru33jIUokFGEvlOlNCeai0GUc++cQP8w==}
+
+  '@storybook/addon-viewport@8.0.9':
+    resolution: {integrity: sha512-Ao4+D56cO7biaw+iTlMU1FBec1idX0cmdosDeCFZin06MSawcPkeBlRBeruaSQYdLes8TBMdZPFgfuqI5yIk6g==}
+
+  '@storybook/blocks@8.0.9':
+    resolution: {integrity: sha512-F2zSrfSwzTFN7qW3zB80tG+EXtmfmCDC6Ird0F7tolszb6tOqJcAcBOwQbE2O0wI63sLu21qxzXgaKBMkiWvJg==}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+    peerDependenciesMeta:
+      react:
+        optional: true
+      react-dom:
+        optional: true
+
+  '@storybook/builder-manager@8.0.9':
+    resolution: {integrity: sha512-/PxDwZIfMc/PSRZcasb6SIdGr3azIlenzx7dBF7Imt8i4jLHiAf1t00GvghlfJsvsrn4DNp95rbRbXTDyTj7tQ==}
+
+  '@storybook/builder-vite@8.0.9':
+    resolution: {integrity: sha512-7hEQFZIIz7VvxdySDpPE96iMvZxQvRZcRdhaNGeE+8Y2pyc3DgYE4WY3sjr+LUoB0a6TYLpAIKqbXwtLz0R+PQ==}
+    peerDependencies:
+      '@preact/preset-vite': '*'
+      typescript: '>= 4.3.x'
+      vite: ^4.0.0 || ^5.0.0
+      vite-plugin-glimmerx: '*'
+    peerDependenciesMeta:
+      '@preact/preset-vite':
+        optional: true
+      typescript:
+        optional: true
+      vite-plugin-glimmerx:
+        optional: true
+
+  '@storybook/channels@8.0.9':
+    resolution: {integrity: sha512-7Lcfyy5CsLWWGhMPO9WG4jZ/Alzp0AjepFhEreYHRPtQrfttp6qMAjE/g1aHgun0qHCYWxwqIG4NLR/hqDNrXQ==}
+
+  '@storybook/cli@8.0.9':
+    resolution: {integrity: sha512-lilYTKn8F5YOePijqfRYFa5v2mHVIJxPCIgTn+OXAmAFbcizZ6P8P6niU4J/NXulgx68Ln1M7hYhFtTP25hVTw==}
+    hasBin: true
+
+  '@storybook/client-logger@8.0.9':
+    resolution: {integrity: sha512-LzV/RHkbf07sRc1Jc0ff36RlapKf9Ul7/+9VMvVbI3hshH1CpmrZK4t/tsIdpX/EVOdJ1Gg5cES06PnleOAIPA==}
+
+  '@storybook/codemod@8.0.9':
+    resolution: {integrity: sha512-VBeGpSZSQpL6iyLLqceJSNGhdCqcNwv+xC/aWdDFOkmuE1YfbmNNwpa9QYv4ZFJ2QjUsm4iTWG60qK+9NXeSKA==}
+
+  '@storybook/components@8.0.9':
+    resolution: {integrity: sha512-JcwBGADzIJs0PSzqykrrD2KHzNG9wtexUOKuidt+FSv9szpUhe3qBAXIHpdfBRl7mOJ9TRZ5rt+mukEnfncdzA==}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+
+  '@storybook/core-common@8.0.9':
+    resolution: {integrity: sha512-Jmue+sfHFb4GTYBzyWYw1MygoJiQSfISIrKmNIzAmZ+oR9EOr+jpu/i/bH+uetZ2Hqg1AGhj1VB7OtJp9HQyWw==}
+
+  '@storybook/core-events@8.0.9':
+    resolution: {integrity: sha512-DxSUx7wG9Qe3OFUBnv3OrYq48J8UWNo2DUR5/JecJCtp3n++L4fAEW3J0IF5FfxpQDMQSp1yTNjZ2PaWCMd2ag==}
+
+  '@storybook/core-server@8.0.9':
+    resolution: {integrity: sha512-BIe1T5YUBl0GYxEjRoTQsvXD2pyuzL8rPTUD41zlzSQM0R8U6Iant9SzRms4u0+rKUm2mGxxKuODlUo5ewqaGA==}
+
+  '@storybook/csf-plugin@8.0.9':
+    resolution: {integrity: sha512-pXaNCNi++kxKsqSWwvx215fPx8cNqvepLVxQ7B69qXLHj80DHn0Q3DFBO3sLXNiQMJ2JK4OYcTxMfuOiyzszKw==}
+
+  '@storybook/csf-tools@8.0.9':
+    resolution: {integrity: sha512-PiNMhL97giLytTdQwuhsZ92buVk4gy9H/8DtrDhUc45/1OmF95gogm6T2Yap729SIFwgpOcuq/U3aVo6d6swVQ==}
+
+  '@storybook/csf@0.1.6':
+    resolution: {integrity: sha512-JjWnBptVhBYJ14yq+cHs66BXjykRUWQ5TlD1RhPxMOtavynYyV/Q+QR98/N+XB+mcPtFMm5I2DvNkpj0/Dk8Mw==}
+
+  '@storybook/docs-mdx@3.0.0':
+    resolution: {integrity: sha512-NmiGXl2HU33zpwTv1XORe9XG9H+dRUC1Jl11u92L4xr062pZtrShLmD4VKIsOQujxhhOrbxpwhNOt+6TdhyIdQ==}
+
+  '@storybook/docs-tools@8.0.9':
+    resolution: {integrity: sha512-OzogAeOmeHea/MxSPKRBWtOQVNSpoq+OOpimO9YRA5h5GBRJ2TUOGT44Gny6QT4ll5AvQA8fIiq9KezKcLekAg==}
+
+  '@storybook/global@5.0.0':
+    resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==}
+
+  '@storybook/icons@1.2.5':
+    resolution: {integrity: sha512-m3jnuE+zmkZy6K+cdUDzAoUuCJyl0fWCAXPCji7VZCH1TzFohyvnPqhc9JMkQpanej2TOW3wWXaplPzHghcBSg==}
+    engines: {node: '>=14.0.0'}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+
+  '@storybook/instrumenter@8.0.9':
+    resolution: {integrity: sha512-Gw74dgpTU/2p7FG0s7DuVdqCbJ2MEcSuRJjDo7HcXRYcvWp7I6Ly+C0v7N5VaoS+kbBVerAhLKIHZgG/LZf1og==}
+
+  '@storybook/manager-api@8.0.9':
+    resolution: {integrity: sha512-99b3yKArDSvfabXL7QE3nA95e4DdW/5H/ZCcr6/E2qCQJayZ6G1v/WWamKXbiaTpkndulFmcb/+ZmnDXcweIIQ==}
+
+  '@storybook/manager@8.0.9':
+    resolution: {integrity: sha512-+NnRo+5JQFGNqveKrLtC0b+Z08Tae4m44iq292bPeZMpr9OkFsIkU0PBPsHTHPkrqC/zZXRNsCsTEgvu3p2OIA==}
+
+  '@storybook/node-logger@8.0.9':
+    resolution: {integrity: sha512-5ajMdZFrYrjGLJOVDq7dlEQNFsgeLHymt4dCK9MulL/ciXykmXUZXE3Bye0wFy+I2qqDVvrvR8uzCvSFvm5MAQ==}
+
+  '@storybook/preview-api@8.0.9':
+    resolution: {integrity: sha512-zHfX34bkAMzzmE7vbDzaqFwSW6ExiBD0HiO1L/IsHF55f0f7xV7IH8uJyFRrDTvAoW3ReSxZDMvvPpeydFPKGA==}
+
+  '@storybook/preview@8.0.9':
+    resolution: {integrity: sha512-tFsR8xc8AYBZZrZw8enklFbSQt7ZAV+rv20BoxwDhd3q7fjXyK7O4moGPqUwBZ7rukTG13nPoISxr+VXAk/HYA==}
+
+  '@storybook/react-dom-shim@8.0.9':
+    resolution: {integrity: sha512-8011KlRuG3obr5pZZ7bcEyYYNWF3tR596YadoMd267NPoHKvwAbKL1L/DNgb6kiYjZDUf9QfaKSCWW31k0kcRQ==}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+
+  '@storybook/react-vite@8.0.9':
+    resolution: {integrity: sha512-FT5KeulUH6grfzOJOxJCxpv9+81UVDrT9UPcgiFhQT9rKtsgmltezThwbHknByZNw3WWnf+ieidMLEis9hd73A==}
+    engines: {node: '>=18.0.0'}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+      vite: ^4.0.0 || ^5.0.0
+
+  '@storybook/react@8.0.9':
+    resolution: {integrity: sha512-NeQ6suZG3HKikwe3Tx9cAIaRx7uP8FKCmlVvIiBg4LTTI5orCt94PPakvuZukZcbkqvcCnEBkebAzwUpn8PiJw==}
+    engines: {node: '>=18.0.0'}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+      typescript: '>= 4.2.x'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@storybook/router@8.0.9':
+    resolution: {integrity: sha512-aAOWxbM9J4mt+cp4o88T2PB29mgBBTOzU37/pUsTHYnKnR9XI4npXEXdN8Gv+ryqM0kj0AbBpz/llFlnR2MNNA==}
+
+  '@storybook/source-loader@8.0.9':
+    resolution: {integrity: sha512-FDnpxIGE5nIYT15pvYe6rz95TSBrdLcDll7lOHNyZisWt19MI3wZU3YkVsFNRBuFrebo+FjVU3wHyoV81ur1Qw==}
+
+  '@storybook/telemetry@8.0.9':
+    resolution: {integrity: sha512-AGGfcup06t+wxhBIkHd0iybieOh9PDVZQJ9oPct5JGB39+ni9wvs0WOD+MYlHbsjp8id7+aGkh6mYuYOvfck+Q==}
+
+  '@storybook/test@8.0.9':
+    resolution: {integrity: sha512-bRd5tBJnPzR6UKbDXONWnFWtdkNOY99HMLDUWe5fTRo50GwkrpFBVqPflhdkruEeof0kAbBUbnoN2CIYgtnAFw==}
+
+  '@storybook/theming@8.0.9':
+    resolution: {integrity: sha512-jgfDuYoiNMMirQiASN3Eg0hGDXsEtpdAcMxyShqYGwu9elxgD9yUnYC2nSckYsM74a3ZQ3JaViZ9ZFSe2FHmeQ==}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+    peerDependenciesMeta:
+      react:
+        optional: true
+      react-dom:
+        optional: true
+
+  '@storybook/types@8.0.9':
+    resolution: {integrity: sha512-ew0EXzk9k4B557P1qIWYrnvUcgaE0WWA5qQS0AU8l+fRTp5nvl9O3SP/zNIB0SN1qDFO7dXr3idTNTyIikTcEQ==}
+
+  '@storybook/vue3-vite@8.0.9':
+    resolution: {integrity: sha512-IkzYsEyCo5HIvLWbJeGrBu/VIN4u+LvdIAz7vcFqVVXBtTUhy+9/8caLx8fdnM0FWgKcBRQs8HnjBB2V0lOFcg==}
+    engines: {node: '>=18.0.0'}
+    peerDependencies:
+      vite: ^4.0.0 || ^5.0.0
+
+  '@storybook/vue3@8.0.9':
+    resolution: {integrity: sha512-EqVdS62YbOCAE0wJrQKW0sHpM90be8N8Mvmj+HzB0QYhJNtFqP9ehwbcTfwEKtaVGudisHgGBOzNoSKDlxFaag==}
+    engines: {node: '>=18.0.0'}
+    peerDependencies:
+      vue: ^3.0.0
+
+  '@swc/cli@0.3.12':
+    resolution: {integrity: sha512-h7bvxT+4+UDrLWJLFHt6V+vNAcUNii2G4aGSSotKz1ECEk4MyEh5CWxmeSscwuz5K3i+4DWTgm4+4EyMCQKn+g==}
+    engines: {node: '>= 16.14.0'}
+    hasBin: true
+    peerDependencies:
+      '@swc/core': ^1.2.66
+      chokidar: 3.5.3
+    peerDependenciesMeta:
+      chokidar:
+        optional: true
+
+  '@swc/core-android-arm64@1.3.11':
+    resolution: {integrity: sha512-M7FamR3kFpVTyTw73FzKcOZmS7/TWHX75eqtwBTaU9fW4shf0KTLr/h9DnMxNKAnwUMeub/lqlINUe5EKFIKwQ==}
+    engines: {node: '>=10'}
+    cpu: [arm64]
+    os: [android]
+
+  '@swc/core-darwin-arm64@1.3.56':
+    resolution: {integrity: sha512-DZcu7BzDaLEdWHabz9DRTP0yEBLqkrWmskFcD5BX0lGAvoIvE4duMnAqi5F2B3X7630QioHRCYFoRw2WkeE3Cw==}
+    engines: {node: '>=10'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@swc/core-darwin-arm64@1.4.17':
+    resolution: {integrity: sha512-HVl+W4LezoqHBAYg2JCqR+s9ife9yPfgWSj37iIawLWzOmuuJ7jVdIB7Ee2B75bEisSEKyxRlTl6Y1Oq3owBgw==}
+    engines: {node: '>=10'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@swc/core-darwin-x64@1.3.56':
+    resolution: {integrity: sha512-VH5saqYFasdRXJy6RAT+MXm0+IjkMZvOkohJwUei+oA65cKJofQwrJ1jZro8yOJFYvUSI3jgNRGsdBkmo/4hMw==}
+    engines: {node: '>=10'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@swc/core-darwin-x64@1.4.17':
+    resolution: {integrity: sha512-WYRO9Fdzq4S/he8zjW5I95G1zcvyd9yyD3Tgi4/ic84P5XDlSMpBDpBLbr/dCPjmSg7aUXxNQqKqGkl6dQxYlA==}
+    engines: {node: '>=10'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@swc/core-freebsd-x64@1.3.11':
+    resolution: {integrity: sha512-02uqYktPp6WmZfZ2Crc/yIVOcgANtjo8ciHcT7yLHvz7v+S7gx1I2tyNGUFtTX5hcR2IFNGrL8Yj4DvpTABFHg==}
+    engines: {node: '>=10'}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@swc/core-linux-arm-gnueabihf@1.3.56':
+    resolution: {integrity: sha512-LWwPo6NnJkH01+ukqvkoNIOpMdw+Zundm4vBeicwyVrkP+mC3kwVfi03TUFpQUz3kRKdw/QEnxGTj+MouCPbtw==}
+    engines: {node: '>=10'}
+    cpu: [arm]
+    os: [linux]
+
+  '@swc/core-linux-arm-gnueabihf@1.4.17':
+    resolution: {integrity: sha512-cgbvpWOvtMH0XFjvwppUCR+Y+nf6QPaGu6AQ5hqCP+5Lv2zO5PG0RfasC4zBIjF53xgwEaaWmGP5/361P30X8Q==}
+    engines: {node: '>=10'}
+    cpu: [arm]
+    os: [linux]
+
+  '@swc/core-linux-arm64-gnu@1.3.56':
+    resolution: {integrity: sha512-GzsUy/4egJ4cMlxbM+Ub7AMi5CKAc+pxBxrh8MUPQbyStW8jGgnQsJouTnGy0LHawtdEnsCOl6PcO6OgvktXuQ==}
+    engines: {node: '>=10'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@swc/core-linux-arm64-gnu@1.4.17':
+    resolution: {integrity: sha512-l7zHgaIY24cF9dyQ/FOWbmZDsEj2a9gRFbmgx2u19e3FzOPuOnaopFj0fRYXXKCmtdx+anD750iBIYnTR+pq/Q==}
+    engines: {node: '>=10'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@swc/core-linux-arm64-musl@1.3.56':
+    resolution: {integrity: sha512-9gxL09BIiAv8zY0DjfnFf19bo8+P4T9tdhzPwcm+1yPJcY5yr1+YFWLNFzz01agtOj6VlZ2/wUJTaOfdjjtc+A==}
+    engines: {node: '>=10'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@swc/core-linux-arm64-musl@1.4.17':
+    resolution: {integrity: sha512-qhH4gr9gAlVk8MBtzXbzTP3BJyqbAfUOATGkyUtohh85fPXQYuzVlbExix3FZXTwFHNidGHY8C+ocscI7uDaYw==}
+    engines: {node: '>=10'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@swc/core-linux-x64-gnu@1.3.56':
+    resolution: {integrity: sha512-n0ORNknl50vMRkll3BDO1E4WOqY6iISlPV1ZQCRLWQ6YQ2q8/WAryBxc2OAybcGHBUFkxyACpJukeU1QZ/9tNw==}
+    engines: {node: '>=10'}
+    cpu: [x64]
+    os: [linux]
+
+  '@swc/core-linux-x64-gnu@1.4.17':
+    resolution: {integrity: sha512-vRDFATL1oN5oZMImkwbgSHEkp8xG1ofEASBypze01W1Tqto8t+yo6gsp69wzCZBlxldsvPpvFZW55Jq0Rn+UnA==}
+    engines: {node: '>=10'}
+    cpu: [x64]
+    os: [linux]
+
+  '@swc/core-linux-x64-musl@1.3.56':
+    resolution: {integrity: sha512-r+D34WLAOAlJtfw1gaVWpHRwCncU9nzW9i7w9kSw4HpWYnHJOz54jLGSEmNsrhdTCz1VK2ar+V2ktFUsrlGlDA==}
+    engines: {node: '>=10'}
+    cpu: [x64]
+    os: [linux]
+
+  '@swc/core-linux-x64-musl@1.4.17':
+    resolution: {integrity: sha512-zQNPXAXn3nmPqv54JVEN8k2JMEcMTQ6veVuU0p5O+A7KscJq+AGle/7ZQXzpXSfUCXlLMX4wvd+rwfGhh3J4cw==}
+    engines: {node: '>=10'}
+    cpu: [x64]
+    os: [linux]
+
+  '@swc/core-win32-arm64-msvc@1.3.56':
+    resolution: {integrity: sha512-29Yt75Is6X24z3x8h/xZC1HnDPkPpyLH9mDQiM6Cuc0I9mVr1XSriPEUB2N/awf5IE4SA8c+3IVq1DtKWbkJIw==}
+    engines: {node: '>=10'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@swc/core-win32-arm64-msvc@1.4.17':
+    resolution: {integrity: sha512-z86n7EhOwyzxwm+DLE5NoLkxCTme2lq7QZlDjbQyfCxOt6isWz8rkW5QowTX8w9Rdmk34ncrjSLvnHOeLY17+w==}
+    engines: {node: '>=10'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@swc/core-win32-ia32-msvc@1.3.56':
+    resolution: {integrity: sha512-mplp0zbYDrcHtfvkniXlXdB04e2qIjz2Gq/XHKr4Rnc6xVORJjjXF91IemXKpavx2oZYJws+LNJL7UFQ8jyCdQ==}
+    engines: {node: '>=10'}
+    cpu: [ia32]
+    os: [win32]
+
+  '@swc/core-win32-ia32-msvc@1.4.17':
+    resolution: {integrity: sha512-JBwuSTJIgiJJX6wtr4wmXbfvOswHFj223AumUrK544QV69k60FJ9q2adPW9Csk+a8wm1hLxq4HKa2K334UHJ/g==}
+    engines: {node: '>=10'}
+    cpu: [ia32]
+    os: [win32]
+
+  '@swc/core-win32-x64-msvc@1.3.56':
+    resolution: {integrity: sha512-zp8MBnrw/bjdLenO/ifYzHrImSjKunqL0C2IF4LXYNRfcbYFh2NwobsVQMZ20IT0474lKRdlP8Oxdt+bHuXrzA==}
+    engines: {node: '>=10'}
+    cpu: [x64]
+    os: [win32]
+
+  '@swc/core-win32-x64-msvc@1.4.17':
+    resolution: {integrity: sha512-jFkOnGQamtVDBm3MF5Kq1lgW8vx4Rm1UvJWRUfg+0gx7Uc3Jp3QMFeMNw/rDNQYRDYPG3yunCC+2463ycd5+dg==}
+    engines: {node: '>=10'}
+    cpu: [x64]
+    os: [win32]
+
+  '@swc/core@1.4.17':
+    resolution: {integrity: sha512-tq+mdWvodMBNBBZbwFIMTVGYHe9N7zvEaycVVjfvAx20k1XozHbHhRv+9pEVFJjwRxLdXmtvFZd3QZHRAOpoNQ==}
+    engines: {node: '>=10'}
+    peerDependencies:
+      '@swc/helpers': ^0.5.0
+    peerDependenciesMeta:
+      '@swc/helpers':
+        optional: true
+
+  '@swc/counter@0.1.3':
+    resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
+
+  '@swc/jest@0.2.36':
+    resolution: {integrity: sha512-8X80dp81ugxs4a11z1ka43FPhP+/e+mJNXJSxiNYk8gIX/jPBtY4gQTrKu/KIoco8bzKuPI5lUxjfLiGsfvnlw==}
+    engines: {npm: '>= 7.0.0'}
+    peerDependencies:
+      '@swc/core': '*'
+
+  '@swc/types@0.1.5':
+    resolution: {integrity: sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==}
+
+  '@swc/wasm@1.2.130':
+    resolution: {integrity: sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==}
+
+  '@syuilo/aiscript@0.18.0':
+    resolution: {integrity: sha512-/iY9Vv4LLjtW/KUzId1QwXC4BlpIEPCMcoT7dyRhYdyxtwhS3Hx4b/4j1HYP+n3Pq9XKyW5zvkY72/+DNu4g6Q==}
+
+  '@szmarczak/http-timer@4.0.6':
+    resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==}
+    engines: {node: '>=10'}
+
+  '@szmarczak/http-timer@5.0.1':
+    resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==}
+    engines: {node: '>=14.16'}
+
+  '@tabler/icons-webfont@3.3.0':
+    resolution: {integrity: sha512-vMsxtwTXdC4QH4uDajZjBYThILEI0dP+Mn1s4XZkVtnJ793IF31i3596nYetWhAJnrED0UJ0HQWSbmqVxVQbxA==}
+
+  '@tabler/icons@3.3.0':
+    resolution: {integrity: sha512-PLVe9d7b59sKytbx00KgeGhQG3N176Ezv8YMmsnSz4s0ifDzMWlp/h2wEfQZ0ZNe8e377GY2OW6kovUe3Rnd0g==}
+
+  '@tensorflow/tfjs-backend-cpu@4.4.0':
+    resolution: {integrity: sha512-d4eln500/qNym78z9IrUUzF0ITBoJGLrxV8xd92kLVoXhg35Mm+zqUXShjFcrH8joOHOFuST0qZ0TbDDqcPzPA==}
+    engines: {yarn: '>= 1.3.2'}
+    peerDependencies:
+      '@tensorflow/tfjs-core': 4.4.0
+
+  '@tensorflow/tfjs-backend-webgl@4.4.0':
+    resolution: {integrity: sha512-TzQKvfAPgGt9cMG+5bVoTckoG1xr/PVJM/uODkPvzcMqi3j97kuWDXwkYJIgXldStmfiKkU7f5CmyD3Cq3E6BA==}
+    engines: {yarn: '>= 1.3.2'}
+    peerDependencies:
+      '@tensorflow/tfjs-core': 4.4.0
+
+  '@tensorflow/tfjs-converter@4.4.0':
+    resolution: {integrity: sha512-JUjpRStrAuw37tgPd5UENu0UjQVuJT09yF7KpOur4BriJ0uQqrbEZHMPHmvUtr5nYzkqlXJTuXIyxvEY/olNpg==}
+    peerDependencies:
+      '@tensorflow/tfjs-core': 4.4.0
+
+  '@tensorflow/tfjs-core@4.4.0':
+    resolution: {integrity: sha512-Anxpc7cAOA0Q7EUXdTbQKMg3reFvrdkgDlaYzH9ZfkMq2CgLV4Au6E/s6HmbYn/VrAtWy9mLY5c/lLJqh4764g==}
+    engines: {yarn: '>= 1.3.2'}
+
+  '@tensorflow/tfjs-data@4.4.0':
+    resolution: {integrity: sha512-aY4eq4cgrsrXeBU6ABZAAN3tV0fG4YcHd0z+cYuNXnCo+VEQLJnPmhn+xymZ4VQZQH4GXbVS4dV9pXMclFNRFw==}
+    peerDependencies:
+      '@tensorflow/tfjs-core': 4.4.0
+      seedrandom: ^3.0.5
+
+  '@tensorflow/tfjs-layers@4.4.0':
+    resolution: {integrity: sha512-OGC7shfiD9Gc698hINHK4y9slOJvu5m54tVNm4xf+WSNrw/avvgpar6yyoL5bakYIZNQvFNK75Yr8VRPR7oPeQ==}
+    peerDependencies:
+      '@tensorflow/tfjs-core': 4.4.0
+
+  '@tensorflow/tfjs-node@4.4.0':
+    resolution: {integrity: sha512-+JSAddsupjSQUDZeb7QGOFkL3Tty3kjPHx8ethiYFzwTZJHCMvM7wZJd0Fqnjxym6A0KpsmB7SPZgwRRXVIlPA==}
+    engines: {node: '>=8.11.0'}
+
+  '@tensorflow/tfjs@4.4.0':
+    resolution: {integrity: sha512-EmCsnzdvawyk4b+4JKaLLuicHcJQRZtL1zSy9AWJLiiHTbDDseYgLxfaCEfLk8v2bUe7SBXwl3n3B7OjgvH11Q==}
+    hasBin: true
+
+  '@testing-library/dom@9.3.3':
+    resolution: {integrity: sha512-fB0R+fa3AUqbLHWyxXa2kGVtf1Fe1ZZFr0Zp6AIbIAzXb2mKbEXl+PCQNUOaq5lbTab5tfctfXRNsWXxa2f7Aw==}
+    engines: {node: '>=14'}
+
+  '@testing-library/dom@9.3.4':
+    resolution: {integrity: sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==}
+    engines: {node: '>=14'}
+
+  '@testing-library/jest-dom@6.4.2':
+    resolution: {integrity: sha512-CzqH0AFymEMG48CpzXFriYYkOjk6ZGPCLMhW9e9jg3KMCn5OfJecF8GtGW7yGfR/IgCe3SX8BSwjdzI6BBbZLw==}
+    engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
+    peerDependencies:
+      '@jest/globals': '>= 28'
+      '@types/bun': latest
+      '@types/jest': '>= 28'
+      jest: '>= 28'
+      vitest: '>= 0.32'
+    peerDependenciesMeta:
+      '@jest/globals':
+        optional: true
+      '@types/bun':
+        optional: true
+      '@types/jest':
+        optional: true
+      jest:
+        optional: true
+      vitest:
+        optional: true
+
+  '@testing-library/user-event@14.5.2':
+    resolution: {integrity: sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==}
+    engines: {node: '>=12', npm: '>=6'}
+    peerDependencies:
+      '@testing-library/dom': '>=7.21.4'
+
+  '@testing-library/vue@8.0.3':
+    resolution: {integrity: sha512-wSsbNlZ69ZFQgVlHMtc/ZC/g9BHO7MhyDrd4nHyfEubtMr3kToN/w4/BsSBknGIF8w9UmPbsgbIuq/CbdBHzCA==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@vue/compiler-sfc': '>= 3'
+      vue: '>= 3'
+    peerDependenciesMeta:
+      '@vue/compiler-sfc':
+        optional: true
+
+  '@tokenizer/token@0.3.0':
+    resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
+
+  '@trysound/sax@0.2.0':
+    resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
+    engines: {node: '>=10.13.0'}
+
+  '@tsd/typescript@5.3.3':
+    resolution: {integrity: sha512-CQlfzol0ldaU+ftWuG52vH29uRoKboLinLy84wS8TQOu+m+tWoaUfk4svL4ij2V8M5284KymJBlHUusKj6k34w==}
+    engines: {node: '>=14.17'}
+
+  '@twemoji/parser@15.0.0':
+    resolution: {integrity: sha512-lh9515BNsvKSNvyUqbj5yFu83iIDQ77SwVcsN/SnEGawczhsKU6qWuogewN1GweTi5Imo5ToQ9s+nNTf97IXvg==}
+
+  '@twemoji/parser@15.1.1':
+    resolution: {integrity: sha512-CChRzIu6ngkCJOmURBlYEdX5DZSu+bBTtqR60XjBkFrmvplKW7OQsea+i8XwF4bLVlUXBO7ZmHhRPDzfQyLwwg==}
+
+  '@types/accepts@1.3.7':
+    resolution: {integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==}
+
+  '@types/archiver@6.0.2':
+    resolution: {integrity: sha512-KmROQqbQzKGuaAbmK+ZcytkJ51+YqDa7NmbXjmtC5YBLSyQYo21YaUnQ3HbaPFKL1ooo6RQ6OPYPIDyxfpDDXw==}
+
+  '@types/argparse@1.0.38':
+    resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==}
+
+  '@types/aria-query@5.0.1':
+    resolution: {integrity: sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==}
+
+  '@types/babel__core@7.20.0':
+    resolution: {integrity: sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==}
+
+  '@types/babel__generator@7.6.4':
+    resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==}
+
+  '@types/babel__template@7.4.1':
+    resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==}
+
+  '@types/babel__traverse@7.20.0':
+    resolution: {integrity: sha512-TBOjqAGf0hmaqRwpii5LLkJLg7c6OMm4nHLmpsUxwk9bBHtoTC6dAHdVWdGv4TBxj2CZOZY8Xfq8WmfoVi7n4Q==}
+
+  '@types/bcryptjs@2.4.6':
+    resolution: {integrity: sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==}
+
+  '@types/body-parser@1.19.5':
+    resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
+
+  '@types/braces@3.0.1':
+    resolution: {integrity: sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ==}
+
+  '@types/cacheable-request@6.0.3':
+    resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==}
+
+  '@types/chai-subset@1.3.5':
+    resolution: {integrity: sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==}
+
+  '@types/chai@4.3.11':
+    resolution: {integrity: sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==}
+
+  '@types/color-convert@2.0.3':
+    resolution: {integrity: sha512-2Q6wzrNiuEvYxVQqhh7sXM2mhIhvZR/Paq4FdsQkOMgWsCIkKvSGj8Le1/XalulrmgOzPMqNa0ix+ePY4hTrfg==}
+
+  '@types/color-name@1.1.1':
+    resolution: {integrity: sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==}
+
+  '@types/connect@3.4.35':
+    resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==}
+
+  '@types/content-disposition@0.5.8':
+    resolution: {integrity: sha512-QVSSvno3dE0MgO76pJhmv4Qyi/j0Yk9pBp0Y7TJ2Tlj+KCgJWY6qX7nnxCOLkZ3VYRSIk1WTxCvwUSdx6CCLdg==}
+
+  '@types/cookie@0.6.0':
+    resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
+
+  '@types/cross-spawn@6.0.2':
+    resolution: {integrity: sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==}
+
+  '@types/debug@4.1.12':
+    resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
+
+  '@types/detect-port@1.3.2':
+    resolution: {integrity: sha512-xxgAGA2SAU4111QefXPSp5eGbDm/hW6zhvYl9IeEPZEry9F4d66QAHm5qpUXjb6IsevZV/7emAEx5MhP6O192g==}
+
+  '@types/disposable-email-domains@1.0.2':
+    resolution: {integrity: sha512-SDKwyYTjk3y5aZBxxc38yRecpJPjsqn57STz1bNxYYlv4k11bBe7QB8w4llXDTmQXKT1mFvgGmJv+8Zdu3YmJw==}
+
+  '@types/doctrine@0.0.3':
+    resolution: {integrity: sha512-w5jZ0ee+HaPOaX25X2/2oGR/7rgAQSYII7X7pp0m9KgBfMP7uKfMfTvcpl5Dj+eDBbpxKGiqE+flqDr6XTd2RA==}
+
+  '@types/doctrine@0.0.9':
+    resolution: {integrity: sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==}
+
+  '@types/ejs@3.1.2':
+    resolution: {integrity: sha512-ZmiaE3wglXVWBM9fyVC17aGPkLo/UgaOjEiI2FXQfyczrCefORPxIe+2dVmnmk3zkVIbizjrlQzmPGhSYGXG5g==}
+
+  '@types/emscripten@1.39.7':
+    resolution: {integrity: sha512-tLqYV94vuqDrXh515F/FOGtBcRMTPGvVV1LzLbtYDcQmmhtpf/gLYf+hikBbQk8MzOHNz37wpFfJbYAuSn8HqA==}
+
+  '@types/escape-regexp@0.0.3':
+    resolution: {integrity: sha512-FQMYUxaf1dVeWLUzJFSvfdDugfOpDyM13p67QfyMdagxSkBa689opkr/q9uR/VWyrWrl0jAyQaSPKxX9MpAXFw==}
+
+  '@types/escodegen@0.0.6':
+    resolution: {integrity: sha512-AjwI4MvWx3HAOaZqYsjKWyEObT9lcVV0Y0V8nXo6cXzN8ZiMxVhf6F3d/UNvXVGKrEzL/Dluc5p+y9GkzlTWig==}
+
+  '@types/eslint@7.29.0':
+    resolution: {integrity: sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==}
+
+  '@types/estree@0.0.51':
+    resolution: {integrity: sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==}
+
+  '@types/estree@1.0.5':
+    resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
+
+  '@types/express-serve-static-core@4.17.33':
+    resolution: {integrity: sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==}
+
+  '@types/express@4.17.17':
+    resolution: {integrity: sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==}
+
+  '@types/find-cache-dir@3.2.1':
+    resolution: {integrity: sha512-frsJrz2t/CeGifcu/6uRo4b+SzAwT4NYCVPu1GN8IB9XTzrpPkGuV0tmh9mN+/L0PklAlsC3u5Fxt0ju00LXIw==}
+
+  '@types/fluent-ffmpeg@2.1.24':
+    resolution: {integrity: sha512-g5oQO8Jgi2kFS3tTub7wLvfLztr1s8tdXmRd8PiL/hLMLzTIAyMR2sANkTggM/rdEDAg3d63nYRRVepwBiCw5A==}
+
+  '@types/glob@7.2.0':
+    resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
+
+  '@types/graceful-fs@4.1.6':
+    resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==}
+
+  '@types/hast@3.0.4':
+    resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
+
+  '@types/htmlescape@1.1.3':
+    resolution: {integrity: sha512-tuC81YJXGUe0q8WRtBNW+uyx79rkkzWK651ALIXXYq5/u/IxjX4iHneGF2uUqzsNp+F+9J2mFZOv9jiLTtIq0w==}
+
+  '@types/http-cache-semantics@4.0.4':
+    resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
+
+  '@types/http-link-header@1.0.5':
+    resolution: {integrity: sha512-AxhIKR8UbyoqCTNp9rRepkktHuUOw3DjfOfDCaO9kwI8AYzjhxyrvZq4+mRw/2daD3hYDknrtSeV6SsPwmc71w==}
+
+  '@types/istanbul-lib-coverage@2.0.4':
+    resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==}
+
+  '@types/istanbul-lib-report@3.0.0':
+    resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==}
+
+  '@types/istanbul-reports@3.0.1':
+    resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==}
+
+  '@types/jest@29.5.12':
+    resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==}
+
+  '@types/js-yaml@4.0.9':
+    resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==}
+
+  '@types/jsdom@21.1.6':
+    resolution: {integrity: sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw==}
+
+  '@types/json-schema@7.0.12':
+    resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==}
+
+  '@types/json-schema@7.0.15':
+    resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+
+  '@types/json5@0.0.29':
+    resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
+
+  '@types/jsonld@1.5.13':
+    resolution: {integrity: sha512-n7fUU6W4kSYK8VQlf/LsE9kddBHPKhODoVOjsZswmve+2qLwBy6naWxs/EiuSZN9NU0N06Ra01FR+j87C62T0A==}
+
+  '@types/jsrsasign@10.5.14':
+    resolution: {integrity: sha512-lppSlfK6etu+cuKs40K4rg8As79PH6hzIB+v55zSqImbSH3SE6Fm8MBHCiI91cWlAP3Z4igtJK1VL3fSN09blQ==}
+
+  '@types/keyv@3.1.4':
+    resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
+
+  '@types/lodash@4.14.191':
+    resolution: {integrity: sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==}
+
+  '@types/long@4.0.2':
+    resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==}
+
+  '@types/matter-js@0.19.6':
+    resolution: {integrity: sha512-ffk6tqJM5scla+ThXmnox+mdfCo3qYk6yMjQsNcrbo6eQ5DqorVdtnaL+1agCoYzxUjmHeiNB7poBMAmhuLY7w==}
+
+  '@types/mdast@4.0.3':
+    resolution: {integrity: sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==}
+
+  '@types/mdx@2.0.3':
+    resolution: {integrity: sha512-IgHxcT3RC8LzFLhKwP3gbMPeaK7BM9eBH46OdapPA7yvuIUJ8H6zHZV53J8hGZcTSnt95jANt+rTBNUUc22ACQ==}
+
+  '@types/micromatch@4.0.7':
+    resolution: {integrity: sha512-C/FMQ8HJAZhTsDpl4wDKZdMeeW5USjgzOczUwTGbRc1ZopPgOhIEnxY2ZgUrsuyy4DwK1JVOJZKFakv3TbCKiA==}
+
+  '@types/mime-types@2.1.4':
+    resolution: {integrity: sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==}
+
+  '@types/mime@3.0.1':
+    resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==}
+
+  '@types/minimatch@5.1.2':
+    resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==}
+
+  '@types/minimist@1.2.2':
+    resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==}
+
+  '@types/ms@0.7.34':
+    resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==}
+
+  '@types/mute-stream@0.0.4':
+    resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==}
+
+  '@types/node-fetch@2.6.4':
+    resolution: {integrity: sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==}
+
+  '@types/node-fetch@3.0.3':
+    resolution: {integrity: sha512-HhggYPH5N+AQe/OmN6fmhKmRRt2XuNJow+R3pQwJxOOF9GuwM7O2mheyGeIrs5MOIeNjDEdgdoyHBOrFeJBR3g==}
+    deprecated: This is a stub types definition. node-fetch provides its own type definitions, so you do not need this installed.
+
+  '@types/node@18.17.15':
+    resolution: {integrity: sha512-2yrWpBk32tvV/JAd3HNHWuZn/VDN1P+72hWirHnvsvTGSqbANi+kSeuQR9yAHnbvaBvHDsoTdXV0Fe+iRtHLKA==}
+
+  '@types/node@20.11.5':
+    resolution: {integrity: sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==}
+
+  '@types/node@20.12.7':
+    resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==}
+
+  '@types/node@20.9.1':
+    resolution: {integrity: sha512-HhmzZh5LSJNS5O8jQKpJ/3ZcrrlG6L70hpGqMIAoM9YVD0YBRNWYsfwcXq8VnSjlNpCpgLzMXdiPo+dxcvSmiA==}
+
+  '@types/nodemailer@6.4.15':
+    resolution: {integrity: sha512-0EBJxawVNjPkng1zm2vopRctuWVCxk34JcIlRuXSf54habUWdz1FB7wHDqOqvDa8Mtpt0Q3LTXQkAs2LNyK5jQ==}
+
+  '@types/normalize-package-data@2.4.1':
+    resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
+
+  '@types/oauth2orize-pkce@0.1.2':
+    resolution: {integrity: sha512-g5rDzqQTTUIJJpY7UWxb0EU1WyURIwOj3TndKC2krEEEmaKrnZXgoEBkR72QY2kp4cJ6N9cF2AqTPJ0Qyg+caA==}
+
+  '@types/oauth2orize@1.11.5':
+    resolution: {integrity: sha512-C6hrRoh9hCnqis39OpeUZSwgw+TIzcV0CsxwJMGfQjTx4I1r+CLmuEPzoDJr5NRTfc7OMwHNLkQwrGFLKrJjMQ==}
+
+  '@types/oauth@0.9.4':
+    resolution: {integrity: sha512-qk9orhti499fq5XxKCCEbd0OzdPZuancneyse3KtR+vgMiHRbh+mn8M4G6t64ob/Fg+GZGpa565MF/2dKWY32A==}
+
+  '@types/offscreencanvas@2019.3.0':
+    resolution: {integrity: sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==}
+
+  '@types/offscreencanvas@2019.7.0':
+    resolution: {integrity: sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==}
+
+  '@types/pg@8.11.5':
+    resolution: {integrity: sha512-2xMjVviMxneZHDHX5p5S6tsRRs7TpDHeeK7kTTMe/kAC/mRRNjWHjZg0rkiY+e17jXSZV3zJYDxXV8Cy72/Vuw==}
+
+  '@types/pretty-hrtime@1.0.1':
+    resolution: {integrity: sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ==}
+
+  '@types/prop-types@15.7.5':
+    resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
+
+  '@types/pug@2.0.10':
+    resolution: {integrity: sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==}
+
+  '@types/punycode@2.1.4':
+    resolution: {integrity: sha512-trzh6NzBnq8yw5e35f8xe8VTYjqM3NE7bohBtvDVf/dtUer3zYTLK1Ka3DG3p7bdtoaOHZucma6FfVKlQ134pQ==}
+
+  '@types/qrcode@1.5.5':
+    resolution: {integrity: sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==}
+
+  '@types/qs@6.9.7':
+    resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==}
+
+  '@types/random-seed@0.3.5':
+    resolution: {integrity: sha512-CftxcDPAHgs0SLHU2dt+ZlDPJfGqLW3sZlC/ATr5vJDSe5tRLeOne7HMvCOJnFyF8e1U41wqzs3h6AMC613xtA==}
+
+  '@types/range-parser@1.2.4':
+    resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==}
+
+  '@types/ratelimiter@3.4.6':
+    resolution: {integrity: sha512-Bv6WLSXPGLVsBjkizXtn+ef78R92e36/DFQo2wXPTHtp1cYXF6rCULMqf9WcZPAtyMZMvQAtIPeYMA1xAyxghw==}
+
+  '@types/react@18.0.28':
+    resolution: {integrity: sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==}
+
+  '@types/readdir-glob@1.1.1':
+    resolution: {integrity: sha512-ImM6TmoF8bgOwvehGviEj3tRdRBbQujr1N+0ypaln/GWjaerOB26jb93vsRHmdMtvVQZQebOlqt2HROark87mQ==}
+
+  '@types/rename@1.0.7':
+    resolution: {integrity: sha512-E9qapfghUGfBMi3jNhsmCKPIp3f2zvNKpaX1BDGLGJNjzpgsZ/RTx7NaNksFjGoJ+r9NvWF1NSM5vVecnNjVmw==}
+
+  '@types/resolve@1.20.3':
+    resolution: {integrity: sha512-NH5oErHOtHZYcjCtg69t26aXEk4BN2zLWqf7wnDZ+dpe0iR7Rds1SPGEItl3fca21oOe0n3OCnZ4W7jBxu7FOw==}
+
+  '@types/responselike@1.0.0':
+    resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
+
+  '@types/sanitize-html@2.11.0':
+    resolution: {integrity: sha512-7oxPGNQHXLHE48r/r/qjn7q0hlrs3kL7oZnGj0Wf/h9tj/6ibFyRkNbsDxaBBZ4XUZ0Dx5LGCyDJ04ytSofacQ==}
+
+  '@types/scheduler@0.16.2':
+    resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
+
+  '@types/seedrandom@2.4.30':
+    resolution: {integrity: sha512-AnxLHewubLVzoF/A4qdxBGHCKifw8cY32iro3DQX9TPcetE95zBeVt3jnsvtvAUf1vwzMfwzp4t/L2yqPlnjkQ==}
+
+  '@types/seedrandom@3.0.8':
+    resolution: {integrity: sha512-TY1eezMU2zH2ozQoAFAQFOPpvP15g+ZgSfTZt31AUUH/Rxtnz3H+A/Sv1Snw2/amp//omibc+AEkTaA8KUeOLQ==}
+
+  '@types/semver@7.5.8':
+    resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==}
+
+  '@types/serve-static@1.15.1':
+    resolution: {integrity: sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==}
+
+  '@types/serviceworker@0.0.67':
+    resolution: {integrity: sha512-7TCH7iNsCSNb+aUD9M/36TekrWFSLCjNK8zw/3n5kOtRjbLtDfGYMXTrDnGhSfqXNwpqmt9Vd90w5C/ad1tX6Q==}
+
+  '@types/simple-oauth2@5.0.7':
+    resolution: {integrity: sha512-8JbWVJbiTSBQP/7eiyGKyXWAqp3dKQZpaA+pdW16FCi32ujkzRMG8JfjoAzdWt6W8U591ZNdHcPtP2D7ILTKuA==}
+
+  '@types/sinon@10.0.13':
+    resolution: {integrity: sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ==}
+
+  '@types/sinonjs__fake-timers@8.1.1':
+    resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==}
+
+  '@types/sinonjs__fake-timers@8.1.5':
+    resolution: {integrity: sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==}
+
+  '@types/sizzle@2.3.3':
+    resolution: {integrity: sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==}
+
+  '@types/stack-utils@2.0.1':
+    resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==}
+
+  '@types/statuses@2.0.4':
+    resolution: {integrity: sha512-eqNDvZsCNY49OAXB0Firg/Sc2BgoWsntsLUdybGFOhAfCD6QJ2n9HXUIHGqt5qjrxmMv4wS8WLAw43ZkKcJ8Pw==}
+
+  '@types/throttle-debounce@5.0.2':
+    resolution: {integrity: sha512-pDzSNulqooSKvSNcksnV72nk8p7gRqN8As71Sp28nov1IgmPKWbOEIwAWvBME5pPTtaXJAvG3O4oc76HlQ4kqQ==}
+
+  '@types/tinycolor2@1.4.6':
+    resolution: {integrity: sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==}
+
+  '@types/tmp@0.2.6':
+    resolution: {integrity: sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==}
+
+  '@types/tough-cookie@4.0.2':
+    resolution: {integrity: sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==}
+
+  '@types/unist@3.0.2':
+    resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==}
+
+  '@types/uuid@9.0.8':
+    resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==}
+
+  '@types/vary@1.1.3':
+    resolution: {integrity: sha512-XJT8/ZQCL7NUut9QDLf6l24JfAEl7bnNdgxfj50cHIpEPRJLHHDDFOAq6i+GsEmeFfH7NamhBE4c4Thtb2egWg==}
+
+  '@types/web-push@3.6.3':
+    resolution: {integrity: sha512-v3oT4mMJsHeJ/rraliZ+7TbZtr5bQQuxcgD7C3/1q/zkAj29c8RE0F9lVZVu3hiQe5Z9fYcBreV7TLnfKR+4mg==}
+
+  '@types/webgl-ext@0.0.30':
+    resolution: {integrity: sha512-LKVgNmBxN0BbljJrVUwkxwRYqzsAEPcZOe6S2T6ZaBDIrFp0qu4FNlpc5sM1tGbXUYFgdVQIoeLk1Y1UoblyEg==}
+
+  '@types/wrap-ansi@3.0.0':
+    resolution: {integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==}
+
+  '@types/ws@8.5.10':
+    resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==}
+
+  '@types/yargs-parser@21.0.0':
+    resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==}
+
+  '@types/yargs@17.0.19':
+    resolution: {integrity: sha512-cAx3qamwaYX9R0fzOIZAlFpo4A+1uBVCxqpKz9D26uTF4srRXaGTTsikQmaotCtNdbhzyUH7ft6p9ktz9s6UNQ==}
+
+  '@types/yauzl@2.10.0':
+    resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==}
+
+  '@typescript-eslint/eslint-plugin@6.11.0':
+    resolution: {integrity: sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    peerDependencies:
+      '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha
+      eslint: ^7.0.0 || ^8.0.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/eslint-plugin@7.1.0':
+    resolution: {integrity: sha512-j6vT/kCulhG5wBmGtstKeiVr1rdXE4nk+DT1k6trYkwlrvW9eOF5ZbgKnd/YR6PcM4uTEXa0h6Fcvf6X7Dxl0w==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    peerDependencies:
+      '@typescript-eslint/parser': ^7.0.0
+      eslint: ^8.56.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/eslint-plugin@7.7.1':
+    resolution: {integrity: sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==}
+    engines: {node: ^18.18.0 || >=20.0.0}
+    peerDependencies:
+      '@typescript-eslint/parser': ^7.0.0
+      eslint: ^8.56.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/parser@6.11.0':
+    resolution: {integrity: sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    peerDependencies:
+      eslint: ^7.0.0 || ^8.0.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/parser@7.1.0':
+    resolution: {integrity: sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    peerDependencies:
+      eslint: ^8.56.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/parser@7.7.1':
+    resolution: {integrity: sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==}
+    engines: {node: ^18.18.0 || >=20.0.0}
+    peerDependencies:
+      eslint: ^8.56.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/scope-manager@6.11.0':
+    resolution: {integrity: sha512-0A8KoVvIURG4uhxAdjSaxy8RdRE//HztaZdG8KiHLP8WOXSk0vlF7Pvogv+vlJA5Rnjj/wDcFENvDaHb+gKd1A==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+
+  '@typescript-eslint/scope-manager@7.1.0':
+    resolution: {integrity: sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+
+  '@typescript-eslint/scope-manager@7.7.1':
+    resolution: {integrity: sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==}
+    engines: {node: ^18.18.0 || >=20.0.0}
+
+  '@typescript-eslint/type-utils@6.11.0':
+    resolution: {integrity: sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    peerDependencies:
+      eslint: ^7.0.0 || ^8.0.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/type-utils@7.1.0':
+    resolution: {integrity: sha512-UZIhv8G+5b5skkcuhgvxYWHjk7FW7/JP5lPASMEUoliAPwIH/rxoUSQPia2cuOj9AmDZmwUl1usKm85t5VUMew==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    peerDependencies:
+      eslint: ^8.56.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/type-utils@7.7.1':
+    resolution: {integrity: sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==}
+    engines: {node: ^18.18.0 || >=20.0.0}
+    peerDependencies:
+      eslint: ^8.56.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/types@6.11.0':
+    resolution: {integrity: sha512-ZbEzuD4DwEJxwPqhv3QULlRj8KYTAnNsXxmfuUXFCxZmO6CF2gM/y+ugBSAQhrqaJL3M+oe4owdWunaHM6beqA==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+
+  '@typescript-eslint/types@7.1.0':
+    resolution: {integrity: sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+
+  '@typescript-eslint/types@7.7.1':
+    resolution: {integrity: sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==}
+    engines: {node: ^18.18.0 || >=20.0.0}
+
+  '@typescript-eslint/typescript-estree@6.11.0':
+    resolution: {integrity: sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/typescript-estree@7.1.0':
+    resolution: {integrity: sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/typescript-estree@7.7.1':
+    resolution: {integrity: sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==}
+    engines: {node: ^18.18.0 || >=20.0.0}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/utils@6.11.0':
+    resolution: {integrity: sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    peerDependencies:
+      eslint: ^7.0.0 || ^8.0.0
+
+  '@typescript-eslint/utils@7.1.0':
+    resolution: {integrity: sha512-WUFba6PZC5OCGEmbweGpnNJytJiLG7ZvDBJJoUcX4qZYf1mGZ97mO2Mps6O2efxJcJdRNpqweCistDbZMwIVHw==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    peerDependencies:
+      eslint: ^8.56.0
+
+  '@typescript-eslint/utils@7.7.1':
+    resolution: {integrity: sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==}
+    engines: {node: ^18.18.0 || >=20.0.0}
+    peerDependencies:
+      eslint: ^8.56.0
+
+  '@typescript-eslint/visitor-keys@6.11.0':
+    resolution: {integrity: sha512-+SUN/W7WjBr05uRxPggJPSzyB8zUpaYo2hByKasWbqr3PM8AXfZt8UHdNpBS1v9SA62qnSSMF3380SwDqqprgQ==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+
+  '@typescript-eslint/visitor-keys@7.1.0':
+    resolution: {integrity: sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+
+  '@typescript-eslint/visitor-keys@7.7.1':
+    resolution: {integrity: sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==}
+    engines: {node: ^18.18.0 || >=20.0.0}
+
+  '@ungap/structured-clone@1.2.0':
+    resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
+
+  '@vitejs/plugin-vue@5.0.4':
+    resolution: {integrity: sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==}
+    engines: {node: ^18.0.0 || >=20.0.0}
+    peerDependencies:
+      vite: ^5.0.0
+      vue: ^3.2.25
+
+  '@vitest/coverage-v8@0.34.6':
+    resolution: {integrity: sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw==}
+    peerDependencies:
+      vitest: '>=0.32.0 <1'
+
+  '@vitest/expect@0.34.6':
+    resolution: {integrity: sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==}
+
+  '@vitest/expect@1.3.1':
+    resolution: {integrity: sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==}
+
+  '@vitest/runner@0.34.6':
+    resolution: {integrity: sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==}
+
+  '@vitest/snapshot@0.34.6':
+    resolution: {integrity: sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==}
+
+  '@vitest/spy@0.34.6':
+    resolution: {integrity: sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==}
+
+  '@vitest/spy@1.3.1':
+    resolution: {integrity: sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==}
+
+  '@vitest/spy@1.6.0':
+    resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==}
+
+  '@vitest/utils@0.34.6':
+    resolution: {integrity: sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==}
+
+  '@vitest/utils@1.3.1':
+    resolution: {integrity: sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==}
+
+  '@vitest/utils@1.6.0':
+    resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==}
+
+  '@volar/language-core@2.2.0':
+    resolution: {integrity: sha512-a8WG9+4OdeNDW4ywABZIM6S6UN7em8uIlM/BZ2pWQUYrVmX+m8sj/X+QadvO+Li/t/LjAqbWJQtVgxdpEWLALQ==}
+
+  '@volar/source-map@2.2.0':
+    resolution: {integrity: sha512-HQlPRlHOVqCCHK8wI76ZldHkEwKsjp7E6idUc36Ekni+KJDNrqgSqPvyHQixybXPHNU7CI9Uxd9/IkxO7LuNBw==}
+
+  '@volar/typescript@2.2.0':
+    resolution: {integrity: sha512-wC6l4zLiiCLxF+FGaHCbWlQYf4vMsnRxYhcI6WgvaNppOD6r1g+Ef1RKRJUApALWU46Yy/JDU/TbdV6w/X6Liw==}
+
+  '@vue/compiler-core@3.4.21':
+    resolution: {integrity: sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==}
+
+  '@vue/compiler-core@3.4.25':
+    resolution: {integrity: sha512-Y2pLLopaElgWnMNolgG8w3C5nNUVev80L7hdQ5iIKPtMJvhVpG0zhnBG/g3UajJmZdvW0fktyZTotEHD1Srhbg==}
+
+  '@vue/compiler-core@3.4.26':
+    resolution: {integrity: sha512-N9Vil6Hvw7NaiyFUFBPXrAyETIGlQ8KcFMkyk6hW1Cl6NvoqvP+Y8p1Eqvx+UdqsnrnI9+HMUEJegzia3mhXmQ==}
+
+  '@vue/compiler-dom@3.4.21':
+    resolution: {integrity: sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==}
+
+  '@vue/compiler-dom@3.4.25':
+    resolution: {integrity: sha512-Ugz5DusW57+HjllAugLci19NsDK+VyjGvmbB2TXaTcSlQxwL++2PETHx/+Qv6qFwNLzSt7HKepPe4DcTE3pBWg==}
+
+  '@vue/compiler-dom@3.4.26':
+    resolution: {integrity: sha512-4CWbR5vR9fMg23YqFOhr6t6WB1Fjt62d6xdFPyj8pxrYub7d+OgZaObMsoxaF9yBUHPMiPFK303v61PwAuGvZA==}
+
+  '@vue/compiler-sfc@3.4.26':
+    resolution: {integrity: sha512-It1dp+FAOCgluYSVYlDn5DtZBxk1NCiJJfu2mlQqa/b+k8GL6NG/3/zRbJnHdhV2VhxFghaDq5L4K+1dakW6cw==}
+
+  '@vue/compiler-ssr@3.4.25':
+    resolution: {integrity: sha512-H2ohvM/Pf6LelGxDBnfbbXFPyM4NE3hrw0e/EpwuSiYu8c819wx+SVGdJ65p/sFrYDd6OnSDxN1MB2mN07hRSQ==}
+
+  '@vue/compiler-ssr@3.4.26':
+    resolution: {integrity: sha512-FNwLfk7LlEPRY/g+nw2VqiDKcnDTVdCfBREekF8X74cPLiWHUX6oldktf/Vx28yh4STNy7t+/yuLoMBBF7YDiQ==}
+
+  '@vue/devtools-api@6.6.1':
+    resolution: {integrity: sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA==}
+
+  '@vue/language-core@2.0.16':
+    resolution: {integrity: sha512-Bc2sexRH99pznOph8mLw2BlRZ9edm7tW51kcBXgx8adAoOcZUWJj3UNSsdQ6H9Y8meGz7BoazVrVo/jUukIsPw==}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@vue/reactivity@3.4.26':
+    resolution: {integrity: sha512-E/ynEAu/pw0yotJeLdvZEsp5Olmxt+9/WqzvKff0gE67tw73gmbx6tRkiagE/eH0UCubzSlGRebCbidB1CpqZQ==}
+
+  '@vue/runtime-core@3.4.26':
+    resolution: {integrity: sha512-AFJDLpZvhT4ujUgZSIL9pdNcO23qVFh7zWCsNdGQBw8ecLNxOOnPcK9wTTIYCmBJnuPHpukOwo62a2PPivihqw==}
+
+  '@vue/runtime-dom@3.4.26':
+    resolution: {integrity: sha512-UftYA2hUXR2UOZD/Fc3IndZuCOOJgFxJsWOxDkhfVcwLbsfh2CdXE2tG4jWxBZuDAs9J9PzRTUFt1PgydEtItw==}
+
+  '@vue/server-renderer@3.4.25':
+    resolution: {integrity: sha512-8VTwq0Zcu3K4dWV0jOwIVINESE/gha3ifYCOKEhxOj6MEl5K5y8J8clQncTcDhKF+9U765nRw4UdUEXvrGhyVQ==}
+    peerDependencies:
+      vue: 3.4.25
+
+  '@vue/server-renderer@3.4.26':
+    resolution: {integrity: sha512-xoGAqSjYDPGAeRWxeoYwqJFD/gw7mpgzOvSxEmjWaFO2rE6qpbD1PC172YRpvKhrihkyHJkNDADFXTfCyVGhKw==}
+    peerDependencies:
+      vue: 3.4.26
+
+  '@vue/shared@3.4.21':
+    resolution: {integrity: sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==}
+
+  '@vue/shared@3.4.25':
+    resolution: {integrity: sha512-k0yappJ77g2+KNrIaF0FFnzwLvUBLUYr8VOwz+/6vLsmItFp51AcxLL7Ey3iPd7BIRyWPOcqUjMnm7OkahXllA==}
+
+  '@vue/shared@3.4.26':
+    resolution: {integrity: sha512-Fg4zwR0GNnjzodMt3KRy2AWGMKQXByl56+4HjN87soxLNU9P5xcJkstAlIeEF3cU6UYOzmJl1tV0dVPGIljCnQ==}
+
+  '@vue/test-utils@2.4.1':
+    resolution: {integrity: sha512-VO8nragneNzUZUah6kOjiFmD/gwRjUauG9DROh6oaOeFwX1cZRUNHhdeogE8635cISigXFTtGLUQWx5KCb0xeg==}
+    peerDependencies:
+      '@vue/server-renderer': ^3.0.1
+      vue: ^3.0.1
+    peerDependenciesMeta:
+      '@vue/server-renderer':
+        optional: true
+
+  '@webgpu/types@0.1.30':
+    resolution: {integrity: sha512-9AXJSmL3MzY8ZL//JjudA//q+2kBRGhLBFpkdGksWIuxrMy81nFrCzj2Am+mbh8WoU6rXmv7cY5E3rdlyru2Qg==}
+
+  '@yarnpkg/esbuild-plugin-pnp@3.0.0-rc.15':
+    resolution: {integrity: sha512-kYzDJO5CA9sy+on/s2aIW0411AklfCi8Ck/4QDivOqsMKpStZA2SsR+X27VTggGwpStWaLrjJcDcdDMowtG8MA==}
+    engines: {node: '>=14.15.0'}
+    peerDependencies:
+      esbuild: '>=0.10.0'
+
+  '@yarnpkg/fslib@2.10.3':
+    resolution: {integrity: sha512-41H+Ga78xT9sHvWLlFOZLIhtU6mTGZ20pZ29EiZa97vnxdohJD2AF42rCoAoWfqUz486xY6fhjMH+DYEM9r14A==}
+    engines: {node: '>=12 <14 || 14.2 - 14.9 || >14.10.0'}
+
+  '@yarnpkg/libzip@2.3.0':
+    resolution: {integrity: sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==}
+    engines: {node: '>=12 <14 || 14.2 - 14.9 || >14.10.0'}
+
+  abbrev@1.1.1:
+    resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
+
+  abbrev@2.0.0:
+    resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
+  abort-controller@3.0.0:
+    resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
+    engines: {node: '>=6.5'}
+
+  abstract-logging@2.0.1:
+    resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==}
+
+  accepts@1.3.8:
+    resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
+    engines: {node: '>= 0.6'}
+
+  acorn-jsx@5.3.2:
+    resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+    peerDependencies:
+      acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+
+  acorn-walk@7.2.0:
+    resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==}
+    engines: {node: '>=0.4.0'}
+
+  acorn-walk@8.3.2:
+    resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==}
+    engines: {node: '>=0.4.0'}
+
+  acorn@7.4.1:
+    resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==}
+    engines: {node: '>=0.4.0'}
+    hasBin: true
+
+  acorn@8.11.3:
+    resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==}
+    engines: {node: '>=0.4.0'}
+    hasBin: true
+
+  address@1.2.2:
+    resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==}
+    engines: {node: '>= 10.0.0'}
+
+  adm-zip@0.5.10:
+    resolution: {integrity: sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==}
+    engines: {node: '>=6.0'}
+
+  agent-base@4.3.0:
+    resolution: {integrity: sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==}
+    engines: {node: '>= 4.0.0'}
+
+  agent-base@6.0.2:
+    resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
+    engines: {node: '>= 6.0.0'}
+
+  agent-base@7.1.0:
+    resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==}
+    engines: {node: '>= 14'}
+
+  aggregate-error@3.1.0:
+    resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
+    engines: {node: '>=8'}
+
+  aggregate-error@5.0.0:
+    resolution: {integrity: sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==}
+    engines: {node: '>=18'}
+
+  aiscript-vscode@https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/3f79d6f0550369267220aa67702287948d885424:
+    resolution: {tarball: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/3f79d6f0550369267220aa67702287948d885424}
+    version: 0.1.4
+    engines: {vscode: ^1.83.0}
+
+  ajv-draft-04@1.0.0:
+    resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==}
+    peerDependencies:
+      ajv: ^8.5.0
+    peerDependenciesMeta:
+      ajv:
+        optional: true
+
+  ajv-formats@2.1.1:
+    resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
+    peerDependencies:
+      ajv: ^8.0.0
+    peerDependenciesMeta:
+      ajv:
+        optional: true
+
+  ajv@6.12.6:
+    resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+
+  ajv@8.13.0:
+    resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==}
+
+  ansi-colors@4.1.3:
+    resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
+    engines: {node: '>=6'}
+
+  ansi-escapes@4.3.2:
+    resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
+    engines: {node: '>=8'}
+
+  ansi-regex@5.0.1:
+    resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+    engines: {node: '>=8'}
+
+  ansi-regex@6.0.1:
+    resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
+    engines: {node: '>=12'}
+
+  ansi-styles@3.2.1:
+    resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
+    engines: {node: '>=4'}
+
+  ansi-styles@4.3.0:
+    resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+    engines: {node: '>=8'}
+
+  ansi-styles@5.2.0:
+    resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
+    engines: {node: '>=10'}
+
+  ansi-styles@6.2.1:
+    resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
+    engines: {node: '>=12'}
+
+  any-promise@1.3.0:
+    resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
+
+  anymatch@3.1.3:
+    resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+    engines: {node: '>= 8'}
+
+  app-root-dir@1.0.2:
+    resolution: {integrity: sha512-jlpIfsOoNoafl92Sz//64uQHGSyMrD2vYG5d8o2a4qGvyNCvXur7bzIsWtAC/6flI2RYAp3kv8rsfBtaLm7w0g==}
+
+  app-root-path@3.1.0:
+    resolution: {integrity: sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==}
+    engines: {node: '>= 6.0.0'}
+
+  append-field@1.0.0:
+    resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==}
+
+  aproba@2.0.0:
+    resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==}
+
+  arch@2.2.0:
+    resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==}
+
+  archiver-utils@5.0.2:
+    resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==}
+    engines: {node: '>= 14'}
+
+  archiver@7.0.1:
+    resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==}
+    engines: {node: '>= 14'}
+
+  archy@1.0.0:
+    resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==}
+
+  are-we-there-yet@2.0.0:
+    resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==}
+    engines: {node: '>=10'}
+
+  arg@5.0.2:
+    resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
+
+  argparse@1.0.10:
+    resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
+
+  argparse@2.0.1:
+    resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
+  aria-query@5.1.3:
+    resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==}
+
+  array-buffer-byte-length@1.0.0:
+    resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==}
+
+  array-flatten@1.1.1:
+    resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
+
+  array-includes@3.1.7:
+    resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==}
+    engines: {node: '>= 0.4'}
+
+  array-union@2.1.0:
+    resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+    engines: {node: '>=8'}
+
+  array.prototype.findlastindex@1.2.3:
+    resolution: {integrity: sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==}
+    engines: {node: '>= 0.4'}
+
+  array.prototype.flat@1.3.2:
+    resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==}
+    engines: {node: '>= 0.4'}
+
+  array.prototype.flatmap@1.3.2:
+    resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==}
+    engines: {node: '>= 0.4'}
+
+  arraybuffer.prototype.slice@1.0.1:
+    resolution: {integrity: sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==}
+    engines: {node: '>= 0.4'}
+
+  arrify@1.0.1:
+    resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==}
+    engines: {node: '>=0.10.0'}
+
+  asap@2.0.6:
+    resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
+
+  asn1.js@5.4.1:
+    resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==}
+
+  asn1@0.2.6:
+    resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
+
+  asn1js@3.0.5:
+    resolution: {integrity: sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==}
+    engines: {node: '>=12.0.0'}
+
+  assert-never@1.2.1:
+    resolution: {integrity: sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==}
+
+  assert-plus@1.0.0:
+    resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==}
+    engines: {node: '>=0.8'}
+
+  assert@2.1.0:
+    resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==}
+
+  assertion-error@1.1.0:
+    resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
+
+  ast-types@0.16.1:
+    resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==}
+    engines: {node: '>=4'}
+
+  astral-regex@2.0.0:
+    resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
+    engines: {node: '>=8'}
+
+  astring@1.8.6:
+    resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==}
+    hasBin: true
+
+  async-mutex@0.5.0:
+    resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==}
+
+  async@3.2.4:
+    resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==}
+
+  asynckit@0.4.0:
+    resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+
+  at-least-node@1.0.0:
+    resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
+    engines: {node: '>= 4.0.0'}
+
+  atomic-sleep@1.0.0:
+    resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==}
+    engines: {node: '>=8.0.0'}
+
+  available-typed-arrays@1.0.5:
+    resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
+    engines: {node: '>= 0.4'}
+
+  avvio@8.3.0:
+    resolution: {integrity: sha512-VBVH0jubFr9LdFASy/vNtm5giTrnbVquWBhT0fyizuNK2rQ7e7ONU2plZQWUNqtE1EmxFEb+kbSkFRkstiaS9Q==}
+
+  aws-sdk-client-mock@3.0.1:
+    resolution: {integrity: sha512-9VAzJLl8mz99KP9HjOm/93d8vznRRUTpJooPBOunRdUAnVYopCe9xmMuu7eVemu8fQ+w6rP7o5bBK1kAFkB2KQ==}
+
+  aws-sign2@0.7.0:
+    resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==}
+
+  aws4@1.12.0:
+    resolution: {integrity: sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==}
+
+  axios@0.24.0:
+    resolution: {integrity: sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==}
+
+  axios@1.6.2:
+    resolution: {integrity: sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==}
+
+  b4a@1.6.4:
+    resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==}
+
+  babel-core@7.0.0-bridge.0:
+    resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  babel-jest@29.7.0:
+    resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+    peerDependencies:
+      '@babel/core': ^7.8.0
+
+  babel-plugin-istanbul@6.1.1:
+    resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==}
+    engines: {node: '>=8'}
+
+  babel-plugin-jest-hoist@29.6.3:
+    resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  babel-plugin-polyfill-corejs2@0.4.6:
+    resolution: {integrity: sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==}
+    peerDependencies:
+      '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
+
+  babel-plugin-polyfill-corejs3@0.8.6:
+    resolution: {integrity: sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==}
+    peerDependencies:
+      '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
+
+  babel-plugin-polyfill-regenerator@0.5.3:
+    resolution: {integrity: sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==}
+    peerDependencies:
+      '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
+
+  babel-preset-current-node-syntax@1.0.1:
+    resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  babel-preset-jest@29.6.3:
+    resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  babel-walk@3.0.0-canary-5:
+    resolution: {integrity: sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==}
+    engines: {node: '>= 10.0.0'}
+
+  bail@2.0.2:
+    resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
+
+  balanced-match@1.0.2:
+    resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+  base64-js@1.5.1:
+    resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+
+  bcrypt-pbkdf@1.0.2:
+    resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==}
+
+  bcryptjs@2.4.3:
+    resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==}
+
+  better-opn@3.0.2:
+    resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==}
+    engines: {node: '>=12.0.0'}
+
+  big-integer@1.6.51:
+    resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==}
+    engines: {node: '>=0.6'}
+
+  bin-check@4.1.0:
+    resolution: {integrity: sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==}
+    engines: {node: '>=4'}
+
+  bin-version-check@5.0.0:
+    resolution: {integrity: sha512-Q3FMQnS5eZmrBGqmDXLs4dbAn/f+52voP6ykJYmweSA60t6DyH4UTSwZhtbK5UH+LBoWvDljILUQMLRUtsynsA==}
+    engines: {node: '>=12'}
+
+  bin-version@6.0.0:
+    resolution: {integrity: sha512-nk5wEsP4RiKjG+vF+uG8lFsEn4d7Y6FVDamzzftSunXOoOcOOkzcWdKVlGgFFwlUQCj63SgnUkLLGF8v7lufhw==}
+    engines: {node: '>=12'}
+
+  binary-extensions@2.2.0:
+    resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
+    engines: {node: '>=8'}
+
+  bl@4.1.0:
+    resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
+
+  blob-util@2.0.2:
+    resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==}
+
+  bluebird@3.7.2:
+    resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
+
+  blurhash@2.0.5:
+    resolution: {integrity: sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w==}
+
+  bn.js@4.12.0:
+    resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==}
+
+  body-parser@1.20.1:
+    resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==}
+    engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+
+  body-parser@1.20.2:
+    resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==}
+    engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+
+  boolbase@1.0.0:
+    resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
+
+  bowser@2.11.0:
+    resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==}
+
+  bplist-parser@0.2.0:
+    resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==}
+    engines: {node: '>= 5.10.0'}
+
+  brace-expansion@1.1.11:
+    resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+
+  brace-expansion@2.0.1:
+    resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+
+  braces@3.0.2:
+    resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
+    engines: {node: '>=8'}
+
+  broadcast-channel@7.0.0:
+    resolution: {integrity: sha512-a2tW0Ia1pajcPBOGUF2jXlDnvE9d5/dg6BG9h60OmRUcZVr/veUrU8vEQFwwQIhwG3KVzYwSk3v2nRRGFgQDXQ==}
+
+  browser-assert@1.2.1:
+    resolution: {integrity: sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==}
+
+  browserify-zlib@0.1.4:
+    resolution: {integrity: sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ==}
+
+  browserslist@4.22.2:
+    resolution: {integrity: sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==}
+    engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+    hasBin: true
+
+  browserslist@4.23.0:
+    resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==}
+    engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+    hasBin: true
+
+  bser@2.1.1:
+    resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
+
+  buffer-crc32@0.2.13:
+    resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
+
+  buffer-crc32@1.0.0:
+    resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==}
+    engines: {node: '>=8.0.0'}
+
+  buffer-equal-constant-time@1.0.1:
+    resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
+
+  buffer-from@1.1.2:
+    resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
+
+  buffer@5.6.0:
+    resolution: {integrity: sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==}
+
+  buffer@5.7.1:
+    resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
+
+  buffer@6.0.3:
+    resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
+
+  bufferutil@4.0.7:
+    resolution: {integrity: sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==}
+    engines: {node: '>=6.14.2'}
+
+  bullmq@5.7.8:
+    resolution: {integrity: sha512-F/Haeu6AVHkFrfeaU/kLOjhfrH6x3CaKAZlQQ+76fa8l3kfI9oaUHeFMW+1mYVz0NtYPF7PNTWFq4ylAHYcCgA==}
+
+  buraha@0.0.1:
+    resolution: {integrity: sha512-G563A0mTbzknm2jDaNxfZuNKIdeArs8T+XQN6t+KbmgnOoevXSXhKDkyf8Md/36Jrx99ikwbCag37VGe3myExQ==}
+
+  busboy@1.6.0:
+    resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
+    engines: {node: '>=10.16.0'}
+
+  bytes@3.0.0:
+    resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==}
+    engines: {node: '>= 0.8'}
+
+  bytes@3.1.2:
+    resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
+    engines: {node: '>= 0.8'}
+
+  cac@6.7.14:
+    resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
+    engines: {node: '>=8'}
+
+  cacache@18.0.0:
+    resolution: {integrity: sha512-I7mVOPl3PUCeRub1U8YoGz2Lqv9WOBpobZ8RyWFXmReuILz+3OAyTa5oH3QPdtKZD7N0Yk00aLfzn0qvp8dZ1w==}
+    engines: {node: ^16.14.0 || >=18.0.0}
+
+  cacheable-lookup@5.0.4:
+    resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==}
+    engines: {node: '>=10.6.0'}
+
+  cacheable-lookup@7.0.0:
+    resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==}
+    engines: {node: '>=14.16'}
+
+  cacheable-request@10.2.14:
+    resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==}
+    engines: {node: '>=14.16'}
+
+  cacheable-request@7.0.2:
+    resolution: {integrity: sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==}
+    engines: {node: '>=8'}
+
+  cachedir@2.3.0:
+    resolution: {integrity: sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==}
+    engines: {node: '>=6'}
+
+  call-bind@1.0.2:
+    resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
+
+  call-me-maybe@1.0.2:
+    resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==}
+
+  callsites@3.1.0:
+    resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+    engines: {node: '>=6'}
+
+  camelcase-keys@6.2.2:
+    resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==}
+    engines: {node: '>=8'}
+
+  camelcase@5.3.1:
+    resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
+    engines: {node: '>=6'}
+
+  camelcase@6.3.0:
+    resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
+    engines: {node: '>=10'}
+
+  caniuse-api@3.0.0:
+    resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==}
+
+  caniuse-lite@1.0.30001566:
+    resolution: {integrity: sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==}
+
+  caniuse-lite@1.0.30001591:
+    resolution: {integrity: sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==}
+
+  canonicalize@1.0.8:
+    resolution: {integrity: sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==}
+
+  canvas-confetti@1.9.3:
+    resolution: {integrity: sha512-rFfTURMvmVEX1gyXFgn5QMn81bYk70qa0HLzcIOSVEyl57n6o9ItHeBtUSWdvKAPY0xlvBHno4/v3QPrT83q9g==}
+
+  caseless@0.12.0:
+    resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
+
+  cbor@9.0.2:
+    resolution: {integrity: sha512-JPypkxsB10s9QOWwa6zwPzqE1Md3vqpPc+cai4sAecuCsRyAtAl/pMyhPlMbT/xtPnm2dznJZYRLui57qiRhaQ==}
+    engines: {node: '>=16'}
+
+  ccount@2.0.1:
+    resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
+
+  chai@4.3.10:
+    resolution: {integrity: sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==}
+    engines: {node: '>=4'}
+
+  chalk-template@1.1.0:
+    resolution: {integrity: sha512-T2VJbcDuZQ0Tb2EWwSotMPJjgpy1/tGee1BTpUNsGZ/qgNjV2t7Mvu+d4600U564nbLesN1x2dPL+xii174Ekg==}
+    engines: {node: '>=14.16'}
+
+  chalk@2.4.2:
+    resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
+    engines: {node: '>=4'}
+
+  chalk@3.0.0:
+    resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==}
+    engines: {node: '>=8'}
+
+  chalk@4.1.2:
+    resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+    engines: {node: '>=10'}
+
+  chalk@5.3.0:
+    resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
+    engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+
+  char-regex@1.0.2:
+    resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
+    engines: {node: '>=10'}
+
+  character-entities@2.0.2:
+    resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==}
+
+  character-parser@2.2.0:
+    resolution: {integrity: sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==}
+
+  chart.js@4.4.2:
+    resolution: {integrity: sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==}
+    engines: {pnpm: '>=8'}
+
+  chartjs-adapter-date-fns@3.0.0:
+    resolution: {integrity: sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==}
+    peerDependencies:
+      chart.js: '>=2.8.0'
+      date-fns: '>=2.0.0'
+
+  chartjs-chart-matrix@2.0.1:
+    resolution: {integrity: sha512-BGfeY+/PHnITyDlc7WfnKJ1RyOfgOzIqWp/gxzzl7pUjyoGzHDcw51qd2xJF9gdT9Def7ZwOnOMm8GJUXDxI0w==}
+    peerDependencies:
+      chart.js: '>=3.0.0'
+
+  chartjs-plugin-gradient@0.6.1:
+    resolution: {integrity: sha512-TGHNIh8KqQMLdb+UfY80cBHYRyOC47eeokmgkeajRdKGbFt462lJiyiq4ZJ25fiM7BGsmzoBLhmVyEw4B3gQxw==}
+    peerDependencies:
+      chart.js: '>=2.6.0'
+
+  chartjs-plugin-zoom@2.0.1:
+    resolution: {integrity: sha512-ogOmLu6e+Q7E1XWOCOz9YwybMslz9qNfGV2a+qjfmqJYpsw5ZMoRHZBUyW+NGhkpQ5PwwPA/+rikHpBZb7PZuA==}
+    peerDependencies:
+      chart.js: '>=3.2.0'
+
+  check-error@1.0.3:
+    resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==}
+
+  check-more-types@2.24.0:
+    resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==}
+    engines: {node: '>= 0.8.0'}
+
+  cheerio-select@2.1.0:
+    resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==}
+
+  cheerio@1.0.0-rc.12:
+    resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==}
+    engines: {node: '>= 6'}
+
+  chokidar@3.5.3:
+    resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
+    engines: {node: '>= 8.10.0'}
+
+  chownr@1.1.4:
+    resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
+
+  chownr@2.0.0:
+    resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
+    engines: {node: '>=10'}
+
+  chromatic@11.3.0:
+    resolution: {integrity: sha512-q1ZtJDJrjLGnz60ivpC16gmd7KFzcaA4eTb7gcytCqbaKqlHhCFr1xQmcUDsm14CK7JsqdkFU6S+JQdOd2ZNJg==}
+    hasBin: true
+    peerDependencies:
+      '@chromatic-com/cypress': ^0.*.* || ^1.0.0
+      '@chromatic-com/playwright': ^0.*.* || ^1.0.0
+    peerDependenciesMeta:
+      '@chromatic-com/cypress':
+        optional: true
+      '@chromatic-com/playwright':
+        optional: true
+
+  ci-info@3.7.1:
+    resolution: {integrity: sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==}
+    engines: {node: '>=8'}
+
+  cjs-module-lexer@1.2.2:
+    resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==}
+
+  clean-stack@2.2.0:
+    resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
+    engines: {node: '>=6'}
+
+  clean-stack@5.2.0:
+    resolution: {integrity: sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==}
+    engines: {node: '>=14.16'}
+
+  cli-cursor@3.1.0:
+    resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
+    engines: {node: '>=8'}
+
+  cli-highlight@2.1.11:
+    resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==}
+    engines: {node: '>=8.0.0', npm: '>=5.0.0'}
+    hasBin: true
+
+  cli-spinners@2.7.0:
+    resolution: {integrity: sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==}
+    engines: {node: '>=6'}
+
+  cli-spinners@2.9.2:
+    resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==}
+    engines: {node: '>=6'}
+
+  cli-table3@0.6.3:
+    resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==}
+    engines: {node: 10.* || >= 12.*}
+
+  cli-truncate@2.1.0:
+    resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==}
+    engines: {node: '>=8'}
+
+  cli-width@4.1.0:
+    resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==}
+    engines: {node: '>= 12'}
+
+  cliui@6.0.0:
+    resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
+
+  cliui@7.0.4:
+    resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==}
+
+  cliui@8.0.1:
+    resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
+    engines: {node: '>=12'}
+
+  clone-deep@4.0.1:
+    resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==}
+    engines: {node: '>=6'}
+
+  clone-response@1.0.3:
+    resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==}
+
+  clone@1.0.4:
+    resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
+    engines: {node: '>=0.8'}
+
+  cluster-key-slot@1.1.2:
+    resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
+    engines: {node: '>=0.10.0'}
+
+  co@4.6.0:
+    resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
+    engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
+
+  code-error-fragment@0.0.230:
+    resolution: {integrity: sha512-cadkfKp6932H8UkhzE/gcUqhRMNf8jHzkAN7+5Myabswaghu4xABTgPHDCjW+dBAJxj/SpkTYokpzDqY4pCzQw==}
+    engines: {node: '>= 4'}
+
+  collect-v8-coverage@1.0.1:
+    resolution: {integrity: sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==}
+
+  color-convert@1.9.3:
+    resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
+
+  color-convert@2.0.1:
+    resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+    engines: {node: '>=7.0.0'}
+
+  color-name@1.1.3:
+    resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
+
+  color-name@1.1.4:
+    resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+  color-string@1.9.1:
+    resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
+
+  color-support@1.1.3:
+    resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
+    hasBin: true
+
+  color@4.2.3:
+    resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
+    engines: {node: '>=12.5.0'}
+
+  colord@2.9.3:
+    resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
+
+  colorette@2.0.19:
+    resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==}
+
+  combined-stream@1.0.8:
+    resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+    engines: {node: '>= 0.8'}
+
+  commander@10.0.1:
+    resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
+    engines: {node: '>=14'}
+
+  commander@2.20.3:
+    resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
+
+  commander@6.2.1:
+    resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==}
+    engines: {node: '>= 6'}
+
+  commander@7.2.0:
+    resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
+    engines: {node: '>= 10'}
+
+  commander@8.3.0:
+    resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==}
+    engines: {node: '>= 12'}
+
+  commander@9.5.0:
+    resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
+    engines: {node: ^12.20.0 || >=14}
+
+  common-tags@1.8.2:
+    resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==}
+    engines: {node: '>=4.0.0'}
+
+  commondir@1.0.1:
+    resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
+
+  compare-versions@6.1.0:
+    resolution: {integrity: sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==}
+
+  compress-commons@6.0.2:
+    resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==}
+    engines: {node: '>= 14'}
+
+  compressible@2.0.18:
+    resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==}
+    engines: {node: '>= 0.6'}
+
+  compression@1.7.4:
+    resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==}
+    engines: {node: '>= 0.8.0'}
+
+  computeds@0.0.1:
+    resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==}
+
+  concat-map@0.0.1:
+    resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+
+  concat-stream@1.6.2:
+    resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==}
+    engines: {'0': node >= 0.8}
+
+  config-chain@1.1.13:
+    resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
+
+  consola@2.15.3:
+    resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==}
+
+  console-control-strings@1.1.0:
+    resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==}
+
+  constantinople@4.0.1:
+    resolution: {integrity: sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==}
+
+  content-disposition@0.5.4:
+    resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
+    engines: {node: '>= 0.6'}
+
+  content-type@1.0.5:
+    resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
+    engines: {node: '>= 0.6'}
+
+  convert-source-map@2.0.0:
+    resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
+  cookie-signature@1.0.6:
+    resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
+
+  cookie-signature@1.2.1:
+    resolution: {integrity: sha512-78KWk9T26NhzXtuL26cIJ8/qNHANyJ/ZYrmEXFzUmhZdjpBv+DlWlOANRTGBt48YcyslsLrj0bMLFTmXvLRCOw==}
+    engines: {node: '>=6.6.0'}
+
+  cookie@0.5.0:
+    resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
+    engines: {node: '>= 0.6'}
+
+  cookie@0.6.0:
+    resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
+    engines: {node: '>= 0.6'}
+
+  core-js-compat@3.33.3:
+    resolution: {integrity: sha512-cNzGqFsh3Ot+529GIXacjTJ7kegdt5fPXxCBVS1G0iaZpuo/tBz399ymceLJveQhFFZ8qThHiP3fzuoQjKN2ow==}
+
+  core-js@3.29.1:
+    resolution: {integrity: sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw==}
+
+  core-util-is@1.0.2:
+    resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
+
+  core-util-is@1.0.3:
+    resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
+
+  cors@2.8.5:
+    resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
+    engines: {node: '>= 0.10'}
+
+  crc-32@1.2.2:
+    resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==}
+    engines: {node: '>=0.8'}
+    hasBin: true
+
+  crc32-stream@6.0.0:
+    resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==}
+    engines: {node: '>= 14'}
+
+  create-jest@29.7.0:
+    resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+    hasBin: true
+
+  cron-parser@4.8.1:
+    resolution: {integrity: sha512-jbokKWGcyU4gl6jAfX97E1gDpY12DJ1cLJZmoDzaAln/shZ+S3KBFBuA2Q6WeUN4gJf/8klnV1EfvhA2lK5IRQ==}
+    engines: {node: '>=12.0.0'}
+
+  cropperjs@2.0.0-beta.5:
+    resolution: {integrity: sha512-8RIynsyHV7KyCxbjV4fCQubGiM6sHMgYvRPKkzuUQSTYHK6shoUNvdvbBekwAwS8QRLsxEBcJ5lvl0W3dvkDQA==}
+
+  cross-env@7.0.3:
+    resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==}
+    engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'}
+    hasBin: true
+
+  cross-fetch@3.1.6:
+    resolution: {integrity: sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==}
+
+  cross-fetch@4.0.0:
+    resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==}
+
+  cross-spawn@5.1.0:
+    resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}
+
+  cross-spawn@7.0.3:
+    resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
+    engines: {node: '>= 8'}
+
+  crypto-random-string@2.0.0:
+    resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==}
+    engines: {node: '>=8'}
+
+  css-declaration-sorter@7.2.0:
+    resolution: {integrity: sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==}
+    engines: {node: ^14 || ^16 || >=18}
+    peerDependencies:
+      postcss: ^8.0.9
+
+  css-select@5.1.0:
+    resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
+
+  css-tree@2.2.1:
+    resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==}
+    engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
+
+  css-tree@2.3.1:
+    resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
+    engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
+
+  css-what@6.1.0:
+    resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
+    engines: {node: '>= 6'}
+
+  css.escape@1.5.1:
+    resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
+
+  cssesc@3.0.0:
+    resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+    engines: {node: '>=4'}
+    hasBin: true
+
+  cssnano-preset-default@6.1.2:
+    resolution: {integrity: sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  cssnano-utils@4.0.2:
+    resolution: {integrity: sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  cssnano@6.1.2:
+    resolution: {integrity: sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  csso@5.0.5:
+    resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==}
+    engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
+
+  cssstyle@4.0.1:
+    resolution: {integrity: sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==}
+    engines: {node: '>=18'}
+
+  csstype@3.1.3:
+    resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+
+  cwise-compiler@1.1.3:
+    resolution: {integrity: sha512-WXlK/m+Di8DMMcCjcWr4i+XzcQra9eCdXIJrgh4TUgh0pIS/yJduLxS9JgefsHJ/YVLdgPtXm9r62W92MvanEQ==}
+
+  cypress@13.7.3:
+    resolution: {integrity: sha512-uoecY6FTCAuIEqLUYkTrxamDBjMHTYak/1O7jtgwboHiTnS1NaMOoR08KcTrbRZFCBvYOiS4tEkQRmsV+xcrag==}
+    engines: {node: ^16.0.0 || ^18.0.0 || >=20.0.0}
+    hasBin: true
+
+  cypress@13.8.1:
+    resolution: {integrity: sha512-Uk6ovhRbTg6FmXjeZW/TkbRM07KPtvM5gah1BIMp4Y2s+i/NMxgaLw0+PbYTOdw1+egE0FP3mWRiGcRkjjmhzA==}
+    engines: {node: ^16.0.0 || ^18.0.0 || >=20.0.0}
+    hasBin: true
+
+  dashdash@1.14.1:
+    resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==}
+    engines: {node: '>=0.10'}
+
+  data-uri-to-buffer@0.0.3:
+    resolution: {integrity: sha512-Cp+jOa8QJef5nXS5hU7M1DWzXPEIoVR3kbV0dQuVGwROZg8bGf1DcCnkmajBTnvghTtSNMUdRrPjgaT6ZQucbw==}
+
+  data-uri-to-buffer@4.0.0:
+    resolution: {integrity: sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==}
+    engines: {node: '>= 12'}
+
+  data-urls@5.0.0:
+    resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
+    engines: {node: '>=18'}
+
+  date-fns@2.30.0:
+    resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
+    engines: {node: '>=0.11'}
+
+  dayjs@1.11.10:
+    resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==}
+
+  de-indent@1.0.2:
+    resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
+
+  debug@2.6.9:
+    resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+
+  debug@3.2.7:
+    resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+
+  debug@4.3.4:
+    resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
+    engines: {node: '>=6.0'}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+
+  decamelize-keys@1.1.1:
+    resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==}
+    engines: {node: '>=0.10.0'}
+
+  decamelize@1.2.0:
+    resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
+    engines: {node: '>=0.10.0'}
+
+  decimal.js@10.4.3:
+    resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
+
+  decode-bmp@0.2.1:
+    resolution: {integrity: sha512-NiOaGe+GN0KJqi2STf24hfMkFitDUaIoUU3eKvP/wAbLe8o6FuW5n/x7MHPR0HKvBokp6MQY/j7w8lewEeVCIA==}
+    engines: {node: '>=8.6.0'}
+
+  decode-ico@0.4.1:
+    resolution: {integrity: sha512-69NZfbKIzux1vBOd31al3XnMnH+2mqDhEgLdpygErm4d60N+UwA5Sq5WFjmEDQzumgB9fElojGwWG0vybVfFmA==}
+    engines: {node: '>=8.6'}
+
+  decode-named-character-reference@1.0.2:
+    resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==}
+
+  decompress-response@6.0.0:
+    resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
+    engines: {node: '>=10'}
+
+  dedent@1.3.0:
+    resolution: {integrity: sha512-7glNLfvdsMzZm3FpRY1CHuI2lbYDR+71YmrhmTZjYFD5pfT0ACgnGRdrrC9Mk2uICnzkcdelCx5at787UDGOvg==}
+    peerDependencies:
+      babel-plugin-macros: ^3.1.0
+    peerDependenciesMeta:
+      babel-plugin-macros:
+        optional: true
+
+  deep-email-validator@0.1.21:
+    resolution: {integrity: sha512-DBAmMzbr+MAubXQ+TS9tZuPwLcdKscb8YzKZiwoLqF3NmaeEgXvSSHhZ0EXOFeKFE2FNWC4mNXCyiQ/JdFXUwg==}
+
+  deep-eql@4.1.3:
+    resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==}
+    engines: {node: '>=6'}
+
+  deep-equal@2.2.0:
+    resolution: {integrity: sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==}
+
+  deep-is@0.1.4:
+    resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+
+  deepmerge@4.2.2:
+    resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==}
+    engines: {node: '>=0.10.0'}
+
+  default-browser-id@3.0.0:
+    resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==}
+    engines: {node: '>=12'}
+
+  defaults@1.0.4:
+    resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
+
+  defer-to-connect@2.0.1:
+    resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==}
+    engines: {node: '>=10'}
+
+  define-lazy-prop@2.0.0:
+    resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==}
+    engines: {node: '>=8'}
+
+  define-properties@1.2.0:
+    resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==}
+    engines: {node: '>= 0.4'}
+
+  defu@6.1.4:
+    resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
+
+  del@6.1.1:
+    resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==}
+    engines: {node: '>=10'}
+
+  delayed-stream@1.0.0:
+    resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+    engines: {node: '>=0.4.0'}
+
+  delegates@1.0.0:
+    resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
+
+  denque@2.1.0:
+    resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
+    engines: {node: '>=0.10'}
+
+  depd@2.0.0:
+    resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
+    engines: {node: '>= 0.8'}
+
+  dequal@2.0.3:
+    resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+    engines: {node: '>=6'}
+
+  destroy@1.2.0:
+    resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
+    engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+
+  detect-indent@6.1.0:
+    resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==}
+    engines: {node: '>=8'}
+
+  detect-libc@2.0.2:
+    resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
+    engines: {node: '>=8'}
+
+  detect-libc@2.0.3:
+    resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
+    engines: {node: '>=8'}
+
+  detect-newline@3.1.0:
+    resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
+    engines: {node: '>=8'}
+
+  detect-package-manager@2.0.1:
+    resolution: {integrity: sha512-j/lJHyoLlWi6G1LDdLgvUtz60Zo5GEj+sVYtTVXnYLDPuzgC3llMxonXym9zIwhhUII8vjdw0LXxavpLqTbl1A==}
+    engines: {node: '>=12'}
+
+  detect-port@1.5.1:
+    resolution: {integrity: sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==}
+    hasBin: true
+
+  devlop@1.1.0:
+    resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
+
+  diff-match-patch@1.0.5:
+    resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==}
+
+  diff-sequences@29.6.3:
+    resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  diff@5.1.0:
+    resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==}
+    engines: {node: '>=0.3.1'}
+
+  dijkstrajs@1.0.2:
+    resolution: {integrity: sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==}
+
+  dir-glob@3.0.1:
+    resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+    engines: {node: '>=8'}
+
+  disposable-email-domains@1.0.62:
+    resolution: {integrity: sha512-LBQvhRw7mznQTPoyZbsmYeNOZt1pN5aCsx4BAU/3siVFuiM9f2oyKzUaB8v1jbxFjE3aYqYiMo63kAL4pHgfWQ==}
+
+  doctrine@2.1.0:
+    resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
+    engines: {node: '>=0.10.0'}
+
+  doctrine@3.0.0:
+    resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
+    engines: {node: '>=6.0.0'}
+
+  doctypes@1.1.0:
+    resolution: {integrity: sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==}
+
+  dom-accessibility-api@0.5.16:
+    resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==}
+
+  dom-accessibility-api@0.6.3:
+    resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==}
+
+  dom-serializer@2.0.0:
+    resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
+
+  domelementtype@2.3.0:
+    resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
+
+  domhandler@5.0.3:
+    resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
+    engines: {node: '>= 4'}
+
+  domutils@3.0.1:
+    resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==}
+
+  dotenv-expand@10.0.0:
+    resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==}
+    engines: {node: '>=12'}
+
+  dotenv@16.0.3:
+    resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==}
+    engines: {node: '>=12'}
+
+  duplexer@0.1.2:
+    resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
+
+  duplexify@3.7.1:
+    resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==}
+
+  eastasianwidth@0.2.0:
+    resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+
+  ecc-jsbn@0.1.2:
+    resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==}
+
+  ecdsa-sig-formatter@1.0.11:
+    resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
+
+  editorconfig@1.0.4:
+    resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==}
+    engines: {node: '>=14'}
+    hasBin: true
+
+  ee-first@1.1.1:
+    resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
+
+  ejs@3.1.9:
+    resolution: {integrity: sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==}
+    engines: {node: '>=0.10.0'}
+    hasBin: true
+
+  electron-to-chromium@1.4.601:
+    resolution: {integrity: sha512-SpwUMDWe9tQu8JX5QCO1+p/hChAi9AE9UpoC3rcHVc+gdCGlbT3SGb5I1klgb952HRIyvt9wZhSz9bNBYz9swA==}
+
+  electron-to-chromium@1.4.686:
+    resolution: {integrity: sha512-3avY1B+vUzNxEgkBDpKOP8WarvUAEwpRaiCL0He5OKWEFxzaOFiq4WoZEZe7qh0ReS7DiWoHMnYoQCKxNZNzSg==}
+
+  emittery@0.13.1:
+    resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
+    engines: {node: '>=12'}
+
+  emoji-regex@8.0.0:
+    resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+
+  emoji-regex@9.2.2:
+    resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+
+  encode-utf8@1.0.3:
+    resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==}
+
+  encodeurl@1.0.2:
+    resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
+    engines: {node: '>= 0.8'}
+
+  encoding@0.1.13:
+    resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==}
+
+  end-of-stream@1.4.4:
+    resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
+
+  enquirer@2.3.6:
+    resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==}
+    engines: {node: '>=8.6'}
+
+  entities@2.2.0:
+    resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==}
+
+  entities@4.5.0:
+    resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+    engines: {node: '>=0.12'}
+
+  env-paths@2.2.1:
+    resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
+    engines: {node: '>=6'}
+
+  envinfo@7.8.1:
+    resolution: {integrity: sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==}
+    engines: {node: '>=4'}
+    hasBin: true
+
+  err-code@2.0.3:
+    resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==}
+
+  error-ex@1.3.2:
+    resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
+
+  es-abstract@1.22.1:
+    resolution: {integrity: sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==}
+    engines: {node: '>= 0.4'}
+
+  es-get-iterator@1.1.3:
+    resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==}
+
+  es-module-lexer@0.9.3:
+    resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==}
+
+  es-set-tostringtag@2.0.1:
+    resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==}
+    engines: {node: '>= 0.4'}
+
+  es-shim-unscopables@1.0.0:
+    resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==}
+
+  es-to-primitive@1.2.1:
+    resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
+    engines: {node: '>= 0.4'}
+
+  es6-promise@4.2.8:
+    resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==}
+
+  es6-promisify@5.0.0:
+    resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==}
+
+  esbuild-plugin-alias@0.2.1:
+    resolution: {integrity: sha512-jyfL/pwPqaFXyKnj8lP8iLk6Z0m099uXR45aSN8Av1XD4vhvQutxxPzgA2bTcAwQpa1zCXDcWOlhFgyP3GKqhQ==}
+
+  esbuild-register@3.5.0:
+    resolution: {integrity: sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==}
+    peerDependencies:
+      esbuild: '>=0.12 <1'
+
+  esbuild@0.18.20:
+    resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==}
+    engines: {node: '>=12'}
+    hasBin: true
+
+  esbuild@0.19.11:
+    resolution: {integrity: sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==}
+    engines: {node: '>=12'}
+    hasBin: true
+
+  esbuild@0.20.2:
+    resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==}
+    engines: {node: '>=12'}
+    hasBin: true
+
+  escalade@3.1.1:
+    resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
+    engines: {node: '>=6'}
+
+  escape-html@1.0.3:
+    resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
+
+  escape-regexp@0.0.1:
+    resolution: {integrity: sha512-jVgdsYRa7RKxTT6MKNC3gdT+BF0Gfhpel19+HMRZJC2L0PufB0XOBuXBoXj29NKHwuktnAXd1Z1lyiH/8vOTpw==}
+
+  escape-string-regexp@1.0.5:
+    resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
+    engines: {node: '>=0.8.0'}
+
+  escape-string-regexp@2.0.0:
+    resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
+    engines: {node: '>=8'}
+
+  escape-string-regexp@4.0.0:
+    resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+    engines: {node: '>=10'}
+
+  escape-string-regexp@5.0.0:
+    resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
+    engines: {node: '>=12'}
+
+  escodegen@2.1.0:
+    resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==}
+    engines: {node: '>=6.0'}
+    hasBin: true
+
+  eslint-formatter-pretty@4.1.0:
+    resolution: {integrity: sha512-IsUTtGxF1hrH6lMWiSl1WbGaiP01eT6kzywdY1U+zLc0MP+nwEnUiS9UI8IaOTUhTeQJLlCEWIbXINBH4YJbBQ==}
+    engines: {node: '>=10'}
+
+  eslint-import-resolver-node@0.3.9:
+    resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
+
+  eslint-module-utils@2.8.0:
+    resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==}
+    engines: {node: '>=4'}
+    peerDependencies:
+      '@typescript-eslint/parser': '*'
+      eslint: '*'
+      eslint-import-resolver-node: '*'
+      eslint-import-resolver-typescript: '*'
+      eslint-import-resolver-webpack: '*'
+    peerDependenciesMeta:
+      '@typescript-eslint/parser':
+        optional: true
+      eslint:
+        optional: true
+      eslint-import-resolver-node:
+        optional: true
+      eslint-import-resolver-typescript:
+        optional: true
+      eslint-import-resolver-webpack:
+        optional: true
+
+  eslint-plugin-import@2.29.1:
+    resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
+    engines: {node: '>=4'}
+    peerDependencies:
+      '@typescript-eslint/parser': '*'
+      eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
+    peerDependenciesMeta:
+      '@typescript-eslint/parser':
+        optional: true
+
+  eslint-plugin-vue@9.25.0:
+    resolution: {integrity: sha512-tDWlx14bVe6Bs+Nnh3IGrD+hb11kf2nukfm6jLsmJIhmiRQ1SUaksvwY9U5MvPB0pcrg0QK0xapQkfITs3RKOA==}
+    engines: {node: ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0
+
+  eslint-rule-docs@1.1.235:
+    resolution: {integrity: sha512-+TQ+x4JdTnDoFEXXb3fDvfGOwnyNV7duH8fXWTPD1ieaBmB8omj7Gw/pMBBu4uI2uJCCU8APDaQJzWuXnTsH4A==}
+
+  eslint-scope@7.2.2:
+    resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  eslint-visitor-keys@3.4.3:
+    resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  eslint@8.53.0:
+    resolution: {integrity: sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    hasBin: true
+
+  eslint@8.57.0:
+    resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    hasBin: true
+
+  espree@9.6.1:
+    resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  esprima@4.0.1:
+    resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
+    engines: {node: '>=4'}
+    hasBin: true
+
+  esquery@1.4.2:
+    resolution: {integrity: sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==}
+    engines: {node: '>=0.10'}
+
+  esrecurse@4.3.0:
+    resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+    engines: {node: '>=4.0'}
+
+  estraverse@5.3.0:
+    resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+    engines: {node: '>=4.0'}
+
+  estree-walker@2.0.2:
+    resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+
+  estree-walker@3.0.3:
+    resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+
+  esutils@2.0.3:
+    resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+    engines: {node: '>=0.10.0'}
+
+  etag@1.8.1:
+    resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
+    engines: {node: '>= 0.6'}
+
+  event-stream@3.3.4:
+    resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==}
+
+  event-target-shim@5.0.1:
+    resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
+    engines: {node: '>=6'}
+
+  eventemitter2@6.4.7:
+    resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==}
+
+  eventemitter3@4.0.7:
+    resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
+
+  eventemitter3@5.0.1:
+    resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
+
+  events@3.3.0:
+    resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
+    engines: {node: '>=0.8.x'}
+
+  execa@0.7.0:
+    resolution: {integrity: sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==}
+    engines: {node: '>=4'}
+
+  execa@4.1.0:
+    resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==}
+    engines: {node: '>=10'}
+
+  execa@5.1.1:
+    resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
+    engines: {node: '>=10'}
+
+  execa@6.1.0:
+    resolution: {integrity: sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+  execa@8.0.1:
+    resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
+    engines: {node: '>=16.17'}
+
+  executable@4.1.1:
+    resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==}
+    engines: {node: '>=4'}
+
+  exit@0.1.2:
+    resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}
+    engines: {node: '>= 0.8.0'}
+
+  expect@29.7.0:
+    resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  exponential-backoff@3.1.1:
+    resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==}
+
+  express@4.18.2:
+    resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==}
+    engines: {node: '>= 0.10.0'}
+
+  express@4.19.2:
+    resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==}
+    engines: {node: '>= 0.10.0'}
+
+  ext-list@2.2.2:
+    resolution: {integrity: sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==}
+    engines: {node: '>=0.10.0'}
+
+  ext-name@5.0.0:
+    resolution: {integrity: sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==}
+    engines: {node: '>=4'}
+
+  extend@3.0.2:
+    resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
+
+  extract-zip@2.0.1:
+    resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==}
+    engines: {node: '>= 10.17.0'}
+    hasBin: true
+
+  extsprintf@1.3.0:
+    resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==}
+    engines: {'0': node >=0.6.0}
+
+  fast-content-type-parse@1.1.0:
+    resolution: {integrity: sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==}
+
+  fast-decode-uri-component@1.0.1:
+    resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==}
+
+  fast-deep-equal@3.1.3:
+    resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
+  fast-fifo@1.3.0:
+    resolution: {integrity: sha512-IgfweLvEpwyA4WgiQe9Nx6VV2QkML2NkvZnk1oKnIzXgXdWxuhF7zw4DvLTPZJn6PIUneiAXPF24QmoEqHTjyw==}
+
+  fast-glob@3.3.2:
+    resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
+    engines: {node: '>=8.6.0'}
+
+  fast-json-stable-stringify@2.1.0:
+    resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+
+  fast-json-stringify@5.8.0:
+    resolution: {integrity: sha512-VVwK8CFMSALIvt14U8AvrSzQAwN/0vaVRiFFUVlpnXSnDGrSkOAO5MtzyN8oQNjLd5AqTW5OZRgyjoNuAuR3jQ==}
+
+  fast-levenshtein@2.0.6:
+    resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+
+  fast-querystring@1.1.2:
+    resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==}
+
+  fast-redact@3.1.2:
+    resolution: {integrity: sha512-+0em+Iya9fKGfEQGcd62Yv6onjBmmhV1uh86XVfOU8VwAe6kaFdQCWI9s0/Nnugx5Vd9tdbZ7e6gE2tR9dzXdw==}
+    engines: {node: '>=6'}
+
+  fast-safe-stringify@2.1.1:
+    resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
+
+  fast-uri@2.2.0:
+    resolution: {integrity: sha512-cIusKBIt/R/oI6z/1nyfe2FvGKVTohVRfvkOhvx0nCEW+xf5NoCXjAHcWp93uOUBchzYcsvPlrapAdX1uW+YGg==}
+
+  fast-xml-parser@4.2.5:
+    resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==}
+    hasBin: true
+
+  fastify-plugin@4.5.0:
+    resolution: {integrity: sha512-79ak0JxddO0utAXAQ5ccKhvs6vX2MGyHHMMsmZkBANrq3hXc1CHzvNPHOcvTsVMEPl5I+NT+RO4YKMGehOfSIg==}
+
+  fastify-raw-body@4.3.0:
+    resolution: {integrity: sha512-F4o8ZIMVx4YoxGfwrZys6wyjl40gF3Yv6AWWRy62ozFAyZBSS831/uyyCAqKYw3tR73g180ryG98yih6To1PUQ==}
+    engines: {node: '>= 10'}
+
+  fastify@4.26.2:
+    resolution: {integrity: sha512-90pjTuPGrfVKtdpLeLzND5nyC4woXZN5VadiNQCicj/iJU4viNHKhsAnb7jmv1vu2IzkLXyBiCzdWuzeXgQ5Ug==}
+
+  fastq@1.15.0:
+    resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
+
+  fastq@1.17.1:
+    resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
+
+  fb-watchman@2.0.2:
+    resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
+
+  fd-slicer@1.1.0:
+    resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
+
+  feed@4.2.2:
+    resolution: {integrity: sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==}
+    engines: {node: '>=0.4.0'}
+
+  fetch-blob@3.2.0:
+    resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
+    engines: {node: ^12.20 || >= 14.13}
+
+  fetch-retry@5.0.4:
+    resolution: {integrity: sha512-LXcdgpdcVedccGg0AZqg+S8lX/FCdwXD92WNZ5k5qsb0irRhSFsBOpcJt7oevyqT2/C2nEE0zSFNdBEpj3YOSw==}
+
+  figures@3.2.0:
+    resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
+    engines: {node: '>=8'}
+
+  file-entry-cache@6.0.1:
+    resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
+    engines: {node: ^10.12.0 || >=12.0.0}
+
+  file-system-cache@2.3.0:
+    resolution: {integrity: sha512-l4DMNdsIPsVnKrgEXbJwDJsA5mB8rGwHYERMgqQx/xAUtChPJMre1bXBzDEqqVbWv9AIbFezXMxeEkZDSrXUOQ==}
+
+  file-type@17.1.6:
+    resolution: {integrity: sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+  file-type@19.0.0:
+    resolution: {integrity: sha512-s7cxa7/leUWLiXO78DVVfBVse+milos9FitauDLG1pI7lNaJ2+5lzPnr2N24ym+84HVwJL6hVuGfgVE+ALvU8Q==}
+    engines: {node: '>=18'}
+
+  filelist@1.0.4:
+    resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==}
+
+  filename-reserved-regex@3.0.0:
+    resolution: {integrity: sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+  filenamify@5.1.1:
+    resolution: {integrity: sha512-M45CbrJLGACfrPOkrTp3j2EcO9OBkKUYME0eiqOCa7i2poaklU0jhlIaMlr8ijLorT0uLAzrn3qXOp5684CkfA==}
+    engines: {node: '>=12.20'}
+
+  fill-range@7.0.1:
+    resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
+    engines: {node: '>=8'}
+
+  finalhandler@1.2.0:
+    resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==}
+    engines: {node: '>= 0.8'}
+
+  find-cache-dir@2.1.0:
+    resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==}
+    engines: {node: '>=6'}
+
+  find-cache-dir@3.3.2:
+    resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==}
+    engines: {node: '>=8'}
+
+  find-my-way@8.2.0:
+    resolution: {integrity: sha512-HdWXgFYc6b1BJcOBDBwjqWuHJj1WYiqrxSh25qtU4DabpMFdj/gSunNBQb83t+8Zt67D7CXEzJWTkxaShMTMOA==}
+    engines: {node: '>=14'}
+
+  find-package-json@1.2.0:
+    resolution: {integrity: sha512-+SOGcLGYDJHtyqHd87ysBhmaeQ95oWspDKnMXBrnQ9Eq4OkLNqejgoaD8xVWu6GPa0B6roa6KinCMEMcVeqONw==}
+
+  find-up@3.0.0:
+    resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==}
+    engines: {node: '>=6'}
+
+  find-up@4.1.0:
+    resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
+    engines: {node: '>=8'}
+
+  find-up@5.0.0:
+    resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+    engines: {node: '>=10'}
+
+  find-versions@5.1.0:
+    resolution: {integrity: sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==}
+    engines: {node: '>=12'}
+
+  fkill@9.0.0:
+    resolution: {integrity: sha512-MdYSsbdCaIRjzo5edthZtWmEZVMfr1qrtYZUHIdO3swCE+CoZA8S5l0s4jDsYlTa9ZiXv0pTgpzE7s4N8NeUOA==}
+    engines: {node: '>=18'}
+
+  flat-cache@3.0.4:
+    resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==}
+    engines: {node: ^10.12.0 || >=12.0.0}
+
+  flatted@3.2.7:
+    resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
+
+  flow-parser@0.202.0:
+    resolution: {integrity: sha512-ZiXxSIXK3zPmY3zrzCofFonM2T+/3Jz5QZKJyPVtUERQEJUnYkXBQ+0H3FzyqiyJs+VXqb/UNU6/K6sziVYdxw==}
+    engines: {node: '>=0.4.0'}
+
+  fluent-ffmpeg@2.1.2:
+    resolution: {integrity: sha512-IZTB4kq5GK0DPp7sGQ0q/BWurGHffRtQQwVkiqDgeO6wYJLLV5ZhgNOQ65loZxxuPMKZKZcICCUnaGtlxBiR0Q==}
+    engines: {node: '>=0.8.0'}
+
+  follow-redirects@1.15.2:
+    resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
+    engines: {node: '>=4.0'}
+    peerDependencies:
+      debug: '*'
+    peerDependenciesMeta:
+      debug:
+        optional: true
+
+  for-each@0.3.3:
+    resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
+
+  foreground-child@3.1.1:
+    resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
+    engines: {node: '>=14'}
+
+  forever-agent@0.6.1:
+    resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==}
+
+  form-data-encoder@2.1.4:
+    resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==}
+    engines: {node: '>= 14.17'}
+
+  form-data-encoder@4.0.2:
+    resolution: {integrity: sha512-KQVhvhK8ZkWzxKxOr56CPulAhH3dobtuQ4+hNQ+HekH/Wp5gSOafqRAeTphQUJAIk0GBvHZgJ2ZGRWd5kphMuw==}
+    engines: {node: '>= 18'}
+
+  form-data@2.3.3:
+    resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==}
+    engines: {node: '>= 0.12'}
+
+  form-data@3.0.1:
+    resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==}
+    engines: {node: '>= 6'}
+
+  form-data@4.0.0:
+    resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
+    engines: {node: '>= 6'}
+
+  formdata-polyfill@4.0.10:
+    resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
+    engines: {node: '>=12.20.0'}
+
+  forwarded@0.2.0:
+    resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
+    engines: {node: '>= 0.6'}
+
+  fresh@0.5.2:
+    resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
+    engines: {node: '>= 0.6'}
+
+  from@0.1.7:
+    resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==}
+
+  fs-constants@1.0.0:
+    resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
+
+  fs-extra@11.1.1:
+    resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==}
+    engines: {node: '>=14.14'}
+
+  fs-extra@7.0.1:
+    resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
+    engines: {node: '>=6 <7 || >=8'}
+
+  fs-extra@8.1.0:
+    resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==}
+    engines: {node: '>=6 <7 || >=8'}
+
+  fs-extra@9.1.0:
+    resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==}
+    engines: {node: '>=10'}
+
+  fs-minipass@1.2.7:
+    resolution: {integrity: sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==}
+
+  fs-minipass@2.1.0:
+    resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
+    engines: {node: '>= 8'}
+
+  fs-minipass@3.0.2:
+    resolution: {integrity: sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
+  fs.realpath@1.0.0:
+    resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+
+  fsevents@2.3.3:
+    resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+    engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+    os: [darwin]
+
+  function-bind@1.1.2:
+    resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+  function.prototype.name@1.1.5:
+    resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==}
+    engines: {node: '>= 0.4'}
+
+  functions-have-names@1.2.3:
+    resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
+
+  gauge@3.0.2:
+    resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==}
+    engines: {node: '>=10'}
+
+  gensync@1.0.0-beta.2:
+    resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+    engines: {node: '>=6.9.0'}
+
+  get-caller-file@2.0.5:
+    resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
+    engines: {node: 6.* || 8.* || >= 10.*}
+
+  get-func-name@2.0.2:
+    resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
+
+  get-intrinsic@1.2.1:
+    resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==}
+
+  get-npm-tarball-url@2.0.3:
+    resolution: {integrity: sha512-R/PW6RqyaBQNWYaSyfrh54/qtcnOp22FHCCiRhSSZj0FP3KQWCsxxt0DzIdVTbwTqe9CtQfvl/FPD4UIPt4pqw==}
+    engines: {node: '>=12.17'}
+
+  get-package-type@0.1.0:
+    resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
+    engines: {node: '>=8.0.0'}
+
+  get-pixels-frame-info-update@3.3.2:
+    resolution: {integrity: sha512-LzVij57X/gK4Y6LpcDdqj+R9WCpD6Sv3ZH85GMA+S3xgPGCz81mHql4GiSnF4GijRjk7TE0ja2sDr8FFYKLe2g==}
+
+  get-stream@3.0.0:
+    resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==}
+    engines: {node: '>=4'}
+
+  get-stream@5.2.0:
+    resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
+    engines: {node: '>=8'}
+
+  get-stream@6.0.1:
+    resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
+    engines: {node: '>=10'}
+
+  get-stream@8.0.1:
+    resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
+    engines: {node: '>=16'}
+
+  get-symbol-description@1.0.0:
+    resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
+    engines: {node: '>= 0.4'}
+
+  get-tsconfig@4.7.2:
+    resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==}
+
+  getos@3.2.1:
+    resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==}
+
+  getpass@0.1.7:
+    resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==}
+
+  gif-encoder@0.4.1:
+    resolution: {integrity: sha512-++rNGpDBgWQ9eXj9JfTBLHMUEd7lDOdzIvFyHQM9yL8ffxkcg4G6jWmsgu/r59Uq6nHc3wcVwtgy3geLnIWunQ==}
+    engines: {node: '>= 0.8.0'}
+
+  giget@1.1.2:
+    resolution: {integrity: sha512-HsLoS07HiQ5oqvObOI+Qb2tyZH4Gj5nYGfF9qQcZNrPw+uEFhdXtgJr01aO2pWadGHucajYDLxxbtQkm97ON2A==}
+    hasBin: true
+
+  github-slugger@2.0.0:
+    resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==}
+
+  glob-parent@5.1.2:
+    resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+    engines: {node: '>= 6'}
+
+  glob-parent@6.0.2:
+    resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+    engines: {node: '>=10.13.0'}
+
+  glob-promise@4.2.2:
+    resolution: {integrity: sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw==}
+    engines: {node: '>=12'}
+    peerDependencies:
+      glob: ^7.1.6
+
+  glob-to-regexp@0.4.1:
+    resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
+
+  glob@10.3.10:
+    resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==}
+    engines: {node: '>=16 || 14 >=14.17'}
+    hasBin: true
+
+  glob@10.3.12:
+    resolution: {integrity: sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==}
+    engines: {node: '>=16 || 14 >=14.17'}
+    hasBin: true
+
+  glob@7.2.3:
+    resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+
+  glob@8.1.0:
+    resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
+    engines: {node: '>=12'}
+
+  global-dirs@3.0.1:
+    resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==}
+    engines: {node: '>=10'}
+
+  globals@11.12.0:
+    resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
+    engines: {node: '>=4'}
+
+  globals@13.19.0:
+    resolution: {integrity: sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==}
+    engines: {node: '>=8'}
+
+  globals@13.24.0:
+    resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
+    engines: {node: '>=8'}
+
+  globalthis@1.0.3:
+    resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
+    engines: {node: '>= 0.4'}
+
+  globby@11.1.0:
+    resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+    engines: {node: '>=10'}
+
+  google-protobuf@3.21.2:
+    resolution: {integrity: sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==}
+
+  gopd@1.0.1:
+    resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
+
+  got@11.8.5:
+    resolution: {integrity: sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==}
+    engines: {node: '>=10.19.0'}
+
+  got@12.6.1:
+    resolution: {integrity: sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==}
+    engines: {node: '>=14.16'}
+
+  got@14.2.1:
+    resolution: {integrity: sha512-KOaPMremmsvx6l9BLC04LYE6ZFW4x7e4HkTe3LwBmtuYYQwpeS4XKqzhubTIkaQ1Nr+eXxeori0zuwupXMovBQ==}
+    engines: {node: '>=20'}
+
+  graceful-fs@4.2.11:
+    resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
+  grapheme-splitter@1.0.4:
+    resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==}
+
+  graphemer@1.4.0:
+    resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+
+  graphql@16.8.1:
+    resolution: {integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==}
+    engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0}
+
+  gunzip-maybe@1.4.2:
+    resolution: {integrity: sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==}
+    hasBin: true
+
+  hammerjs@2.0.8:
+    resolution: {integrity: sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==}
+    engines: {node: '>=0.8.0'}
+
+  handlebars@4.7.7:
+    resolution: {integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==}
+    engines: {node: '>=0.4.7'}
+    hasBin: true
+
+  happy-dom@14.7.1:
+    resolution: {integrity: sha512-v60Q0evZ4clvMcrAh5/F8EdxDdfHdFrtffz/CNe10jKD+nFweZVxM91tW+UyY2L4AtpgIaXdZ7TQmiO1pfcwbg==}
+    engines: {node: '>=16.0.0'}
+
+  har-schema@2.0.0:
+    resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==}
+    engines: {node: '>=4'}
+
+  har-validator@5.1.5:
+    resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==}
+    engines: {node: '>=6'}
+    deprecated: this library is no longer supported
+
+  hard-rejection@2.1.0:
+    resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==}
+    engines: {node: '>=6'}
+
+  has-bigints@1.0.2:
+    resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
+
+  has-flag@3.0.0:
+    resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
+    engines: {node: '>=4'}
+
+  has-flag@4.0.0:
+    resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+    engines: {node: '>=8'}
+
+  has-property-descriptors@1.0.0:
+    resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
+
+  has-proto@1.0.1:
+    resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
+    engines: {node: '>= 0.4'}
+
+  has-symbols@1.0.3:
+    resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
+    engines: {node: '>= 0.4'}
+
+  has-tostringtag@1.0.0:
+    resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==}
+    engines: {node: '>= 0.4'}
+
+  has-unicode@2.0.1:
+    resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
+
+  has@1.0.3:
+    resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
+    engines: {node: '>= 0.4.0'}
+
+  hash-sum@2.0.0:
+    resolution: {integrity: sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==}
+
+  hashlru@2.3.0:
+    resolution: {integrity: sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A==}
+
+  hasown@2.0.0:
+    resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==}
+    engines: {node: '>= 0.4'}
+
+  hast-util-heading-rank@3.0.0:
+    resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==}
+
+  hast-util-is-element@3.0.0:
+    resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==}
+
+  hast-util-to-string@3.0.0:
+    resolution: {integrity: sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==}
+
+  he@1.2.0:
+    resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
+    hasBin: true
+
+  headers-polyfill@4.0.2:
+    resolution: {integrity: sha512-EWGTfnTqAO2L/j5HZgoM/3z82L7necsJ0pO9Tp0X1wil3PDLrkypTBRgVO2ExehEEvUycejZD3FuRaXpZZc3kw==}
+
+  highlight.js@10.7.3:
+    resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==}
+
+  highlight.js@11.9.0:
+    resolution: {integrity: sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==}
+    engines: {node: '>=12.0.0'}
+
+  hosted-git-info@2.8.9:
+    resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
+
+  hosted-git-info@4.1.0:
+    resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==}
+    engines: {node: '>=10'}
+
+  hpagent@1.2.0:
+    resolution: {integrity: sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==}
+    engines: {node: '>=14'}
+
+  html-encoding-sniffer@4.0.0:
+    resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
+    engines: {node: '>=18'}
+
+  html-entities@2.3.2:
+    resolution: {integrity: sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==}
+
+  html-escaper@2.0.2:
+    resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
+
+  html-tags@3.2.0:
+    resolution: {integrity: sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==}
+    engines: {node: '>=8'}
+
+  htmlescape@1.1.1:
+    resolution: {integrity: sha512-eVcrzgbR4tim7c7soKQKtxa/kQM4TzjnlU83rcZ9bHU6t31ehfV7SktN6McWgwPWg+JYMA/O3qpGxBvFq1z2Jg==}
+    engines: {node: '>=0.10'}
+
+  htmlparser2@8.0.1:
+    resolution: {integrity: sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==}
+
+  http-cache-semantics@4.1.1:
+    resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
+
+  http-errors@2.0.0:
+    resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
+    engines: {node: '>= 0.8'}
+
+  http-link-header@1.1.3:
+    resolution: {integrity: sha512-3cZ0SRL8fb9MUlU3mKM61FcQvPfXx2dBrZW3Vbg5CXa8jFlK8OaEpePenLe1oEXQduhz8b0QjsqfS59QP4AJDQ==}
+    engines: {node: '>=6.0.0'}
+
+  http-proxy-agent@7.0.0:
+    resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==}
+    engines: {node: '>= 14'}
+
+  http-signature@1.2.0:
+    resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==}
+    engines: {node: '>=0.8', npm: '>=1.3.7'}
+
+  http-signature@1.3.6:
+    resolution: {integrity: sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==}
+    engines: {node: '>=0.10'}
+
+  http2-wrapper@1.0.3:
+    resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==}
+    engines: {node: '>=10.19.0'}
+
+  http2-wrapper@2.2.1:
+    resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==}
+    engines: {node: '>=10.19.0'}
+
+  http_ece@1.2.0:
+    resolution: {integrity: sha512-JrF8SSLVmcvc5NducxgyOrKXe3EsyHMgBFgSaIUGmArKe+rwr0uphRkRXvwiom3I+fpIfoItveHrfudL8/rxuA==}
+    engines: {node: '>=16'}
+
+  https-proxy-agent@2.2.4:
+    resolution: {integrity: sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==}
+    engines: {node: '>= 4.5.0'}
+
+  https-proxy-agent@5.0.1:
+    resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
+    engines: {node: '>= 6'}
+
+  https-proxy-agent@7.0.2:
+    resolution: {integrity: sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==}
+    engines: {node: '>= 14'}
+
+  human-signals@1.1.1:
+    resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==}
+    engines: {node: '>=8.12.0'}
+
+  human-signals@2.1.0:
+    resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
+    engines: {node: '>=10.17.0'}
+
+  human-signals@3.0.1:
+    resolution: {integrity: sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==}
+    engines: {node: '>=12.20.0'}
+
+  human-signals@5.0.0:
+    resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
+    engines: {node: '>=16.17.0'}
+
+  iconv-lite@0.4.24:
+    resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
+    engines: {node: '>=0.10.0'}
+
+  iconv-lite@0.6.3:
+    resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+    engines: {node: '>=0.10.0'}
+
+  idb-keyval@6.2.1:
+    resolution: {integrity: sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==}
+
+  ieee754@1.2.1:
+    resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+
+  ignore-by-default@1.0.1:
+    resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
+
+  ignore-walk@6.0.4:
+    resolution: {integrity: sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
+  ignore@5.2.4:
+    resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
+    engines: {node: '>= 4'}
+
+  ignore@5.3.1:
+    resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
+    engines: {node: '>= 4'}
+
+  immutable@4.2.2:
+    resolution: {integrity: sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og==}
+
+  import-fresh@3.3.0:
+    resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
+    engines: {node: '>=6'}
+
+  import-lazy@4.0.0:
+    resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==}
+    engines: {node: '>=8'}
+
+  import-local@3.1.0:
+    resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==}
+    engines: {node: '>=8'}
+    hasBin: true
+
+  imurmurhash@0.1.4:
+    resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+    engines: {node: '>=0.8.19'}
+
+  indent-string@4.0.0:
+    resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
+    engines: {node: '>=8'}
+
+  indent-string@5.0.0:
+    resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==}
+    engines: {node: '>=12'}
+
+  inflight@1.0.6:
+    resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+
+  inherits@2.0.4:
+    resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+
+  ini@1.3.8:
+    resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
+
+  ini@2.0.0:
+    resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==}
+    engines: {node: '>=10'}
+
+  insert-text-at-cursor@0.3.0:
+    resolution: {integrity: sha512-/nPtyeX9xPUvxZf+r0518B7uqNKlP+LqNJqSiXFEaa2T71rWIwTVXGH7hB9xO/EVdwa5/pWlFCPwShOW81XIxQ==}
+
+  install-artifact-from-github@1.3.5:
+    resolution: {integrity: sha512-gZHC7f/cJgXz7MXlHFBxPVMsvIbev1OQN1uKQYKVJDydGNm9oYf9JstbU4Atnh/eSvk41WtEovoRm+8IF686xg==}
+    hasBin: true
+
+  internal-slot@1.0.5:
+    resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==}
+    engines: {node: '>= 0.4'}
+
+  intersection-observer@0.12.2:
+    resolution: {integrity: sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==}
+
+  ioredis@5.4.1:
+    resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==}
+    engines: {node: '>=12.22.0'}
+
+  iota-array@1.0.0:
+    resolution: {integrity: sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==}
+
+  ip-address@7.1.0:
+    resolution: {integrity: sha512-V9pWC/VJf2lsXqP7IWJ+pe3P1/HCYGBMZrrnT62niLGjAfCbeiwXMUxaeHvnVlz19O27pvXP4azs+Pj/A0x+SQ==}
+    engines: {node: '>= 10'}
+
+  ip-cidr@3.1.0:
+    resolution: {integrity: sha512-HUCn4snshEX1P8cja/IyU3qk8FVDW8T5zZcegDFbu4w7NojmAhk5NcOgj3M8+0fmumo1afJTPDtJlzsxLdOjtg==}
+    engines: {node: '>=10.0.0'}
+
+  ip-regex@4.3.0:
+    resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==}
+    engines: {node: '>=8'}
+
+  ip@2.0.1:
+    resolution: {integrity: sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==}
+
+  ipaddr.js@1.9.1:
+    resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
+    engines: {node: '>= 0.10'}
+
+  ipaddr.js@2.2.0:
+    resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==}
+    engines: {node: '>= 10'}
+
+  irregular-plurals@3.5.0:
+    resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==}
+    engines: {node: '>=8'}
+
+  is-absolute-url@4.0.1:
+    resolution: {integrity: sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+  is-arguments@1.1.1:
+    resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==}
+    engines: {node: '>= 0.4'}
+
+  is-array-buffer@3.0.2:
+    resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==}
+
+  is-arrayish@0.2.1:
+    resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
+
+  is-arrayish@0.3.2:
+    resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
+
+  is-bigint@1.0.4:
+    resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
+
+  is-binary-path@2.1.0:
+    resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+    engines: {node: '>=8'}
+
+  is-boolean-object@1.1.2:
+    resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
+    engines: {node: '>= 0.4'}
+
+  is-buffer@1.1.6:
+    resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
+
+  is-callable@1.2.7:
+    resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
+    engines: {node: '>= 0.4'}
+
+  is-ci@3.0.1:
+    resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==}
+    hasBin: true
+
+  is-core-module@2.13.1:
+    resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
+
+  is-date-object@1.0.5:
+    resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
+    engines: {node: '>= 0.4'}
+
+  is-deflate@1.0.0:
+    resolution: {integrity: sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ==}
+
+  is-docker@2.2.1:
+    resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==}
+    engines: {node: '>=8'}
+    hasBin: true
+
+  is-expression@4.0.0:
+    resolution: {integrity: sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==}
+
+  is-extglob@2.1.1:
+    resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+    engines: {node: '>=0.10.0'}
+
+  is-file-animated@1.0.2:
+    resolution: {integrity: sha512-TAYDUkvyBmxqneRU26zzpeHLAgtzEOIsRQWrtDidPT/tFK3Yc0WKgtF3u4oOEAiN0kAuVfl7MTgbD0vXdFDztA==}
+
+  is-fullwidth-code-point@3.0.0:
+    resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+    engines: {node: '>=8'}
+
+  is-generator-fn@2.1.0:
+    resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
+    engines: {node: '>=6'}
+
+  is-generator-function@1.0.10:
+    resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==}
+    engines: {node: '>= 0.4'}
+
+  is-glob@4.0.3:
+    resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+    engines: {node: '>=0.10.0'}
+
+  is-gzip@1.0.0:
+    resolution: {integrity: sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ==}
+    engines: {node: '>=0.10.0'}
+
+  is-installed-globally@0.4.0:
+    resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==}
+    engines: {node: '>=10'}
+
+  is-interactive@1.0.0:
+    resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==}
+    engines: {node: '>=8'}
+
+  is-ip@3.1.0:
+    resolution: {integrity: sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==}
+    engines: {node: '>=8'}
+
+  is-lambda@1.0.1:
+    resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==}
+
+  is-map@2.0.2:
+    resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==}
+
+  is-nan@1.3.2:
+    resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==}
+    engines: {node: '>= 0.4'}
+
+  is-negative-zero@2.0.2:
+    resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==}
+    engines: {node: '>= 0.4'}
+
+  is-node-process@1.2.0:
+    resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==}
+
+  is-number-object@1.0.7:
+    resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
+    engines: {node: '>= 0.4'}
+
+  is-number@7.0.0:
+    resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+    engines: {node: '>=0.12.0'}
+
+  is-path-cwd@2.2.0:
+    resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==}
+    engines: {node: '>=6'}
+
+  is-path-inside@3.0.3:
+    resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
+    engines: {node: '>=8'}
+
+  is-plain-obj@1.1.0:
+    resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==}
+    engines: {node: '>=0.10.0'}
+
+  is-plain-obj@4.1.0:
+    resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
+    engines: {node: '>=12'}
+
+  is-plain-object@2.0.4:
+    resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
+    engines: {node: '>=0.10.0'}
+
+  is-plain-object@5.0.0:
+    resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
+    engines: {node: '>=0.10.0'}
+
+  is-potential-custom-element-name@1.0.1:
+    resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
+
+  is-promise@2.2.2:
+    resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==}
+
+  is-regex@1.1.4:
+    resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
+    engines: {node: '>= 0.4'}
+
+  is-set@2.0.2:
+    resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==}
+
+  is-shared-array-buffer@1.0.2:
+    resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==}
+
+  is-stream@1.1.0:
+    resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==}
+    engines: {node: '>=0.10.0'}
+
+  is-stream@2.0.1:
+    resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
+    engines: {node: '>=8'}
+
+  is-stream@3.0.0:
+    resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+  is-string@1.0.7:
+    resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
+    engines: {node: '>= 0.4'}
+
+  is-svg@5.0.0:
+    resolution: {integrity: sha512-sRl7J0oX9yUNamSdc8cwgzh9KBLnQXNzGmW0RVHwg/jEYjGNYHC6UvnYD8+hAeut9WwxRvhG9biK7g/wDGxcMw==}
+    engines: {node: '>=14.16'}
+
+  is-symbol@1.0.4:
+    resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==}
+    engines: {node: '>= 0.4'}
+
+  is-typed-array@1.1.10:
+    resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==}
+    engines: {node: '>= 0.4'}
+
+  is-typedarray@1.0.0:
+    resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}
+
+  is-unicode-supported@0.1.0:
+    resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
+    engines: {node: '>=10'}
+
+  is-weakmap@2.0.1:
+    resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==}
+
+  is-weakref@1.0.2:
+    resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
+
+  is-weakset@2.0.2:
+    resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==}
+
+  is-wsl@2.2.0:
+    resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
+    engines: {node: '>=8'}
+
+  isarray@0.0.1:
+    resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==}
+
+  isarray@1.0.0:
+    resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
+
+  isarray@2.0.5:
+    resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
+
+  isexe@2.0.0:
+    resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+  isexe@3.1.1:
+    resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==}
+    engines: {node: '>=16'}
+
+  isobject@3.0.1:
+    resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==}
+    engines: {node: '>=0.10.0'}
+
+  isstream@0.1.2:
+    resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==}
+
+  istanbul-lib-coverage@3.2.2:
+    resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
+    engines: {node: '>=8'}
+
+  istanbul-lib-instrument@5.2.1:
+    resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==}
+    engines: {node: '>=8'}
+
+  istanbul-lib-instrument@6.0.0:
+    resolution: {integrity: sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==}
+    engines: {node: '>=10'}
+
+  istanbul-lib-report@3.0.1:
+    resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
+    engines: {node: '>=10'}
+
+  istanbul-lib-source-maps@4.0.1:
+    resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
+    engines: {node: '>=10'}
+
+  istanbul-reports@3.1.6:
+    resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==}
+    engines: {node: '>=8'}
+
+  iterare@1.2.1:
+    resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==}
+    engines: {node: '>=6'}
+
+  jackspeak@2.3.6:
+    resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
+    engines: {node: '>=14'}
+
+  jake@10.8.5:
+    resolution: {integrity: sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==}
+    engines: {node: '>=10'}
+    hasBin: true
+
+  jest-changed-files@29.7.0:
+    resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-circus@29.7.0:
+    resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-cli@29.7.0:
+    resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+    hasBin: true
+    peerDependencies:
+      node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+    peerDependenciesMeta:
+      node-notifier:
+        optional: true
+
+  jest-config@29.7.0:
+    resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+    peerDependencies:
+      '@types/node': '*'
+      ts-node: '>=9.0.0'
+    peerDependenciesMeta:
+      '@types/node':
+        optional: true
+      ts-node:
+        optional: true
+
+  jest-diff@29.7.0:
+    resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-docblock@29.7.0:
+    resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-each@29.7.0:
+    resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-environment-node@29.7.0:
+    resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-fetch-mock@3.0.3:
+    resolution: {integrity: sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==}
+
+  jest-get-type@29.6.3:
+    resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-haste-map@29.7.0:
+    resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-leak-detector@29.7.0:
+    resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-matcher-utils@29.7.0:
+    resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-message-util@29.7.0:
+    resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-mock@29.7.0:
+    resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-pnp-resolver@1.2.3:
+    resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==}
+    engines: {node: '>=6'}
+    peerDependencies:
+      jest-resolve: '*'
+    peerDependenciesMeta:
+      jest-resolve:
+        optional: true
+
+  jest-regex-util@29.6.3:
+    resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-resolve-dependencies@29.7.0:
+    resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-resolve@29.7.0:
+    resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-runner@29.7.0:
+    resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-runtime@29.7.0:
+    resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-snapshot@29.7.0:
+    resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-util@29.7.0:
+    resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-validate@29.7.0:
+    resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-watcher@29.7.0:
+    resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest-websocket-mock@2.5.0:
+    resolution: {integrity: sha512-a+UJGfowNIWvtIKIQBHoEWIUqRxxQHFx4CXT+R5KxxKBtEQ5rS3pPOV/5299sHzqbmeCzxxY5qE4+yfXePePig==}
+
+  jest-worker@29.7.0:
+    resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  jest@29.7.0:
+    resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+    hasBin: true
+    peerDependencies:
+      node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+    peerDependenciesMeta:
+      node-notifier:
+        optional: true
+
+  jju@1.4.0:
+    resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
+
+  joi@17.11.0:
+    resolution: {integrity: sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==}
+
+  jpeg-js@0.3.7:
+    resolution: {integrity: sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ==}
+
+  js-beautify@1.14.9:
+    resolution: {integrity: sha512-coM7xq1syLcMyuVGyToxcj2AlzhkDjmfklL8r0JgJ7A76wyGMpJ1oA35mr4APdYNO/o/4YY8H54NQIJzhMbhBg==}
+    engines: {node: '>=12'}
+    hasBin: true
+
+  js-stringify@1.0.2:
+    resolution: {integrity: sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==}
+
+  js-tokens@4.0.0:
+    resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+  js-yaml@3.14.1:
+    resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
+    hasBin: true
+
+  js-yaml@4.1.0:
+    resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+    hasBin: true
+
+  jsbn@0.1.1:
+    resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==}
+
+  jsbn@1.1.0:
+    resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==}
+
+  jschardet@3.0.0:
+    resolution: {integrity: sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ==}
+    engines: {node: '>=0.1.90'}
+
+  jscodeshift@0.15.1:
+    resolution: {integrity: sha512-hIJfxUy8Rt4HkJn/zZPU9ChKfKZM1342waJ1QC2e2YsPcWhM+3BJ4dcfQCzArTrk1jJeNLB341H+qOcEHRxJZg==}
+    hasBin: true
+    peerDependencies:
+      '@babel/preset-env': ^7.1.6
+    peerDependenciesMeta:
+      '@babel/preset-env':
+        optional: true
+
+  jsdom@24.0.0:
+    resolution: {integrity: sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==}
+    engines: {node: '>=18'}
+    peerDependencies:
+      canvas: ^2.11.2
+    peerDependenciesMeta:
+      canvas:
+        optional: true
+
+  jsesc@0.5.0:
+    resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==}
+    hasBin: true
+
+  jsesc@2.5.2:
+    resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
+    engines: {node: '>=4'}
+    hasBin: true
+
+  json-buffer@3.0.1:
+    resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+
+  json-parse-even-better-errors@2.3.1:
+    resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+
+  json-schema-traverse@0.4.1:
+    resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+
+  json-schema-traverse@1.0.0:
+    resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
+
+  json-schema@0.4.0:
+    resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
+
+  json-stable-stringify-without-jsonify@1.0.1:
+    resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+
+  json-stringify-safe@5.0.1:
+    resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
+
+  json-to-ast@2.1.0:
+    resolution: {integrity: sha512-W9Lq347r8tA1DfMvAGn9QNcgYm4Wm7Yc+k8e6vezpMnRT+NHbtlxgNBXRVjXe9YM6eTn6+p/MKOlV/aABJcSnQ==}
+    engines: {node: '>= 4'}
+
+  json5@1.0.2:
+    resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
+    hasBin: true
+
+  json5@2.2.3:
+    resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+    engines: {node: '>=6'}
+    hasBin: true
+
+  jsonc-parser@3.2.0:
+    resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==}
+
+  jsonfile@4.0.0:
+    resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
+
+  jsonfile@5.0.0:
+    resolution: {integrity: sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==}
+
+  jsonfile@6.1.0:
+    resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
+
+  jsonld@8.3.2:
+    resolution: {integrity: sha512-MwBbq95szLwt8eVQ1Bcfwmgju/Y5P2GdtlHE2ncyfuYjIdEhluUVyj1eudacf1mOkWIoS9GpDBTECqhmq7EOaA==}
+    engines: {node: '>=14'}
+
+  jsonpointer@5.0.1:
+    resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==}
+    engines: {node: '>=0.10.0'}
+
+  jsprim@1.4.2:
+    resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==}
+    engines: {node: '>=0.6.0'}
+
+  jsprim@2.0.2:
+    resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==}
+    engines: {'0': node >=0.6.0}
+
+  jsrsasign@11.1.0:
+    resolution: {integrity: sha512-Ov74K9GihaK9/9WncTe1mPmvrO7Py665TUfUKvraXBpu+xcTWitrtuOwcjf4KMU9maPaYn0OuaWy0HOzy/GBXg==}
+
+  jssha@3.3.1:
+    resolution: {integrity: sha512-VCMZj12FCFMQYcFLPRm/0lOBbLi8uM2BhXPTqw3U4YAfs4AZfiApOoBLoN8cQE60Z50m1MYMTQVCfgF/KaCVhQ==}
+
+  jstransformer@1.0.0:
+    resolution: {integrity: sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==}
+
+  just-extend@4.2.1:
+    resolution: {integrity: sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==}
+
+  jwa@2.0.0:
+    resolution: {integrity: sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==}
+
+  jws@4.0.0:
+    resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==}
+
+  keyv@4.5.4:
+    resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+
+  kind-of@6.0.3:
+    resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
+    engines: {node: '>=0.10.0'}
+
+  kleur@3.0.3:
+    resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
+    engines: {node: '>=6'}
+
+  ky-universal@0.11.0:
+    resolution: {integrity: sha512-65KyweaWvk+uKKkCrfAf+xqN2/epw1IJDtlyCPxYffFCMR8u1sp2U65NtWpnozYfZxQ6IUzIlvUcw+hQ82U2Xw==}
+    engines: {node: '>=14.16'}
+    peerDependencies:
+      ky: '>=0.31.4'
+      web-streams-polyfill: '>=3.2.1'
+    peerDependenciesMeta:
+      web-streams-polyfill:
+        optional: true
+
+  ky@0.33.3:
+    resolution: {integrity: sha512-CasD9OCEQSFIam2U8efFK81Yeg8vNMTBUqtMOHlrcWQHqUX3HeCl9Dr31u4toV7emlH8Mymk5+9p0lL6mKb/Xw==}
+    engines: {node: '>=14.16'}
+
+  lazy-ass@1.6.0:
+    resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==}
+    engines: {node: '> 0.8'}
+
+  lazy-universal-dotenv@4.0.0:
+    resolution: {integrity: sha512-aXpZJRnTkpK6gQ/z4nk+ZBLd/Qdp118cvPruLSIQzQNRhKwEcdXCOzXuF55VDqIiuAaY3UGZ10DJtvZzDcvsxg==}
+    engines: {node: '>=14.0.0'}
+
+  lazystream@1.0.1:
+    resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==}
+    engines: {node: '>= 0.6.3'}
+
+  leven@3.1.0:
+    resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
+    engines: {node: '>=6'}
+
+  levn@0.4.1:
+    resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+    engines: {node: '>= 0.8.0'}
+
+  light-my-request@5.11.0:
+    resolution: {integrity: sha512-qkFCeloXCOMpmEdZ/MV91P8AT4fjwFXWaAFz3lUeStM8RcoM1ks4J/F8r1b3r6y/H4u3ACEJ1T+Gv5bopj7oDA==}
+
+  lilconfig@3.1.1:
+    resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==}
+    engines: {node: '>=14'}
+
+  lines-and-columns@1.2.4:
+    resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+
+  listr2@3.14.0:
+    resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==}
+    engines: {node: '>=10.0.0'}
+    peerDependencies:
+      enquirer: '>= 2.3.0 < 3'
+    peerDependenciesMeta:
+      enquirer:
+        optional: true
+
+  local-pkg@0.4.3:
+    resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==}
+    engines: {node: '>=14'}
+
+  locate-path@3.0.0:
+    resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==}
+    engines: {node: '>=6'}
+
+  locate-path@5.0.0:
+    resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
+    engines: {node: '>=8'}
+
+  locate-path@6.0.0:
+    resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+    engines: {node: '>=10'}
+
+  lodash.debounce@4.0.8:
+    resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
+
+  lodash.defaults@4.2.0:
+    resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
+
+  lodash.get@4.4.2:
+    resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
+
+  lodash.isarguments@3.1.0:
+    resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
+
+  lodash.isequal@4.5.0:
+    resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
+
+  lodash.memoize@4.1.2:
+    resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
+
+  lodash.merge@4.6.2:
+    resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+
+  lodash.once@4.1.1:
+    resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
+
+  lodash.uniq@4.5.0:
+    resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==}
+
+  lodash@4.17.21:
+    resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+
+  log-symbols@4.1.0:
+    resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
+    engines: {node: '>=10'}
+
+  log-update@4.0.0:
+    resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==}
+    engines: {node: '>=10'}
+
+  long@4.0.0:
+    resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==}
+
+  longest-streak@3.1.0:
+    resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
+
+  loose-envify@1.4.0:
+    resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
+    hasBin: true
+
+  loupe@2.3.7:
+    resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
+
+  lowercase-keys@2.0.0:
+    resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==}
+    engines: {node: '>=8'}
+
+  lowercase-keys@3.0.0:
+    resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+  lru-cache@10.0.2:
+    resolution: {integrity: sha512-Yj9mA8fPiVgOUpByoTZO5pNrcl5Yk37FcSHsUINpAsaBIEZIuqcCclDZJCVxqQShDsmYX8QG63svJiTbOATZwg==}
+    engines: {node: 14 || >=16.14}
+
+  lru-cache@10.2.2:
+    resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==}
+    engines: {node: 14 || >=16.14}
+
+  lru-cache@4.1.5:
+    resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
+
+  lru-cache@5.1.1:
+    resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+  lru-cache@6.0.0:
+    resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
+    engines: {node: '>=10'}
+
+  lru-cache@8.0.4:
+    resolution: {integrity: sha512-E9FF6+Oc/uFLqZCuZwRKUzgFt5Raih6LfxknOSAVTjNkrCZkBf7DQCwJxZQgd9l4eHjIJDGR+E+1QKD1RhThPw==}
+    engines: {node: '>=16.14'}
+
+  luxon@3.3.0:
+    resolution: {integrity: sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==}
+    engines: {node: '>=12'}
+
+  lz-string@1.5.0:
+    resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
+    hasBin: true
+
+  magic-string@0.27.0:
+    resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==}
+    engines: {node: '>=12'}
+
+  magic-string@0.30.10:
+    resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
+
+  magic-string@0.30.7:
+    resolution: {integrity: sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==}
+    engines: {node: '>=12'}
+
+  mailcheck@1.1.1:
+    resolution: {integrity: sha512-3WjL8+ZDouZwKlyJBMp/4LeziLFXgleOdsYu87piGcMLqhBzCsy2QFdbtAwv757TFC/rtqd738fgJw1tFQCSgA==}
+
+  make-dir@2.1.0:
+    resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
+    engines: {node: '>=6'}
+
+  make-dir@3.1.0:
+    resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
+    engines: {node: '>=8'}
+
+  make-dir@4.0.0:
+    resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
+    engines: {node: '>=10'}
+
+  make-fetch-happen@13.0.0:
+    resolution: {integrity: sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==}
+    engines: {node: ^16.14.0 || >=18.0.0}
+
+  makeerror@1.0.12:
+    resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
+
+  map-obj@1.0.1:
+    resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==}
+    engines: {node: '>=0.10.0'}
+
+  map-obj@4.3.0:
+    resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==}
+    engines: {node: '>=8'}
+
+  map-or-similar@1.5.0:
+    resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==}
+
+  map-stream@0.1.0:
+    resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==}
+
+  markdown-table@3.0.3:
+    resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==}
+
+  markdown-to-jsx@7.3.2:
+    resolution: {integrity: sha512-B+28F5ucp83aQm+OxNrPkS8z0tMKaeHiy0lHJs3LqCyDQFtWuenaIrkaVTgAm1pf1AU85LXltva86hlaT17i8Q==}
+    engines: {node: '>= 10'}
+    peerDependencies:
+      react: '>= 0.14.0'
+
+  matter-js@0.19.0:
+    resolution: {integrity: sha512-v2huwvQGOHTGOkMqtHd2hercCG3f6QAObTisPPHg8TZqq2lz7eIY/5i/5YUV8Ibf3mEioFEmwibcPUF2/fnKKQ==}
+
+  mdast-util-find-and-replace@3.0.1:
+    resolution: {integrity: sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==}
+
+  mdast-util-from-markdown@2.0.0:
+    resolution: {integrity: sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==}
+
+  mdast-util-gfm-autolink-literal@2.0.0:
+    resolution: {integrity: sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==}
+
+  mdast-util-gfm-footnote@2.0.0:
+    resolution: {integrity: sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==}
+
+  mdast-util-gfm-strikethrough@2.0.0:
+    resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==}
+
+  mdast-util-gfm-table@2.0.0:
+    resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==}
+
+  mdast-util-gfm-task-list-item@2.0.0:
+    resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==}
+
+  mdast-util-gfm@3.0.0:
+    resolution: {integrity: sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==}
+
+  mdast-util-phrasing@4.1.0:
+    resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==}
+
+  mdast-util-to-markdown@2.1.0:
+    resolution: {integrity: sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==}
+
+  mdast-util-to-string@4.0.0:
+    resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
+
+  mdn-data@2.0.28:
+    resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==}
+
+  mdn-data@2.0.30:
+    resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
+
+  media-typer@0.3.0:
+    resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
+    engines: {node: '>= 0.6'}
+
+  meilisearch@0.38.0:
+    resolution: {integrity: sha512-bHaq8nYxSKw9/Qslq1Zes5g9tHgFkxy/I9o8942wv2PqlNOT0CzptIkh/x98N52GikoSZOXSQkgt6oMjtf5uZw==}
+
+  memoizerific@1.11.3:
+    resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==}
+
+  meow@9.0.0:
+    resolution: {integrity: sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==}
+    engines: {node: '>=10'}
+
+  merge-descriptors@1.0.1:
+    resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
+
+  merge-stream@2.0.0:
+    resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+
+  merge2@1.4.1:
+    resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+    engines: {node: '>= 8'}
+
+  methods@1.1.2:
+    resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
+    engines: {node: '>= 0.6'}
+
+  mfm-js@0.24.0:
+    resolution: {integrity: sha512-6m8N0ElH9/4CA1izhVqmxTfLj5Z9RspdqM/lMew4xU/UTgm4Pf//VpDunpasxbRFjeJSVW+zoVwL4ZPfPtfiQg==}
+
+  microformats-parser@2.0.2:
+    resolution: {integrity: sha512-tUf9DmN4Jq/tGyp1YH2V6D/Cud+9Uc0WhjjUFirqVeHTRkkfLDacv6BQFT7h7HFsD0Z8wja5eKkRgzZU8bv0Fw==}
+    engines: {node: '>=18'}
+
+  micromark-core-commonmark@2.0.0:
+    resolution: {integrity: sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==}
+
+  micromark-extension-gfm-autolink-literal@2.0.0:
+    resolution: {integrity: sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==}
+
+  micromark-extension-gfm-footnote@2.0.0:
+    resolution: {integrity: sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==}
+
+  micromark-extension-gfm-strikethrough@2.0.0:
+    resolution: {integrity: sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==}
+
+  micromark-extension-gfm-table@2.0.0:
+    resolution: {integrity: sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==}
+
+  micromark-extension-gfm-tagfilter@2.0.0:
+    resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==}
+
+  micromark-extension-gfm-task-list-item@2.0.1:
+    resolution: {integrity: sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==}
+
+  micromark-extension-gfm@3.0.0:
+    resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==}
+
+  micromark-factory-destination@2.0.0:
+    resolution: {integrity: sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==}
+
+  micromark-factory-label@2.0.0:
+    resolution: {integrity: sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==}
+
+  micromark-factory-space@2.0.0:
+    resolution: {integrity: sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==}
+
+  micromark-factory-title@2.0.0:
+    resolution: {integrity: sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==}
+
+  micromark-factory-whitespace@2.0.0:
+    resolution: {integrity: sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==}
+
+  micromark-util-character@2.1.0:
+    resolution: {integrity: sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==}
+
+  micromark-util-chunked@2.0.0:
+    resolution: {integrity: sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==}
+
+  micromark-util-classify-character@2.0.0:
+    resolution: {integrity: sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==}
+
+  micromark-util-combine-extensions@2.0.0:
+    resolution: {integrity: sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==}
+
+  micromark-util-decode-numeric-character-reference@2.0.1:
+    resolution: {integrity: sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==}
+
+  micromark-util-decode-string@2.0.0:
+    resolution: {integrity: sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==}
+
+  micromark-util-encode@2.0.0:
+    resolution: {integrity: sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==}
+
+  micromark-util-html-tag-name@2.0.0:
+    resolution: {integrity: sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==}
+
+  micromark-util-normalize-identifier@2.0.0:
+    resolution: {integrity: sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==}
+
+  micromark-util-resolve-all@2.0.0:
+    resolution: {integrity: sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==}
+
+  micromark-util-sanitize-uri@2.0.0:
+    resolution: {integrity: sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==}
+
+  micromark-util-subtokenize@2.0.0:
+    resolution: {integrity: sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==}
+
+  micromark-util-symbol@2.0.0:
+    resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==}
+
+  micromark-util-types@2.0.0:
+    resolution: {integrity: sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==}
+
+  micromark@4.0.0:
+    resolution: {integrity: sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==}
+
+  micromatch@4.0.5:
+    resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
+    engines: {node: '>=8.6'}
+
+  mime-db@1.52.0:
+    resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+    engines: {node: '>= 0.6'}
+
+  mime-types@2.1.35:
+    resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+    engines: {node: '>= 0.6'}
+
+  mime@1.6.0:
+    resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
+    engines: {node: '>=4'}
+    hasBin: true
+
+  mime@3.0.0:
+    resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==}
+    engines: {node: '>=10.0.0'}
+    hasBin: true
+
+  mimic-fn@2.1.0:
+    resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
+    engines: {node: '>=6'}
+
+  mimic-fn@4.0.0:
+    resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
+    engines: {node: '>=12'}
+
+  mimic-response@1.0.1:
+    resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==}
+    engines: {node: '>=4'}
+
+  mimic-response@3.1.0:
+    resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
+    engines: {node: '>=10'}
+
+  mimic-response@4.0.0:
+    resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+  min-indent@1.0.1:
+    resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
+    engines: {node: '>=4'}
+
+  minimalistic-assert@1.0.1:
+    resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
+
+  minimatch@3.0.8:
+    resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==}
+
+  minimatch@3.1.2:
+    resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+
+  minimatch@5.1.2:
+    resolution: {integrity: sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==}
+    engines: {node: '>=10'}
+
+  minimatch@9.0.1:
+    resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==}
+    engines: {node: '>=16 || 14 >=14.17'}
+
+  minimatch@9.0.3:
+    resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
+    engines: {node: '>=16 || 14 >=14.17'}
+
+  minimatch@9.0.4:
+    resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==}
+    engines: {node: '>=16 || 14 >=14.17'}
+
+  minimist-options@4.1.0:
+    resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==}
+    engines: {node: '>= 6'}
+
+  minimist@1.2.8:
+    resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+
+  minipass-collect@1.0.2:
+    resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==}
+    engines: {node: '>= 8'}
+
+  minipass-fetch@3.0.3:
+    resolution: {integrity: sha512-n5ITsTkDqYkYJZjcRWzZt9qnZKCT7nKCosJhHoj7S7zD+BP4jVbWs+odsniw5TA3E0sLomhTKOKjF86wf11PuQ==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
+  minipass-flush@1.0.5:
+    resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==}
+    engines: {node: '>= 8'}
+
+  minipass-pipeline@1.2.4:
+    resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==}
+    engines: {node: '>=8'}
+
+  minipass-sized@1.0.3:
+    resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==}
+    engines: {node: '>=8'}
+
+  minipass@2.9.0:
+    resolution: {integrity: sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==}
+
+  minipass@3.3.6:
+    resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
+    engines: {node: '>=8'}
+
+  minipass@5.0.0:
+    resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==}
+    engines: {node: '>=8'}
+
+  minipass@7.0.4:
+    resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==}
+    engines: {node: '>=16 || 14 >=14.17'}
+
+  minizlib@1.3.3:
+    resolution: {integrity: sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==}
+
+  minizlib@2.1.2:
+    resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
+    engines: {node: '>= 8'}
+
+  mkdirp-classic@0.5.3:
+    resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
+
+  mkdirp@0.5.6:
+    resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
+    hasBin: true
+
+  mkdirp@1.0.4:
+    resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
+    engines: {node: '>=10'}
+    hasBin: true
+
+  mkdirp@2.1.6:
+    resolution: {integrity: sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==}
+    engines: {node: '>=10'}
+    hasBin: true
+
+  mlly@1.5.0:
+    resolution: {integrity: sha512-NPVQvAY1xr1QoVeG0cy8yUYC7FQcOx6evl/RjT1wL5FvzPnzOysoqB/jmx/DhssT2dYa8nxECLAaFI/+gVLhDQ==}
+
+  mnemonist@0.39.6:
+    resolution: {integrity: sha512-A/0v5Z59y63US00cRSLiloEIw3t5G+MiKz4BhX21FI+YBJXBOGW0ohFxTxO08dsOYlzxo87T7vGfZKYp2bcAWA==}
+
+  mock-socket@9.3.1:
+    resolution: {integrity: sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==}
+    engines: {node: '>= 8'}
+
+  mri@1.2.0:
+    resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
+    engines: {node: '>=4'}
+
+  ms@2.0.0:
+    resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
+
+  ms@2.1.2:
+    resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+
+  ms@2.1.3:
+    resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+  ms@3.0.0-canary.1:
+    resolution: {integrity: sha512-kh8ARjh8rMN7Du2igDRO9QJnqCb2xYTJxyQYK7vJJS4TvLLmsbyhiKpSW+t+y26gyOyMd0riphX0GeWKU3ky5g==}
+    engines: {node: '>=12.13'}
+
+  msgpackr-extract@3.0.2:
+    resolution: {integrity: sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==}
+    hasBin: true
+
+  msgpackr@1.10.1:
+    resolution: {integrity: sha512-r5VRLv9qouXuLiIBrLpl2d5ZvPt8svdQTl5/vMvE4nzDMyEX4sgW5yWhuBBj5UmgwOTWj8CIdSXn5sAfsHAWIQ==}
+
+  msw-storybook-addon@2.0.1:
+    resolution: {integrity: sha512-pZ3JDQ9HkGQ3XDMIHvMcDSI4Vbp/LHmwHwiZu+pHLzimtI1vhAo1swjFEDAEJuBcozljYvREEC4sS7rQHPNtWg==}
+    peerDependencies:
+      msw: ^2.0.0
+
+  msw@2.2.14:
+    resolution: {integrity: sha512-64i8rNCa1xzDK8ZYsTrVMli05D687jty8+Th+PU5VTbJ2/4P7fkQFVyDQ6ZFT5FrNR8z2BHhbY47fKNvfHrumA==}
+    engines: {node: '>=18'}
+    hasBin: true
+    peerDependencies:
+      typescript: '>= 4.7.x'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  muggle-string@0.4.1:
+    resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
+
+  multer@1.4.4-lts.1:
+    resolution: {integrity: sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==}
+    engines: {node: '>= 6.0.0'}
+
+  multi-integer-range@3.0.0:
+    resolution: {integrity: sha512-uQzynjVJ8F7x5wjaK0g4Ybhy2TvO/pk96+YHyS5g1W4GuUEV6HMebZ8HcRwWgKIRCUT2MLbM5uCKwYcAqkS+8Q==}
+
+  mute-stream@1.0.0:
+    resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
+  mylas@2.1.13:
+    resolution: {integrity: sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg==}
+    engines: {node: '>=12.0.0'}
+
+  mz@2.7.0:
+    resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
+
+  nan@2.18.0:
+    resolution: {integrity: sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==}
+
+  nanoid@3.3.7:
+    resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
+    engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+    hasBin: true
+
+  nanoid@5.0.7:
+    resolution: {integrity: sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ==}
+    engines: {node: ^18 || >=20}
+    hasBin: true
+
+  natural-compare@1.4.0:
+    resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+
+  ncp@2.0.0:
+    resolution: {integrity: sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==}
+    hasBin: true
+
+  ndarray-ops@1.2.2:
+    resolution: {integrity: sha512-BppWAFRjMYF7N/r6Ie51q6D4fs0iiGmeXIACKY66fLpnwIui3Wc3CXiD/30mgLbDjPpSLrsqcp3Z62+IcHZsDw==}
+
+  ndarray-pack@1.2.1:
+    resolution: {integrity: sha512-51cECUJMT0rUZNQa09EoKsnFeDL4x2dHRT0VR5U2H5ZgEcm95ZDWcMA5JShroXjHOejmAD/fg8+H+OvUnVXz2g==}
+
+  ndarray@1.0.18:
+    resolution: {integrity: sha512-jUz6G+CIsEsqs2VlB1EvaQSAA0Jkf8YKm7eFBleKyhiQjYWzTxXqHzWEOm3jFoGCpxGh4DnPUYHB4ECWE+n9SQ==}
+
+  ndarray@1.0.19:
+    resolution: {integrity: sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ==}
+
+  needle@2.9.1:
+    resolution: {integrity: sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==}
+    engines: {node: '>= 4.4.x'}
+    hasBin: true
+
+  negotiator@0.6.3:
+    resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
+    engines: {node: '>= 0.6'}
+
+  neo-async@2.6.2:
+    resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
+
+  nested-property@4.0.0:
+    resolution: {integrity: sha512-yFehXNWRs4cM0+dz7QxCd06hTbWbSkV0ISsqBfkntU6TOY4Qm3Q88fRRLOddkGh2Qq6dZvnKVAahfhjcUvLnyA==}
+
+  netmask@2.0.2:
+    resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==}
+    engines: {node: '>= 0.4.0'}
+
+  nice-napi@1.0.2:
+    resolution: {integrity: sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==}
+    os: ['!win32']
+
+  nise@5.1.4:
+    resolution: {integrity: sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==}
+
+  node-abort-controller@3.1.1:
+    resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==}
+
+  node-addon-api@3.2.1:
+    resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==}
+
+  node-bitmap@0.0.1:
+    resolution: {integrity: sha512-Jx5lPaaLdIaOsj2mVLWMWulXF6GQVdyLvNSxmiYCvZ8Ma2hfKX0POoR2kgKOqz+oFsRreq0yYZjQ2wjE9VNzCA==}
+    engines: {node: '>=v0.6.5'}
+
+  node-dir@0.1.17:
+    resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==}
+    engines: {node: '>= 0.10.5'}
+
+  node-domexception@1.0.0:
+    resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
+    engines: {node: '>=10.5.0'}
+
+  node-fetch-native@1.0.2:
+    resolution: {integrity: sha512-KIkvH1jl6b3O7es/0ShyCgWLcfXxlBrLBbP3rOr23WArC66IMcU4DeZEeYEOwnopYhawLTn7/y+YtmASe8DFVQ==}
+
+  node-fetch@2.6.11:
+    resolution: {integrity: sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==}
+    engines: {node: 4.x || >=6.0.0}
+    peerDependencies:
+      encoding: ^0.1.0
+    peerDependenciesMeta:
+      encoding:
+        optional: true
+
+  node-fetch@2.7.0:
+    resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
+    engines: {node: 4.x || >=6.0.0}
+    peerDependencies:
+      encoding: ^0.1.0
+    peerDependenciesMeta:
+      encoding:
+        optional: true
+
+  node-fetch@3.3.2:
+    resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+  node-gyp-build-optional-packages@5.0.7:
+    resolution: {integrity: sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==}
+    hasBin: true
+
+  node-gyp-build@4.6.0:
+    resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==}
+    hasBin: true
+
+  node-gyp@10.0.1:
+    resolution: {integrity: sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==}
+    engines: {node: ^16.14.0 || >=18.0.0}
+    hasBin: true
+
+  node-int64@0.4.0:
+    resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
+
+  node-releases@2.0.14:
+    resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
+
+  nodemailer@6.9.13:
+    resolution: {integrity: sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==}
+    engines: {node: '>=6.0.0'}
+
+  nodemon@3.0.2:
+    resolution: {integrity: sha512-9qIN2LNTrEzpOPBaWHTm4Asy1LxXLSickZStAQ4IZe7zsoIpD/A7LWxhZV3t4Zu352uBcqVnRsDXSMR2Sc3lTA==}
+    engines: {node: '>=10'}
+    hasBin: true
+
+  nodemon@3.1.0:
+    resolution: {integrity: sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==}
+    engines: {node: '>=10'}
+    hasBin: true
+
+  nofilter@3.1.0:
+    resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==}
+    engines: {node: '>=12.19'}
+
+  nopt@1.0.10:
+    resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==}
+    hasBin: true
+
+  nopt@5.0.0:
+    resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==}
+    engines: {node: '>=6'}
+    hasBin: true
+
+  nopt@6.0.0:
+    resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==}
+    engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+    hasBin: true
+
+  nopt@7.2.0:
+    resolution: {integrity: sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+    hasBin: true
+
+  normalize-package-data@2.5.0:
+    resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
+
+  normalize-package-data@3.0.3:
+    resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==}
+    engines: {node: '>=10'}
+
+  normalize-path@3.0.0:
+    resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+    engines: {node: '>=0.10.0'}
+
+  normalize-url@6.1.0:
+    resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==}
+    engines: {node: '>=10'}
+
+  normalize-url@8.0.0:
+    resolution: {integrity: sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==}
+    engines: {node: '>=14.16'}
+
+  npm-run-path@2.0.2:
+    resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==}
+    engines: {node: '>=4'}
+
+  npm-run-path@4.0.1:
+    resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
+    engines: {node: '>=8'}
+
+  npm-run-path@5.1.0:
+    resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+  npmlog@5.0.1:
+    resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==}
+
+  nsfwjs@2.4.2:
+    resolution: {integrity: sha512-i4Pp2yt59qPQgeZFyg3wXFBX52uSeu/hkDoqdZfe+sILRxNBUu0VDogj7Lmqak0GlrXviS/wLiVeIx40IDUu7A==}
+    peerDependencies:
+      '@tensorflow/tfjs': ^3.18.0
+
+  nth-check@2.1.1:
+    resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
+
+  nwsapi@2.2.9:
+    resolution: {integrity: sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==}
+
+  oauth-sign@0.9.0:
+    resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==}
+
+  oauth2orize-pkce@0.1.2:
+    resolution: {integrity: sha512-grto2UYhXHi9GLE3IBgBBbV87xci55+bCyjpVuxKyzol6I5Rg0K1MiTuXE+JZk54R86SG2wqXODMiZYHraPpxw==}
+
+  oauth2orize@1.12.0:
+    resolution: {integrity: sha512-j4XtFDQUBsvUHPjUmvmNDUDMYed2MphMIJBhyxVVe8hGCjkuYnjIsW+D9qk8c5ciXRdnk6x6tEbiO6PLeOZdCQ==}
+    engines: {node: '>= 0.4.0'}
+
+  oauth@0.10.0:
+    resolution: {integrity: sha512-1orQ9MT1vHFGQxhuy7E/0gECD3fd2fCC+PIX+/jgmU/gI3EpRocXtmtvxCO5x3WZ443FLTLFWNDjl5MPJf9u+Q==}
+
+  object-assign@4.1.1:
+    resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
+    engines: {node: '>=0.10.0'}
+
+  object-inspect@1.12.3:
+    resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
+
+  object-is@1.1.5:
+    resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==}
+    engines: {node: '>= 0.4'}
+
+  object-keys@1.1.1:
+    resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
+    engines: {node: '>= 0.4'}
+
+  object.assign@4.1.4:
+    resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==}
+    engines: {node: '>= 0.4'}
+
+  object.fromentries@2.0.7:
+    resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==}
+    engines: {node: '>= 0.4'}
+
+  object.groupby@1.0.1:
+    resolution: {integrity: sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==}
+
+  object.values@1.1.7:
+    resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==}
+    engines: {node: '>= 0.4'}
+
+  obliterator@2.0.4:
+    resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==}
+
+  oblivious-set@1.4.0:
+    resolution: {integrity: sha512-szyd0ou0T8nsAqHtprRcP3WidfsN1TnAR5yWXf2mFCEr5ek3LEOkT6EZ/92Xfs74HIdyhG5WkGxIssMU0jBaeg==}
+    engines: {node: '>=16'}
+
+  obuf@1.1.2:
+    resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==}
+
+  omggif@1.0.10:
+    resolution: {integrity: sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==}
+
+  on-exit-leak-free@2.1.0:
+    resolution: {integrity: sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==}
+
+  on-finished@2.4.1:
+    resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
+    engines: {node: '>= 0.8'}
+
+  on-headers@1.0.2:
+    resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==}
+    engines: {node: '>= 0.8'}
+
+  once@1.4.0:
+    resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+
+  onetime@5.1.2:
+    resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
+    engines: {node: '>=6'}
+
+  onetime@6.0.0:
+    resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
+    engines: {node: '>=12'}
+
+  open@8.4.2:
+    resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==}
+    engines: {node: '>=12'}
+
+  openapi-types@12.1.3:
+    resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==}
+
+  openapi-typescript@6.7.3:
+    resolution: {integrity: sha512-es3mGcDXV6TKPo6n3aohzHm0qxhLyR39MhF6mkD1FwFGjhxnqMqfSIgM0eCpInZvqatve4CxmXcMZw3jnnsaXw==}
+    hasBin: true
+
+  optionator@0.9.3:
+    resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
+    engines: {node: '>= 0.8.0'}
+
+  ora@5.4.1:
+    resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==}
+    engines: {node: '>=10'}
+
+  os-filter-obj@2.0.0:
+    resolution: {integrity: sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==}
+    engines: {node: '>=4'}
+
+  os-utils@0.0.14:
+    resolution: {integrity: sha512-ajB8csaHLBvJOYsHJkp8YdO2FvlBbf/ZxaYQwXXRDyQ84UoE+uTuLXxqd0shekXMX6Qr/pt/DDyLMRAMsgfWzg==}
+
+  ospath@1.2.2:
+    resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==}
+
+  otpauth@9.2.3:
+    resolution: {integrity: sha512-oAG55Ch4MBL5Jdg+RXfKiRCZ2lCwa/UIQKsmSfYbGGLSI4dErY1HPZv0JGPPESIYGyDO3s9iJqM4HU/1IppMoQ==}
+
+  outvariant@1.4.2:
+    resolution: {integrity: sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ==}
+
+  p-cancelable@2.1.1:
+    resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==}
+    engines: {node: '>=8'}
+
+  p-cancelable@3.0.0:
+    resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==}
+    engines: {node: '>=12.20'}
+
+  p-cancelable@4.0.1:
+    resolution: {integrity: sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==}
+    engines: {node: '>=14.16'}
+
+  p-finally@1.0.0:
+    resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==}
+    engines: {node: '>=4'}
+
+  p-limit@2.3.0:
+    resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
+    engines: {node: '>=6'}
+
+  p-limit@3.1.0:
+    resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+    engines: {node: '>=10'}
+
+  p-limit@4.0.0:
+    resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+  p-locate@3.0.0:
+    resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==}
+    engines: {node: '>=6'}
+
+  p-locate@4.1.0:
+    resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
+    engines: {node: '>=8'}
+
+  p-locate@5.0.0:
+    resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+    engines: {node: '>=10'}
+
+  p-map@4.0.0:
+    resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
+    engines: {node: '>=10'}
+
+  p-queue@6.6.2:
+    resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==}
+    engines: {node: '>=8'}
+
+  p-timeout@3.2.0:
+    resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==}
+    engines: {node: '>=8'}
+
+  p-try@2.2.0:
+    resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
+    engines: {node: '>=6'}
+
+  pako@0.2.9:
+    resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
+
+  parent-module@1.0.1:
+    resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+    engines: {node: '>=6'}
+
+  parse-data-uri@0.2.0:
+    resolution: {integrity: sha512-uOtts8NqDcaCt1rIsO3VFDRsAfgE4c6osG4d9z3l4dCBlxYFzni6Di/oNU270SDrjkfZuUvLZx1rxMyqh46Y9w==}
+
+  parse-json@5.2.0:
+    resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
+    engines: {node: '>=8'}
+
+  parse-srcset@1.0.2:
+    resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==}
+
+  parse5-htmlparser2-tree-adapter@6.0.1:
+    resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==}
+
+  parse5-htmlparser2-tree-adapter@7.0.0:
+    resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==}
+
+  parse5@5.1.1:
+    resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==}
+
+  parse5@6.0.1:
+    resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==}
+
+  parse5@7.1.2:
+    resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==}
+
+  parseurl@1.3.3:
+    resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
+    engines: {node: '>= 0.8'}
+
+  path-browserify@1.0.1:
+    resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
+
+  path-exists@3.0.0:
+    resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==}
+    engines: {node: '>=4'}
+
+  path-exists@4.0.0:
+    resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+    engines: {node: '>=8'}
+
+  path-is-absolute@1.0.1:
+    resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
+    engines: {node: '>=0.10.0'}
+
+  path-key@2.0.1:
+    resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==}
+    engines: {node: '>=4'}
+
+  path-key@3.1.1:
+    resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+    engines: {node: '>=8'}
+
+  path-key@4.0.0:
+    resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
+    engines: {node: '>=12'}
+
+  path-parse@1.0.7:
+    resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+
+  path-scurry@1.10.1:
+    resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==}
+    engines: {node: '>=16 || 14 >=14.17'}
+
+  path-scurry@1.10.2:
+    resolution: {integrity: sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==}
+    engines: {node: '>=16 || 14 >=14.17'}
+
+  path-to-regexp@0.1.7:
+    resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
+
+  path-to-regexp@1.8.0:
+    resolution: {integrity: sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==}
+
+  path-to-regexp@3.2.0:
+    resolution: {integrity: sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==}
+
+  path-to-regexp@6.2.1:
+    resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==}
+
+  path-type@4.0.0:
+    resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+    engines: {node: '>=8'}
+
+  pathe@1.1.2:
+    resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
+
+  pathval@1.1.1:
+    resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
+
+  pause-stream@0.0.11:
+    resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==}
+
+  peek-readable@5.0.0:
+    resolution: {integrity: sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==}
+    engines: {node: '>=14.16'}
+
+  peek-stream@1.1.3:
+    resolution: {integrity: sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==}
+
+  pend@1.2.0:
+    resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
+
+  performance-now@2.1.0:
+    resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
+
+  pg-cloudflare@1.1.1:
+    resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==}
+
+  pg-connection-string@2.6.4:
+    resolution: {integrity: sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==}
+
+  pg-int8@1.0.1:
+    resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
+    engines: {node: '>=4.0.0'}
+
+  pg-numeric@1.0.2:
+    resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==}
+    engines: {node: '>=4'}
+
+  pg-pool@3.6.2:
+    resolution: {integrity: sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==}
+    peerDependencies:
+      pg: '>=8.0'
+
+  pg-protocol@1.6.0:
+    resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==}
+
+  pg-protocol@1.6.1:
+    resolution: {integrity: sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==}
+
+  pg-types@2.2.0:
+    resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==}
+    engines: {node: '>=4'}
+
+  pg-types@4.0.1:
+    resolution: {integrity: sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g==}
+    engines: {node: '>=10'}
+
+  pg@8.11.5:
+    resolution: {integrity: sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==}
+    engines: {node: '>= 8.0.0'}
+    peerDependencies:
+      pg-native: '>=3.0.1'
+    peerDependenciesMeta:
+      pg-native:
+        optional: true
+
+  pgpass@1.0.5:
+    resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
+
+  photoswipe@5.4.3:
+    resolution: {integrity: sha512-9UC6oJBK4oXFZ5HcdlcvGkfEHsVrmE4csUdCQhEjHYb3PvPLO3PG7UhnPuOgjxwmhq5s17Un5NUdum01LgBDng==}
+    engines: {node: '>= 0.12.0'}
+
+  picocolors@1.0.0:
+    resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
+
+  picomatch@2.3.1:
+    resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+    engines: {node: '>=8.6'}
+
+  pid-port@1.0.0:
+    resolution: {integrity: sha512-LSNBeKChRPA4Xlrs6+zV588G1hSrFvANtPV5rt/5MPfSPK3V9XPWxx1d29svsrOjngT9ifLisXWCLS7DvO9ZhQ==}
+    engines: {node: '>=18'}
+
+  pify@2.3.0:
+    resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
+    engines: {node: '>=0.10.0'}
+
+  pify@4.0.1:
+    resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
+    engines: {node: '>=6'}
+
+  pino-abstract-transport@1.1.0:
+    resolution: {integrity: sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==}
+
+  pino-std-serializers@6.1.0:
+    resolution: {integrity: sha512-KO0m2f1HkrPe9S0ldjx7za9BJjeHqBku5Ch8JyxETxT8dEFGz1PwgrHaOQupVYitpzbFSYm7nnljxD8dik2c+g==}
+
+  pino@8.17.0:
+    resolution: {integrity: sha512-ey+Mku+PVPhvxglLXMg1l1zQMwSHuNrKC3MD40EDZbkckJmmuY7DYZLIOwwjZ8ix/Nvhe9dZt5H99cgkot9bAw==}
+    hasBin: true
+
+  pirates@4.0.5:
+    resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==}
+    engines: {node: '>= 6'}
+
+  piscina@4.4.0:
+    resolution: {integrity: sha512-+AQduEJefrOApE4bV7KRmp3N2JnnyErlVqq4P/jmko4FPz9Z877BCccl/iB3FdrWSUkvbGV9Kan/KllJgat3Vg==}
+
+  pkce-challenge@4.1.0:
+    resolution: {integrity: sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ==}
+    engines: {node: '>=16.20.0'}
+
+  pkg-dir@3.0.0:
+    resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==}
+    engines: {node: '>=6'}
+
+  pkg-dir@4.2.0:
+    resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
+    engines: {node: '>=8'}
+
+  pkg-dir@5.0.0:
+    resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==}
+    engines: {node: '>=10'}
+
+  pkg-types@1.0.3:
+    resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==}
+
+  plimit-lit@1.5.0:
+    resolution: {integrity: sha512-Eb/MqCb1Iv/ok4m1FqIXqvUKPISufcjZ605hl3KM/n8GaX8zfhtgdLwZU3vKjuHGh2O9Rjog/bHTq8ofIShdng==}
+
+  plur@4.0.0:
+    resolution: {integrity: sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==}
+    engines: {node: '>=10'}
+
+  pngjs-nozlib@1.0.0:
+    resolution: {integrity: sha512-N1PggqLp9xDqwAoKvGohmZ3m4/N9xpY0nDZivFqQLcpLHmliHnCp9BuNCsOeqHWMuEEgFjpEaq9dZq6RZyy0fA==}
+    engines: {iojs: '>= 1.0.0', node: '>=0.10.0'}
+
+  pngjs@3.4.0:
+    resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==}
+    engines: {node: '>=4.0.0'}
+
+  pngjs@5.0.0:
+    resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
+    engines: {node: '>=10.13.0'}
+
+  polished@4.2.2:
+    resolution: {integrity: sha512-Sz2Lkdxz6F2Pgnpi9U5Ng/WdWAUZxmHrNPoVlm3aAemxoy2Qy7LGjQg4uf8qKelDAUW94F4np3iH2YPf2qefcQ==}
+    engines: {node: '>=10'}
+
+  postcss-calc@9.0.1:
+    resolution: {integrity: sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.2.2
+
+  postcss-colormin@6.1.0:
+    resolution: {integrity: sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-convert-values@6.1.0:
+    resolution: {integrity: sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-discard-comments@6.0.2:
+    resolution: {integrity: sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-discard-duplicates@6.0.3:
+    resolution: {integrity: sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-discard-empty@6.0.3:
+    resolution: {integrity: sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-discard-overridden@6.0.2:
+    resolution: {integrity: sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-merge-longhand@6.0.5:
+    resolution: {integrity: sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-merge-rules@6.1.1:
+    resolution: {integrity: sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-minify-font-values@6.1.0:
+    resolution: {integrity: sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-minify-gradients@6.0.3:
+    resolution: {integrity: sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-minify-params@6.1.0:
+    resolution: {integrity: sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-minify-selectors@6.0.4:
+    resolution: {integrity: sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-normalize-charset@6.0.2:
+    resolution: {integrity: sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-normalize-display-values@6.0.2:
+    resolution: {integrity: sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-normalize-positions@6.0.2:
+    resolution: {integrity: sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-normalize-repeat-style@6.0.2:
+    resolution: {integrity: sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-normalize-string@6.0.2:
+    resolution: {integrity: sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-normalize-timing-functions@6.0.2:
+    resolution: {integrity: sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-normalize-unicode@6.1.0:
+    resolution: {integrity: sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-normalize-url@6.0.2:
+    resolution: {integrity: sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-normalize-whitespace@6.0.2:
+    resolution: {integrity: sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-ordered-values@6.0.2:
+    resolution: {integrity: sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-reduce-initial@6.1.0:
+    resolution: {integrity: sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-reduce-transforms@6.0.2:
+    resolution: {integrity: sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-selector-parser@6.0.15:
+    resolution: {integrity: sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==}
+    engines: {node: '>=4'}
+
+  postcss-selector-parser@6.0.16:
+    resolution: {integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==}
+    engines: {node: '>=4'}
+
+  postcss-svgo@6.0.3:
+    resolution: {integrity: sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==}
+    engines: {node: ^14 || ^16 || >= 18}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-unique-selectors@6.0.4:
+    resolution: {integrity: sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  postcss-value-parser@4.2.0:
+    resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
+
+  postcss@8.4.38:
+    resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
+    engines: {node: ^10 || ^12 || >=14}
+
+  postgres-array@2.0.0:
+    resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
+    engines: {node: '>=4'}
+
+  postgres-array@3.0.2:
+    resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==}
+    engines: {node: '>=12'}
+
+  postgres-bytea@1.0.0:
+    resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==}
+    engines: {node: '>=0.10.0'}
+
+  postgres-bytea@3.0.0:
+    resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==}
+    engines: {node: '>= 6'}
+
+  postgres-date@1.0.7:
+    resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==}
+    engines: {node: '>=0.10.0'}
+
+  postgres-date@2.0.1:
+    resolution: {integrity: sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw==}
+    engines: {node: '>=12'}
+
+  postgres-interval@1.2.0:
+    resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
+    engines: {node: '>=0.10.0'}
+
+  postgres-interval@3.0.0:
+    resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==}
+    engines: {node: '>=12'}
+
+  postgres-range@1.1.3:
+    resolution: {integrity: sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==}
+
+  prelude-ls@1.2.1:
+    resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+    engines: {node: '>= 0.8.0'}
+
+  prettier@3.2.5:
+    resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==}
+    engines: {node: '>=14'}
+    hasBin: true
+
+  pretty-bytes@5.6.0:
+    resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==}
+    engines: {node: '>=6'}
+
+  pretty-format@27.5.1:
+    resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}
+    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
+
+  pretty-format@29.7.0:
+    resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+  pretty-hrtime@1.0.3:
+    resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==}
+    engines: {node: '>= 0.8'}
+
+  private-ip@2.3.3:
+    resolution: {integrity: sha512-5zyFfekIVUOTVbL92hc8LJOtE/gyGHeREHkJ2yTyByP8Q2YZVoBqLg3EfYLeF0oVvGqtaEX2t2Qovja0/gStXw==}
+
+  probe-image-size@7.2.3:
+    resolution: {integrity: sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w==}
+
+  proc-log@3.0.0:
+    resolution: {integrity: sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
+  process-exists@5.0.0:
+    resolution: {integrity: sha512-6QPRh5fyHD8MaXr4GYML8K/YY0Sq5dKHGIOrAKS3cYpHQdmygFCcijIu1dVoNKAZ0TWAMoeh8KDK9dF8auBkJA==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+  process-nextick-args@2.0.1:
+    resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
+
+  process-warning@2.2.0:
+    resolution: {integrity: sha512-/1WZ8+VQjR6avWOgHeEPd7SDQmFQ1B5mC1eRXsCm5TarlNmx/wCsa5GEaxGm05BORRtyG/Ex/3xq3TuRvq57qg==}
+
+  process-warning@3.0.0:
+    resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==}
+
+  process@0.11.10:
+    resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
+    engines: {node: '>= 0.6.0'}
+
+  progress@2.0.3:
+    resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
+    engines: {node: '>=0.4.0'}
+
+  promise-limit@2.7.0:
+    resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==}
+
+  promise-polyfill@8.3.0:
+    resolution: {integrity: sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg==}
+
+  promise-retry@2.0.1:
+    resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==}
+    engines: {node: '>=10'}
+
+  promise@7.3.1:
+    resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==}
+
+  prompts@2.4.2:
+    resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
+    engines: {node: '>= 6'}
+
+  prop-types@15.8.1:
+    resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
+
+  proto-list@1.2.4:
+    resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
+
+  proxy-addr@2.0.7:
+    resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
+    engines: {node: '>= 0.10'}
+
+  proxy-from-env@1.0.0:
+    resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==}
+
+  proxy-from-env@1.1.0:
+    resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+
+  ps-list@8.1.1:
+    resolution: {integrity: sha512-OPS9kEJYVmiO48u/B9qneqhkMvgCxT+Tm28VCEJpheTpl8cJ0ffZRRNgS5mrQRTrX5yRTpaJ+hRDeefXYmmorQ==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+  ps-tree@1.2.0:
+    resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==}
+    engines: {node: '>= 0.10'}
+    hasBin: true
+
+  pseudomap@1.0.2:
+    resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
+
+  psl@1.9.0:
+    resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
+
+  pstree.remy@1.1.8:
+    resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==}
+
+  pug-attrs@3.0.0:
+    resolution: {integrity: sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==}
+
+  pug-code-gen@3.0.2:
+    resolution: {integrity: sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==}
+
+  pug-error@2.0.0:
+    resolution: {integrity: sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==}
+
+  pug-filters@4.0.0:
+    resolution: {integrity: sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==}
+
+  pug-lexer@5.0.1:
+    resolution: {integrity: sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==}
+
+  pug-linker@4.0.0:
+    resolution: {integrity: sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==}
+
+  pug-load@3.0.0:
+    resolution: {integrity: sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==}
+
+  pug-parser@6.0.0:
+    resolution: {integrity: sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==}
+
+  pug-runtime@3.0.1:
+    resolution: {integrity: sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==}
+
+  pug-strip-comments@2.0.0:
+    resolution: {integrity: sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==}
+
+  pug-walk@2.0.0:
+    resolution: {integrity: sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==}
+
+  pug@3.0.2:
+    resolution: {integrity: sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==}
+
+  pump@2.0.1:
+    resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==}
+
+  pump@3.0.0:
+    resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
+
+  pumpify@1.5.1:
+    resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==}
+
+  punycode@2.3.1:
+    resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+    engines: {node: '>=6'}
+
+  pure-rand@6.0.0:
+    resolution: {integrity: sha512-rLSBxJjP+4DQOgcJAx6RZHT2he2pkhQdSnofG5VWyVl6GRq/K02ISOuOLcsMOrtKDIJb8JN2zm3FFzWNbezdPw==}
+
+  pvtsutils@1.3.5:
+    resolution: {integrity: sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==}
+
+  pvutils@1.1.3:
+    resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==}
+    engines: {node: '>=6.0.0'}
+
+  qrcode@1.5.3:
+    resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==}
+    engines: {node: '>=10.13.0'}
+    hasBin: true
+
+  qs@6.10.4:
+    resolution: {integrity: sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==}
+    engines: {node: '>=0.6'}
+
+  qs@6.11.0:
+    resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
+    engines: {node: '>=0.6'}
+
+  qs@6.11.1:
+    resolution: {integrity: sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ==}
+    engines: {node: '>=0.6'}
+
+  qs@6.5.3:
+    resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==}
+    engines: {node: '>=0.6'}
+
+  querystringify@2.2.0:
+    resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
+
+  queue-lit@1.5.0:
+    resolution: {integrity: sha512-IslToJ4eiCEE9xwMzq3viOO5nH8sUWUCwoElrhNMozzr9IIt2qqvB4I+uHu/zJTQVqc9R5DFwok4ijNK1pU3fA==}
+
+  queue-microtask@1.2.3:
+    resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+
+  queue-tick@1.0.1:
+    resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==}
+
+  quick-format-unescaped@4.0.4:
+    resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
+
+  quick-lru@4.0.1:
+    resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==}
+    engines: {node: '>=8'}
+
+  quick-lru@5.1.1:
+    resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
+    engines: {node: '>=10'}
+
+  ramda@0.29.0:
+    resolution: {integrity: sha512-BBea6L67bYLtdbOqfp8f58fPMqEwx0doL+pAi8TZyp2YWz8R9G8z9x75CZI8W+ftqhFHCpEX2cRnUUXK130iKA==}
+
+  random-seed@0.3.0:
+    resolution: {integrity: sha512-y13xtn3kcTlLub3HKWXxJNeC2qK4mB59evwZ5EkeRlolx+Bp2ztF7LbcZmyCnOqlHQrLnfuNbi1sVmm9lPDlDA==}
+    engines: {node: '>= 0.6.0'}
+
+  range-parser@1.2.1:
+    resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
+    engines: {node: '>= 0.6'}
+
+  ratelimiter@3.4.1:
+    resolution: {integrity: sha512-5FJbRW/Jkkdk29ksedAfWFkQkhbUrMx3QJGwMKAypeIiQf4yrLW+gtPKZiaWt4zPrtw1uGufOjGO7UGM6VllsQ==}
+
+  raw-body@2.5.1:
+    resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==}
+    engines: {node: '>= 0.8'}
+
+  raw-body@2.5.2:
+    resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
+    engines: {node: '>= 0.8'}
+
+  rdf-canonize@3.4.0:
+    resolution: {integrity: sha512-fUeWjrkOO0t1rg7B2fdyDTvngj+9RlUyL92vOdiB7c0FPguWVsniIMjEtHH+meLBO9rzkUlUzBVXgWrjI8P9LA==}
+    engines: {node: '>=12'}
+
+  re2@1.20.10:
+    resolution: {integrity: sha512-/5JjSPXobSDaKFL6rD5Gb4qD4CVBITQb7NAxfQ/NA7o0HER3SJAPV3lPO2kvzw0/PN1pVJNVATEUk4y9j7oIIA==}
+
+  react-colorful@5.6.1:
+    resolution: {integrity: sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==}
+    peerDependencies:
+      react: '>=16.8.0'
+      react-dom: '>=16.8.0'
+
+  react-docgen-typescript@2.2.2:
+    resolution: {integrity: sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==}
+    peerDependencies:
+      typescript: '>= 4.3.x'
+
+  react-docgen@7.0.1:
+    resolution: {integrity: sha512-rCz0HBIT0LWbIM+///LfRrJoTKftIzzwsYDf0ns5KwaEjejMHQRtphcns+IXFHDNY9pnz6G8l/JbbI6pD4EAIA==}
+    engines: {node: '>=16.14.0'}
+
+  react-dom@18.3.1:
+    resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==}
+    peerDependencies:
+      react: ^18.3.1
+
+  react-element-to-jsx-string@15.0.0:
+    resolution: {integrity: sha512-UDg4lXB6BzlobN60P8fHWVPX3Kyw8ORrTeBtClmIlGdkOOE+GYQSFvmEU5iLLpwp/6v42DINwNcwOhOLfQ//FQ==}
+    peerDependencies:
+      react: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0
+      react-dom: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0
+
+  react-is@16.13.1:
+    resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
+
+  react-is@17.0.2:
+    resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
+
+  react-is@18.1.0:
+    resolution: {integrity: sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==}
+
+  react-is@18.2.0:
+    resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
+
+  react@18.3.1:
+    resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
+    engines: {node: '>=0.10.0'}
+
+  read-pkg-up@7.0.1:
+    resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==}
+    engines: {node: '>=8'}
+
+  read-pkg@5.2.0:
+    resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==}
+    engines: {node: '>=8'}
+
+  readable-stream@1.1.14:
+    resolution: {integrity: sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==}
+
+  readable-stream@2.3.7:
+    resolution: {integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==}
+
+  readable-stream@3.6.0:
+    resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==}
+    engines: {node: '>= 6'}
+
+  readable-stream@4.3.0:
+    resolution: {integrity: sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  readable-web-to-node-stream@3.0.2:
+    resolution: {integrity: sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==}
+    engines: {node: '>=8'}
+
+  readdir-glob@1.1.2:
+    resolution: {integrity: sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA==}
+
+  readdirp@3.6.0:
+    resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+    engines: {node: '>=8.10.0'}
+
+  real-require@0.2.0:
+    resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
+    engines: {node: '>= 12.13.0'}
+
+  recast@0.23.4:
+    resolution: {integrity: sha512-qtEDqIZGVcSZCHniWwZWbRy79Dc6Wp3kT/UmDA2RJKBPg7+7k51aQBZirHmUGn5uvHf2rg8DkjizrN26k61ATw==}
+    engines: {node: '>= 4'}
+
+  recast@0.23.6:
+    resolution: {integrity: sha512-9FHoNjX1yjuesMwuthAmPKabxYQdOgihFYmT5ebXfYGBcnqXZf3WOVz+5foEZ8Y83P4ZY6yQD5GMmtV+pgCCAQ==}
+    engines: {node: '>= 4'}
+
+  reconnecting-websocket@4.4.0:
+    resolution: {integrity: sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==}
+
+  redent@3.0.0:
+    resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
+    engines: {node: '>=8'}
+
+  redis-errors@1.2.0:
+    resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==}
+    engines: {node: '>=4'}
+
+  redis-info@3.1.0:
+    resolution: {integrity: sha512-ER4L9Sh/vm63DkIE0bkSjxluQlioBiBgf5w1UuldaW/3vPcecdljVDisZhmnCMvsxHNiARTTDDHGg9cGwTfrKg==}
+
+  redis-lock@0.1.4:
+    resolution: {integrity: sha512-7/+zu86XVQfJVx1nHTzux5reglDiyUCDwmW7TSlvVezfhH2YLc/Rc8NE0ejQG+8/0lwKzm29/u/4+ogKeLosiA==}
+    engines: {node: '>=0.6'}
+
+  redis-parser@3.0.0:
+    resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==}
+    engines: {node: '>=4'}
+
+  reflect-metadata@0.2.2:
+    resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==}
+
+  regenerate-unicode-properties@10.1.0:
+    resolution: {integrity: sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==}
+    engines: {node: '>=4'}
+
+  regenerate@1.4.2:
+    resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==}
+
+  regenerator-runtime@0.13.11:
+    resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
+
+  regenerator-runtime@0.14.0:
+    resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==}
+
+  regenerator-transform@0.15.2:
+    resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==}
+
+  regexp.prototype.flags@1.5.0:
+    resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==}
+    engines: {node: '>= 0.4'}
+
+  regexpu-core@5.3.2:
+    resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==}
+    engines: {node: '>=4'}
+
+  regjsparser@0.9.1:
+    resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==}
+    hasBin: true
+
+  rehype-external-links@3.0.0:
+    resolution: {integrity: sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==}
+
+  rehype-slug@6.0.0:
+    resolution: {integrity: sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==}
+
+  remark-gfm@4.0.0:
+    resolution: {integrity: sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==}
+
+  remark-parse@11.0.0:
+    resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==}
+
+  remark-stringify@11.0.0:
+    resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==}
+
+  rename@1.0.4:
+    resolution: {integrity: sha512-YMM6Fn3lrFOCjhORKjj+z/yizj8WSzv3F3YUlpJA20fteWCb0HbJU19nvuRBPUM5dWgxJcHP+kix3M+5NowJyA==}
+
+  request-progress@3.0.0:
+    resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==}
+
+  request@2.88.2:
+    resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==}
+    engines: {node: '>= 6'}
+    deprecated: request has been deprecated, see https://github.com/request/request/issues/3142
+
+  require-directory@2.1.1:
+    resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
+    engines: {node: '>=0.10.0'}
+
+  require-from-string@2.0.2:
+    resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
+    engines: {node: '>=0.10.0'}
+
+  require-main-filename@2.0.0:
+    resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
+
+  requires-port@1.0.0:
+    resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
+
+  resolve-alpn@1.2.1:
+    resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
+
+  resolve-cwd@3.0.0:
+    resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
+    engines: {node: '>=8'}
+
+  resolve-from@4.0.0:
+    resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+    engines: {node: '>=4'}
+
+  resolve-from@5.0.0:
+    resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
+    engines: {node: '>=8'}
+
+  resolve-pkg-maps@1.0.0:
+    resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+
+  resolve.exports@2.0.0:
+    resolution: {integrity: sha512-6K/gDlqgQscOlg9fSRpWstA8sYe8rbELsSTNpx+3kTrsVCzvSl0zIvRErM7fdl9ERWDsKnrLnwB+Ne89918XOg==}
+    engines: {node: '>=10'}
+
+  resolve@1.19.0:
+    resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==}
+
+  resolve@1.22.8:
+    resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
+    hasBin: true
+
+  responselike@2.0.1:
+    resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==}
+
+  responselike@3.0.0:
+    resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==}
+    engines: {node: '>=14.16'}
+
+  restore-cursor@3.1.0:
+    resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
+    engines: {node: '>=8'}
+
+  ret@0.4.3:
+    resolution: {integrity: sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==}
+    engines: {node: '>=10'}
+
+  retry@0.12.0:
+    resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==}
+    engines: {node: '>= 4'}
+
+  reusify@1.0.4:
+    resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+    engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+
+  rfdc@1.3.0:
+    resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==}
+
+  rimraf@2.6.3:
+    resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==}
+    hasBin: true
+
+  rimraf@2.7.1:
+    resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
+    hasBin: true
+
+  rimraf@3.0.2:
+    resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
+    hasBin: true
+
+  rollup@4.17.2:
+    resolution: {integrity: sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==}
+    engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+    hasBin: true
+
+  rrweb-cssom@0.6.0:
+    resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
+
+  rss-parser@3.13.0:
+    resolution: {integrity: sha512-7jWUBV5yGN3rqMMj7CZufl/291QAhvrrGpDNE4k/02ZchL0npisiYYqULF71jCEKoIiHvK/Q2e6IkDwPziT7+w==}
+
+  run-parallel@1.2.0:
+    resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+
+  rxjs@7.8.1:
+    resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
+
+  safe-array-concat@1.0.0:
+    resolution: {integrity: sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==}
+    engines: {node: '>=0.4'}
+
+  safe-buffer@5.1.2:
+    resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
+
+  safe-buffer@5.2.1:
+    resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+
+  safe-regex-test@1.0.0:
+    resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
+
+  safe-regex2@3.1.0:
+    resolution: {integrity: sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug==}
+
+  safe-stable-stringify@2.4.2:
+    resolution: {integrity: sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==}
+    engines: {node: '>=10'}
+
+  safer-buffer@2.1.2:
+    resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
+  sanitize-html@2.13.0:
+    resolution: {integrity: sha512-Xff91Z+4Mz5QiNSLdLWwjgBDm5b1RU6xBT0+12rapjiaR7SwfRdjw8f+6Rir2MXKLrDicRFHdb51hGOAxmsUIA==}
+
+  sass@1.76.0:
+    resolution: {integrity: sha512-nc3LeqvF2FNW5xGF1zxZifdW3ffIz5aBb7I7tSvOoNu7z1RQ6pFt9MBuiPtjgaI62YWrM/txjWlOCFiGtf2xpw==}
+    engines: {node: '>=14.0.0'}
+    hasBin: true
+
+  sax@1.2.4:
+    resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==}
+
+  saxes@6.0.0:
+    resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
+    engines: {node: '>=v12.22.7'}
+
+  scheduler@0.23.2:
+    resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
+
+  secure-json-parse@2.7.0:
+    resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==}
+
+  seedrandom@3.0.5:
+    resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==}
+
+  semver-regex@4.0.5:
+    resolution: {integrity: sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==}
+    engines: {node: '>=12'}
+
+  semver-truncate@2.0.0:
+    resolution: {integrity: sha512-Rh266MLDYNeML5h90ttdMwfXe1+Nc4LAWd9X1KdJe8pPHP4kFmvLZALtsMNHNdvTyQygbEC0D59sIz47DIaq8w==}
+    engines: {node: '>=8'}
+
+  semver@5.7.1:
+    resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
+    hasBin: true
+
+  semver@6.3.1:
+    resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+    hasBin: true
+
+  semver@7.5.4:
+    resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
+    engines: {node: '>=10'}
+    hasBin: true
+
+  semver@7.6.0:
+    resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==}
+    engines: {node: '>=10'}
+    hasBin: true
+
+  send@0.18.0:
+    resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
+    engines: {node: '>= 0.8.0'}
+
+  serve-static@1.15.0:
+    resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==}
+    engines: {node: '>= 0.8.0'}
+
+  set-blocking@2.0.0:
+    resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
+
+  set-cookie-parser@2.6.0:
+    resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==}
+
+  setimmediate@1.0.5:
+    resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
+
+  setprototypeof@1.2.0:
+    resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+
+  sha.js@2.4.11:
+    resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==}
+    hasBin: true
+
+  shallow-clone@3.0.1:
+    resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==}
+    engines: {node: '>=8'}
+
+  sharp@0.33.3:
+    resolution: {integrity: sha512-vHUeXJU1UvlO/BNwTpT0x/r53WkLUVxrmb5JTgW92fdFCFk0ispLMAeu/jPO2vjkXM1fYUi3K7/qcLF47pwM1A==}
+    engines: {libvips: '>=8.15.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+
+  shebang-command@1.2.0:
+    resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
+    engines: {node: '>=0.10.0'}
+
+  shebang-command@2.0.0:
+    resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+    engines: {node: '>=8'}
+
+  shebang-regex@1.0.0:
+    resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==}
+    engines: {node: '>=0.10.0'}
+
+  shebang-regex@3.0.0:
+    resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+    engines: {node: '>=8'}
+
+  shiki@1.4.0:
+    resolution: {integrity: sha512-5WIn0OL8PWm7JhnTwRWXniy6eEDY234mRrERVlFa646V2ErQqwIFd2UML7e0Pq9eqSKLoMa3Ke+xbsF+DAuy+Q==}
+
+  side-channel@1.0.4:
+    resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
+
+  siginfo@2.0.0:
+    resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
+
+  signal-exit@3.0.7:
+    resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+
+  signal-exit@4.1.0:
+    resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
+    engines: {node: '>=14'}
+
+  simple-oauth2@5.0.0:
+    resolution: {integrity: sha512-8291lo/z5ZdpmiOFzOs1kF3cxn22bMj5FFH+DNUppLJrpoIlM1QnFiE7KpshHu3J3i21TVcx4yW+gXYjdCKDLQ==}
+
+  simple-swizzle@0.2.2:
+    resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
+
+  simple-update-notifier@2.0.0:
+    resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
+    engines: {node: '>=10'}
+
+  sinon@16.1.3:
+    resolution: {integrity: sha512-mjnWWeyxcAf9nC0bXcPmiDut+oE8HYridTNzBbF98AYVLmWwGRp2ISEpyhYflG1ifILT+eNn3BmKUJPxjXUPlA==}
+
+  sisteransi@1.0.5:
+    resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
+
+  slacc-android-arm-eabi@0.0.10:
+    resolution: {integrity: sha512-U3dVBuM1m8rT1D/w6S4knJ/uscNwsCR+MKxSQFbgDJEh8Atv+ovuC+FMGuaBT4iOQjpMj5dWSsN3ZPjVeo3hgA==}
+    engines: {node: '>= 10'}
+    cpu: [arm]
+    os: [android]
+
+  slacc-android-arm64@0.0.10:
+    resolution: {integrity: sha512-guVp88sW+4j1clTSXMzyDJHG8ondVnd8/FMKXIOfzKCEwSwX3uBxsuyHqtGvXkEwyZAGsBUy13Ei/PZAwElwYA==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [android]
+
+  slacc-darwin-arm64@0.0.10:
+    resolution: {integrity: sha512-633qnOMTP7egvd5IeljAOku0tnxlBXSoCRu7HiT0yeXxN9y5Tbg2X2/FaRzstI36lClfIJ0Lavne4mOw/90z9A==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [darwin]
+
+  slacc-darwin-universal@0.0.10:
+    resolution: {integrity: sha512-x5kEqRMTEQTi3NCufPEukWvaWqcOL+7EkP18ZCCiajcWH83jWnT8DOSGOmmLYdrXd0B7ZZcbd8GyLp3i5zu8PA==}
+    engines: {node: '>= 10'}
+    os: [darwin]
+
+  slacc-darwin-x64@0.0.10:
+    resolution: {integrity: sha512-5gQYboy/4T6Bj3sVXiCpM3EvF1sK/Zx1Nq5YBMUuYb2GzrIwywghHbCD6bK4JYGvNsLN7r4PC45ZUB4gVkU8yA==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [darwin]
+
+  slacc-freebsd-x64@0.0.10:
+    resolution: {integrity: sha512-Jmi5YszELef/aCzYto+LwiNGhCk5mrlJfTJU/pOI91HBbrZlV+aRyIsPCcxAMg5yPsPQuyRljrDouVYrPzNmjw==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [freebsd]
+
+  slacc-linux-arm-gnueabihf@0.0.10:
+    resolution: {integrity: sha512-9lTM3DGtISQlZYSKrMuQyKCiUnHYRcy04mY6HF1ywYcQ2sqfv3bKEnrypVewepIFUtytlIGzkgpiUAk/ghYGoA==}
+    engines: {node: '>= 10'}
+    cpu: [arm]
+    os: [linux]
+
+  slacc-linux-arm64-gnu@0.0.10:
+    resolution: {integrity: sha512-qXrNWSINXOjHRO3c9idGm8DeOAjAjG1xHY8WiplCoHWgsZf3E7V+sPhWqRUaGQEvftsJg40+cFYREBaLQhpAVQ==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [linux]
+
+  slacc-linux-arm64-musl@0.0.10:
+    resolution: {integrity: sha512-3lUX7752f6Okn54aONioaA+9M5TvifqXBAart+u2lNXEdWmmh003cVSU2Vcwg7nJ9lLHtju2DkDmKKfJjFuShA==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [linux]
+
+  slacc-linux-x64-gnu@0.0.10:
+    resolution: {integrity: sha512-BxxvylF9zlOLRLCpiyMvKTIUpdLlpetNBJ+DSMDh5+Ggq+AmQz2NUGawmcBJw58F8nMCj9TpWLlGNWc2AuY+JQ==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [linux]
+
+  slacc-linux-x64-musl@0.0.10:
+    resolution: {integrity: sha512-TYJi8LOtJiTFcZvka4du7bMjF9Bz1RHRwyLnScr5E5yjjgoLRrsvgSu7bxp87xH+rgJ3CdEwE3w3Ux8EiewHpA==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [linux]
+
+  slacc-win32-arm64-msvc@0.0.10:
+    resolution: {integrity: sha512-1CHPLiDB4exzFyT5ndtJDsRRhBxNg8mGz6I6eJEMjelGkJR2KZPT9LZuby/1bS/bcVOr7zuJvGNfbEGBeHRwPQ==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [win32]
+
+  slacc-win32-x64-msvc@0.0.10:
+    resolution: {integrity: sha512-wAXBy5yKCAzfYWjVlyPpu6PscD+j4QhCQEy0wZaVuzNyx60HpXWcTZxxVnMR730Y7tfc7cBxSI8NtRb8RguSgg==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [win32]
+
+  slacc@0.0.10:
+    resolution: {integrity: sha512-2jgms2/4mLr1AMq4oloAwPdKQK9RQvgmoEpMIxvC+HeHMwCR0XxB7gr/rKo4iLOKJ6gx02mnBU0JHWcTIonpmA==}
+    engines: {node: '>= 10'}
+
+  slash@3.0.0:
+    resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+    engines: {node: '>=8'}
+
+  slice-ansi@3.0.0:
+    resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==}
+    engines: {node: '>=8'}
+
+  slice-ansi@4.0.0:
+    resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
+    engines: {node: '>=10'}
+
+  smart-buffer@4.2.0:
+    resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
+    engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
+
+  socks-proxy-agent@8.0.2:
+    resolution: {integrity: sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==}
+    engines: {node: '>= 14'}
+
+  socks@2.7.1:
+    resolution: {integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==}
+    engines: {node: '>= 10.13.0', npm: '>= 3.0.0'}
+
+  sonic-boom@3.7.0:
+    resolution: {integrity: sha512-IudtNvSqA/ObjN97tfgNmOKyDOs4dNcg4cUUsHDebqsgb8wGBBwb31LIgShNO8fye0dFI52X1+tFoKKI6Rq1Gg==}
+
+  sort-keys-length@1.0.1:
+    resolution: {integrity: sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==}
+    engines: {node: '>=0.10.0'}
+
+  sort-keys@1.1.2:
+    resolution: {integrity: sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==}
+    engines: {node: '>=0.10.0'}
+
+  sortablejs@1.14.0:
+    resolution: {integrity: sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==}
+
+  source-map-js@1.0.2:
+    resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
+    engines: {node: '>=0.10.0'}
+
+  source-map-js@1.2.0:
+    resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
+    engines: {node: '>=0.10.0'}
+
+  source-map-support@0.5.13:
+    resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==}
+
+  source-map-support@0.5.21:
+    resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
+
+  source-map@0.6.1:
+    resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+    engines: {node: '>=0.10.0'}
+
+  source-map@0.7.4:
+    resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
+    engines: {node: '>= 8'}
+
+  space-separated-tokens@2.0.2:
+    resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
+
+  spdx-correct@3.1.1:
+    resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==}
+
+  spdx-exceptions@2.3.0:
+    resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==}
+
+  spdx-expression-parse@3.0.1:
+    resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==}
+
+  spdx-license-ids@3.0.12:
+    resolution: {integrity: sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==}
+
+  split2@4.1.0:
+    resolution: {integrity: sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==}
+    engines: {node: '>= 10.x'}
+
+  split@0.3.3:
+    resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==}
+
+  sprintf-js@1.0.3:
+    resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
+
+  sprintf-js@1.1.2:
+    resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==}
+
+  sshpk@1.17.0:
+    resolution: {integrity: sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==}
+    engines: {node: '>=0.10.0'}
+    hasBin: true
+
+  ssri@10.0.4:
+    resolution: {integrity: sha512-12+IR2CB2C28MMAw0Ncqwj5QbTcs0nGIhgJzYWzDkb21vWmfNI83KS4f3Ci6GI98WreIfG7o9UXp3C0qbpA8nQ==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
+  stack-utils@2.0.6:
+    resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
+    engines: {node: '>=10'}
+
+  stackback@0.0.2:
+    resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+
+  standard-as-callback@2.1.0:
+    resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==}
+
+  start-server-and-test@2.0.3:
+    resolution: {integrity: sha512-QsVObjfjFZKJE6CS6bSKNwWZCKBG6975/jKRPPGFfFh+yOQglSeGXiNWjzgQNXdphcBI9nXbyso9tPfX4YAUhg==}
+    engines: {node: '>=16'}
+    hasBin: true
+
+  statuses@2.0.1:
+    resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
+    engines: {node: '>= 0.8'}
+
+  std-env@3.7.0:
+    resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==}
+
+  stop-iteration-iterator@1.0.0:
+    resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==}
+    engines: {node: '>= 0.4'}
+
+  store2@2.14.2:
+    resolution: {integrity: sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==}
+
+  storybook-addon-misskey-theme@https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640:
+    resolution: {tarball: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640}
+    version: 0.0.0
+    peerDependencies:
+      '@storybook/blocks': ^7.0.0-rc.4
+      '@storybook/components': ^7.0.0-rc.4
+      '@storybook/core-events': ^7.0.0-rc.4
+      '@storybook/manager-api': ^7.0.0-rc.4
+      '@storybook/preview-api': ^7.0.0-rc.4
+      '@storybook/theming': ^7.0.0-rc.4
+      '@storybook/types': ^7.0.0-rc.4
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+    peerDependenciesMeta:
+      react:
+        optional: true
+      react-dom:
+        optional: true
+
+  storybook@8.0.9:
+    resolution: {integrity: sha512-/Mvij0Br5bUwJpCvqAUZMEDIWmdRxEyllvVj8Ukw5lIWJePxfpSsz4px5jg9+R6B9tO8sQSqjg4HJvQ/pZk8Tg==}
+    hasBin: true
+
+  stream-browserify@3.0.0:
+    resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==}
+
+  stream-combiner@0.0.4:
+    resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==}
+
+  stream-parser@0.3.1:
+    resolution: {integrity: sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==}
+
+  stream-shift@1.0.1:
+    resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==}
+
+  stream-wormhole@1.1.0:
+    resolution: {integrity: sha512-gHFfL3px0Kctd6Po0M8TzEvt3De/xu6cnRrjlfYNhwbhLPLwigI2t1nc6jrzNuaYg5C4YF78PPFuQPzRiqn9ew==}
+    engines: {node: '>=4.0.0'}
+
+  streamsearch@1.1.0:
+    resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
+    engines: {node: '>=10.0.0'}
+
+  streamx@2.15.0:
+    resolution: {integrity: sha512-HcxY6ncGjjklGs1xsP1aR71INYcsXFJet5CU1CHqihQ2J5nOsbd4OjgjHO42w/4QNv9gZb3BueV+Vxok5pLEXg==}
+
+  strict-event-emitter-types@2.0.0:
+    resolution: {integrity: sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA==}
+
+  strict-event-emitter@0.5.1:
+    resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==}
+
+  string-argv@0.3.1:
+    resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==}
+    engines: {node: '>=0.6.19'}
+
+  string-length@4.0.2:
+    resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
+    engines: {node: '>=10'}
+
+  string-width@4.2.3:
+    resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+    engines: {node: '>=8'}
+
+  string-width@5.1.2:
+    resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+    engines: {node: '>=12'}
+
+  string.prototype.trim@1.2.7:
+    resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==}
+    engines: {node: '>= 0.4'}
+
+  string.prototype.trimend@1.0.6:
+    resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==}
+
+  string.prototype.trimstart@1.0.6:
+    resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==}
+
+  string_decoder@0.10.31:
+    resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==}
+
+  string_decoder@1.1.1:
+    resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
+
+  string_decoder@1.3.0:
+    resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+
+  stringz@2.1.0:
+    resolution: {integrity: sha512-KlywLT+MZ+v0IRepfMxRtnSvDCMc3nR1qqCs3m/qIbSOWkNZYT8XHQA31rS3TnKp0c5xjZu3M4GY/2aRKSi/6A==}
+
+  strip-ansi@6.0.1:
+    resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+    engines: {node: '>=8'}
+
+  strip-ansi@7.1.0:
+    resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
+    engines: {node: '>=12'}
+
+  strip-bom@3.0.0:
+    resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
+    engines: {node: '>=4'}
+
+  strip-bom@4.0.0:
+    resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==}
+    engines: {node: '>=8'}
+
+  strip-eof@1.0.0:
+    resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==}
+    engines: {node: '>=0.10.0'}
+
+  strip-final-newline@2.0.0:
+    resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
+    engines: {node: '>=6'}
+
+  strip-final-newline@3.0.0:
+    resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
+    engines: {node: '>=12'}
+
+  strip-indent@3.0.0:
+    resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
+    engines: {node: '>=8'}
+
+  strip-indent@4.0.0:
+    resolution: {integrity: sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==}
+    engines: {node: '>=12'}
+
+  strip-json-comments@3.1.1:
+    resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+    engines: {node: '>=8'}
+
+  strip-literal@1.3.0:
+    resolution: {integrity: sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==}
+
+  strip-outer@2.0.0:
+    resolution: {integrity: sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+  strnum@1.0.5:
+    resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==}
+
+  strtok3@7.0.0:
+    resolution: {integrity: sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==}
+    engines: {node: '>=14.16'}
+
+  stylehacks@6.1.1:
+    resolution: {integrity: sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==}
+    engines: {node: ^14 || ^16 || >=18.0}
+    peerDependencies:
+      postcss: ^8.4.31
+
+  supports-color@5.5.0:
+    resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
+    engines: {node: '>=4'}
+
+  supports-color@7.2.0:
+    resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+    engines: {node: '>=8'}
+
+  supports-color@8.1.1:
+    resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
+    engines: {node: '>=10'}
+
+  supports-color@9.4.0:
+    resolution: {integrity: sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==}
+    engines: {node: '>=12'}
+
+  supports-hyperlinks@2.3.0:
+    resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==}
+    engines: {node: '>=8'}
+
+  supports-preserve-symlinks-flag@1.0.0:
+    resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+    engines: {node: '>= 0.4'}
+
+  svgo@3.2.0:
+    resolution: {integrity: sha512-4PP6CMW/V7l/GmKRKzsLR8xxjdHTV4IMvhTnpuHwwBazSIlw5W/5SmPjN8Dwyt7lKbSJrRDgp4t9ph0HgChFBQ==}
+    engines: {node: '>=14.0.0'}
+    hasBin: true
+
+  symbol-tree@3.2.4:
+    resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
+
+  systeminformation@5.22.7:
+    resolution: {integrity: sha512-AWxlP05KeHbpGdgvZkcudJpsmChc2Y5Eo/GvxG/iUA/Aws5LZKHAMSeAo+V+nD+nxWZaxrwpWcnx4SH3oxNL3A==}
+    engines: {node: '>=8.0.0'}
+    os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android]
+    hasBin: true
+
+  tar-fs@2.1.1:
+    resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
+
+  tar-stream@2.2.0:
+    resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
+    engines: {node: '>=6'}
+
+  tar-stream@3.1.6:
+    resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==}
+
+  tar@4.4.19:
+    resolution: {integrity: sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==}
+    engines: {node: '>=4.5'}
+
+  tar@6.2.1:
+    resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==}
+    engines: {node: '>=10'}
+
+  taskkill@5.0.0:
+    resolution: {integrity: sha512-+HRtZ40Vc+6YfCDWCeAsixwxJgMbPY4HHuTgzPYH3JXvqHWUlsCfy+ylXlAKhFNcuLp4xVeWeFBUhDk+7KYUvQ==}
+    engines: {node: '>=14.16'}
+
+  telejson@7.2.0:
+    resolution: {integrity: sha512-1QTEcJkJEhc8OnStBx/ILRu5J2p0GjvWsBx56bmZRqnrkdBMUe+nX92jxV+p3dB4CP6PZCdJMQJwCggkNBMzkQ==}
+
+  temp-dir@2.0.0:
+    resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==}
+    engines: {node: '>=8'}
+
+  temp@0.8.4:
+    resolution: {integrity: sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==}
+    engines: {node: '>=6.0.0'}
+
+  tempy@1.0.1:
+    resolution: {integrity: sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==}
+    engines: {node: '>=10'}
+
+  terser@5.30.3:
+    resolution: {integrity: sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==}
+    engines: {node: '>=10'}
+    hasBin: true
+
+  test-exclude@6.0.0:
+    resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
+    engines: {node: '>=8'}
+
+  text-table@0.2.0:
+    resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+
+  textarea-caret@3.1.0:
+    resolution: {integrity: sha512-cXAvzO9pP5CGa6NKx0WYHl+8CHKZs8byMkt3PCJBCmq2a34YA9pO1NrQET5pzeqnBjBdToF5No4rrmkDUgQC2Q==}
+
+  thenify-all@1.6.0:
+    resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
+    engines: {node: '>=0.8'}
+
+  thenify@3.3.1:
+    resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
+
+  thread-stream@2.3.0:
+    resolution: {integrity: sha512-kaDqm1DET9pp3NXwR8382WHbnpXnRkN9xGN9dQt3B2+dmXiW8X1SOwmFOxAErEQ47ObhZ96J6yhZNXuyCOL7KA==}
+
+  three@0.164.1:
+    resolution: {integrity: sha512-iC/hUBbl1vzFny7f5GtqzVXYjMJKaTPxiCxXfrvVdBi1Sf+jhd1CAkitiFwC7mIBFCo3MrDLJG97yisoaWig0w==}
+
+  throttle-debounce@5.0.0:
+    resolution: {integrity: sha512-2iQTSgkkc1Zyk0MeVrt/3BvuOXYPl/R8Z0U2xxo9rjwNciaHDG3R+Lm6dh4EeUci49DanvBnuqI6jshoQQRGEg==}
+    engines: {node: '>=12.22'}
+
+  throttleit@1.0.0:
+    resolution: {integrity: sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==}
+
+  through2@2.0.5:
+    resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==}
+
+  through@2.3.4:
+    resolution: {integrity: sha512-DwbmSAcABsMazNkLOJJSLRC3gfh4cPxUxJCn9npmvbcI6undhgoJ2ShvEOgZrW8BH62Gyr9jKboGbfFcmY5VsQ==}
+
+  through@2.3.8:
+    resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
+
+  tiny-invariant@1.3.1:
+    resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==}
+
+  tiny-invariant@1.3.3:
+    resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
+
+  tiny-lru@10.0.1:
+    resolution: {integrity: sha512-Vst+6kEsWvb17Zpz14sRJV/f8bUWKhqm6Dc+v08iShmIJ/WxqWytHzCTd6m88pS33rE2zpX34TRmOpAJPloNCA==}
+    engines: {node: '>=6'}
+
+  tinybench@2.6.0:
+    resolution: {integrity: sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==}
+
+  tinycolor2@1.6.0:
+    resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
+
+  tinypool@0.7.0:
+    resolution: {integrity: sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==}
+    engines: {node: '>=14.0.0'}
+
+  tinyspy@2.2.0:
+    resolution: {integrity: sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==}
+    engines: {node: '>=14.0.0'}
+
+  tmp@0.2.3:
+    resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==}
+    engines: {node: '>=14.14'}
+
+  tmpl@1.0.5:
+    resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
+
+  to-data-view@1.1.0:
+    resolution: {integrity: sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ==}
+
+  to-fast-properties@2.0.0:
+    resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
+    engines: {node: '>=4'}
+
+  to-regex-range@5.0.1:
+    resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+    engines: {node: '>=8.0'}
+
+  toad-cache@3.3.0:
+    resolution: {integrity: sha512-3oDzcogWGHZdkwrHyvJVpPjA7oNzY6ENOV3PsWJY9XYPZ6INo94Yd47s5may1U+nleBPwDhrRiTPMIvKaa3MQg==}
+    engines: {node: '>=12'}
+
+  toad-cache@3.7.0:
+    resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==}
+    engines: {node: '>=12'}
+
+  tocbot@4.21.1:
+    resolution: {integrity: sha512-IfajhBTeg0HlMXu1f+VMbPef05QpDTsZ9X2Yn1+8npdaXsXg/+wrm9Ze1WG5OS1UDC3qJ5EQN/XOZ3gfXjPFCw==}
+
+  toidentifier@1.0.1:
+    resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
+    engines: {node: '>=0.6'}
+
+  token-stream@1.0.0:
+    resolution: {integrity: sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==}
+
+  token-types@5.0.1:
+    resolution: {integrity: sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==}
+    engines: {node: '>=14.16'}
+
+  touch@3.1.0:
+    resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==}
+    hasBin: true
+
+  tough-cookie@2.5.0:
+    resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==}
+    engines: {node: '>=0.8'}
+
+  tough-cookie@4.1.3:
+    resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==}
+    engines: {node: '>=6'}
+
+  tr46@0.0.3:
+    resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
+
+  tr46@5.0.0:
+    resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==}
+    engines: {node: '>=18'}
+
+  trace-redirect@1.0.6:
+    resolution: {integrity: sha512-UUfa1DjjU5flcjMdaFIiIEGDTyu2y/IiMjOX4uGXa7meKBS4vD4f2Uy/tken9Qkd4Jsm4sRsfZcIIPqrRVF3Mg==}
+
+  trim-newlines@3.0.1:
+    resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==}
+    engines: {node: '>=8'}
+
+  trim-repeated@2.0.0:
+    resolution: {integrity: sha512-QUHBFTJGdOwmp0tbOG505xAgOp/YliZP/6UgafFXYZ26WT1bvQmSMJUvkeVSASuJJHbqsFbynTvkd5W8RBTipg==}
+    engines: {node: '>=12'}
+
+  trough@2.2.0:
+    resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==}
+
+  ts-api-utils@1.0.1:
+    resolution: {integrity: sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==}
+    engines: {node: '>=16.13.0'}
+    peerDependencies:
+      typescript: '>=4.2.0'
+
+  ts-api-utils@1.3.0:
+    resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==}
+    engines: {node: '>=16'}
+    peerDependencies:
+      typescript: '>=4.2.0'
+
+  ts-case-convert@2.0.2:
+    resolution: {integrity: sha512-vdKfx1VAdpvEBOBv5OpVu5ZFqRg9HdTI4sYt6qqMeICBeNyXvitrarCnFWNDAki51IKwCyx+ZssY46Q9jH5otA==}
+    bundledDependencies: []
+
+  ts-dedent@2.2.0:
+    resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==}
+    engines: {node: '>=6.10'}
+
+  ts-map@1.0.3:
+    resolution: {integrity: sha512-vDWbsl26LIcPGmDpoVzjEP6+hvHZkBkLW7JpvwbCv/5IYPJlsbzCVXY3wsCeAxAUeTclNOUZxnLdGh3VBD/J6w==}
+
+  tsc-alias@1.8.8:
+    resolution: {integrity: sha512-OYUOd2wl0H858NvABWr/BoSKNERw3N9GTi3rHPK8Iv4O1UyUXIrTTOAZNHsjlVpXFOhpJBVARI1s+rzwLivN3Q==}
+    hasBin: true
+
+  tsconfig-paths@3.15.0:
+    resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
+
+  tsconfig-paths@4.2.0:
+    resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==}
+    engines: {node: '>=6'}
+
+  tsd@0.30.7:
+    resolution: {integrity: sha512-oTiJ28D6B/KXoU3ww/Eji+xqHJojiuPVMwA12g4KYX1O72N93Nb6P3P3h2OAhhf92Xl8NIhb/xFmBZd5zw/xUw==}
+    engines: {node: '>=14.16'}
+    hasBin: true
+
+  tslib@1.14.1:
+    resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
+
+  tslib@2.6.2:
+    resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
+
+  tsx@4.4.0:
+    resolution: {integrity: sha512-4fwcEjRUxW20ciSaMB8zkpGwCPxuRGnadDuj/pBk5S9uT29zvWz15PK36GrKJo45mSJomDxVejZ73c6lr3811Q==}
+    engines: {node: '>=18.0.0'}
+    hasBin: true
+
+  tunnel-agent@0.6.0:
+    resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
+
+  tweetnacl@0.14.5:
+    resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==}
+
+  type-check@0.4.0:
+    resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+    engines: {node: '>= 0.8.0'}
+
+  type-detect@4.0.8:
+    resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
+    engines: {node: '>=4'}
+
+  type-fest@0.16.0:
+    resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==}
+    engines: {node: '>=10'}
+
+  type-fest@0.18.1:
+    resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==}
+    engines: {node: '>=10'}
+
+  type-fest@0.20.2:
+    resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
+    engines: {node: '>=10'}
+
+  type-fest@0.21.3:
+    resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
+    engines: {node: '>=10'}
+
+  type-fest@0.6.0:
+    resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==}
+    engines: {node: '>=8'}
+
+  type-fest@0.8.1:
+    resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==}
+    engines: {node: '>=8'}
+
+  type-fest@2.19.0:
+    resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
+    engines: {node: '>=12.20'}
+
+  type-fest@4.9.0:
+    resolution: {integrity: sha512-KS/6lh/ynPGiHD/LnAobrEFq3Ad4pBzOlJ1wAnJx9N4EYoqFhMfLIBjUT2UEx4wg5ZE+cC1ob6DCSpppVo+rtg==}
+    engines: {node: '>=16'}
+
+  type-is@1.6.18:
+    resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
+    engines: {node: '>= 0.6'}
+
+  typed-array-buffer@1.0.0:
+    resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==}
+    engines: {node: '>= 0.4'}
+
+  typed-array-byte-length@1.0.0:
+    resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==}
+    engines: {node: '>= 0.4'}
+
+  typed-array-byte-offset@1.0.0:
+    resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==}
+    engines: {node: '>= 0.4'}
+
+  typed-array-length@1.0.4:
+    resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==}
+
+  typedarray@0.0.6:
+    resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
+
+  typeorm@0.3.20:
+    resolution: {integrity: sha512-sJ0T08dV5eoZroaq9uPKBoNcGslHBR4E4y+EBHs//SiGbblGe7IeduP/IH4ddCcj0qp3PHwDwGnuvqEAnKlq/Q==}
+    engines: {node: '>=16.13.0'}
+    hasBin: true
+    peerDependencies:
+      '@google-cloud/spanner': ^5.18.0
+      '@sap/hana-client': ^2.12.25
+      better-sqlite3: ^7.1.2 || ^8.0.0 || ^9.0.0
+      hdb-pool: ^0.1.6
+      ioredis: ^5.0.4
+      mongodb: ^5.8.0
+      mssql: ^9.1.1 || ^10.0.1
+      mysql2: ^2.2.5 || ^3.0.1
+      oracledb: ^6.3.0
+      pg: ^8.5.1
+      pg-native: ^3.0.0
+      pg-query-stream: ^4.0.0
+      redis: ^3.1.1 || ^4.0.0
+      sql.js: ^1.4.0
+      sqlite3: ^5.0.3
+      ts-node: ^10.7.0
+      typeorm-aurora-data-api-driver: ^2.0.0
+    peerDependenciesMeta:
+      '@google-cloud/spanner':
+        optional: true
+      '@sap/hana-client':
+        optional: true
+      better-sqlite3:
+        optional: true
+      hdb-pool:
+        optional: true
+      ioredis:
+        optional: true
+      mongodb:
+        optional: true
+      mssql:
+        optional: true
+      mysql2:
+        optional: true
+      oracledb:
+        optional: true
+      pg:
+        optional: true
+      pg-native:
+        optional: true
+      pg-query-stream:
+        optional: true
+      redis:
+        optional: true
+      sql.js:
+        optional: true
+      sqlite3:
+        optional: true
+      ts-node:
+        optional: true
+      typeorm-aurora-data-api-driver:
+        optional: true
+
+  typescript@5.3.3:
+    resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==}
+    engines: {node: '>=14.17'}
+    hasBin: true
+
+  typescript@5.4.2:
+    resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==}
+    engines: {node: '>=14.17'}
+    hasBin: true
+
+  typescript@5.4.5:
+    resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==}
+    engines: {node: '>=14.17'}
+    hasBin: true
+
+  ufo@1.3.2:
+    resolution: {integrity: sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==}
+
+  uglify-js@3.17.4:
+    resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==}
+    engines: {node: '>=0.8.0'}
+    hasBin: true
+
+  uid2@0.0.4:
+    resolution: {integrity: sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==}
+
+  uid@2.0.2:
+    resolution: {integrity: sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==}
+    engines: {node: '>=8'}
+
+  ulid@2.3.0:
+    resolution: {integrity: sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==}
+    hasBin: true
+
+  unbox-primitive@1.0.2:
+    resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
+
+  undefsafe@2.0.5:
+    resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==}
+
+  undici-types@5.26.5:
+    resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
+
+  undici@5.28.2:
+    resolution: {integrity: sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==}
+    engines: {node: '>=14.0'}
+
+  unicode-canonical-property-names-ecmascript@2.0.0:
+    resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==}
+    engines: {node: '>=4'}
+
+  unicode-match-property-ecmascript@2.0.0:
+    resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==}
+    engines: {node: '>=4'}
+
+  unicode-match-property-value-ecmascript@2.1.0:
+    resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==}
+    engines: {node: '>=4'}
+
+  unicode-property-aliases-ecmascript@2.1.0:
+    resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==}
+    engines: {node: '>=4'}
+
+  unified@11.0.4:
+    resolution: {integrity: sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==}
+
+  uniq@1.0.1:
+    resolution: {integrity: sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==}
+
+  unique-filename@3.0.0:
+    resolution: {integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
+  unique-slug@4.0.0:
+    resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
+  unique-string@2.0.0:
+    resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==}
+    engines: {node: '>=8'}
+
+  unist-util-is@6.0.0:
+    resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
+
+  unist-util-stringify-position@4.0.0:
+    resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
+
+  unist-util-visit-parents@6.0.1:
+    resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==}
+
+  unist-util-visit@5.0.0:
+    resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
+
+  universalify@0.1.2:
+    resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
+    engines: {node: '>= 4.0.0'}
+
+  universalify@0.2.0:
+    resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
+    engines: {node: '>= 4.0.0'}
+
+  universalify@2.0.0:
+    resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==}
+    engines: {node: '>= 10.0.0'}
+
+  unload@2.4.1:
+    resolution: {integrity: sha512-IViSAm8Z3sRBYA+9wc0fLQmU9Nrxb16rcDmIiR6Y9LJSZzI7QY5QsDhqPpKOjAn0O9/kfK1TfNEMMAGPTIraPw==}
+
+  unpipe@1.0.0:
+    resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
+    engines: {node: '>= 0.8'}
+
+  unplugin@1.4.0:
+    resolution: {integrity: sha512-5x4eIEL6WgbzqGtF9UV8VEC/ehKptPXDS6L2b0mv4FRMkJxRtjaJfOWDd6a8+kYbqsjklix7yWP0N3SUepjXcg==}
+
+  untildify@4.0.0:
+    resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==}
+    engines: {node: '>=8'}
+
+  update-browserslist-db@1.0.13:
+    resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
+    hasBin: true
+    peerDependencies:
+      browserslist: '>= 4.21.0'
+
+  uri-js@4.4.1:
+    resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+
+  url-parse@1.5.10:
+    resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
+
+  utf-8-validate@6.0.3:
+    resolution: {integrity: sha512-uIuGf9TWQ/y+0Lp+KGZCMuJWc3N9BHA+l/UmHd/oUHwJJDeysyTRxNQVkbzsIWfGFbRe3OcgML/i0mvVRPOyDA==}
+    engines: {node: '>=6.14.2'}
+
+  util-deprecate@1.0.2:
+    resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+
+  util@0.12.5:
+    resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==}
+
+  utils-merge@1.0.1:
+    resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
+    engines: {node: '>= 0.4.0'}
+
+  uuid@3.4.0:
+    resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==}
+    deprecated: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
+    hasBin: true
+
+  uuid@8.3.2:
+    resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
+    hasBin: true
+
+  uuid@9.0.1:
+    resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
+    hasBin: true
+
+  v-code-diff@1.11.0:
+    resolution: {integrity: sha512-lBlO+FXw3I3qFKbnlorXZ4sb5cFnrdxlc6lj3Y1CWrbn2LC7PoVbGlwH0W+nvAVX1rdJhhc15rKIQdHyMkXe/w==}
+    peerDependencies:
+      '@vue/composition-api': ^1.4.9
+      vue: ^2.6.0 || >=3.0.0
+    peerDependenciesMeta:
+      '@vue/composition-api':
+        optional: true
+
+  v8-to-istanbul@9.2.0:
+    resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==}
+    engines: {node: '>=10.12.0'}
+
+  validate-npm-package-license@3.0.4:
+    resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
+
+  validator@13.9.0:
+    resolution: {integrity: sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==}
+    engines: {node: '>= 0.10'}
+
+  vary@1.1.2:
+    resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
+    engines: {node: '>= 0.8'}
+
+  verror@1.10.0:
+    resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==}
+    engines: {'0': node >=0.6.0}
+
+  vfile-message@4.0.2:
+    resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==}
+
+  vfile@6.0.1:
+    resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==}
+
+  vite-node@0.34.6:
+    resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==}
+    engines: {node: '>=v14.18.0'}
+    hasBin: true
+
+  vite-plugin-turbosnap@1.0.3:
+    resolution: {integrity: sha512-p4D8CFVhZS412SyQX125qxyzOgIFouwOcvjZWk6bQbNPR1wtaEzFT6jZxAjf1dejlGqa6fqHcuCvQea6EWUkUA==}
+
+  vite@5.2.11:
+    resolution: {integrity: sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==}
+    engines: {node: ^18.0.0 || >=20.0.0}
+    hasBin: true
+    peerDependencies:
+      '@types/node': ^18.0.0 || >=20.0.0
+      less: '*'
+      lightningcss: ^1.21.0
+      sass: '*'
+      stylus: '*'
+      sugarss: '*'
+      terser: ^5.4.0
+    peerDependenciesMeta:
+      '@types/node':
+        optional: true
+      less:
+        optional: true
+      lightningcss:
+        optional: true
+      sass:
+        optional: true
+      stylus:
+        optional: true
+      sugarss:
+        optional: true
+      terser:
+        optional: true
+
+  vitest-fetch-mock@0.2.2:
+    resolution: {integrity: sha512-XmH6QgTSjCWrqXoPREIdbj40T7i1xnGmAsTAgfckoO75W1IEHKR8hcPCQ7SO16RsdW1t85oUm6pcQRLeBgjVYQ==}
+    engines: {node: '>=14.14.0'}
+    peerDependencies:
+      vitest: '>=0.16.0'
+
+  vitest@0.34.6:
+    resolution: {integrity: sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==}
+    engines: {node: '>=v14.18.0'}
+    hasBin: true
+    peerDependencies:
+      '@edge-runtime/vm': '*'
+      '@vitest/browser': '*'
+      '@vitest/ui': '*'
+      happy-dom: '*'
+      jsdom: '*'
+      playwright: '*'
+      safaridriver: '*'
+      webdriverio: '*'
+    peerDependenciesMeta:
+      '@edge-runtime/vm':
+        optional: true
+      '@vitest/browser':
+        optional: true
+      '@vitest/ui':
+        optional: true
+      happy-dom:
+        optional: true
+      jsdom:
+        optional: true
+      playwright:
+        optional: true
+      safaridriver:
+        optional: true
+      webdriverio:
+        optional: true
+
+  void-elements@3.1.0:
+    resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
+    engines: {node: '>=0.10.0'}
+
+  vscode-jsonrpc@8.2.0:
+    resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==}
+    engines: {node: '>=14.0.0'}
+
+  vscode-languageclient@9.0.1:
+    resolution: {integrity: sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==}
+    engines: {vscode: ^1.82.0}
+
+  vscode-languageserver-protocol@3.17.5:
+    resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==}
+
+  vscode-languageserver-textdocument@1.0.11:
+    resolution: {integrity: sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==}
+
+  vscode-languageserver-types@3.17.5:
+    resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==}
+
+  vscode-languageserver@9.0.1:
+    resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==}
+    hasBin: true
+
+  vue-component-meta@2.0.16:
+    resolution: {integrity: sha512-IyIMClUMYcKxAL34GqdPbR4V45MUeHXqQiZlHxeYMV5Qcqp4M+CEmtGpF//XBSS138heDkYkceHAtJQjLUB1Lw==}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  vue-component-type-helpers@1.8.4:
+    resolution: {integrity: sha512-6bnLkn8O0JJyiFSIF0EfCogzeqNXpnjJ0vW/SZzNHfe6sPx30lTtTXlE5TFs2qhJlAtDFybStVNpL73cPe3OMQ==}
+
+  vue-component-type-helpers@2.0.16:
+    resolution: {integrity: sha512-qisL/iAfdO++7w+SsfYQJVPj6QKvxp4i1MMxvsNO41z/8zu3KuAw9LkhKUfP/kcOWGDxESp+pQObWppXusejCA==}
+
+  vue-demi@0.14.7:
+    resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
+    engines: {node: '>=12'}
+    hasBin: true
+    peerDependencies:
+      '@vue/composition-api': ^1.0.0-rc.1
+      vue: ^3.0.0-0 || ^2.6.0
+    peerDependenciesMeta:
+      '@vue/composition-api':
+        optional: true
+
+  vue-docgen-api@4.75.1:
+    resolution: {integrity: sha512-MECZ3uExz+ssmhD/2XrFoQQs93y17IVO1KDYTp8nr6i9GNrk67AAto6QAtilW1H/pTDPMkQxJ7w/25ZIqVtfAA==}
+    peerDependencies:
+      vue: '>=2'
+
+  vue-eslint-parser@9.4.2:
+    resolution: {integrity: sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ==}
+    engines: {node: ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: '>=6.0.0'
+
+  vue-i18n@9.13.1:
+    resolution: {integrity: sha512-mh0GIxx0wPtPlcB1q4k277y0iKgo25xmDPWioVVYanjPufDBpvu5ySTjP5wOrSvlYQ2m1xI+CFhGdauv/61uQg==}
+    engines: {node: '>= 16'}
+    peerDependencies:
+      vue: ^3.0.0
+
+  vue-inbrowser-compiler-independent-utils@4.71.1:
+    resolution: {integrity: sha512-K3wt3iVmNGaFEOUR4JIThQRWfqokxLfnPslD41FDZB2ajXp789+wCqJyGYlIFsvEQ2P61PInw6/ph5iiqg51gg==}
+    peerDependencies:
+      vue: '>=2'
+
+  vue-template-compiler@2.7.14:
+    resolution: {integrity: sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==}
+
+  vue-tsc@2.0.16:
+    resolution: {integrity: sha512-/gHAWJa216PeEhfxtAToIbxdWgw01wuQzo48ZUqMYVEyNqDp+OYV9xMO5HaPS2P3Ls0+EsjguMZLY4cGobX4Ew==}
+    hasBin: true
+    peerDependencies:
+      typescript: '*'
+
+  vue@3.4.26:
+    resolution: {integrity: sha512-bUIq/p+VB+0xrJubaemrfhk1/FiW9iX+pDV+62I/XJ6EkspAO9/DXEjbDFoe8pIfOZBqfk45i9BMc41ptP/uRg==}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  vuedraggable@4.1.0:
+    resolution: {integrity: sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==}
+    peerDependencies:
+      vue: ^3.0.1
+
+  w3c-xmlserializer@5.0.0:
+    resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
+    engines: {node: '>=18'}
+
+  wait-on@7.2.0:
+    resolution: {integrity: sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==}
+    engines: {node: '>=12.0.0'}
+    hasBin: true
+
+  walker@1.0.8:
+    resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
+
+  watchpack@2.4.0:
+    resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==}
+    engines: {node: '>=10.13.0'}
+
+  wcwidth@1.0.1:
+    resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
+
+  web-push@3.6.7:
+    resolution: {integrity: sha512-OpiIUe8cuGjrj3mMBFWY+e4MMIkW3SVT+7vEIjvD9kejGUypv8GPDf84JdPWskK8zMRIJ6xYGm+Kxr8YkPyA0A==}
+    engines: {node: '>= 16'}
+    hasBin: true
+
+  web-streams-polyfill@3.2.1:
+    resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==}
+    engines: {node: '>= 8'}
+
+  webidl-conversions@3.0.1:
+    resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
+
+  webidl-conversions@7.0.0:
+    resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
+    engines: {node: '>=12'}
+
+  webpack-sources@3.2.3:
+    resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==}
+    engines: {node: '>=10.13.0'}
+
+  webpack-virtual-modules@0.5.0:
+    resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==}
+
+  whatwg-encoding@3.1.1:
+    resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
+    engines: {node: '>=18'}
+
+  whatwg-mimetype@3.0.0:
+    resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
+    engines: {node: '>=12'}
+
+  whatwg-mimetype@4.0.0:
+    resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
+    engines: {node: '>=18'}
+
+  whatwg-url@14.0.0:
+    resolution: {integrity: sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==}
+    engines: {node: '>=18'}
+
+  whatwg-url@5.0.0:
+    resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
+
+  which-boxed-primitive@1.0.2:
+    resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
+
+  which-collection@1.0.1:
+    resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==}
+
+  which-module@2.0.0:
+    resolution: {integrity: sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==}
+
+  which-typed-array@1.1.11:
+    resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==}
+    engines: {node: '>= 0.4'}
+
+  which@1.3.1:
+    resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
+    hasBin: true
+
+  which@2.0.2:
+    resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+    engines: {node: '>= 8'}
+    hasBin: true
+
+  which@4.0.0:
+    resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==}
+    engines: {node: ^16.13.0 || >=18.0.0}
+    hasBin: true
+
+  why-is-node-running@2.2.2:
+    resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==}
+    engines: {node: '>=8'}
+    hasBin: true
+
+  wide-align@1.1.5:
+    resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
+
+  with@7.0.2:
+    resolution: {integrity: sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==}
+    engines: {node: '>= 10.0.0'}
+
+  wordwrap@1.0.0:
+    resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
+
+  wrap-ansi@6.2.0:
+    resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
+    engines: {node: '>=8'}
+
+  wrap-ansi@7.0.0:
+    resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+    engines: {node: '>=10'}
+
+  wrap-ansi@8.1.0:
+    resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
+    engines: {node: '>=12'}
+
+  wrappy@1.0.2:
+    resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+
+  write-file-atomic@2.4.3:
+    resolution: {integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==}
+
+  write-file-atomic@4.0.2:
+    resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==}
+    engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+
+  ws@8.17.0:
+    resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==}
+    engines: {node: '>=10.0.0'}
+    peerDependencies:
+      bufferutil: ^4.0.1
+      utf-8-validate: '>=5.0.2'
+    peerDependenciesMeta:
+      bufferutil:
+        optional: true
+      utf-8-validate:
+        optional: true
+
+  xev@3.0.2:
+    resolution: {integrity: sha512-8kxuH95iMXzHZj+fwqfA4UrPcYOy6bGIgfWzo9Ji23JoEc30ge/Z++Ubkiuy8c0+M64nXmmxrmJ7C8wnuBhluw==}
+
+  xml-js@1.6.11:
+    resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==}
+    hasBin: true
+
+  xml-name-validator@4.0.0:
+    resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
+    engines: {node: '>=12'}
+
+  xml-name-validator@5.0.0:
+    resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
+    engines: {node: '>=18'}
+
+  xml2js@0.5.0:
+    resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==}
+    engines: {node: '>=4.0.0'}
+
+  xmlbuilder@11.0.1:
+    resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==}
+    engines: {node: '>=4.0'}
+
+  xmlchars@2.2.0:
+    resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+
+  xtend@4.0.2:
+    resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
+    engines: {node: '>=0.4'}
+
+  y18n@4.0.3:
+    resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
+
+  y18n@5.0.8:
+    resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
+    engines: {node: '>=10'}
+
+  yallist@2.1.2:
+    resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
+
+  yallist@3.1.1:
+    resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
+  yallist@4.0.0:
+    resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+
+  yargs-parser@18.1.3:
+    resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
+    engines: {node: '>=6'}
+
+  yargs-parser@20.2.9:
+    resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
+    engines: {node: '>=10'}
+
+  yargs-parser@21.1.1:
+    resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
+    engines: {node: '>=12'}
+
+  yargs@15.4.1:
+    resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
+    engines: {node: '>=8'}
+
+  yargs@16.2.0:
+    resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}
+    engines: {node: '>=10'}
+
+  yargs@17.7.2:
+    resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
+    engines: {node: '>=12'}
+
+  yauzl@2.10.0:
+    resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==}
+
+  yocto-queue@0.1.0:
+    resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+    engines: {node: '>=10'}
+
+  yocto-queue@1.0.0:
+    resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}
+    engines: {node: '>=12.20'}
+
+  z-schema@5.0.5:
+    resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==}
+    engines: {node: '>=8.0.0'}
+    hasBin: true
+
+  zip-stream@6.0.1:
+    resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==}
+    engines: {node: '>= 14'}
+
+  zwitch@2.0.4:
+    resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
+
+snapshots:
+
+  '@aashutoshrathi/word-wrap@1.2.6': {}
+
+  '@adobe/css-tools@4.3.3': {}
+
+  '@aiscript-dev/aiscript-languageserver@https://github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz':
+    dependencies:
+      seedrandom: 3.0.5
+      stringz: 2.1.0
+      uuid: 9.0.1
+      vscode-languageserver: 9.0.1
+      vscode-languageserver-textdocument: 1.0.11
+
+  '@ampproject/remapping@2.2.1':
     dependencies:
       '@jridgewell/gen-mapping': 0.3.2
       '@jridgewell/trace-mapping': 0.3.18
-    dev: true
 
-  /@apidevtools/openapi-schemas@2.1.0:
-    resolution: {integrity: sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==}
-    engines: {node: '>=10'}
-    dev: true
+  '@apidevtools/openapi-schemas@2.1.0': {}
 
-  /@apidevtools/swagger-methods@3.0.2:
-    resolution: {integrity: sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==}
-    dev: true
+  '@apidevtools/swagger-methods@3.0.2': {}
 
-  /@asamuzakjp/dom-selector@2.0.2:
-    resolution: {integrity: sha512-x1KXOatwofR6ZAYzXRBL5wrdV0vwNxlTCK9NCuLqAzQYARqGcvFwiJA6A1ERuh+dgeA4Dxm3JBYictIes+SqUQ==}
-    dependencies:
-      bidi-js: 1.0.3
-      css-tree: 2.3.1
-      is-potential-custom-element-name: 1.0.1
-    dev: false
-
-  /@aw-web-design/x-default-browser@1.4.126:
-    resolution: {integrity: sha512-Xk1sIhyNC/esHGGVjL/niHLowM0csl/kFO5uawBy4IrWwy0o1G8LGt3jP6nmWGz+USxeeqbihAmp/oVZju6wug==}
-    hasBin: true
+  '@aw-web-design/x-default-browser@1.4.126':
     dependencies:
       default-browser-id: 3.0.0
-    dev: true
 
-  /@aws-crypto/crc32@3.0.0:
-    resolution: {integrity: sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==}
+  '@aws-crypto/crc32@3.0.0':
     dependencies:
       '@aws-crypto/util': 3.0.0
       '@aws-sdk/types': 3.413.0
       tslib: 1.14.1
-    dev: false
 
-  /@aws-crypto/crc32c@3.0.0:
-    resolution: {integrity: sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w==}
+  '@aws-crypto/crc32c@3.0.0':
     dependencies:
       '@aws-crypto/util': 3.0.0
       '@aws-sdk/types': 3.413.0
       tslib: 1.14.1
-    dev: false
 
-  /@aws-crypto/ie11-detection@3.0.0:
-    resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==}
+  '@aws-crypto/ie11-detection@3.0.0':
     dependencies:
       tslib: 1.14.1
-    dev: false
 
-  /@aws-crypto/sha1-browser@3.0.0:
-    resolution: {integrity: sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw==}
+  '@aws-crypto/sha1-browser@3.0.0':
     dependencies:
       '@aws-crypto/ie11-detection': 3.0.0
       '@aws-crypto/supports-web-crypto': 3.0.0
@@ -1339,10 +11212,8 @@ packages:
       '@aws-sdk/util-locate-window': 3.208.0
       '@aws-sdk/util-utf8-browser': 3.259.0
       tslib: 1.14.1
-    dev: false
 
-  /@aws-crypto/sha256-browser@3.0.0:
-    resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==}
+  '@aws-crypto/sha256-browser@3.0.0':
     dependencies:
       '@aws-crypto/ie11-detection': 3.0.0
       '@aws-crypto/sha256-js': 3.0.0
@@ -1352,33 +11223,24 @@ packages:
       '@aws-sdk/util-locate-window': 3.208.0
       '@aws-sdk/util-utf8-browser': 3.259.0
       tslib: 1.14.1
-    dev: false
 
-  /@aws-crypto/sha256-js@3.0.0:
-    resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==}
+  '@aws-crypto/sha256-js@3.0.0':
     dependencies:
       '@aws-crypto/util': 3.0.0
       '@aws-sdk/types': 3.413.0
       tslib: 1.14.1
-    dev: false
 
-  /@aws-crypto/supports-web-crypto@3.0.0:
-    resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==}
+  '@aws-crypto/supports-web-crypto@3.0.0':
     dependencies:
       tslib: 1.14.1
-    dev: false
 
-  /@aws-crypto/util@3.0.0:
-    resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==}
+  '@aws-crypto/util@3.0.0':
     dependencies:
       '@aws-sdk/types': 3.413.0
       '@aws-sdk/util-utf8-browser': 3.259.0
       tslib: 1.14.1
-    dev: false
 
-  /@aws-sdk/client-s3@3.412.0:
-    resolution: {integrity: sha512-sNrlx9sSBmFUCqMgTznwk9Fee3PJat0nZ3RIDR5Crhsld/eexxrqb6TYKsxzFfBfXTL/oPh+/S5driRV2xsB8A==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/client-s3@3.412.0':
     dependencies:
       '@aws-crypto/sha1-browser': 3.0.0
       '@aws-crypto/sha256-browser': 3.0.0
@@ -1418,7 +11280,7 @@ packages:
       '@smithy/middleware-serde': 2.0.8
       '@smithy/middleware-stack': 2.0.1
       '@smithy/node-config-provider': 2.0.11
-      '@smithy/node-http-handler': 2.1.10
+      '@smithy/node-http-handler': 2.5.0
       '@smithy/protocol-http': 3.0.10
       '@smithy/smithy-client': 2.1.5
       '@smithy/types': 2.6.0
@@ -1436,11 +11298,8 @@ packages:
       tslib: 2.6.2
     transitivePeerDependencies:
       - aws-crt
-    dev: false
 
-  /@aws-sdk/client-sso@3.410.0:
-    resolution: {integrity: sha512-MC9GrgwtlOuSL2WS3DRM3dQ/5y+49KSMMJRH6JiEcU5vE0dX/OtEcX+VfEwpi73x5pSfIjm7xnzjzOFx+sQBIg==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/client-sso@3.410.0':
     dependencies:
       '@aws-crypto/sha256-browser': 3.0.0
       '@aws-crypto/sha256-js': 3.0.0
@@ -1462,7 +11321,7 @@ packages:
       '@smithy/middleware-serde': 2.0.8
       '@smithy/middleware-stack': 2.0.1
       '@smithy/node-config-provider': 2.0.11
-      '@smithy/node-http-handler': 2.1.10
+      '@smithy/node-http-handler': 2.5.0
       '@smithy/protocol-http': 3.0.10
       '@smithy/smithy-client': 2.1.5
       '@smithy/types': 2.6.0
@@ -1477,11 +11336,8 @@ packages:
       tslib: 2.6.2
     transitivePeerDependencies:
       - aws-crt
-    dev: false
 
-  /@aws-sdk/client-sts@3.410.0:
-    resolution: {integrity: sha512-e6VMrBJtnTxxUXwDmkADGIvyppmDMFf4+cGGA68tVCUm1cFNlCI6M/67bVSIPN/WVKAAfhEL5O2vVXCM7aatYg==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/client-sts@3.410.0':
     dependencies:
       '@aws-crypto/sha256-browser': 3.0.0
       '@aws-crypto/sha256-js': 3.0.0
@@ -1506,7 +11362,7 @@ packages:
       '@smithy/middleware-serde': 2.0.8
       '@smithy/middleware-stack': 2.0.1
       '@smithy/node-config-provider': 2.0.11
-      '@smithy/node-http-handler': 2.1.10
+      '@smithy/node-http-handler': 2.5.0
       '@smithy/protocol-http': 3.0.10
       '@smithy/smithy-client': 2.1.5
       '@smithy/types': 2.6.0
@@ -1522,21 +11378,15 @@ packages:
       tslib: 2.6.2
     transitivePeerDependencies:
       - aws-crt
-    dev: false
 
-  /@aws-sdk/credential-provider-env@3.410.0:
-    resolution: {integrity: sha512-c7TB9LbN0PkFOsXI0lcRJnqPNOmc4VBvrHf8jP/BkTDg4YUoKQKOFd4d0SqzODmlZiAyoMQVZTR4ISZo95Zj4Q==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/credential-provider-env@3.410.0':
     dependencies:
       '@aws-sdk/types': 3.410.0
       '@smithy/property-provider': 2.0.9
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/credential-provider-ini@3.410.0:
-    resolution: {integrity: sha512-D8rcr5bRCFD0f42MPQ7K6TWZq5d3pfqrKINL1/bpfkK5BJbvq1BGYmR88UC6CLpTRtZ1LHY2HgYG0fp/2zjjww==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/credential-provider-ini@3.410.0':
     dependencies:
       '@aws-sdk/credential-provider-env': 3.410.0
       '@aws-sdk/credential-provider-process': 3.410.0
@@ -1550,11 +11400,8 @@ packages:
       tslib: 2.6.2
     transitivePeerDependencies:
       - aws-crt
-    dev: false
 
-  /@aws-sdk/credential-provider-node@3.410.0:
-    resolution: {integrity: sha512-0wmVm33T/j1FS7MZ/j+WsPlgSc0YnCXnpbWSov1Mn6R86SHI2b2JhdIPRRE4XbGfyW2QGNUl2CwoZVaqhXeF5g==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/credential-provider-node@3.410.0':
     dependencies:
       '@aws-sdk/credential-provider-env': 3.410.0
       '@aws-sdk/credential-provider-ini': 3.410.0
@@ -1569,22 +11416,16 @@ packages:
       tslib: 2.6.2
     transitivePeerDependencies:
       - aws-crt
-    dev: false
 
-  /@aws-sdk/credential-provider-process@3.410.0:
-    resolution: {integrity: sha512-BMju1hlDCDNkkSZpKF5SQ8G0WCLRj6/Jvw9QmudLHJuVwYJXEW1r2AsVMg98OZ3hB9G+MAvHruHZIbMiNmUMXQ==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/credential-provider-process@3.410.0':
     dependencies:
       '@aws-sdk/types': 3.410.0
       '@smithy/property-provider': 2.0.9
       '@smithy/shared-ini-file-loader': 2.0.10
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/credential-provider-sso@3.410.0:
-    resolution: {integrity: sha512-zEaoY/sY+KYTlQUkp9dvveAHf175b8RIt0DsQkDrRPtrg/RBHR00r5rFvz9+nrwsR8546RaBU7h/zzTaQGhmcA==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/credential-provider-sso@3.410.0':
     dependencies:
       '@aws-sdk/client-sso': 3.410.0
       '@aws-sdk/token-providers': 3.410.0
@@ -1595,23 +11436,15 @@ packages:
       tslib: 2.6.2
     transitivePeerDependencies:
       - aws-crt
-    dev: false
 
-  /@aws-sdk/credential-provider-web-identity@3.410.0:
-    resolution: {integrity: sha512-cE0l8LmEHdWbDkdPNgrfdYSgp4/cIVXrjUKI1QCATA729CrHZ/OQjB/maOBOrMHO9YTiggko887NkslVvwVB7w==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/credential-provider-web-identity@3.410.0':
     dependencies:
       '@aws-sdk/types': 3.410.0
       '@smithy/property-provider': 2.0.9
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/lib-storage@3.412.0(@aws-sdk/client-s3@3.412.0):
-    resolution: {integrity: sha512-uAdVtNuip06rJOs28zVrYXLNeHfKraxvJRTzTA+DW1dXkzh70GTKqDKHWH9IJkW/xMTE6wGSM+fDs8jsMOn/yA==}
-    engines: {node: '>=14.0.0'}
-    peerDependencies:
-      '@aws-sdk/client-s3': ^3.0.0
+  '@aws-sdk/lib-storage@3.412.0(@aws-sdk/client-s3@3.412.0)':
     dependencies:
       '@aws-sdk/client-s3': 3.412.0
       '@smithy/abort-controller': 2.0.14
@@ -1621,11 +11454,8 @@ packages:
       events: 3.3.0
       stream-browserify: 3.0.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/middleware-bucket-endpoint@3.410.0:
-    resolution: {integrity: sha512-pUGrpFgCKf9fDHu01JJhhw+MUImheS0HFlZwNG37OMubkxUAbCdmYGewGxfTCUvWyZJtx9bVjrSu6gG7w+RARg==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/middleware-bucket-endpoint@3.410.0':
     dependencies:
       '@aws-sdk/types': 3.410.0
       '@aws-sdk/util-arn-parser': 3.310.0
@@ -1634,21 +11464,15 @@ packages:
       '@smithy/types': 2.6.0
       '@smithy/util-config-provider': 2.0.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/middleware-expect-continue@3.410.0:
-    resolution: {integrity: sha512-e5YqGCNmW99GZjEPPujJ02RlEZql19U40oORysBhVF7mKz8BBvF3s8l37tvu37oxebDEkh1u/2cm2+ggOXxLjQ==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/middleware-expect-continue@3.410.0':
     dependencies:
       '@aws-sdk/types': 3.410.0
       '@smithy/protocol-http': 3.0.10
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/middleware-flexible-checksums@3.410.0:
-    resolution: {integrity: sha512-IK7KlvEKtrQVBfmAp/MmGd0wbWLuN2GZwwfAmsU0qFb0f5vOVUbKDsu6tudtDKCBG9uXyTEsx3/QGvoK2zDy+g==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/middleware-flexible-checksums@3.410.0':
     dependencies:
       '@aws-crypto/crc32': 3.0.0
       '@aws-crypto/crc32c': 3.0.0
@@ -1658,70 +11482,49 @@ packages:
       '@smithy/types': 2.6.0
       '@smithy/util-utf8': 2.0.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/middleware-host-header@3.410.0:
-    resolution: {integrity: sha512-ED/OVcyITln5rrxnajZP+V0PN1nug+gSDHJDqdDo/oLy7eiDr/ZWn3nlWW7WcMplQ1/Jnb+hK0UetBp/25XooA==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/middleware-host-header@3.410.0':
     dependencies:
       '@aws-sdk/types': 3.410.0
       '@smithy/protocol-http': 3.0.10
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/middleware-location-constraint@3.410.0:
-    resolution: {integrity: sha512-jAftSpOpw/5AdpOJ/cGiXCb+Vv22KXR5QZmxmllUDsnlm18672tpRaI2plmu/1d98CVvqhY61eSklFMrIf2c4w==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/middleware-location-constraint@3.410.0':
     dependencies:
       '@aws-sdk/types': 3.410.0
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/middleware-logger@3.410.0:
-    resolution: {integrity: sha512-YtmKYCVtBfScq3/UFJk+aSZOktKJBNZL9DaSc2aPcy/goCVsYDOkGwtHk0jIkC1JRSNCkVTqL7ya60sSr8zaQQ==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/middleware-logger@3.410.0':
     dependencies:
       '@aws-sdk/types': 3.410.0
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/middleware-recursion-detection@3.410.0:
-    resolution: {integrity: sha512-KWaes5FLzRqj28vaIEE4Bimpga2E596WdPF2HaH6zsVMJddoRDsc3ZX9ZhLOGrXzIO1RqBd0QxbLrM0S/B2aOQ==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/middleware-recursion-detection@3.410.0':
     dependencies:
       '@aws-sdk/types': 3.410.0
       '@smithy/protocol-http': 3.0.10
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/middleware-sdk-s3@3.410.0:
-    resolution: {integrity: sha512-K2sG2V1ZkezYMCIy3uMt0MwtflcfIwLptwm0iFLaYitiINZQ1tcslk9ggAjyTHg0rslDSI4/zjkhy8VHFOV7HA==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/middleware-sdk-s3@3.410.0':
     dependencies:
       '@aws-sdk/types': 3.410.0
       '@aws-sdk/util-arn-parser': 3.310.0
       '@smithy/protocol-http': 3.0.10
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/middleware-sdk-sts@3.410.0:
-    resolution: {integrity: sha512-YfBpctDocRR4CcROoDueJA7D+aMLBV8nTFfmVNdLLLgyuLZ/AUR11VQSu1lf9gQZKl8IpKE/BLf2fRE/qV1ZuA==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/middleware-sdk-sts@3.410.0':
     dependencies:
       '@aws-sdk/middleware-signing': 3.410.0
       '@aws-sdk/types': 3.410.0
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/middleware-signing@3.410.0:
-    resolution: {integrity: sha512-KBAZ/eoAJUSJv5us2HsKwK2OszG2s9FEyKpEhgnHLcbbKzW873zHBH5GcOGEQu4AWArTy2ndzJu3FF+9/J9hJQ==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/middleware-signing@3.410.0':
     dependencies:
       '@aws-sdk/types': 3.410.0
       '@smithy/property-provider': 2.0.9
@@ -1730,42 +11533,30 @@ packages:
       '@smithy/types': 2.6.0
       '@smithy/util-middleware': 2.0.1
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/middleware-ssec@3.410.0:
-    resolution: {integrity: sha512-DNsjVTXoxIh+PuW9o45CFaMiconbuZRm19MC3NA1yNCaCj3ZxD5OdXAutq6UjQdrx8UG4EjUlCJEEvBKmboITw==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/middleware-ssec@3.410.0':
     dependencies:
       '@aws-sdk/types': 3.410.0
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/middleware-user-agent@3.410.0:
-    resolution: {integrity: sha512-ZayDtLfvCZUohSxQc/49BfoU/y6bDHLfLdyyUJbJ54Sv8zQcrmdyKvCBFUZwE6tHQgAmv9/ZT18xECMl+xiONA==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/middleware-user-agent@3.410.0':
     dependencies:
       '@aws-sdk/types': 3.410.0
       '@aws-sdk/util-endpoints': 3.410.0
       '@smithy/protocol-http': 3.0.10
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/signature-v4-multi-region@3.412.0:
-    resolution: {integrity: sha512-ijxOeYpNDuk2T940S9HYcZ1C+wTP9vqp1Cw37zw9whVY2mKV3Vr7i+44D4FQ5HhWULgdwhjD7IctbNxPIPzUZQ==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/signature-v4-multi-region@3.412.0':
     dependencies:
       '@aws-sdk/types': 3.410.0
       '@smithy/protocol-http': 3.0.10
       '@smithy/signature-v4': 2.0.5
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/token-providers@3.410.0:
-    resolution: {integrity: sha512-d5Nc0xydkH/X0LA1HDyhGY5sEv4LuADFk+QpDtT8ogLilcre+b1jpdY8Sih/gd1KoGS1H+d1tz2hSGwUHAbUbw==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/token-providers@3.410.0':
     dependencies:
       '@aws-crypto/sha256-browser': 3.0.0
       '@aws-crypto/sha256-js': 3.0.0
@@ -1787,7 +11578,7 @@ packages:
       '@smithy/middleware-serde': 2.0.8
       '@smithy/middleware-stack': 2.0.1
       '@smithy/node-config-provider': 2.0.11
-      '@smithy/node-http-handler': 2.1.10
+      '@smithy/node-http-handler': 2.5.0
       '@smithy/property-provider': 2.0.9
       '@smithy/protocol-http': 3.0.10
       '@smithy/shared-ini-file-loader': 2.0.10
@@ -1804,99 +11595,60 @@ packages:
       tslib: 2.6.2
     transitivePeerDependencies:
       - aws-crt
-    dev: false
 
-  /@aws-sdk/types@3.410.0:
-    resolution: {integrity: sha512-D7iaUCszv/v04NDaZUmCmekamy6VD/lKozm/3gS9+dkfU6cC2CsNoUfPV8BlV6dPdw0oWgF91am3I1stdvfVrQ==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/types@3.410.0':
     dependencies:
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/types@3.413.0:
-    resolution: {integrity: sha512-j1xib0f/TazIFc5ySIKOlT1ujntRbaoG4LJFeEezz4ji03/wSJMI8Vi4KjzpBp8J1tTu0oRDnsxRIGixsUBeYQ==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/types@3.413.0':
     dependencies:
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/util-arn-parser@3.310.0:
-    resolution: {integrity: sha512-jL8509owp/xB9+Or0pvn3Fe+b94qfklc2yPowZZIFAkFcCSIdkIglz18cPDWnYAcy9JGewpMS1COXKIUhZkJsA==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/util-arn-parser@3.310.0':
     dependencies:
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/util-endpoints@3.410.0:
-    resolution: {integrity: sha512-iNiqJyC7N3+8zFwnXUqcWSxrZecVZLToo1iTQQdeYL2af1IcOtRgb7n8jpAI/hmXhBSx2+3RI+Y7pxyFo1vu+w==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/util-endpoints@3.410.0':
     dependencies:
       '@aws-sdk/types': 3.410.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/util-locate-window@3.208.0:
-    resolution: {integrity: sha512-iua1A2+P7JJEDHVgvXrRJSvsnzG7stYSGQnBVphIUlemwl6nN5D+QrgbjECtrbxRz8asYFHSzhdhECqN+tFiBg==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/util-locate-window@3.208.0':
     dependencies:
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/util-user-agent-browser@3.410.0:
-    resolution: {integrity: sha512-i1G/XGpXGMRT2zEiAhi1xucJsfCWk8nNYjk/LbC0sA+7B9Huri96YAzVib12wkHPsJQvZxZC6CpQDIHWm4lXMA==}
+  '@aws-sdk/util-user-agent-browser@3.410.0':
     dependencies:
       '@aws-sdk/types': 3.410.0
       '@smithy/types': 2.6.0
       bowser: 2.11.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/util-user-agent-node@3.410.0:
-    resolution: {integrity: sha512-bK70t1jHRl8HrJXd4hEIwc5PBZ7U0w+81AKFnanIVKZwZedd6nLibUXDTK14z/Jp2GFcBqd4zkt2YLGkRt/U4A==}
-    engines: {node: '>=14.0.0'}
-    peerDependencies:
-      aws-crt: '>=1.0.0'
-    peerDependenciesMeta:
-      aws-crt:
-        optional: true
+  '@aws-sdk/util-user-agent-node@3.410.0':
     dependencies:
       '@aws-sdk/types': 3.410.0
       '@smithy/node-config-provider': 2.0.11
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/util-utf8-browser@3.259.0:
-    resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==}
+  '@aws-sdk/util-utf8-browser@3.259.0':
     dependencies:
       tslib: 2.6.2
-    dev: false
 
-  /@aws-sdk/xml-builder@3.310.0:
-    resolution: {integrity: sha512-TqELu4mOuSIKQCqj63fGVs86Yh+vBx5nHRpWKNUNhB2nPTpfbziTs5c1X358be3peVWA4wPxW7Nt53KIg1tnNw==}
-    engines: {node: '>=14.0.0'}
+  '@aws-sdk/xml-builder@3.310.0':
     dependencies:
       tslib: 2.6.2
-    dev: false
 
-  /@babel/code-frame@7.23.5:
-    resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==}
-    engines: {node: '>=6.9.0'}
+  '@babel/code-frame@7.23.5':
     dependencies:
       '@babel/highlight': 7.23.4
       chalk: 2.4.2
-    dev: true
 
-  /@babel/compat-data@7.23.5:
-    resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==}
-    engines: {node: '>=6.9.0'}
-    dev: true
+  '@babel/compat-data@7.23.5': {}
 
-  /@babel/core@7.23.5:
-    resolution: {integrity: sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==}
-    engines: {node: '>=6.9.0'}
+  '@babel/core@7.23.5':
     dependencies:
       '@ampproject/remapping': 2.2.1
       '@babel/code-frame': 7.23.5
@@ -1915,11 +11667,8 @@ packages:
       semver: 6.3.1
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@babel/core@7.24.0:
-    resolution: {integrity: sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==}
-    engines: {node: '>=6.9.0'}
+  '@babel/core@7.24.0':
     dependencies:
       '@ampproject/remapping': 2.2.1
       '@babel/code-frame': 7.23.5
@@ -1938,69 +11687,46 @@ packages:
       semver: 6.3.1
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@babel/generator@7.23.5:
-    resolution: {integrity: sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==}
-    engines: {node: '>=6.9.0'}
+  '@babel/generator@7.23.5':
     dependencies:
       '@babel/types': 7.23.5
       '@jridgewell/gen-mapping': 0.3.2
       '@jridgewell/trace-mapping': 0.3.18
       jsesc: 2.5.2
-    dev: true
 
-  /@babel/generator@7.23.6:
-    resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==}
-    engines: {node: '>=6.9.0'}
+  '@babel/generator@7.23.6':
     dependencies:
       '@babel/types': 7.24.0
       '@jridgewell/gen-mapping': 0.3.2
       '@jridgewell/trace-mapping': 0.3.18
       jsesc: 2.5.2
-    dev: true
 
-  /@babel/helper-annotate-as-pure@7.22.5:
-    resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==}
-    engines: {node: '>=6.9.0'}
+  '@babel/helper-annotate-as-pure@7.22.5':
     dependencies:
       '@babel/types': 7.24.0
-    dev: true
 
-  /@babel/helper-builder-binary-assignment-operator-visitor@7.22.15:
-    resolution: {integrity: sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==}
-    engines: {node: '>=6.9.0'}
+  '@babel/helper-builder-binary-assignment-operator-visitor@7.22.15':
     dependencies:
       '@babel/types': 7.24.0
-    dev: true
 
-  /@babel/helper-compilation-targets@7.22.15:
-    resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==}
-    engines: {node: '>=6.9.0'}
+  '@babel/helper-compilation-targets@7.22.15':
     dependencies:
       '@babel/compat-data': 7.23.5
       '@babel/helper-validator-option': 7.23.5
       browserslist: 4.22.2
       lru-cache: 5.1.1
       semver: 6.3.1
-    dev: true
 
-  /@babel/helper-compilation-targets@7.23.6:
-    resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==}
-    engines: {node: '>=6.9.0'}
+  '@babel/helper-compilation-targets@7.23.6':
     dependencies:
       '@babel/compat-data': 7.23.5
       '@babel/helper-validator-option': 7.23.5
       browserslist: 4.23.0
       lru-cache: 5.1.1
       semver: 6.3.1
-    dev: true
 
-  /@babel/helper-create-class-features-plugin@7.23.5(@babel/core@7.24.0):
-    resolution: {integrity: sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0
+  '@babel/helper-create-class-features-plugin@7.23.5(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-annotate-as-pure': 7.22.5
@@ -2012,24 +11738,15 @@ packages:
       '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
       '@babel/helper-split-export-declaration': 7.22.6
       semver: 6.3.1
-    dev: true
 
-  /@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.24.0):
-    resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0
+  '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-annotate-as-pure': 7.22.5
       regexpu-core: 5.3.2
       semver: 6.3.1
-    dev: true
 
-  /@babel/helper-define-polyfill-provider@0.4.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==}
-    peerDependencies:
-      '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
+  '@babel/helper-define-polyfill-provider@0.4.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-compilation-targets': 7.23.6
@@ -2039,47 +11756,27 @@ packages:
       resolve: 1.22.8
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@babel/helper-environment-visitor@7.22.20:
-    resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==}
-    engines: {node: '>=6.9.0'}
-    dev: true
+  '@babel/helper-environment-visitor@7.22.20': {}
 
-  /@babel/helper-function-name@7.23.0:
-    resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==}
-    engines: {node: '>=6.9.0'}
+  '@babel/helper-function-name@7.23.0':
     dependencies:
-      '@babel/template': 7.22.15
-      '@babel/types': 7.23.5
-    dev: true
+      '@babel/template': 7.24.0
+      '@babel/types': 7.24.0
 
-  /@babel/helper-hoist-variables@7.22.5:
-    resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/types': 7.23.5
-    dev: true
-
-  /@babel/helper-member-expression-to-functions@7.23.0:
-    resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==}
-    engines: {node: '>=6.9.0'}
+  '@babel/helper-hoist-variables@7.22.5':
     dependencies:
       '@babel/types': 7.24.0
-    dev: true
 
-  /@babel/helper-module-imports@7.22.15:
-    resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==}
-    engines: {node: '>=6.9.0'}
+  '@babel/helper-member-expression-to-functions@7.23.0':
+    dependencies:
+      '@babel/types': 7.24.0
+
+  '@babel/helper-module-imports@7.22.15':
     dependencies:
       '@babel/types': 7.23.5
-    dev: true
 
-  /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.5):
-    resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0
+  '@babel/helper-module-transforms@7.23.3(@babel/core@7.23.5)':
     dependencies:
       '@babel/core': 7.23.5
       '@babel/helper-environment-visitor': 7.22.20
@@ -2087,13 +11784,8 @@ packages:
       '@babel/helper-simple-access': 7.22.5
       '@babel/helper-split-export-declaration': 7.22.6
       '@babel/helper-validator-identifier': 7.22.20
-    dev: true
 
-  /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0
+  '@babel/helper-module-transforms@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-environment-visitor': 7.22.20
@@ -2101,586 +11793,327 @@ packages:
       '@babel/helper-simple-access': 7.22.5
       '@babel/helper-split-export-declaration': 7.22.6
       '@babel/helper-validator-identifier': 7.22.20
-    dev: true
 
-  /@babel/helper-optimise-call-expression@7.22.5:
-    resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==}
-    engines: {node: '>=6.9.0'}
+  '@babel/helper-optimise-call-expression@7.22.5':
     dependencies:
       '@babel/types': 7.24.0
-    dev: true
 
-  /@babel/helper-plugin-utils@7.22.5:
-    resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==}
-    engines: {node: '>=6.9.0'}
-    dev: true
+  '@babel/helper-plugin-utils@7.22.5': {}
 
-  /@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.24.0):
-    resolution: {integrity: sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0
+  '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-annotate-as-pure': 7.22.5
       '@babel/helper-environment-visitor': 7.22.20
       '@babel/helper-wrap-function': 7.22.20
-    dev: true
 
-  /@babel/helper-replace-supers@7.22.20(@babel/core@7.24.0):
-    resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0
+  '@babel/helper-replace-supers@7.22.20(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-environment-visitor': 7.22.20
       '@babel/helper-member-expression-to-functions': 7.23.0
       '@babel/helper-optimise-call-expression': 7.22.5
-    dev: true
 
-  /@babel/helper-simple-access@7.22.5:
-    resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==}
-    engines: {node: '>=6.9.0'}
+  '@babel/helper-simple-access@7.22.5':
     dependencies:
       '@babel/types': 7.23.5
-    dev: true
 
-  /@babel/helper-skip-transparent-expression-wrappers@7.22.5:
-    resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==}
-    engines: {node: '>=6.9.0'}
+  '@babel/helper-skip-transparent-expression-wrappers@7.22.5':
     dependencies:
       '@babel/types': 7.24.0
-    dev: true
 
-  /@babel/helper-split-export-declaration@7.22.6:
-    resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==}
-    engines: {node: '>=6.9.0'}
+  '@babel/helper-split-export-declaration@7.22.6':
     dependencies:
       '@babel/types': 7.23.5
-    dev: true
 
-  /@babel/helper-string-parser@7.23.4:
-    resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==}
-    engines: {node: '>=6.9.0'}
+  '@babel/helper-string-parser@7.23.4': {}
 
-  /@babel/helper-validator-identifier@7.22.20:
-    resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==}
-    engines: {node: '>=6.9.0'}
+  '@babel/helper-validator-identifier@7.22.20': {}
 
-  /@babel/helper-validator-option@7.23.5:
-    resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==}
-    engines: {node: '>=6.9.0'}
-    dev: true
+  '@babel/helper-validator-option@7.23.5': {}
 
-  /@babel/helper-wrap-function@7.22.20:
-    resolution: {integrity: sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==}
-    engines: {node: '>=6.9.0'}
+  '@babel/helper-wrap-function@7.22.20':
     dependencies:
       '@babel/helper-function-name': 7.23.0
       '@babel/template': 7.24.0
       '@babel/types': 7.24.0
-    dev: true
 
-  /@babel/helpers@7.23.5:
-    resolution: {integrity: sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==}
-    engines: {node: '>=6.9.0'}
+  '@babel/helpers@7.23.5':
     dependencies:
       '@babel/template': 7.22.15
       '@babel/traverse': 7.23.5
       '@babel/types': 7.23.5
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@babel/helpers@7.24.0:
-    resolution: {integrity: sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==}
-    engines: {node: '>=6.9.0'}
+  '@babel/helpers@7.24.0':
     dependencies:
       '@babel/template': 7.24.0
       '@babel/traverse': 7.24.0
       '@babel/types': 7.24.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@babel/highlight@7.23.4:
-    resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==}
-    engines: {node: '>=6.9.0'}
+  '@babel/highlight@7.23.4':
     dependencies:
       '@babel/helper-validator-identifier': 7.22.20
       chalk: 2.4.2
       js-tokens: 4.0.0
-    dev: true
 
-  /@babel/parser@7.23.9:
-    resolution: {integrity: sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==}
-    engines: {node: '>=6.0.0'}
-    hasBin: true
+  '@babel/parser@7.23.9':
     dependencies:
       '@babel/types': 7.23.5
 
-  /@babel/parser@7.24.0:
-    resolution: {integrity: sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==}
-    engines: {node: '>=6.0.0'}
-    hasBin: true
+  '@babel/parser@7.24.0':
     dependencies:
       '@babel/types': 7.24.0
-    dev: true
 
-  /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0
+  '@babel/parser@7.24.5':
+    dependencies:
+      '@babel/types': 7.24.0
+
+  '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.13.0
+  '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
       '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0
+  '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-environment-visitor': 7.22.20
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.0):
-    resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
-    dev: true
 
-  /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.5):
-    resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.5)':
     dependencies:
       '@babel/core': 7.23.5
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.0):
-    resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.5):
-    resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.5)':
     dependencies:
       '@babel/core': 7.23.5
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.5):
-    resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.5)':
     dependencies:
       '@babel/core': 7.23.5
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.0):
-    resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.0):
-    resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-YZiAIpkJAwQXBJLIQbRFayR5c+gJ35Vcz3bg954k7cd73zqjvhacJuL9RbrzPz8qPmZdgqP6EUKwy0PCNhaaPA==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.5):
-    resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.5)':
     dependencies:
       '@babel/core': 7.23.5
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.0):
-    resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.5):
-    resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.5)':
     dependencies:
       '@babel/core': 7.23.5
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.5):
-    resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.5)':
     dependencies:
       '@babel/core': 7.23.5
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.5):
-    resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.5)':
     dependencies:
       '@babel/core': 7.23.5
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.0):
-    resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.5):
-    resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.5)':
     dependencies:
       '@babel/core': 7.23.5
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.5):
-    resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.5)':
     dependencies:
       '@babel/core': 7.23.5
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.0):
-    resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.5):
-    resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.5)':
     dependencies:
       '@babel/core': 7.23.5
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.5):
-    resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.5)':
     dependencies:
       '@babel/core': 7.23.5
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.5):
-    resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.5)':
     dependencies:
       '@babel/core': 7.23.5
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.0):
-    resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.5):
-    resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.5)':
     dependencies:
       '@babel/core': 7.23.5
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.0):
-    resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.5):
-    resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.5)':
     dependencies:
       '@babel/core': 7.23.5
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.0):
-    resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0
+  '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-async-generator-functions@7.23.4(@babel/core@7.24.0):
-    resolution: {integrity: sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-async-generator-functions@7.23.4(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-environment-visitor': 7.22.20
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.0)
       '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-module-imports': 7.22.15
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.24.0):
-    resolution: {integrity: sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.24.0):
-    resolution: {integrity: sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.12.0
+  '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/plugin-transform-classes@7.23.5(@babel/core@7.24.0):
-    resolution: {integrity: sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-classes@7.23.5(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-annotate-as-pure': 7.22.5
@@ -2692,253 +12125,138 @@ packages:
       '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.0)
       '@babel/helper-split-export-declaration': 7.22.6
       globals: 11.12.0
-    dev: true
 
-  /@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/template': 7.24.0
-    dev: true
 
-  /@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.24.0):
-    resolution: {integrity: sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.24.0):
-    resolution: {integrity: sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-26/pQTf9nQSNVJCrLB1IkHUKyPxR+lMrH2QDPG89+Znu9rAMbtrybdbWeE9bb7gzjmE5iXHEY+e0HUwM6Co93Q==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/plugin-transform-for-of@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-for-of@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-function-name@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-compilation-targets': 7.23.6
       '@babel/helper-function-name': 7.23.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.24.0):
-    resolution: {integrity: sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/plugin-transform-literals@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-literals@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.24.0):
-    resolution: {integrity: sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/helper-simple-access': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-modules-systemjs@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-modules-systemjs@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-hoist-variables': 7.22.5
       '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/helper-validator-identifier': 7.22.20
-    dev: true
 
-  /@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.24.0):
-    resolution: {integrity: sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0
+  '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-new-target@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.24.0):
-    resolution: {integrity: sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.24.0):
-    resolution: {integrity: sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.24.0):
-    resolution: {integrity: sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.24.0)':
     dependencies:
       '@babel/compat-data': 7.23.5
       '@babel/core': 7.24.0
@@ -2946,219 +12264,119 @@ packages:
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.0)
       '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/plugin-transform-object-super@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.24.0):
-    resolution: {integrity: sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.24.0):
-    resolution: {integrity: sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
       '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/plugin-transform-parameters@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.24.0):
-    resolution: {integrity: sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-annotate-as-pure': 7.22.5
       '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       regenerator-transform: 0.15.2
-    dev: true
 
-  /@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-spread@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-spread@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-typescript@7.23.5(@babel/core@7.24.0):
-    resolution: {integrity: sha512-2fMkXEJkrmwgu2Bsv1Saxgj30IXZdJ+84lQcKKI7sm719oXs0BBw2ZENKdJdR1PjWndgLCEBNXJOri0fk7RYQA==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-typescript@7.23.5(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-annotate-as-pure': 7.22.5
       '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0
+  '@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
       '@babel/helper-plugin-utils': 7.22.5
-    dev: true
 
-  /@babel/preset-env@7.23.5(@babel/core@7.24.0):
-    resolution: {integrity: sha512-0d/uxVD6tFGWXGDSfyMD1p2otoaKmu6+GD+NfAx0tMaH+dxORnp7T9TaVQ6mKyya7iBtCIVxHjWT7MuzzM9z+A==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/preset-env@7.23.5(@babel/core@7.24.0)':
     dependencies:
       '@babel/compat-data': 7.23.5
       '@babel/core': 7.24.0
@@ -3243,36 +12461,22 @@ packages:
       semver: 6.3.1
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@babel/preset-flow@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-7yn6hl8RIv+KNk6iIrGZ+D06VhVY35wLVf23Cz/mMu1zOr7u4MMP4j0nZ9tLf8+4ZFpnib8cFYgB/oYg9hfswA==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/preset-flow@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/helper-validator-option': 7.23.5
       '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.0):
-    resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0
+  '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
       '@babel/types': 7.24.0
       esutils: 2.0.3
-    dev: true
 
-  /@babel/preset-typescript@7.23.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/preset-typescript@7.23.3(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-plugin-utils': 7.22.5
@@ -3280,13 +12484,8 @@ packages:
       '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.24.0)
       '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.24.0)
       '@babel/plugin-transform-typescript': 7.23.5(@babel/core@7.24.0)
-    dev: true
 
-  /@babel/register@7.22.15(@babel/core@7.24.0):
-    resolution: {integrity: sha512-V3Q3EqoQdn65RCgTLwauZaTfd1ShhwPmbBv+1dkZV/HpCGMKVyn6oFcRlI7RaKqiDQjX2Qd3AuoEguBgdjIKlg==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  '@babel/register@7.22.15(@babel/core@7.24.0)':
     dependencies:
       '@babel/core': 7.24.0
       clone-deep: 4.0.1
@@ -3294,39 +12493,26 @@ packages:
       make-dir: 2.1.0
       pirates: 4.0.5
       source-map-support: 0.5.21
-    dev: true
 
-  /@babel/regjsgen@0.8.0:
-    resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==}
-    dev: true
+  '@babel/regjsgen@0.8.0': {}
 
-  /@babel/runtime@7.23.4:
-    resolution: {integrity: sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg==}
-    engines: {node: '>=6.9.0'}
+  '@babel/runtime@7.23.4':
     dependencies:
       regenerator-runtime: 0.14.0
 
-  /@babel/template@7.22.15:
-    resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==}
-    engines: {node: '>=6.9.0'}
+  '@babel/template@7.22.15':
     dependencies:
       '@babel/code-frame': 7.23.5
       '@babel/parser': 7.23.9
       '@babel/types': 7.23.5
-    dev: true
 
-  /@babel/template@7.24.0:
-    resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==}
-    engines: {node: '>=6.9.0'}
+  '@babel/template@7.24.0':
     dependencies:
       '@babel/code-frame': 7.23.5
       '@babel/parser': 7.24.0
       '@babel/types': 7.24.0
-    dev: true
 
-  /@babel/traverse@7.23.5:
-    resolution: {integrity: sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==}
-    engines: {node: '>=6.9.0'}
+  '@babel/traverse@7.23.5':
     dependencies:
       '@babel/code-frame': 7.23.5
       '@babel/generator': 7.23.5
@@ -3340,11 +12526,8 @@ packages:
       globals: 11.12.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@babel/traverse@7.24.0:
-    resolution: {integrity: sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==}
-    engines: {node: '>=6.9.0'}
+  '@babel/traverse@7.24.0':
     dependencies:
       '@babel/code-frame': 7.23.5
       '@babel/generator': 7.23.6
@@ -3358,172 +12541,120 @@ packages:
       globals: 11.12.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@babel/types@7.23.5:
-    resolution: {integrity: sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==}
-    engines: {node: '>=6.9.0'}
+  '@babel/types@7.23.5':
     dependencies:
       '@babel/helper-string-parser': 7.23.4
       '@babel/helper-validator-identifier': 7.22.20
       to-fast-properties: 2.0.0
 
-  /@babel/types@7.24.0:
-    resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==}
-    engines: {node: '>=6.9.0'}
+  '@babel/types@7.24.0':
     dependencies:
       '@babel/helper-string-parser': 7.23.4
       '@babel/helper-validator-identifier': 7.22.20
       to-fast-properties: 2.0.0
-    dev: true
 
-  /@base2/pretty-print-object@1.0.1:
-    resolution: {integrity: sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==}
-    dev: true
+  '@base2/pretty-print-object@1.0.1': {}
 
-  /@bcoe/v8-coverage@0.2.3:
-    resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
-    dev: true
+  '@bcoe/v8-coverage@0.2.3': {}
 
-  /@bull-board/api@5.14.2(@bull-board/ui@5.14.2):
-    resolution: {integrity: sha512-0wppAGPU7ZMwWMpzkmtrlmm7ySI5immymyaRS1cVNJ54rUiGOZP5tnm+Sj7MwPdf63rxqIM843un8+PvQyARGg==}
-    peerDependencies:
-      '@bull-board/ui': 5.14.2
+  '@bull-board/api@5.17.0(@bull-board/ui@5.17.0)':
     dependencies:
-      '@bull-board/ui': 5.14.2
+      '@bull-board/ui': 5.17.0
       redis-info: 3.1.0
-    dev: false
 
-  /@bull-board/fastify@5.14.2:
-    resolution: {integrity: sha512-GQMK70tKOu2gjBi2pjWXMXcftzWRvQNSm+deLmGlJUgqUUbNlzIGRyvaTk7giT4CFzgKcP+hT+lphcAsGTKBQw==}
+  '@bull-board/fastify@5.17.0':
     dependencies:
-      '@bull-board/api': 5.14.2(@bull-board/ui@5.14.2)
-      '@bull-board/ui': 5.14.2
+      '@bull-board/api': 5.17.0(@bull-board/ui@5.17.0)
+      '@bull-board/ui': 5.17.0
       '@fastify/static': 6.12.0
       '@fastify/view': 8.2.0
       ejs: 3.1.9
-    dev: false
 
-  /@bull-board/ui@5.14.2:
-    resolution: {integrity: sha512-NiyKWLjKjy29I6ySCnSYbzGX4ZJyPE4xlS5/Z5dVsF2bJLoAV+yD1obflxteJMt60FiEgLV7tfs6tMSVa+Htew==}
+  '@bull-board/ui@5.17.0':
     dependencies:
-      '@bull-board/api': 5.14.2(@bull-board/ui@5.14.2)
-    dev: false
+      '@bull-board/api': 5.17.0(@bull-board/ui@5.17.0)
 
-  /@bundled-es-modules/cookie@2.0.0:
-    resolution: {integrity: sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==}
+  '@bundled-es-modules/cookie@2.0.0':
     dependencies:
       cookie: 0.5.0
-    dev: true
 
-  /@bundled-es-modules/statuses@1.0.1:
-    resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==}
+  '@bundled-es-modules/statuses@1.0.1':
     dependencies:
       statuses: 2.0.1
-    dev: true
 
-  /@canvas/image-data@1.0.0:
-    resolution: {integrity: sha512-BxOqI5LgsIQP1odU5KMwV9yoijleOPzHL18/YvNqF9KFSGF2K/DLlYAbDQsWqd/1nbaFuSkYD/191dpMtNh4vw==}
-    dev: false
+  '@canvas/image-data@1.0.0': {}
 
-  /@colors/colors@1.5.0:
-    resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
-    engines: {node: '>=0.1.90'}
-    requiresBuild: true
-    dev: true
+  '@colors/colors@1.5.0':
     optional: true
 
-  /@cropper/element-canvas@2.0.0-beta.4:
-    resolution: {integrity: sha512-xL7k5YgtbCLdR/QEj81An4HpPcBTJXf1lq+2xisyHALGeUKQXjA9cJQL7bldYscHAKjmFgNZ5xOMrNaYM++qZw==}
+  '@cropper/element-canvas@2.0.0-beta.5':
     dependencies:
-      '@cropper/element': 2.0.0-beta.4
-      '@cropper/utils': 2.0.0-beta.4
-    dev: false
+      '@cropper/element': 2.0.0-beta.5
+      '@cropper/utils': 2.0.0-beta.5
 
-  /@cropper/element-crosshair@2.0.0-beta.4:
-    resolution: {integrity: sha512-NiwIQZFh963i3E3QbXFiU9oNqs+P1cLJur3+e+DK0E3oLTa7rEfcigP/ZoMj/3DZ9Et0LPhKKRDY2SJ8ZszyPA==}
+  '@cropper/element-crosshair@2.0.0-beta.5':
     dependencies:
-      '@cropper/element': 2.0.0-beta.4
-      '@cropper/utils': 2.0.0-beta.4
-    dev: false
+      '@cropper/element': 2.0.0-beta.5
+      '@cropper/utils': 2.0.0-beta.5
 
-  /@cropper/element-grid@2.0.0-beta.4:
-    resolution: {integrity: sha512-uMVVNk1SICwM2nA/7BHkyEojc0DAqsDFIUnC/sIGPtNf3fe5hYQyukby8BEPO7dlqzfIXYmnxacgLaPM9BZ7GQ==}
+  '@cropper/element-grid@2.0.0-beta.5':
     dependencies:
-      '@cropper/element': 2.0.0-beta.4
-      '@cropper/utils': 2.0.0-beta.4
-    dev: false
+      '@cropper/element': 2.0.0-beta.5
+      '@cropper/utils': 2.0.0-beta.5
 
-  /@cropper/element-handle@2.0.0-beta.4:
-    resolution: {integrity: sha512-PHjC4ptBi0leQ82mPWvivNilNOpiBnV90ueqz99tli8f9bQobx+Os7dzKFwLIpj4WKCNRYhyEvxf1KuKhQisIg==}
+  '@cropper/element-handle@2.0.0-beta.5':
     dependencies:
-      '@cropper/element': 2.0.0-beta.4
-      '@cropper/utils': 2.0.0-beta.4
-    dev: false
+      '@cropper/element': 2.0.0-beta.5
+      '@cropper/utils': 2.0.0-beta.5
 
-  /@cropper/element-image@2.0.0-beta.4:
-    resolution: {integrity: sha512-Nu5z5EFpyOEC2CAdhNZGfvpG9Xj6ZD46jvpJGKxsel7J7Kqf4qy+5m6nNdq2J+lK7YfTi16svkHeFwzNWZYLAA==}
+  '@cropper/element-image@2.0.0-beta.5':
     dependencies:
-      '@cropper/element': 2.0.0-beta.4
-      '@cropper/element-canvas': 2.0.0-beta.4
-      '@cropper/utils': 2.0.0-beta.4
-    dev: false
+      '@cropper/element': 2.0.0-beta.5
+      '@cropper/element-canvas': 2.0.0-beta.5
+      '@cropper/utils': 2.0.0-beta.5
 
-  /@cropper/element-selection@2.0.0-beta.4:
-    resolution: {integrity: sha512-wHZhWI80cC5TfFHI/2HT1A+ZbHifnAO+/IAr4IqkbaxtDZ9duqEvM2hhC+ZXgB3BYqVidAJNwpSnZkVK+DlJ6A==}
+  '@cropper/element-selection@2.0.0-beta.5':
     dependencies:
-      '@cropper/element': 2.0.0-beta.4
-      '@cropper/element-canvas': 2.0.0-beta.4
-      '@cropper/element-image': 2.0.0-beta.4
-      '@cropper/utils': 2.0.0-beta.4
-    dev: false
+      '@cropper/element': 2.0.0-beta.5
+      '@cropper/element-canvas': 2.0.0-beta.5
+      '@cropper/element-image': 2.0.0-beta.5
+      '@cropper/utils': 2.0.0-beta.5
 
-  /@cropper/element-shade@2.0.0-beta.4:
-    resolution: {integrity: sha512-sTFTzlmu+Z31Hp7RHgUAxfDsRIQ/uG8RueOBBHLeKVGFZbYhsIElQaLcVDwebgqXLHVr9imCEvvIX11JeTqiTQ==}
+  '@cropper/element-shade@2.0.0-beta.5':
     dependencies:
-      '@cropper/element': 2.0.0-beta.4
-      '@cropper/element-canvas': 2.0.0-beta.4
-      '@cropper/element-selection': 2.0.0-beta.4
-      '@cropper/utils': 2.0.0-beta.4
-    dev: false
+      '@cropper/element': 2.0.0-beta.5
+      '@cropper/element-canvas': 2.0.0-beta.5
+      '@cropper/element-selection': 2.0.0-beta.5
+      '@cropper/utils': 2.0.0-beta.5
 
-  /@cropper/element-viewer@2.0.0-beta.4:
-    resolution: {integrity: sha512-bXW8OuezoHjyGFmQzX1QEj3OqvmSZwaLiQts+mVhcarYqAEVrK9s/bC/OqZKR2ZKkHeaiGWq+rTOBVAmhZja/A==}
+  '@cropper/element-viewer@2.0.0-beta.5':
     dependencies:
-      '@cropper/element': 2.0.0-beta.4
-      '@cropper/element-canvas': 2.0.0-beta.4
-      '@cropper/element-image': 2.0.0-beta.4
-      '@cropper/element-selection': 2.0.0-beta.4
-      '@cropper/utils': 2.0.0-beta.4
-    dev: false
+      '@cropper/element': 2.0.0-beta.5
+      '@cropper/element-canvas': 2.0.0-beta.5
+      '@cropper/element-image': 2.0.0-beta.5
+      '@cropper/element-selection': 2.0.0-beta.5
+      '@cropper/utils': 2.0.0-beta.5
 
-  /@cropper/element@2.0.0-beta.4:
-    resolution: {integrity: sha512-1P8Vm9+OqTQz4B/rEA0t8xmzKUkYyxzxTiOaDMPKjKbG2R3UZgJBWRzvTgTsDudld9vlR6FfXpDBU1ZWA1BWxQ==}
+  '@cropper/element@2.0.0-beta.5':
     dependencies:
-      '@cropper/utils': 2.0.0-beta.4
-    dev: false
+      '@cropper/utils': 2.0.0-beta.5
 
-  /@cropper/elements@2.0.0-beta.4:
-    resolution: {integrity: sha512-cXKNFwudKcFrxn75VU9nLWNpjUnHcY0rUvtLn+2YVOLAnCTFLlu+azjOW1XZJ01FAEcC62Itb4CvDae+qgDpcQ==}
+  '@cropper/elements@2.0.0-beta.5':
     dependencies:
-      '@cropper/element': 2.0.0-beta.4
-      '@cropper/element-canvas': 2.0.0-beta.4
-      '@cropper/element-crosshair': 2.0.0-beta.4
-      '@cropper/element-grid': 2.0.0-beta.4
-      '@cropper/element-handle': 2.0.0-beta.4
-      '@cropper/element-image': 2.0.0-beta.4
-      '@cropper/element-selection': 2.0.0-beta.4
-      '@cropper/element-shade': 2.0.0-beta.4
-      '@cropper/element-viewer': 2.0.0-beta.4
-    dev: false
+      '@cropper/element': 2.0.0-beta.5
+      '@cropper/element-canvas': 2.0.0-beta.5
+      '@cropper/element-crosshair': 2.0.0-beta.5
+      '@cropper/element-grid': 2.0.0-beta.5
+      '@cropper/element-handle': 2.0.0-beta.5
+      '@cropper/element-image': 2.0.0-beta.5
+      '@cropper/element-selection': 2.0.0-beta.5
+      '@cropper/element-shade': 2.0.0-beta.5
+      '@cropper/element-viewer': 2.0.0-beta.5
 
-  /@cropper/utils@2.0.0-beta.4:
-    resolution: {integrity: sha512-mrUTA3LbEq1Y3nPTC5X6koTd2Dk8P+6xTuhp4P8X3mg5Z7d8AVK+0OU5kbB49OLAaEfvGEqbZJ84rLwgMy9RHw==}
-    dev: false
+  '@cropper/utils@2.0.0-beta.5': {}
 
-  /@cypress/request@3.0.0:
-    resolution: {integrity: sha512-GKFCqwZwMYmL3IBoNeR2MM1SnxRIGERsQOTWeQKoYBt2JLqcqiy7JXqO894FLrpjZYqGxW92MNwRH2BN56obdQ==}
-    engines: {node: '>= 6'}
+  '@cypress/request@3.0.0':
     dependencies:
       aws-sign2: 0.7.0
       aws4: 1.12.0
@@ -3543,468 +12674,259 @@ packages:
       tough-cookie: 4.1.3
       tunnel-agent: 0.6.0
       uuid: 8.3.2
-    dev: true
 
-  /@cypress/xvfb@1.2.4(supports-color@8.1.1):
-    resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==}
+  '@cypress/xvfb@1.2.4(supports-color@8.1.1)':
     dependencies:
       debug: 3.2.7(supports-color@8.1.1)
       lodash.once: 4.1.1
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@digitalbazaar/http-client@3.4.1:
-    resolution: {integrity: sha512-Ahk1N+s7urkgj7WvvUND5f8GiWEPfUw0D41hdElaqLgu8wZScI8gdI0q+qWw5N1d35x7GCRH2uk9mi+Uzo9M3g==}
-    engines: {node: '>=14.0'}
+  '@digitalbazaar/http-client@3.4.1(web-streams-polyfill@3.2.1)':
     dependencies:
       ky: 0.33.3
-      ky-universal: 0.11.0(ky@0.33.3)
+      ky-universal: 0.11.0(ky@0.33.3)(web-streams-polyfill@3.2.1)
       undici: 5.28.2
     transitivePeerDependencies:
       - web-streams-polyfill
-    dev: false
 
-  /@discordapp/twemoji@15.0.2:
-    resolution: {integrity: sha512-SrWKcv3SrGfrLQ/vfUnA+bAG73Q6Yjys01UuoY5SzUlc9iS03amQ6DxLhzVsjW/aTdgiMQdUatLidD+YPfYMCw==}
+  '@discordapp/twemoji@15.0.3':
     dependencies:
       '@twemoji/parser': 15.0.0
       fs-extra: 8.1.0
       jsonfile: 5.0.0
       universalify: 0.1.2
-    dev: false
 
-  /@discoveryjs/json-ext@0.5.7:
-    resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==}
-    engines: {node: '>=10.0.0'}
-    dev: true
+  '@discoveryjs/json-ext@0.5.7': {}
 
-  /@emnapi/runtime@0.45.0:
-    resolution: {integrity: sha512-Txumi3td7J4A/xTTwlssKieHKTGl3j4A1tglBx72auZ49YK7ePY6XZricgIg9mnZT4xPfA+UPCUdnhRuEFDL+w==}
-    requiresBuild: true
+  '@emnapi/runtime@1.1.1':
     dependencies:
       tslib: 2.6.2
-    dev: false
     optional: true
 
-  /@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.2.0):
-    resolution: {integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==}
-    peerDependencies:
-      react: '>=16.8.0'
+  '@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.3.1)':
     dependencies:
-      react: 18.2.0
-    dev: true
+      react: 18.3.1
 
-  /@esbuild/aix-ppc64@0.19.11:
-    resolution: {integrity: sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==}
-    engines: {node: '>=12'}
-    cpu: [ppc64]
-    os: [aix]
-    requiresBuild: true
+  '@esbuild/aix-ppc64@0.19.11':
     optional: true
 
-  /@esbuild/android-arm64@0.18.20:
-    resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [android]
-    requiresBuild: true
-    dev: true
+  '@esbuild/aix-ppc64@0.20.2':
     optional: true
 
-  /@esbuild/android-arm64@0.19.11:
-    resolution: {integrity: sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [android]
-    requiresBuild: true
+  '@esbuild/android-arm64@0.18.20':
     optional: true
 
-  /@esbuild/android-arm@0.18.20:
-    resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==}
-    engines: {node: '>=12'}
-    cpu: [arm]
-    os: [android]
-    requiresBuild: true
-    dev: true
+  '@esbuild/android-arm64@0.19.11':
     optional: true
 
-  /@esbuild/android-arm@0.19.11:
-    resolution: {integrity: sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==}
-    engines: {node: '>=12'}
-    cpu: [arm]
-    os: [android]
-    requiresBuild: true
+  '@esbuild/android-arm64@0.20.2':
     optional: true
 
-  /@esbuild/android-x64@0.18.20:
-    resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [android]
-    requiresBuild: true
-    dev: true
+  '@esbuild/android-arm@0.18.20':
     optional: true
 
-  /@esbuild/android-x64@0.19.11:
-    resolution: {integrity: sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [android]
-    requiresBuild: true
+  '@esbuild/android-arm@0.19.11':
     optional: true
 
-  /@esbuild/darwin-arm64@0.18.20:
-    resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
-    dev: true
+  '@esbuild/android-arm@0.20.2':
     optional: true
 
-  /@esbuild/darwin-arm64@0.19.11:
-    resolution: {integrity: sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
+  '@esbuild/android-x64@0.18.20':
     optional: true
 
-  /@esbuild/darwin-x64@0.18.20:
-    resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
-    dev: true
+  '@esbuild/android-x64@0.19.11':
     optional: true
 
-  /@esbuild/darwin-x64@0.19.11:
-    resolution: {integrity: sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
+  '@esbuild/android-x64@0.20.2':
     optional: true
 
-  /@esbuild/freebsd-arm64@0.18.20:
-    resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [freebsd]
-    requiresBuild: true
-    dev: true
+  '@esbuild/darwin-arm64@0.18.20':
     optional: true
 
-  /@esbuild/freebsd-arm64@0.19.11:
-    resolution: {integrity: sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [freebsd]
-    requiresBuild: true
+  '@esbuild/darwin-arm64@0.19.11':
     optional: true
 
-  /@esbuild/freebsd-x64@0.18.20:
-    resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [freebsd]
-    requiresBuild: true
-    dev: true
+  '@esbuild/darwin-arm64@0.20.2':
     optional: true
 
-  /@esbuild/freebsd-x64@0.19.11:
-    resolution: {integrity: sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [freebsd]
-    requiresBuild: true
+  '@esbuild/darwin-x64@0.18.20':
     optional: true
 
-  /@esbuild/linux-arm64@0.18.20:
-    resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
+  '@esbuild/darwin-x64@0.19.11':
     optional: true
 
-  /@esbuild/linux-arm64@0.19.11:
-    resolution: {integrity: sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
+  '@esbuild/darwin-x64@0.20.2':
     optional: true
 
-  /@esbuild/linux-arm@0.18.20:
-    resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==}
-    engines: {node: '>=12'}
-    cpu: [arm]
-    os: [linux]
-    requiresBuild: true
-    dev: true
+  '@esbuild/freebsd-arm64@0.18.20':
     optional: true
 
-  /@esbuild/linux-arm@0.19.11:
-    resolution: {integrity: sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==}
-    engines: {node: '>=12'}
-    cpu: [arm]
-    os: [linux]
-    requiresBuild: true
+  '@esbuild/freebsd-arm64@0.19.11':
     optional: true
 
-  /@esbuild/linux-ia32@0.18.20:
-    resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==}
-    engines: {node: '>=12'}
-    cpu: [ia32]
-    os: [linux]
-    requiresBuild: true
-    dev: true
+  '@esbuild/freebsd-arm64@0.20.2':
     optional: true
 
-  /@esbuild/linux-ia32@0.19.11:
-    resolution: {integrity: sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==}
-    engines: {node: '>=12'}
-    cpu: [ia32]
-    os: [linux]
-    requiresBuild: true
+  '@esbuild/freebsd-x64@0.18.20':
     optional: true
 
-  /@esbuild/linux-loong64@0.18.20:
-    resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==}
-    engines: {node: '>=12'}
-    cpu: [loong64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
+  '@esbuild/freebsd-x64@0.19.11':
     optional: true
 
-  /@esbuild/linux-loong64@0.19.11:
-    resolution: {integrity: sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==}
-    engines: {node: '>=12'}
-    cpu: [loong64]
-    os: [linux]
-    requiresBuild: true
+  '@esbuild/freebsd-x64@0.20.2':
     optional: true
 
-  /@esbuild/linux-mips64el@0.18.20:
-    resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==}
-    engines: {node: '>=12'}
-    cpu: [mips64el]
-    os: [linux]
-    requiresBuild: true
-    dev: true
+  '@esbuild/linux-arm64@0.18.20':
     optional: true
 
-  /@esbuild/linux-mips64el@0.19.11:
-    resolution: {integrity: sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==}
-    engines: {node: '>=12'}
-    cpu: [mips64el]
-    os: [linux]
-    requiresBuild: true
+  '@esbuild/linux-arm64@0.19.11':
     optional: true
 
-  /@esbuild/linux-ppc64@0.18.20:
-    resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==}
-    engines: {node: '>=12'}
-    cpu: [ppc64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
+  '@esbuild/linux-arm64@0.20.2':
     optional: true
 
-  /@esbuild/linux-ppc64@0.19.11:
-    resolution: {integrity: sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==}
-    engines: {node: '>=12'}
-    cpu: [ppc64]
-    os: [linux]
-    requiresBuild: true
+  '@esbuild/linux-arm@0.18.20':
     optional: true
 
-  /@esbuild/linux-riscv64@0.18.20:
-    resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==}
-    engines: {node: '>=12'}
-    cpu: [riscv64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
+  '@esbuild/linux-arm@0.19.11':
     optional: true
 
-  /@esbuild/linux-riscv64@0.19.11:
-    resolution: {integrity: sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==}
-    engines: {node: '>=12'}
-    cpu: [riscv64]
-    os: [linux]
-    requiresBuild: true
+  '@esbuild/linux-arm@0.20.2':
     optional: true
 
-  /@esbuild/linux-s390x@0.18.20:
-    resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==}
-    engines: {node: '>=12'}
-    cpu: [s390x]
-    os: [linux]
-    requiresBuild: true
-    dev: true
+  '@esbuild/linux-ia32@0.18.20':
     optional: true
 
-  /@esbuild/linux-s390x@0.19.11:
-    resolution: {integrity: sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==}
-    engines: {node: '>=12'}
-    cpu: [s390x]
-    os: [linux]
-    requiresBuild: true
+  '@esbuild/linux-ia32@0.19.11':
     optional: true
 
-  /@esbuild/linux-x64@0.18.20:
-    resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
+  '@esbuild/linux-ia32@0.20.2':
     optional: true
 
-  /@esbuild/linux-x64@0.19.11:
-    resolution: {integrity: sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
+  '@esbuild/linux-loong64@0.18.20':
     optional: true
 
-  /@esbuild/netbsd-x64@0.18.20:
-    resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [netbsd]
-    requiresBuild: true
-    dev: true
+  '@esbuild/linux-loong64@0.19.11':
     optional: true
 
-  /@esbuild/netbsd-x64@0.19.11:
-    resolution: {integrity: sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [netbsd]
-    requiresBuild: true
+  '@esbuild/linux-loong64@0.20.2':
     optional: true
 
-  /@esbuild/openbsd-x64@0.18.20:
-    resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [openbsd]
-    requiresBuild: true
-    dev: true
+  '@esbuild/linux-mips64el@0.18.20':
     optional: true
 
-  /@esbuild/openbsd-x64@0.19.11:
-    resolution: {integrity: sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [openbsd]
-    requiresBuild: true
+  '@esbuild/linux-mips64el@0.19.11':
     optional: true
 
-  /@esbuild/sunos-x64@0.18.20:
-    resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [sunos]
-    requiresBuild: true
-    dev: true
+  '@esbuild/linux-mips64el@0.20.2':
     optional: true
 
-  /@esbuild/sunos-x64@0.19.11:
-    resolution: {integrity: sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [sunos]
-    requiresBuild: true
+  '@esbuild/linux-ppc64@0.18.20':
     optional: true
 
-  /@esbuild/win32-arm64@0.18.20:
-    resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [win32]
-    requiresBuild: true
-    dev: true
+  '@esbuild/linux-ppc64@0.19.11':
     optional: true
 
-  /@esbuild/win32-arm64@0.19.11:
-    resolution: {integrity: sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [win32]
-    requiresBuild: true
+  '@esbuild/linux-ppc64@0.20.2':
     optional: true
 
-  /@esbuild/win32-ia32@0.18.20:
-    resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==}
-    engines: {node: '>=12'}
-    cpu: [ia32]
-    os: [win32]
-    requiresBuild: true
-    dev: true
+  '@esbuild/linux-riscv64@0.18.20':
     optional: true
 
-  /@esbuild/win32-ia32@0.19.11:
-    resolution: {integrity: sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==}
-    engines: {node: '>=12'}
-    cpu: [ia32]
-    os: [win32]
-    requiresBuild: true
+  '@esbuild/linux-riscv64@0.19.11':
     optional: true
 
-  /@esbuild/win32-x64@0.18.20:
-    resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [win32]
-    requiresBuild: true
-    dev: true
+  '@esbuild/linux-riscv64@0.20.2':
     optional: true
 
-  /@esbuild/win32-x64@0.19.11:
-    resolution: {integrity: sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [win32]
-    requiresBuild: true
+  '@esbuild/linux-s390x@0.18.20':
     optional: true
 
-  /@eslint-community/eslint-utils@4.4.0(eslint@8.53.0):
-    resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
-    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-    peerDependencies:
-      eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+  '@esbuild/linux-s390x@0.19.11':
+    optional: true
+
+  '@esbuild/linux-s390x@0.20.2':
+    optional: true
+
+  '@esbuild/linux-x64@0.18.20':
+    optional: true
+
+  '@esbuild/linux-x64@0.19.11':
+    optional: true
+
+  '@esbuild/linux-x64@0.20.2':
+    optional: true
+
+  '@esbuild/netbsd-x64@0.18.20':
+    optional: true
+
+  '@esbuild/netbsd-x64@0.19.11':
+    optional: true
+
+  '@esbuild/netbsd-x64@0.20.2':
+    optional: true
+
+  '@esbuild/openbsd-x64@0.18.20':
+    optional: true
+
+  '@esbuild/openbsd-x64@0.19.11':
+    optional: true
+
+  '@esbuild/openbsd-x64@0.20.2':
+    optional: true
+
+  '@esbuild/sunos-x64@0.18.20':
+    optional: true
+
+  '@esbuild/sunos-x64@0.19.11':
+    optional: true
+
+  '@esbuild/sunos-x64@0.20.2':
+    optional: true
+
+  '@esbuild/win32-arm64@0.18.20':
+    optional: true
+
+  '@esbuild/win32-arm64@0.19.11':
+    optional: true
+
+  '@esbuild/win32-arm64@0.20.2':
+    optional: true
+
+  '@esbuild/win32-ia32@0.18.20':
+    optional: true
+
+  '@esbuild/win32-ia32@0.19.11':
+    optional: true
+
+  '@esbuild/win32-ia32@0.20.2':
+    optional: true
+
+  '@esbuild/win32-x64@0.18.20':
+    optional: true
+
+  '@esbuild/win32-x64@0.19.11':
+    optional: true
+
+  '@esbuild/win32-x64@0.20.2':
+    optional: true
+
+  '@eslint-community/eslint-utils@4.4.0(eslint@8.53.0)':
     dependencies:
       eslint: 8.53.0
       eslint-visitor-keys: 3.4.3
-    dev: true
 
-  /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0):
-    resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
-    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-    peerDependencies:
-      eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+  '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)':
     dependencies:
       eslint: 8.57.0
       eslint-visitor-keys: 3.4.3
-    dev: true
 
-  /@eslint-community/regexpp@4.6.2:
-    resolution: {integrity: sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==}
-    engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
-    dev: true
+  '@eslint-community/regexpp@4.10.0': {}
 
-  /@eslint/eslintrc@2.1.4:
-    resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
-    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+  '@eslint-community/regexpp@4.6.2': {}
+
+  '@eslint/eslintrc@2.1.4':
     dependencies:
       ajv: 6.12.6
       debug: 4.3.4(supports-color@8.1.1)
@@ -4017,115 +12939,73 @@ packages:
       strip-json-comments: 3.1.1
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@eslint/js@8.53.0:
-    resolution: {integrity: sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==}
-    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-    dev: true
+  '@eslint/js@8.53.0': {}
 
-  /@eslint/js@8.57.0:
-    resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==}
-    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-    dev: true
+  '@eslint/js@8.57.0': {}
 
-  /@fal-works/esbuild-plugin-global-externals@2.1.2:
-    resolution: {integrity: sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==}
-    dev: true
+  '@fal-works/esbuild-plugin-global-externals@2.1.2': {}
 
-  /@fastify/accept-negotiator@1.0.0:
-    resolution: {integrity: sha512-4R/N2KfYeld7A5LGkai+iUFMahXcxxYbDp+XS2B1yuL3cdmZLJ9TlCnNzT3q5xFTqsYm0GPpinLUwfSwjcVjyA==}
-    engines: {node: '>=14'}
-    dev: false
+  '@fastify/accept-negotiator@1.0.0': {}
 
-  /@fastify/accepts@4.3.0:
-    resolution: {integrity: sha512-QK4FoqXdwwPmaPOLL6NrxsyaXVvdviYVoS6ltHyOLdFlUyREIaMykHQIp+x0aJz9hB3B3n/Ht6QRdvBeGkptGQ==}
+  '@fastify/accepts@4.3.0':
     dependencies:
       accepts: 1.3.8
       fastify-plugin: 4.5.0
-    dev: false
 
-  /@fastify/ajv-compiler@3.5.0:
-    resolution: {integrity: sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==}
+  '@fastify/ajv-compiler@3.5.0':
     dependencies:
-      ajv: 8.12.0
-      ajv-formats: 2.1.1(ajv@8.12.0)
+      ajv: 8.13.0
+      ajv-formats: 2.1.1(ajv@8.13.0)
       fast-uri: 2.2.0
-    dev: false
 
-  /@fastify/busboy@1.1.0:
-    resolution: {integrity: sha512-Fv854f94v0CzIDllbY3i/0NJPNBRNLDawf3BTYVGCe9VrIIs3Wi7AFx24F9NzCxdf0wyx/x0Q9kEVnvDOPnlxA==}
-    engines: {node: '>=10.17.0'}
-    dependencies:
-      text-decoding: 1.0.0
-    dev: false
+  '@fastify/busboy@2.1.0': {}
 
-  /@fastify/busboy@2.1.0:
-    resolution: {integrity: sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==}
-    engines: {node: '>=14'}
-
-  /@fastify/cookie@9.3.1:
-    resolution: {integrity: sha512-h1NAEhB266+ZbZ0e9qUE6NnNR07i7DnNXWG9VbbZ8uC6O/hxHpl+Zoe5sw1yfdZ2U6XhToUGDnzQtWJdCaPwfg==}
+  '@fastify/cookie@9.3.1':
     dependencies:
       cookie-signature: 1.2.1
       fastify-plugin: 4.5.0
-    dev: false
 
-  /@fastify/cors@8.5.0:
-    resolution: {integrity: sha512-/oZ1QSb02XjP0IK1U0IXktEsw/dUBTxJOW7IpIeO8c/tNalw/KjoNSJv1Sf6eqoBPO+TDGkifq6ynFK3v68HFQ==}
+  '@fastify/cors@9.0.1':
     dependencies:
       fastify-plugin: 4.5.0
       mnemonist: 0.39.6
-    dev: false
 
-  /@fastify/deepmerge@1.3.0:
-    resolution: {integrity: sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A==}
-    dev: false
+  '@fastify/deepmerge@1.3.0': {}
 
-  /@fastify/error@3.4.0:
-    resolution: {integrity: sha512-e/mafFwbK3MNqxUcFBLgHhgxsF8UT1m8aj0dAlqEa2nJEgPsRtpHTZ3ObgrgkZ2M1eJHPTwgyUl/tXkvabsZdQ==}
-    dev: false
+  '@fastify/error@3.4.0': {}
 
-  /@fastify/express@2.3.0:
-    resolution: {integrity: sha512-jvvjlPPCfJsSHfF6tQDyARJ3+c3xXiqcxVZu6bi3xMWCWB3fl07vrjFDeaqnwqKhLZ9+m6cog5dw7gIMKEsTnQ==}
+  '@fastify/express@3.0.0':
     dependencies:
-      express: 4.18.2
+      express: 4.19.2
       fastify-plugin: 4.5.0
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /@fastify/fast-json-stringify-compiler@4.3.0:
-    resolution: {integrity: sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==}
+  '@fastify/fast-json-stringify-compiler@4.3.0':
     dependencies:
       fast-json-stringify: 5.8.0
-    dev: false
 
-  /@fastify/http-proxy@9.3.0(bufferutil@4.0.7)(utf-8-validate@6.0.3):
-    resolution: {integrity: sha512-fQkdgwco8q7eI2PQA8lH++y3Q+hNlIByBYsphl+r4FKRbmrU7ey4WOA/CA9tBhe4oEojGpa3eTU4jXvqf2DBuQ==}
+  '@fastify/http-proxy@9.5.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)':
     dependencies:
       '@fastify/reply-from': 9.0.1
       fast-querystring: 1.1.2
       fastify-plugin: 4.5.0
-      ws: 8.16.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
+      ws: 8.17.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
     transitivePeerDependencies:
       - bufferutil
       - utf-8-validate
-    dev: false
 
-  /@fastify/multipart@8.1.0:
-    resolution: {integrity: sha512-sRX9X4ZhAqRbe2kDvXY2NK7i6Wf1Rm2g/CjpGYYM7+Np8E6uWQXcj761j08qPfPO8PJXM+vJ7yrKbK1GPB+OeQ==}
+  '@fastify/multipart@8.2.0':
     dependencies:
-      '@fastify/busboy': 1.1.0
+      '@fastify/busboy': 2.1.0
       '@fastify/deepmerge': 1.3.0
       '@fastify/error': 3.4.0
       fastify-plugin: 4.5.0
       secure-json-parse: 2.7.0
       stream-wormhole: 1.1.0
-    dev: false
 
-  /@fastify/reply-from@9.0.1:
-    resolution: {integrity: sha512-q9vFNUiXZTY1x8omDPe59os2MYq+3y7KgO/kZoXpZlnud+45Nd8Ot/svEvrUATzjkizIggfS4K8LR9zXDyZZKg==}
+  '@fastify/reply-from@9.0.1':
     dependencies:
       '@fastify/error': 3.4.0
       end-of-stream: 1.4.4
@@ -4134,20 +13014,16 @@ packages:
       pump: 3.0.0
       tiny-lru: 10.0.1
       undici: 5.28.2
-    dev: false
 
-  /@fastify/send@2.0.1:
-    resolution: {integrity: sha512-8jdouu0o5d0FMq1+zCKeKXc1tmOQ5tTGYdQP3MpyF9+WWrZT1KCBdh6hvoEYxOm3oJG/akdE9BpehLiJgYRvGw==}
+  '@fastify/send@2.0.1':
     dependencies:
       '@lukeed/ms': 2.0.1
       escape-html: 1.0.3
       fast-decode-uri-component: 1.0.1
       http-errors: 2.0.0
       mime: 3.0.0
-    dev: false
 
-  /@fastify/static@6.12.0:
-    resolution: {integrity: sha512-KK1B84E6QD/FcQWxDI2aiUCwHxMJBI1KeCUzm1BwYpPY1b742+jeKruGHP2uOluuM6OkBPI8CIANrXcCRtC2oQ==}
+  '@fastify/static@6.12.0':
     dependencies:
       '@fastify/accept-negotiator': 1.0.0
       '@fastify/send': 2.0.1
@@ -4155,353 +13031,233 @@ packages:
       fastify-plugin: 4.5.0
       glob: 8.1.0
       p-limit: 3.1.0
-    dev: false
 
-  /@fastify/view@8.2.0:
-    resolution: {integrity: sha512-hBSiBofCnJNlPHEMZWpO1SL84eqOaqujJ1hR3jntFyZZCkweH5jMs12DKYyGesjVll7SJFRRxPUBB8kmUmneRQ==}
+  '@fastify/static@7.0.3':
+    dependencies:
+      '@fastify/accept-negotiator': 1.0.0
+      '@fastify/send': 2.0.1
+      content-disposition: 0.5.4
+      fastify-plugin: 4.5.0
+      fastq: 1.17.1
+      glob: 10.3.12
+
+  '@fastify/view@8.2.0':
     dependencies:
       fastify-plugin: 4.5.0
       hashlru: 2.3.0
-    dev: false
 
-  /@github/webauthn-json@2.1.1:
-    resolution: {integrity: sha512-XrftRn4z75SnaJOmZQbt7Mk+IIjqVHw+glDGOxuHwXkZBZh/MBoRS7MHjSZMDaLhT4RjN2VqiEU7EOYleuJWSQ==}
-    hasBin: true
-    dev: false
+  '@fastify/view@9.1.0':
+    dependencies:
+      fastify-plugin: 4.5.0
+      toad-cache: 3.7.0
 
-  /@hapi/boom@10.0.1:
-    resolution: {integrity: sha512-ERcCZaEjdH3OgSJlyjVk8pHIFeus91CjKP3v+MpgBNp5IvGzP2l/bRiD78nqYcKPaZdbKkK5vDBVPd2ohHBlsA==}
+  '@github/webauthn-json@2.1.1': {}
+
+  '@hapi/boom@10.0.1':
     dependencies:
       '@hapi/hoek': 11.0.2
-    dev: true
 
-  /@hapi/bourne@3.0.0:
-    resolution: {integrity: sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==}
-    dev: true
+  '@hapi/bourne@3.0.0': {}
 
-  /@hapi/hoek@10.0.1:
-    resolution: {integrity: sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==}
-    dev: true
+  '@hapi/hoek@10.0.1': {}
 
-  /@hapi/hoek@11.0.2:
-    resolution: {integrity: sha512-aKmlCO57XFZ26wso4rJsW4oTUnrgTFw2jh3io7CAtO9w4UltBNwRXvXIVzzyfkaaLRo3nluP/19msA8vDUUuKw==}
-    dev: true
+  '@hapi/hoek@11.0.2': {}
 
-  /@hapi/hoek@9.3.0:
-    resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==}
-    dev: true
+  '@hapi/hoek@9.3.0': {}
 
-  /@hapi/topo@5.1.0:
-    resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==}
+  '@hapi/topo@5.1.0':
     dependencies:
       '@hapi/hoek': 9.3.0
-    dev: true
 
-  /@hapi/wreck@18.0.1:
-    resolution: {integrity: sha512-OLHER70+rZxvDl75xq3xXOfd3e8XIvz8fWY0dqg92UvhZ29zo24vQgfqgHSYhB5ZiuFpSLeriOisAlxAo/1jWg==}
+  '@hapi/wreck@18.0.1':
     dependencies:
       '@hapi/boom': 10.0.1
       '@hapi/bourne': 3.0.0
       '@hapi/hoek': 11.0.2
-    dev: true
 
-  /@hexagon/base64@1.1.27:
-    resolution: {integrity: sha512-PdUmzpvcUM3Rh39kvz9RdbPVYhMjBjdV7Suw7ZduP7urRLsZR8l5tzgSWKm7TExwBYDFwTnYrZbnE0rQ3N5NLQ==}
-    dev: false
+  '@hexagon/base64@1.1.27': {}
 
-  /@humanwhocodes/config-array@0.11.13:
-    resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==}
-    engines: {node: '>=10.10.0'}
+  '@humanwhocodes/config-array@0.11.13':
     dependencies:
       '@humanwhocodes/object-schema': 2.0.1
       debug: 4.3.4(supports-color@8.1.1)
       minimatch: 3.1.2
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@humanwhocodes/config-array@0.11.14:
-    resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
-    engines: {node: '>=10.10.0'}
+  '@humanwhocodes/config-array@0.11.14':
     dependencies:
       '@humanwhocodes/object-schema': 2.0.2
       debug: 4.3.4(supports-color@8.1.1)
       minimatch: 3.1.2
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@humanwhocodes/module-importer@1.0.1:
-    resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
-    engines: {node: '>=12.22'}
-    dev: true
+  '@humanwhocodes/module-importer@1.0.1': {}
 
-  /@humanwhocodes/momoa@2.0.4:
-    resolution: {integrity: sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==}
-    engines: {node: '>=10.10.0'}
-    dev: true
+  '@humanwhocodes/momoa@2.0.4': {}
 
-  /@humanwhocodes/object-schema@2.0.1:
-    resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
-    dev: true
+  '@humanwhocodes/object-schema@2.0.1': {}
 
-  /@humanwhocodes/object-schema@2.0.2:
-    resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==}
-    dev: true
+  '@humanwhocodes/object-schema@2.0.2': {}
 
-  /@img/sharp-darwin-arm64@0.33.2:
-    resolution: {integrity: sha512-itHBs1rPmsmGF9p4qRe++CzCgd+kFYktnsoR1sbIAfsRMrJZau0Tt1AH9KVnufc2/tU02Gf6Ibujx+15qRE03w==}
-    engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
+  '@img/sharp-darwin-arm64@0.33.3':
     optionalDependencies:
-      '@img/sharp-libvips-darwin-arm64': 1.0.1
-    dev: false
+      '@img/sharp-libvips-darwin-arm64': 1.0.2
     optional: true
 
-  /@img/sharp-darwin-x64@0.33.2:
-    resolution: {integrity: sha512-/rK/69Rrp9x5kaWBjVN07KixZanRr+W1OiyKdXcbjQD6KbW+obaTeBBtLUAtbBsnlTTmWthw99xqoOS7SsySDg==}
-    engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
+  '@img/sharp-darwin-x64@0.33.3':
     optionalDependencies:
-      '@img/sharp-libvips-darwin-x64': 1.0.1
-    dev: false
+      '@img/sharp-libvips-darwin-x64': 1.0.2
     optional: true
 
-  /@img/sharp-libvips-darwin-arm64@1.0.1:
-    resolution: {integrity: sha512-kQyrSNd6lmBV7O0BUiyu/OEw9yeNGFbQhbxswS1i6rMDwBBSX+e+rPzu3S+MwAiGU3HdLze3PanQ4Xkfemgzcw==}
-    engines: {macos: '>=11', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
-    dev: false
+  '@img/sharp-libvips-darwin-arm64@1.0.2':
     optional: true
 
-  /@img/sharp-libvips-darwin-x64@1.0.1:
-    resolution: {integrity: sha512-eVU/JYLPVjhhrd8Tk6gosl5pVlvsqiFlt50wotCvdkFGf+mDNBJxMh+bvav+Wt3EBnNZWq8Sp2I7XfSjm8siog==}
-    engines: {macos: '>=10.13', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
-    dev: false
+  '@img/sharp-libvips-darwin-x64@1.0.2':
     optional: true
 
-  /@img/sharp-libvips-linux-arm64@1.0.1:
-    resolution: {integrity: sha512-bnGG+MJjdX70mAQcSLxgeJco11G+MxTz+ebxlz8Y3dxyeb3Nkl7LgLI0mXupoO+u1wRNx/iRj5yHtzA4sde1yA==}
-    engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  '@img/sharp-libvips-linux-arm64@1.0.2':
     optional: true
 
-  /@img/sharp-libvips-linux-arm@1.0.1:
-    resolution: {integrity: sha512-FtdMvR4R99FTsD53IA3LxYGghQ82t3yt0ZQ93WMZ2xV3dqrb0E8zq4VHaTOuLEAuA83oDawHV3fd+BsAPadHIQ==}
-    engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [arm]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  '@img/sharp-libvips-linux-arm@1.0.2':
     optional: true
 
-  /@img/sharp-libvips-linux-s390x@1.0.1:
-    resolution: {integrity: sha512-3+rzfAR1YpMOeA2zZNp+aYEzGNWK4zF3+sdMxuCS3ey9HhDbJ66w6hDSHDMoap32DueFwhhs3vwooAB2MaK4XQ==}
-    engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [s390x]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  '@img/sharp-libvips-linux-s390x@1.0.2':
     optional: true
 
-  /@img/sharp-libvips-linux-x64@1.0.1:
-    resolution: {integrity: sha512-3NR1mxFsaSgMMzz1bAnnKbSAI+lHXVTqAHgc1bgzjHuXjo4hlscpUxc0vFSAPKI3yuzdzcZOkq7nDPrP2F8Jgw==}
-    engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  '@img/sharp-libvips-linux-x64@1.0.2':
     optional: true
 
-  /@img/sharp-libvips-linuxmusl-arm64@1.0.1:
-    resolution: {integrity: sha512-5aBRcjHDG/T6jwC3Edl3lP8nl9U2Yo8+oTl5drd1dh9Z1EBfzUKAJFUDTDisDjUwc7N4AjnPGfCA3jl3hY8uDg==}
-    engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  '@img/sharp-libvips-linuxmusl-arm64@1.0.2':
     optional: true
 
-  /@img/sharp-libvips-linuxmusl-x64@1.0.1:
-    resolution: {integrity: sha512-dcT7inI9DBFK6ovfeWRe3hG30h51cBAP5JXlZfx6pzc/Mnf9HFCQDLtYf4MCBjxaaTfjCCjkBxcy3XzOAo5txw==}
-    engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  '@img/sharp-libvips-linuxmusl-x64@1.0.2':
     optional: true
 
-  /@img/sharp-linux-arm64@0.33.2:
-    resolution: {integrity: sha512-pz0NNo882vVfqJ0yNInuG9YH71smP4gRSdeL09ukC2YLE6ZyZePAlWKEHgAzJGTiOh8Qkaov6mMIMlEhmLdKew==}
-    engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
+  '@img/sharp-linux-arm64@0.33.3':
     optionalDependencies:
-      '@img/sharp-libvips-linux-arm64': 1.0.1
-    dev: false
+      '@img/sharp-libvips-linux-arm64': 1.0.2
     optional: true
 
-  /@img/sharp-linux-arm@0.33.2:
-    resolution: {integrity: sha512-Fndk/4Zq3vAc4G/qyfXASbS3HBZbKrlnKZLEJzPLrXoJuipFNNwTes71+Ki1hwYW5lch26niRYoZFAtZVf3EGA==}
-    engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [arm]
-    os: [linux]
-    requiresBuild: true
+  '@img/sharp-linux-arm@0.33.3':
     optionalDependencies:
-      '@img/sharp-libvips-linux-arm': 1.0.1
-    dev: false
+      '@img/sharp-libvips-linux-arm': 1.0.2
     optional: true
 
-  /@img/sharp-linux-s390x@0.33.2:
-    resolution: {integrity: sha512-MBoInDXDppMfhSzbMmOQtGfloVAflS2rP1qPcUIiITMi36Mm5YR7r0ASND99razjQUpHTzjrU1flO76hKvP5RA==}
-    engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [s390x]
-    os: [linux]
-    requiresBuild: true
+  '@img/sharp-linux-s390x@0.33.3':
     optionalDependencies:
-      '@img/sharp-libvips-linux-s390x': 1.0.1
-    dev: false
+      '@img/sharp-libvips-linux-s390x': 1.0.2
     optional: true
 
-  /@img/sharp-linux-x64@0.33.2:
-    resolution: {integrity: sha512-xUT82H5IbXewKkeF5aiooajoO1tQV4PnKfS/OZtb5DDdxS/FCI/uXTVZ35GQ97RZXsycojz/AJ0asoz6p2/H/A==}
-    engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
+  '@img/sharp-linux-x64@0.33.3':
     optionalDependencies:
-      '@img/sharp-libvips-linux-x64': 1.0.1
-    dev: false
+      '@img/sharp-libvips-linux-x64': 1.0.2
     optional: true
 
-  /@img/sharp-linuxmusl-arm64@0.33.2:
-    resolution: {integrity: sha512-F+0z8JCu/UnMzg8IYW1TMeiViIWBVg7IWP6nE0p5S5EPQxlLd76c8jYemG21X99UzFwgkRo5yz2DS+zbrnxZeA==}
-    engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
+  '@img/sharp-linuxmusl-arm64@0.33.3':
     optionalDependencies:
-      '@img/sharp-libvips-linuxmusl-arm64': 1.0.1
-    dev: false
+      '@img/sharp-libvips-linuxmusl-arm64': 1.0.2
     optional: true
 
-  /@img/sharp-linuxmusl-x64@0.33.2:
-    resolution: {integrity: sha512-+ZLE3SQmSL+Fn1gmSaM8uFusW5Y3J9VOf+wMGNnTtJUMUxFhv+P4UPaYEYT8tqnyYVaOVGgMN/zsOxn9pSsO2A==}
-    engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
+  '@img/sharp-linuxmusl-x64@0.33.3':
     optionalDependencies:
-      '@img/sharp-libvips-linuxmusl-x64': 1.0.1
-    dev: false
+      '@img/sharp-libvips-linuxmusl-x64': 1.0.2
     optional: true
 
-  /@img/sharp-wasm32@0.33.2:
-    resolution: {integrity: sha512-fLbTaESVKuQcpm8ffgBD7jLb/CQLcATju/jxtTXR1XCLwbOQt+OL5zPHSDMmp2JZIeq82e18yE0Vv7zh6+6BfQ==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [wasm32]
-    requiresBuild: true
+  '@img/sharp-wasm32@0.33.3':
     dependencies:
-      '@emnapi/runtime': 0.45.0
-    dev: false
+      '@emnapi/runtime': 1.1.1
     optional: true
 
-  /@img/sharp-win32-ia32@0.33.2:
-    resolution: {integrity: sha512-okBpql96hIGuZ4lN3+nsAjGeggxKm7hIRu9zyec0lnfB8E7Z6p95BuRZzDDXZOl2e8UmR4RhYt631i7mfmKU8g==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [ia32]
-    os: [win32]
-    requiresBuild: true
-    dev: false
+  '@img/sharp-win32-ia32@0.33.3':
     optional: true
 
-  /@img/sharp-win32-x64@0.33.2:
-    resolution: {integrity: sha512-E4magOks77DK47FwHUIGH0RYWSgRBfGdK56kIHSVeB9uIS4pPFr4N2kIVsXdQQo4LzOsENKV5KAhRlRL7eMAdg==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
-    cpu: [x64]
-    os: [win32]
-    requiresBuild: true
-    dev: false
+  '@img/sharp-win32-x64@0.33.3':
     optional: true
 
-  /@ioredis/commands@1.2.0:
-    resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==}
-    dev: false
+  '@inquirer/confirm@3.1.6':
+    dependencies:
+      '@inquirer/core': 8.1.0
+      '@inquirer/type': 1.3.1
 
-  /@isaacs/cliui@8.0.2:
-    resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
-    engines: {node: '>=12'}
+  '@inquirer/core@8.1.0':
+    dependencies:
+      '@inquirer/figures': 1.0.1
+      '@inquirer/type': 1.3.1
+      '@types/mute-stream': 0.0.4
+      '@types/node': 20.12.7
+      '@types/wrap-ansi': 3.0.0
+      ansi-escapes: 4.3.2
+      chalk: 4.1.2
+      cli-spinners: 2.9.2
+      cli-width: 4.1.0
+      mute-stream: 1.0.0
+      signal-exit: 4.1.0
+      strip-ansi: 6.0.1
+      wrap-ansi: 6.2.0
+
+  '@inquirer/figures@1.0.1': {}
+
+  '@inquirer/type@1.3.1': {}
+
+  '@intlify/core-base@9.13.1':
+    dependencies:
+      '@intlify/message-compiler': 9.13.1
+      '@intlify/shared': 9.13.1
+
+  '@intlify/message-compiler@9.13.1':
+    dependencies:
+      '@intlify/shared': 9.13.1
+      source-map-js: 1.0.2
+
+  '@intlify/shared@9.13.1': {}
+
+  '@ioredis/commands@1.2.0': {}
+
+  '@isaacs/cliui@8.0.2':
     dependencies:
       string-width: 5.1.2
-      string-width-cjs: /string-width@4.2.3
+      string-width-cjs: string-width@4.2.3
       strip-ansi: 7.1.0
-      strip-ansi-cjs: /strip-ansi@6.0.1
+      strip-ansi-cjs: strip-ansi@6.0.1
       wrap-ansi: 8.1.0
-      wrap-ansi-cjs: /wrap-ansi@7.0.0
+      wrap-ansi-cjs: wrap-ansi@7.0.0
 
-  /@istanbuljs/load-nyc-config@1.1.0:
-    resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
-    engines: {node: '>=8'}
+  '@istanbuljs/load-nyc-config@1.1.0':
     dependencies:
       camelcase: 5.3.1
       find-up: 4.1.0
       get-package-type: 0.1.0
       js-yaml: 3.14.1
       resolve-from: 5.0.0
-    dev: true
 
-  /@istanbuljs/schema@0.1.3:
-    resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
-    engines: {node: '>=8'}
-    dev: true
+  '@istanbuljs/schema@0.1.3': {}
 
-  /@jest/console@29.7.0:
-    resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  '@jest/console@29.7.0':
     dependencies:
       '@jest/types': 29.6.3
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       chalk: 4.1.2
       jest-message-util: 29.7.0
       jest-util: 29.7.0
       slash: 3.0.0
-    dev: true
 
-  /@jest/core@29.7.0:
-    resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-    peerDependencies:
-      node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
-    peerDependenciesMeta:
-      node-notifier:
-        optional: true
+  '@jest/core@29.7.0':
     dependencies:
       '@jest/console': 29.7.0
       '@jest/reporters': 29.7.0
       '@jest/test-result': 29.7.0
       '@jest/transform': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       ansi-escapes: 4.3.2
       chalk: 4.1.2
       ci-info: 3.7.1
       exit: 0.1.2
       graceful-fs: 4.2.11
       jest-changed-files: 29.7.0
-      jest-config: 29.7.0(@types/node@20.11.22)
+      jest-config: 29.7.0(@types/node@20.12.7)
       jest-haste-map: 29.7.0
       jest-message-util: 29.7.0
       jest-regex-util: 29.6.3
@@ -4521,57 +13277,39 @@ packages:
       - babel-plugin-macros
       - supports-color
       - ts-node
-    dev: true
 
-  /@jest/create-cache-key-function@29.7.0:
-    resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  '@jest/create-cache-key-function@29.7.0':
     dependencies:
       '@jest/types': 29.6.3
-    dev: true
 
-  /@jest/environment@29.7.0:
-    resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  '@jest/environment@29.7.0':
     dependencies:
       '@jest/fake-timers': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       jest-mock: 29.7.0
-    dev: true
 
-  /@jest/expect-utils@29.7.0:
-    resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  '@jest/expect-utils@29.7.0':
     dependencies:
       jest-get-type: 29.6.3
-    dev: true
 
-  /@jest/expect@29.7.0:
-    resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  '@jest/expect@29.7.0':
     dependencies:
       expect: 29.7.0
       jest-snapshot: 29.7.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@jest/fake-timers@29.7.0:
-    resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  '@jest/fake-timers@29.7.0':
     dependencies:
       '@jest/types': 29.6.3
       '@sinonjs/fake-timers': 10.3.0
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       jest-message-util: 29.7.0
       jest-mock: 29.7.0
       jest-util: 29.7.0
-    dev: true
 
-  /@jest/globals@29.7.0:
-    resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  '@jest/globals@29.7.0':
     dependencies:
       '@jest/environment': 29.7.0
       '@jest/expect': 29.7.0
@@ -4579,16 +13317,8 @@ packages:
       jest-mock: 29.7.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@jest/reporters@29.7.0:
-    resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-    peerDependencies:
-      node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
-    peerDependenciesMeta:
-      node-notifier:
-        optional: true
+  '@jest/reporters@29.7.0':
     dependencies:
       '@bcoe/v8-coverage': 0.2.3
       '@jest/console': 29.7.0
@@ -4596,7 +13326,7 @@ packages:
       '@jest/transform': 29.7.0
       '@jest/types': 29.6.3
       '@jridgewell/trace-mapping': 0.3.18
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       chalk: 4.1.2
       collect-v8-coverage: 1.0.1
       exit: 0.1.2
@@ -4616,47 +13346,32 @@ packages:
       v8-to-istanbul: 9.2.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@jest/schemas@29.6.3:
-    resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  '@jest/schemas@29.6.3':
     dependencies:
       '@sinclair/typebox': 0.27.8
-    dev: true
 
-  /@jest/source-map@29.6.3:
-    resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  '@jest/source-map@29.6.3':
     dependencies:
       '@jridgewell/trace-mapping': 0.3.18
       callsites: 3.1.0
       graceful-fs: 4.2.11
-    dev: true
 
-  /@jest/test-result@29.7.0:
-    resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  '@jest/test-result@29.7.0':
     dependencies:
       '@jest/console': 29.7.0
       '@jest/types': 29.6.3
       '@types/istanbul-lib-coverage': 2.0.4
       collect-v8-coverage: 1.0.1
-    dev: true
 
-  /@jest/test-sequencer@29.7.0:
-    resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  '@jest/test-sequencer@29.7.0':
     dependencies:
       '@jest/test-result': 29.7.0
       graceful-fs: 4.2.11
       jest-haste-map: 29.7.0
       slash: 3.0.0
-    dev: true
 
-  /@jest/transform@29.7.0:
-    resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  '@jest/transform@29.7.0':
     dependencies:
       '@babel/core': 7.23.5
       '@jest/types': 29.6.3
@@ -4675,218 +13390,153 @@ packages:
       write-file-atomic: 4.0.2
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@jest/types@29.6.3:
-    resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  '@jest/types@29.6.3':
     dependencies:
       '@jest/schemas': 29.6.3
       '@types/istanbul-lib-coverage': 2.0.4
       '@types/istanbul-reports': 3.0.1
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       '@types/yargs': 17.0.19
       chalk: 4.1.2
-    dev: true
 
-  /@joshwooding/vite-plugin-react-docgen-typescript@0.3.0(typescript@5.3.3)(vite@5.1.4):
-    resolution: {integrity: sha512-2D6y7fNvFmsLmRt6UCOFJPvFoPMJGT0Uh1Wg0RaigUp7kdQPs6yYn8Dmx6GZkOH/NW0yMTwRz/p0SRMMRo50vA==}
-    peerDependencies:
-      typescript: '>= 4.3.x'
-      vite: ^3.0.0 || ^4.0.0 || ^5.0.0
-    peerDependenciesMeta:
-      typescript:
-        optional: true
+  '@joshwooding/vite-plugin-react-docgen-typescript@0.3.0(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))':
     dependencies:
       glob: 7.2.3
       glob-promise: 4.2.2(glob@7.2.3)
       magic-string: 0.27.0
-      react-docgen-typescript: 2.2.2(typescript@5.3.3)
-      typescript: 5.3.3
-      vite: 5.1.4(@types/node@20.11.22)(sass@1.71.1)(terser@5.28.1)
-    dev: true
+      react-docgen-typescript: 2.2.2(typescript@5.4.5)
+      vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
+    optionalDependencies:
+      typescript: 5.4.5
 
-  /@jridgewell/gen-mapping@0.3.2:
-    resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==}
-    engines: {node: '>=6.0.0'}
+  '@jridgewell/gen-mapping@0.3.2':
     dependencies:
       '@jridgewell/set-array': 1.1.2
       '@jridgewell/sourcemap-codec': 1.4.15
       '@jridgewell/trace-mapping': 0.3.18
 
-  /@jridgewell/resolve-uri@3.1.0:
-    resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
-    engines: {node: '>=6.0.0'}
+  '@jridgewell/resolve-uri@3.1.0': {}
 
-  /@jridgewell/set-array@1.1.2:
-    resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
-    engines: {node: '>=6.0.0'}
+  '@jridgewell/set-array@1.1.2': {}
 
-  /@jridgewell/source-map@0.3.5:
-    resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==}
+  '@jridgewell/source-map@0.3.5':
     dependencies:
       '@jridgewell/gen-mapping': 0.3.2
       '@jridgewell/trace-mapping': 0.3.18
 
-  /@jridgewell/sourcemap-codec@1.4.14:
-    resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==}
+  '@jridgewell/sourcemap-codec@1.4.14': {}
 
-  /@jridgewell/sourcemap-codec@1.4.15:
-    resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
+  '@jridgewell/sourcemap-codec@1.4.15': {}
 
-  /@jridgewell/trace-mapping@0.3.18:
-    resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==}
+  '@jridgewell/trace-mapping@0.3.18':
     dependencies:
       '@jridgewell/resolve-uri': 3.1.0
       '@jridgewell/sourcemap-codec': 1.4.14
 
-  /@jsdevtools/ono@7.1.3:
-    resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==}
-    dev: true
+  '@jsdevtools/ono@7.1.3': {}
 
-  /@kurkle/color@0.3.2:
-    resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==}
-    dev: false
+  '@kurkle/color@0.3.2': {}
 
-  /@levischuck/tiny-cbor@0.2.2:
-    resolution: {integrity: sha512-f5CnPw997Y2GQ8FAvtuVVC19FX8mwNNC+1XJcIi16n/LTJifKO6QBgGLgN3YEmqtGMk17SKSuoWES3imJVxAVw==}
-    dev: false
+  '@levischuck/tiny-cbor@0.2.2': {}
 
-  /@lukeed/csprng@1.0.1:
-    resolution: {integrity: sha512-uSvJdwQU5nK+Vdf6zxcWAY2A8r7uqe+gePwLWzJ+fsQehq18pc0I2hJKwypZ2aLM90+Er9u1xn4iLJPZ+xlL4g==}
-    engines: {node: '>=8'}
+  '@lukeed/csprng@1.0.1': {}
 
-  /@lukeed/ms@2.0.1:
-    resolution: {integrity: sha512-Xs/4RZltsAL7pkvaNStUQt7netTkyxrS0K+RILcVr3TRMS/ToOg4I6uNfhB9SlGsnWBym4U+EaXq0f0cEMNkHA==}
-    engines: {node: '>=8'}
-    dev: false
+  '@lukeed/ms@2.0.1': {}
 
-  /@mapbox/node-pre-gyp@1.0.9:
-    resolution: {integrity: sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==}
-    hasBin: true
-    requiresBuild: true
+  '@mapbox/node-pre-gyp@1.0.9(encoding@0.1.13)':
     dependencies:
       detect-libc: 2.0.2
       https-proxy-agent: 5.0.1
       make-dir: 3.1.0
-      node-fetch: 2.7.0
+      node-fetch: 2.7.0(encoding@0.1.13)
       nopt: 5.0.0
       npmlog: 5.0.1
       rimraf: 3.0.2
       semver: 7.5.4
-      tar: 6.2.0
+      tar: 6.2.1
     transitivePeerDependencies:
       - encoding
       - supports-color
-    dev: false
     optional: true
 
-  /@mcaptcha/core-glue@0.1.0-alpha-5:
-    resolution: {integrity: sha512-16qWm5O5X0Y9LXULULaAks8Vf9FNlUUBcR5KDt49aWhFhG5++JzxNmCwQM9EJSHNU7y0U+FdyAWcGmjfKlkRLA==}
-    dev: false
+  '@mcaptcha/core-glue@0.1.0-alpha-5': {}
 
-  /@mcaptcha/vanilla-glue@0.1.0-alpha-3:
-    resolution: {integrity: sha512-GT6TJBgmViGXcXiT5VOr+h/6iOnThSlZuCoOWncubyTZU9R3cgU5vWPkF7G6Ob6ee2CBe3yqBxxk24CFVGTVXw==}
+  '@mcaptcha/vanilla-glue@0.1.0-alpha-3':
     dependencies:
       '@mcaptcha/core-glue': 0.1.0-alpha-5
-    dev: false
 
-  /@mdx-js/react@3.0.1(@types/react@18.0.28)(react@18.2.0):
-    resolution: {integrity: sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==}
-    peerDependencies:
-      '@types/react': '>=16'
-      react: '>=16'
+  '@mdx-js/react@3.0.1(@types/react@18.0.28)(react@18.3.1)':
     dependencies:
       '@types/mdx': 2.0.3
       '@types/react': 18.0.28
-      react: 18.2.0
-    dev: true
+      react: 18.3.1
 
-  /@microsoft/api-extractor-model@7.28.4(@types/node@20.11.22):
-    resolution: {integrity: sha512-vucgyPmgHrJ/D4/xQywAmjTmSfxAx2/aDmD6TkIoLu51FdsAfuWRbijWA48AePy60OO+l+mmy9p2P/CEeBZqig==}
+  '@microsoft/api-extractor-model@7.28.14(@types/node@20.12.7)':
     dependencies:
       '@microsoft/tsdoc': 0.14.2
       '@microsoft/tsdoc-config': 0.16.2
-      '@rushstack/node-core-library': 3.63.0(@types/node@20.11.22)
+      '@rushstack/node-core-library': 4.1.0(@types/node@20.12.7)
     transitivePeerDependencies:
       - '@types/node'
-    dev: true
 
-  /@microsoft/api-extractor@7.39.1(@types/node@20.11.22):
-    resolution: {integrity: sha512-V0HtCufWa8hZZvSmlEzQZfINcJkHAU/bmpyJQj6w+zpI87EkR8DuBOW6RWrO9c7mUYFZoDaNgUTyKo83ytv+QQ==}
-    hasBin: true
+  '@microsoft/api-extractor@7.43.1(@types/node@20.12.7)':
     dependencies:
-      '@microsoft/api-extractor-model': 7.28.4(@types/node@20.11.22)
+      '@microsoft/api-extractor-model': 7.28.14(@types/node@20.12.7)
       '@microsoft/tsdoc': 0.14.2
       '@microsoft/tsdoc-config': 0.16.2
-      '@rushstack/node-core-library': 3.63.0(@types/node@20.11.22)
-      '@rushstack/rig-package': 0.5.1
-      '@rushstack/ts-command-line': 4.17.1
-      colors: 1.2.5
+      '@rushstack/node-core-library': 4.1.0(@types/node@20.12.7)
+      '@rushstack/rig-package': 0.5.2
+      '@rushstack/terminal': 0.10.1(@types/node@20.12.7)
+      '@rushstack/ts-command-line': 4.19.2(@types/node@20.12.7)
       lodash: 4.17.21
+      minimatch: 3.0.8
       resolve: 1.22.8
       semver: 7.5.4
       source-map: 0.6.1
-      typescript: 5.3.3
+      typescript: 5.4.2
     transitivePeerDependencies:
       - '@types/node'
-    dev: true
 
-  /@microsoft/tsdoc-config@0.16.2:
-    resolution: {integrity: sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==}
+  '@microsoft/tsdoc-config@0.16.2':
     dependencies:
       '@microsoft/tsdoc': 0.14.2
       ajv: 6.12.6
       jju: 1.4.0
       resolve: 1.19.0
-    dev: true
 
-  /@microsoft/tsdoc@0.14.2:
-    resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==}
-    dev: true
+  '@microsoft/tsdoc@0.14.2': {}
 
-  /@misskey-dev/browser-image-resizer@2024.1.0:
-    resolution: {integrity: sha512-4EnO0zLW5NDtng3Gaz5MuT761uiuoOuplwX18wBqgj8w56LTU5BjLn/vbHwDIIe0j2gwqDYhMb7bDjmr1/Fomg==}
-    dev: false
+  '@misskey-dev/browser-image-resizer@2024.1.0': {}
 
-  /@misskey-dev/eslint-plugin@1.0.0(@typescript-eslint/eslint-plugin@6.11.0)(@typescript-eslint/parser@6.11.0)(eslint-plugin-import@2.29.1)(eslint@8.53.0):
-    resolution: {integrity: sha512-dh6UbcrNDVg5DD8k8Qh4ab30OPpuEYIlJCqaBV/lkIV8wNN/AfCJ2V7iTP8V8KjryM4t+sf5IqzQLQnT0mWI4A==}
-    peerDependencies:
-      '@typescript-eslint/eslint-plugin': '>= 6'
-      '@typescript-eslint/parser': '>= 6'
-      eslint: '>= 3'
-      eslint-plugin-import: '>= 2'
+  '@misskey-dev/eslint-plugin@1.0.0(@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0)(typescript@5.3.3))(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0))(eslint@8.53.0)':
     dependencies:
-      '@typescript-eslint/eslint-plugin': 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.3)
+      '@typescript-eslint/eslint-plugin': 6.11.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0)(typescript@5.3.3)
       '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
       eslint: 8.53.0
-      eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)
-    dev: true
+      eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0)
 
-  /@misskey-dev/eslint-plugin@1.0.0(@typescript-eslint/eslint-plugin@7.1.0)(@typescript-eslint/parser@7.1.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0):
-    resolution: {integrity: sha512-dh6UbcrNDVg5DD8k8Qh4ab30OPpuEYIlJCqaBV/lkIV8wNN/AfCJ2V7iTP8V8KjryM4t+sf5IqzQLQnT0mWI4A==}
-    peerDependencies:
-      '@typescript-eslint/eslint-plugin': '>= 6'
-      '@typescript-eslint/parser': '>= 6'
-      eslint: '>= 3'
-      eslint-plugin-import: '>= 2'
+  '@misskey-dev/eslint-plugin@1.0.0(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0))(eslint@8.57.0)':
     dependencies:
-      '@typescript-eslint/eslint-plugin': 7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3)
+      '@typescript-eslint/eslint-plugin': 7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3)
       '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3)
       eslint: 8.57.0
-      eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)
-    dev: true
+      eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)
 
-  /@misskey-dev/sharp-read-bmp@1.2.0:
-    resolution: {integrity: sha512-er4pRakXzHYfEgOFAFfQagqDouG+wLm+kwNq1I30oSdIHDa0wM3KjFpfIGQ25Fks4GcmOl1s7Zh6xoQu5dNjTw==}
+  '@misskey-dev/eslint-plugin@1.0.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0)':
+    dependencies:
+      '@typescript-eslint/eslint-plugin': 7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
+      '@typescript-eslint/parser': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
+      eslint: 8.57.0
+      eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)
+
+  '@misskey-dev/sharp-read-bmp@1.2.0':
     dependencies:
       decode-bmp: 0.2.1
       decode-ico: 0.4.1
-      sharp: 0.33.2
-    dev: false
+      sharp: 0.33.3
 
-  /@misskey-dev/summaly@5.0.3:
-    resolution: {integrity: sha512-jVkuLEDrq2FaeHL8VY51LTqB6j0Jv5L7s0nmKGKMnE0jPBpSj6flswnZgntGmz5mbdCj47utEqu8FY43kH7PVg==}
+  '@misskey-dev/summaly@5.1.0':
     dependencies:
       cheerio: 1.0.0-rc.12
       escape-regexp: 0.0.1
@@ -4896,24 +13546,8 @@ packages:
       jschardet: 3.0.0
       private-ip: 2.3.3
       trace-redirect: 1.0.6
-    dev: true
 
-  /@misskey-dev/summaly@5.1.0:
-    resolution: {integrity: sha512-WAUrgX3/z4h4aI8Y/WVwmJcJ6Fa1Zf2LJCSS651t9MHoWVGABLsQ2KCXRGmlpk4i+cMDNIwweObUroosE7j8rg==}
-    dependencies:
-      cheerio: 1.0.0-rc.12
-      escape-regexp: 0.0.1
-      got: 12.6.1
-      html-entities: 2.3.2
-      iconv-lite: 0.6.3
-      jschardet: 3.0.0
-      private-ip: 2.3.3
-      trace-redirect: 1.0.6
-    dev: false
-
-  /@mole-inc/bin-wrapper@8.0.1:
-    resolution: {integrity: sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+  '@mole-inc/bin-wrapper@8.0.1':
     dependencies:
       bin-check: 4.1.0
       bin-version-check: 5.0.0
@@ -4923,64 +13557,28 @@ packages:
       filenamify: 5.1.1
       got: 11.8.5
       os-filter-obj: 2.0.0
-    dev: false
 
-  /@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2:
-    resolution: {integrity: sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
-    dev: false
+  '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2':
     optional: true
 
-  /@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.2:
-    resolution: {integrity: sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
-    dev: false
+  '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.2':
     optional: true
 
-  /@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.2:
-    resolution: {integrity: sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.2':
     optional: true
 
-  /@msgpackr-extract/msgpackr-extract-linux-arm@3.0.2:
-    resolution: {integrity: sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==}
-    cpu: [arm]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.2':
     optional: true
 
-  /@msgpackr-extract/msgpackr-extract-linux-x64@3.0.2:
-    resolution: {integrity: sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.2':
     optional: true
 
-  /@msgpackr-extract/msgpackr-extract-win32-x64@3.0.2:
-    resolution: {integrity: sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==}
-    cpu: [x64]
-    os: [win32]
-    requiresBuild: true
-    dev: false
+  '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.2':
     optional: true
 
-  /@mswjs/cookies@1.1.0:
-    resolution: {integrity: sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw==}
-    engines: {node: '>=18'}
-    dev: true
+  '@mswjs/cookies@1.1.0': {}
 
-  /@mswjs/interceptors@0.25.16:
-    resolution: {integrity: sha512-8QC8JyKztvoGAdPgyZy49c9vSHHAZjHagwl4RY9E8carULk8ym3iTaiawrT1YoLF/qb449h48f71XDPgkUSOUg==}
-    engines: {node: '>=18'}
+  '@mswjs/interceptors@0.26.15':
     dependencies:
       '@open-draft/deferred-promise': 2.2.0
       '@open-draft/logger': 0.3.0
@@ -4988,122 +13586,109 @@ packages:
       is-node-process: 1.2.0
       outvariant: 1.4.2
       strict-event-emitter: 0.5.1
-    dev: true
 
-  /@ndelangen/get-tarball@3.0.7:
-    resolution: {integrity: sha512-NqGfTZIZpRFef1GoVaShSSRwDC3vde3ThtTeqFdcYd6ipKqnfEVhjK2hUeHjCQUcptyZr2TONqcloFXM+5QBrQ==}
+  '@napi-rs/canvas-android-arm64@0.1.52':
+    optional: true
+
+  '@napi-rs/canvas-darwin-arm64@0.1.52':
+    optional: true
+
+  '@napi-rs/canvas-darwin-x64@0.1.52':
+    optional: true
+
+  '@napi-rs/canvas-linux-arm-gnueabihf@0.1.52':
+    optional: true
+
+  '@napi-rs/canvas-linux-arm64-gnu@0.1.52':
+    optional: true
+
+  '@napi-rs/canvas-linux-arm64-musl@0.1.52':
+    optional: true
+
+  '@napi-rs/canvas-linux-x64-gnu@0.1.52':
+    optional: true
+
+  '@napi-rs/canvas-linux-x64-musl@0.1.52':
+    optional: true
+
+  '@napi-rs/canvas-win32-x64-msvc@0.1.52':
+    optional: true
+
+  '@napi-rs/canvas@0.1.52':
+    optionalDependencies:
+      '@napi-rs/canvas-android-arm64': 0.1.52
+      '@napi-rs/canvas-darwin-arm64': 0.1.52
+      '@napi-rs/canvas-darwin-x64': 0.1.52
+      '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.52
+      '@napi-rs/canvas-linux-arm64-gnu': 0.1.52
+      '@napi-rs/canvas-linux-arm64-musl': 0.1.52
+      '@napi-rs/canvas-linux-x64-gnu': 0.1.52
+      '@napi-rs/canvas-linux-x64-musl': 0.1.52
+      '@napi-rs/canvas-win32-x64-msvc': 0.1.52
+
+  '@ndelangen/get-tarball@3.0.7':
     dependencies:
       gunzip-maybe: 1.4.2
       pump: 3.0.0
       tar-fs: 2.1.1
-    dev: true
 
-  /@nestjs/common@10.3.3(reflect-metadata@0.2.1)(rxjs@7.8.1):
-    resolution: {integrity: sha512-LAkTe8/CF0uNWM0ecuDwUNTHCi1lVSITmmR4FQ6Ftz1E7ujQCnJ5pMRzd8JRN14vdBkxZZ8VbVF0BDUKoKNxMQ==}
-    peerDependencies:
-      class-transformer: '*'
-      class-validator: '*'
-      reflect-metadata: ^0.1.12 || ^0.2.0
-      rxjs: ^7.1.0
-    peerDependenciesMeta:
-      class-transformer:
-        optional: true
-      class-validator:
-        optional: true
+  '@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1)':
     dependencies:
       iterare: 1.2.1
-      reflect-metadata: 0.2.1
+      reflect-metadata: 0.2.2
       rxjs: 7.8.1
       tslib: 2.6.2
       uid: 2.0.2
 
-  /@nestjs/core@10.3.3(@nestjs/common@10.3.3)(@nestjs/platform-express@10.3.3)(reflect-metadata@0.2.1)(rxjs@7.8.1):
-    resolution: {integrity: sha512-kxJWggQAPX3RuZx9JVec69eSLaYLNIox2emkZJpfBJ5Qq7cAq7edQIt1r4LGjTKq6kFubNTPsqhWf5y7yFRBPw==}
-    requiresBuild: true
-    peerDependencies:
-      '@nestjs/common': ^10.0.0
-      '@nestjs/microservices': ^10.0.0
-      '@nestjs/platform-express': ^10.0.0
-      '@nestjs/websockets': ^10.0.0
-      reflect-metadata: ^0.1.12 || ^0.2.0
-      rxjs: ^7.1.0
-    peerDependenciesMeta:
-      '@nestjs/microservices':
-        optional: true
-      '@nestjs/platform-express':
-        optional: true
-      '@nestjs/websockets':
-        optional: true
+  '@nestjs/core@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)':
     dependencies:
-      '@nestjs/common': 10.3.3(reflect-metadata@0.2.1)(rxjs@7.8.1)
-      '@nestjs/platform-express': 10.3.3(@nestjs/common@10.3.3)(@nestjs/core@10.3.3)
-      '@nuxtjs/opencollective': 0.3.2
+      '@nestjs/common': 10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1)
+      '@nuxtjs/opencollective': 0.3.2(encoding@0.1.13)
       fast-safe-stringify: 2.1.1
       iterare: 1.2.1
       path-to-regexp: 3.2.0
-      reflect-metadata: 0.2.1
+      reflect-metadata: 0.2.2
       rxjs: 7.8.1
       tslib: 2.6.2
       uid: 2.0.2
+    optionalDependencies:
+      '@nestjs/platform-express': 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)
     transitivePeerDependencies:
       - encoding
 
-  /@nestjs/platform-express@10.3.3(@nestjs/common@10.3.3)(@nestjs/core@10.3.3):
-    resolution: {integrity: sha512-GGKSEU48Os7nYFIsUM0nutuFUGn5AbeP8gzFBiBCAtiuJWrXZXpZ58pMBYxAbMf7IrcOZFInHEukjHGAQU0OZw==}
-    peerDependencies:
-      '@nestjs/common': ^10.0.0
-      '@nestjs/core': ^10.0.0
+  '@nestjs/platform-express@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)':
     dependencies:
-      '@nestjs/common': 10.3.3(reflect-metadata@0.2.1)(rxjs@7.8.1)
-      '@nestjs/core': 10.3.3(@nestjs/common@10.3.3)(@nestjs/platform-express@10.3.3)(reflect-metadata@0.2.1)(rxjs@7.8.1)
+      '@nestjs/common': 10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1)
+      '@nestjs/core': 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)
       body-parser: 1.20.2
       cors: 2.8.5
-      express: 4.18.2
+      express: 4.19.2
       multer: 1.4.4-lts.1
       tslib: 2.6.2
     transitivePeerDependencies:
       - supports-color
 
-  /@nestjs/testing@10.3.3(@nestjs/common@10.3.3)(@nestjs/core@10.3.3)(@nestjs/platform-express@10.3.3):
-    resolution: {integrity: sha512-kX20GfjAImL5grd/i69uD/x7sc00BaqGcP2dRG3ilqshQUuy5DOmspLCr3a2C8xmVU7kzK4spT0oTxhe6WcCAA==}
-    peerDependencies:
-      '@nestjs/common': ^10.0.0
-      '@nestjs/core': ^10.0.0
-      '@nestjs/microservices': ^10.0.0
-      '@nestjs/platform-express': ^10.0.0
-    peerDependenciesMeta:
-      '@nestjs/microservices':
-        optional: true
-      '@nestjs/platform-express':
-        optional: true
+  '@nestjs/testing@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8))':
     dependencies:
-      '@nestjs/common': 10.3.3(reflect-metadata@0.2.1)(rxjs@7.8.1)
-      '@nestjs/core': 10.3.3(@nestjs/common@10.3.3)(@nestjs/platform-express@10.3.3)(reflect-metadata@0.2.1)(rxjs@7.8.1)
-      '@nestjs/platform-express': 10.3.3(@nestjs/common@10.3.3)(@nestjs/core@10.3.3)
+      '@nestjs/common': 10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1)
+      '@nestjs/core': 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)
       tslib: 2.6.2
-    dev: false
+    optionalDependencies:
+      '@nestjs/platform-express': 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)
 
-  /@nodelib/fs.scandir@2.1.5:
-    resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
-    engines: {node: '>= 8'}
+  '@nodelib/fs.scandir@2.1.5':
     dependencies:
       '@nodelib/fs.stat': 2.0.5
       run-parallel: 1.2.0
 
-  /@nodelib/fs.stat@2.0.5:
-    resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
-    engines: {node: '>= 8'}
+  '@nodelib/fs.stat@2.0.5': {}
 
-  /@nodelib/fs.walk@1.2.8:
-    resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
-    engines: {node: '>= 8'}
+  '@nodelib/fs.walk@1.2.8':
     dependencies:
       '@nodelib/fs.scandir': 2.1.5
       fastq: 1.15.0
 
-  /@npmcli/agent@2.2.0:
-    resolution: {integrity: sha512-2yThA1Es98orMkpSLVqlDZAMPK3jHJhifP2gnNUdk1754uZ8yI5c+ulCoVG+WlntQA6MzhrURMXjSd9Z7dJ2/Q==}
-    engines: {node: ^16.14.0 || >=18.0.0}
+  '@npmcli/agent@2.2.0':
     dependencies:
       agent-base: 7.1.0
       http-proxy-agent: 7.0.0
@@ -5112,380 +13697,244 @@ packages:
       socks-proxy-agent: 8.0.2
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /@npmcli/fs@3.1.0:
-    resolution: {integrity: sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==}
-    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+  '@npmcli/fs@3.1.0':
     dependencies:
       semver: 7.6.0
-    dev: false
 
-  /@nsfw-filter/gif-frames@1.0.2:
-    resolution: {integrity: sha512-XZrbJWEN8YfVla5i+PD4Wj51rRlJ8OgnXiPjjOt/OsrbsCR9GZRD4jr953oNWcwiRaoIcOCFWQNMQukO7Yb1dA==}
+  '@nsfw-filter/gif-frames@1.0.2':
     dependencies:
       '@nsfw-filter/save-pixels': 2.3.4
       get-pixels-frame-info-update: 3.3.2
       multi-integer-range: 3.0.0
-    dev: false
 
-  /@nsfw-filter/save-pixels@2.3.4:
-    resolution: {integrity: sha512-dRZXwrXadMvxwJYKChrDBqC6GNvxVqlmdkyvZJO5DV65qyBsHZw8bPg9CnX7EgpxGl6+4ba/MAdHDLxs2XoD0Q==}
+  '@nsfw-filter/save-pixels@2.3.4':
     dependencies:
       gif-encoder: 0.4.1
       ndarray: 1.0.18
       ndarray-ops: 1.2.2
       pngjs-nozlib: 1.0.0
       through: 2.3.4
-    dev: false
 
-  /@nuxtjs/opencollective@0.3.2:
-    resolution: {integrity: sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==}
-    engines: {node: '>=8.0.0', npm: '>=5.0.0'}
-    hasBin: true
+  '@nuxtjs/opencollective@0.3.2(encoding@0.1.13)':
     dependencies:
       chalk: 4.1.2
       consola: 2.15.3
-      node-fetch: 2.7.0
+      node-fetch: 2.7.0(encoding@0.1.13)
     transitivePeerDependencies:
       - encoding
 
-  /@one-ini/wasm@0.1.1:
-    resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==}
-    dev: true
+  '@one-ini/wasm@0.1.1': {}
 
-  /@open-draft/deferred-promise@2.2.0:
-    resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==}
-    dev: true
+  '@open-draft/deferred-promise@2.2.0': {}
 
-  /@open-draft/logger@0.3.0:
-    resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==}
+  '@open-draft/logger@0.3.0':
     dependencies:
       is-node-process: 1.2.0
       outvariant: 1.4.2
-    dev: true
 
-  /@open-draft/until@2.1.0:
-    resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==}
-    dev: true
+  '@open-draft/until@2.1.0': {}
 
-  /@peculiar/asn1-android@2.3.10:
-    resolution: {integrity: sha512-z9Rx9cFJv7UUablZISe7uksNbFJCq13hO0yEAOoIpAymALTLlvUOSLnGiQS7okPaM5dP42oTLhezH6XDXRXjGw==}
+  '@peculiar/asn1-android@2.3.10':
     dependencies:
       '@peculiar/asn1-schema': 2.3.8
       asn1js: 3.0.5
       tslib: 2.6.2
-    dev: false
 
-  /@peculiar/asn1-ecc@2.3.8:
-    resolution: {integrity: sha512-Ah/Q15y3A/CtxbPibiLM/LKcMbnLTdUdLHUgdpB5f60sSvGkXzxJCu5ezGTFHogZXWNX3KSmYqilCrfdmBc6pQ==}
+  '@peculiar/asn1-ecc@2.3.8':
     dependencies:
       '@peculiar/asn1-schema': 2.3.8
       '@peculiar/asn1-x509': 2.3.8
       asn1js: 3.0.5
       tslib: 2.6.2
-    dev: false
 
-  /@peculiar/asn1-rsa@2.3.8:
-    resolution: {integrity: sha512-ES/RVEHu8VMYXgrg3gjb1m/XG0KJWnV4qyZZ7mAg7rrF3VTmRbLxO8mk+uy0Hme7geSMebp+Wvi2U6RLLEs12Q==}
+  '@peculiar/asn1-rsa@2.3.8':
     dependencies:
       '@peculiar/asn1-schema': 2.3.8
       '@peculiar/asn1-x509': 2.3.8
       asn1js: 3.0.5
       tslib: 2.6.2
-    dev: false
 
-  /@peculiar/asn1-schema@2.3.8:
-    resolution: {integrity: sha512-ULB1XqHKx1WBU/tTFIA+uARuRoBVZ4pNdOA878RDrRbBfBGcSzi5HBkdScC6ZbHn8z7L8gmKCgPC1LHRrP46tA==}
+  '@peculiar/asn1-schema@2.3.8':
     dependencies:
       asn1js: 3.0.5
       pvtsutils: 1.3.5
       tslib: 2.6.2
-    dev: false
 
-  /@peculiar/asn1-x509@2.3.8:
-    resolution: {integrity: sha512-voKxGfDU1c6r9mKiN5ZUsZWh3Dy1BABvTM3cimf0tztNwyMJPhiXY94eRTgsMQe6ViLfT6EoXxkWVzcm3mFAFw==}
+  '@peculiar/asn1-x509@2.3.8':
     dependencies:
       '@peculiar/asn1-schema': 2.3.8
       asn1js: 3.0.5
-      ipaddr.js: 2.1.0
+      ipaddr.js: 2.2.0
       pvtsutils: 1.3.5
       tslib: 2.6.2
-    dev: false
 
-  /@peertube/http-signature@1.7.0:
-    resolution: {integrity: sha512-aGQIwo6/sWtyyqhVK4e1MtxYz4N1X8CNt6SOtCc+Wnczs5S5ONaLHDDR8LYaGn0MgOwvGgXyuZ5sJIfd7iyoUw==}
-    engines: {node: '>=0.10'}
+  '@peertube/http-signature@1.7.0':
     dependencies:
       assert-plus: 1.0.0
       jsprim: 1.4.2
       sshpk: 1.17.0
-    dev: false
 
-  /@pkgjs/parseargs@0.11.0:
-    resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
-    engines: {node: '>=14'}
-    requiresBuild: true
+  '@pkgjs/parseargs@0.11.0':
     optional: true
 
-  /@radix-ui/react-compose-refs@1.0.1(@types/react@18.0.28)(react@18.2.0):
-    resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==}
-    peerDependencies:
-      '@types/react': '*'
-      react: ^16.8 || ^17.0 || ^18.0
-    peerDependenciesMeta:
-      '@types/react':
-        optional: true
+  '@radix-ui/react-compose-refs@1.0.1(@types/react@18.0.28)(react@18.3.1)':
     dependencies:
       '@babel/runtime': 7.23.4
+      react: 18.3.1
+    optionalDependencies:
       '@types/react': 18.0.28
-      react: 18.2.0
-    dev: true
 
-  /@radix-ui/react-slot@1.0.2(@types/react@18.0.28)(react@18.2.0):
-    resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==}
-    peerDependencies:
-      '@types/react': '*'
-      react: ^16.8 || ^17.0 || ^18.0
-    peerDependenciesMeta:
-      '@types/react':
-        optional: true
+  '@radix-ui/react-slot@1.0.2(@types/react@18.0.28)(react@18.3.1)':
     dependencies:
       '@babel/runtime': 7.23.4
-      '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.0.28)(react@18.2.0)
+      '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.0.28)(react@18.3.1)
+      react: 18.3.1
+    optionalDependencies:
       '@types/react': 18.0.28
-      react: 18.2.0
-    dev: true
 
-  /@readme/better-ajv-errors@1.6.0(ajv@8.12.0):
-    resolution: {integrity: sha512-9gO9rld84Jgu13kcbKRU+WHseNhaVt76wYMeRDGsUGYxwJtI3RmEJ9LY9dZCYQGI8eUZLuxb5qDja0nqklpFjQ==}
-    engines: {node: '>=14'}
-    peerDependencies:
-      ajv: 4.11.8 - 8
+  '@readme/better-ajv-errors@1.6.0(ajv@8.13.0)':
     dependencies:
       '@babel/code-frame': 7.23.5
       '@babel/runtime': 7.23.4
       '@humanwhocodes/momoa': 2.0.4
-      ajv: 8.12.0
+      ajv: 8.13.0
       chalk: 4.1.2
       json-to-ast: 2.1.0
       jsonpointer: 5.0.1
       leven: 3.1.0
-    dev: true
 
-  /@readme/json-schema-ref-parser@1.2.0:
-    resolution: {integrity: sha512-Bt3QVovFSua4QmHa65EHUmh2xS0XJ3rgTEUPH998f4OW4VVJke3BuS16f+kM0ZLOGdvIrzrPRqwihuv5BAjtrA==}
+  '@readme/json-schema-ref-parser@1.2.0':
     dependencies:
       '@jsdevtools/ono': 7.1.3
       '@types/json-schema': 7.0.12
       call-me-maybe: 1.0.2
       js-yaml: 4.1.0
-    dev: true
 
-  /@readme/openapi-parser@2.5.0(openapi-types@12.1.3):
-    resolution: {integrity: sha512-IbymbOqRuUzoIgxfAAR7XJt2FWl6n2yqN09fF5adacGm7W03siA3bj1Emql0X9D2T+RpBYz3x9zDsMhuoMP62A==}
-    engines: {node: '>=14'}
-    peerDependencies:
-      openapi-types: '>=7'
+  '@readme/openapi-parser@2.5.0(openapi-types@12.1.3)':
     dependencies:
       '@apidevtools/openapi-schemas': 2.1.0
       '@apidevtools/swagger-methods': 3.0.2
       '@jsdevtools/ono': 7.1.3
-      '@readme/better-ajv-errors': 1.6.0(ajv@8.12.0)
+      '@readme/better-ajv-errors': 1.6.0(ajv@8.13.0)
       '@readme/json-schema-ref-parser': 1.2.0
-      ajv: 8.12.0
-      ajv-draft-04: 1.0.0(ajv@8.12.0)
+      ajv: 8.13.0
+      ajv-draft-04: 1.0.0(ajv@8.13.0)
       call-me-maybe: 1.0.2
       openapi-types: 12.1.3
-    dev: true
 
-  /@rollup/plugin-json@6.1.0(rollup@4.12.0):
-    resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==}
-    engines: {node: '>=14.0.0'}
-    peerDependencies:
-      rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
-    peerDependenciesMeta:
-      rollup:
-        optional: true
+  '@rollup/plugin-json@6.1.0(rollup@4.17.2)':
     dependencies:
-      '@rollup/pluginutils': 5.1.0(rollup@4.12.0)
-      rollup: 4.12.0
-    dev: false
+      '@rollup/pluginutils': 5.1.0(rollup@4.17.2)
+    optionalDependencies:
+      rollup: 4.17.2
 
-  /@rollup/plugin-replace@5.0.5(rollup@4.12.0):
-    resolution: {integrity: sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==}
-    engines: {node: '>=14.0.0'}
-    peerDependencies:
-      rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
-    peerDependenciesMeta:
-      rollup:
-        optional: true
+  '@rollup/plugin-replace@5.0.5(rollup@4.17.2)':
     dependencies:
-      '@rollup/pluginutils': 5.1.0(rollup@4.12.0)
+      '@rollup/pluginutils': 5.1.0(rollup@4.17.2)
       magic-string: 0.30.7
-      rollup: 4.12.0
-    dev: false
+    optionalDependencies:
+      rollup: 4.17.2
 
-  /@rollup/pluginutils@5.1.0(rollup@4.12.0):
-    resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==}
-    engines: {node: '>=14.0.0'}
-    peerDependencies:
-      rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
-    peerDependenciesMeta:
-      rollup:
-        optional: true
+  '@rollup/pluginutils@5.1.0(rollup@4.17.2)':
     dependencies:
       '@types/estree': 1.0.5
       estree-walker: 2.0.2
       picomatch: 2.3.1
-      rollup: 4.12.0
+    optionalDependencies:
+      rollup: 4.17.2
 
-  /@rollup/rollup-android-arm-eabi@4.12.0:
-    resolution: {integrity: sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w==}
-    cpu: [arm]
-    os: [android]
-    requiresBuild: true
+  '@rollup/rollup-android-arm-eabi@4.17.2':
     optional: true
 
-  /@rollup/rollup-android-arm64@4.12.0:
-    resolution: {integrity: sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ==}
-    cpu: [arm64]
-    os: [android]
-    requiresBuild: true
+  '@rollup/rollup-android-arm64@4.17.2':
     optional: true
 
-  /@rollup/rollup-darwin-arm64@4.12.0:
-    resolution: {integrity: sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ==}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
+  '@rollup/rollup-darwin-arm64@4.17.2':
     optional: true
 
-  /@rollup/rollup-darwin-x64@4.12.0:
-    resolution: {integrity: sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg==}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
+  '@rollup/rollup-darwin-x64@4.17.2':
     optional: true
 
-  /@rollup/rollup-linux-arm-gnueabihf@4.12.0:
-    resolution: {integrity: sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA==}
-    cpu: [arm]
-    os: [linux]
-    requiresBuild: true
+  '@rollup/rollup-linux-arm-gnueabihf@4.17.2':
     optional: true
 
-  /@rollup/rollup-linux-arm64-gnu@4.12.0:
-    resolution: {integrity: sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA==}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
+  '@rollup/rollup-linux-arm-musleabihf@4.17.2':
     optional: true
 
-  /@rollup/rollup-linux-arm64-musl@4.12.0:
-    resolution: {integrity: sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ==}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
+  '@rollup/rollup-linux-arm64-gnu@4.17.2':
     optional: true
 
-  /@rollup/rollup-linux-riscv64-gnu@4.12.0:
-    resolution: {integrity: sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw==}
-    cpu: [riscv64]
-    os: [linux]
-    requiresBuild: true
+  '@rollup/rollup-linux-arm64-musl@4.17.2':
     optional: true
 
-  /@rollup/rollup-linux-x64-gnu@4.12.0:
-    resolution: {integrity: sha512-TenQhZVOtw/3qKOPa7d+QgkeM6xY0LtwzR8OplmyL5LrgTWIXpTQg2Q2ycBf8jm+SFW2Wt/DTn1gf7nFp3ssVA==}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
+  '@rollup/rollup-linux-powerpc64le-gnu@4.17.2':
     optional: true
 
-  /@rollup/rollup-linux-x64-musl@4.12.0:
-    resolution: {integrity: sha512-LfFdRhNnW0zdMvdCb5FNuWlls2WbbSridJvxOvYWgSBOYZtgBfW9UGNJG//rwMqTX1xQE9BAodvMH9tAusKDUw==}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
+  '@rollup/rollup-linux-riscv64-gnu@4.17.2':
     optional: true
 
-  /@rollup/rollup-win32-arm64-msvc@4.12.0:
-    resolution: {integrity: sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw==}
-    cpu: [arm64]
-    os: [win32]
-    requiresBuild: true
+  '@rollup/rollup-linux-s390x-gnu@4.17.2':
     optional: true
 
-  /@rollup/rollup-win32-ia32-msvc@4.12.0:
-    resolution: {integrity: sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA==}
-    cpu: [ia32]
-    os: [win32]
-    requiresBuild: true
+  '@rollup/rollup-linux-x64-gnu@4.17.2':
     optional: true
 
-  /@rollup/rollup-win32-x64-msvc@4.12.0:
-    resolution: {integrity: sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==}
-    cpu: [x64]
-    os: [win32]
-    requiresBuild: true
+  '@rollup/rollup-linux-x64-musl@4.17.2':
     optional: true
 
-  /@rushstack/node-core-library@3.63.0(@types/node@20.11.22):
-    resolution: {integrity: sha512-Q7B3dVpBQF1v+mUfxNcNZh5uHVR8ntcnkN5GYjbBLrxUYHBGKbnCM+OdcN+hzCpFlLBH6Ob0dEHhZ0spQwf24A==}
-    peerDependencies:
-      '@types/node': '*'
-    peerDependenciesMeta:
-      '@types/node':
-        optional: true
+  '@rollup/rollup-win32-arm64-msvc@4.17.2':
+    optional: true
+
+  '@rollup/rollup-win32-ia32-msvc@4.17.2':
+    optional: true
+
+  '@rollup/rollup-win32-x64-msvc@4.17.2':
+    optional: true
+
+  '@rushstack/node-core-library@4.1.0(@types/node@20.12.7)':
     dependencies:
-      '@types/node': 20.11.22
-      colors: 1.2.5
       fs-extra: 7.0.1
       import-lazy: 4.0.0
       jju: 1.4.0
       resolve: 1.22.8
       semver: 7.5.4
       z-schema: 5.0.5
-    dev: true
+    optionalDependencies:
+      '@types/node': 20.12.7
 
-  /@rushstack/rig-package@0.5.1:
-    resolution: {integrity: sha512-pXRYSe29TjRw7rqxD4WS3HN/sRSbfr+tJs4a9uuaSIBAITbUggygdhuG0VrO0EO+QqH91GhYMN4S6KRtOEmGVA==}
+  '@rushstack/rig-package@0.5.2':
     dependencies:
       resolve: 1.22.8
       strip-json-comments: 3.1.1
-    dev: true
 
-  /@rushstack/ts-command-line@4.17.1:
-    resolution: {integrity: sha512-2jweO1O57BYP5qdBGl6apJLB+aRIn5ccIRTPDyULh0KMwVzFqWtw6IZWt1qtUoZD/pD2RNkIOosH6Cq45rIYeg==}
+  '@rushstack/terminal@0.10.1(@types/node@20.12.7)':
     dependencies:
+      '@rushstack/node-core-library': 4.1.0(@types/node@20.12.7)
+      supports-color: 8.1.1
+    optionalDependencies:
+      '@types/node': 20.12.7
+
+  '@rushstack/ts-command-line@4.19.2(@types/node@20.12.7)':
+    dependencies:
+      '@rushstack/terminal': 0.10.1(@types/node@20.12.7)
       '@types/argparse': 1.0.38
       argparse: 1.0.10
-      colors: 1.2.5
       string-argv: 0.3.1
-    dev: true
+    transitivePeerDependencies:
+      - '@types/node'
 
-  /@shikijs/core@1.2.0:
-    resolution: {integrity: sha512-OlFvx+nyr5C8zpcMBnSGir0YPD6K11uYhouqhNmm1qLiis4GA7SsGtu07r9gKS9omks8RtQqHrJL4S+lqWK01A==}
-    dev: false
+  '@shikijs/core@1.4.0': {}
 
-  /@sideway/address@4.1.4:
-    resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==}
+  '@sideway/address@4.1.4':
     dependencies:
       '@hapi/hoek': 9.3.0
-    dev: true
 
-  /@sideway/formula@3.0.1:
-    resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==}
-    dev: true
+  '@sideway/formula@3.0.1': {}
 
-  /@sideway/pinpoint@2.0.0:
-    resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==}
-    dev: true
+  '@sideway/pinpoint@2.0.0': {}
 
-  /@simplewebauthn/server@9.0.3:
-    resolution: {integrity: sha512-FMZieoBosrVLFxCnxPFD9Enhd1U7D8nidVDT4MsHc6l4fdVcjoeHjDueeXCloO1k5O/fZg1fsSXXPKbY2XTzDA==}
-    engines: {node: '>=16.0.0'}
+  '@simplewebauthn/server@10.0.0(encoding@0.1.13)':
     dependencies:
       '@hexagon/base64': 1.1.27
       '@levischuck/tiny-cbor': 0.2.2
@@ -5494,238 +13943,168 @@ packages:
       '@peculiar/asn1-rsa': 2.3.8
       '@peculiar/asn1-schema': 2.3.8
       '@peculiar/asn1-x509': 2.3.8
-      '@simplewebauthn/types': 9.0.1
-      cross-fetch: 4.0.0
+      '@simplewebauthn/types': 10.0.0
+      cross-fetch: 4.0.0(encoding@0.1.13)
     transitivePeerDependencies:
       - encoding
-    dev: false
 
-  /@simplewebauthn/types@9.0.1:
-    resolution: {integrity: sha512-tGSRP1QvsAvsJmnOlRQyw/mvK9gnPtjEc5fg2+m8n+QUa+D7rvrKkOYyfpy42GTs90X3RDOnqJgfHt+qO67/+w==}
+  '@simplewebauthn/types@10.0.0': {}
 
-  /@sinclair/typebox@0.27.8:
-    resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
-    dev: true
+  '@sinclair/typebox@0.27.8': {}
 
-  /@sindresorhus/is@4.6.0:
-    resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
-    engines: {node: '>=10'}
-    dev: false
+  '@sindresorhus/is@4.6.0': {}
 
-  /@sindresorhus/is@5.3.0:
-    resolution: {integrity: sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==}
-    engines: {node: '>=14.16'}
+  '@sindresorhus/is@5.3.0': {}
 
-  /@sindresorhus/is@6.1.0:
-    resolution: {integrity: sha512-BuvU07zq3tQ/2SIgBsEuxKYDyDjC0n7Zir52bpHy2xnBbW81+po43aLFPLbeV3HRAheFbGud1qgcqSYfhtHMAg==}
-    engines: {node: '>=16'}
-    dev: false
+  '@sindresorhus/is@6.1.0': {}
 
-  /@sinonjs/commons@2.0.0:
-    resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==}
-    dependencies:
-      type-detect: 4.0.8
-    dev: true
-
-  /@sinonjs/commons@3.0.0:
-    resolution: {integrity: sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==}
+  '@sinonjs/commons@2.0.0':
     dependencies:
       type-detect: 4.0.8
 
-  /@sinonjs/fake-timers@10.3.0:
-    resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==}
+  '@sinonjs/commons@3.0.0':
+    dependencies:
+      type-detect: 4.0.8
+
+  '@sinonjs/fake-timers@10.3.0':
     dependencies:
       '@sinonjs/commons': 3.0.0
-    dev: true
 
-  /@sinonjs/fake-timers@11.2.2:
-    resolution: {integrity: sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==}
+  '@sinonjs/fake-timers@11.2.2':
     dependencies:
       '@sinonjs/commons': 3.0.0
-    dev: false
 
-  /@sinonjs/samsam@8.0.0:
-    resolution: {integrity: sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==}
+  '@sinonjs/samsam@8.0.0':
     dependencies:
       '@sinonjs/commons': 2.0.0
       lodash.get: 4.4.2
       type-detect: 4.0.8
-    dev: true
 
-  /@sinonjs/text-encoding@0.7.2:
-    resolution: {integrity: sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==}
-    dev: true
+  '@sinonjs/text-encoding@0.7.2': {}
 
-  /@smithy/abort-controller@2.0.14:
-    resolution: {integrity: sha512-zXtteuYLWbSXnzI3O6xq3FYvigYZFW8mdytGibfarLL2lxHto9L3ILtGVnVGmFZa7SDh62l39EnU5hesLN87Fw==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/abort-controller@2.0.14':
     dependencies:
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/chunked-blob-reader-native@2.0.0:
-    resolution: {integrity: sha512-HM8V2Rp1y8+1343tkZUKZllFhEQPNmpNdgFAncbTsxkZ18/gqjk23XXv3qGyXWp412f3o43ZZ1UZHVcHrpRnCQ==}
+  '@smithy/abort-controller@2.2.0':
+    dependencies:
+      '@smithy/types': 2.12.0
+      tslib: 2.6.2
+
+  '@smithy/chunked-blob-reader-native@2.0.0':
     dependencies:
       '@smithy/util-base64': 2.0.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/chunked-blob-reader@2.0.0:
-    resolution: {integrity: sha512-k+J4GHJsMSAIQPChGBrjEmGS+WbPonCXesoqP9fynIqjn7rdOThdH8FAeCmokP9mxTYKQAKoHCLPzNlm6gh7Wg==}
+  '@smithy/chunked-blob-reader@2.0.0':
     dependencies:
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/config-resolver@2.0.9:
-    resolution: {integrity: sha512-QBkGPLUqyPmis9Erz8v4q5lo/ErnF7+GD5WZHa6JZiXopUPfaaM+B21n8gzS5xCkIXZmnwzNQhObP9xQPu8oqQ==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/config-resolver@2.0.9':
     dependencies:
       '@smithy/node-config-provider': 2.0.11
       '@smithy/types': 2.6.0
       '@smithy/util-config-provider': 2.0.0
       '@smithy/util-middleware': 2.0.1
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/credential-provider-imds@2.0.11:
-    resolution: {integrity: sha512-uJJs8dnM5iXkn8a2GaKvlKMhcOJ+oJPYqY9gY3CM/EieCVObIDjxUtR/g8lU/k/A+OauA78GzScAfulmFjPOYA==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/credential-provider-imds@2.0.11':
     dependencies:
       '@smithy/node-config-provider': 2.0.11
       '@smithy/property-provider': 2.0.9
       '@smithy/types': 2.6.0
       '@smithy/url-parser': 2.0.8
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/eventstream-codec@2.0.8:
-    resolution: {integrity: sha512-onO4to8ujCKn4m5XagReT9Nc6FlNG5vveuvjp1H7AtaG7njdet1LOl6/jmUOkskF2C/w+9jNw3r9Ak+ghOvN0A==}
+  '@smithy/eventstream-codec@2.0.8':
     dependencies:
       '@aws-crypto/crc32': 3.0.0
       '@smithy/types': 2.6.0
       '@smithy/util-hex-encoding': 2.0.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/eventstream-serde-browser@2.0.8:
-    resolution: {integrity: sha512-/RGlkKUnC0sd+xKBKH/2APSBRmVMZTeLOKZMhrZmrO+ONoU+DwyMr/RLJ6WnmBKN+2ebjffM4pcIJTKLNNDD8g==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/eventstream-serde-browser@2.0.8':
     dependencies:
       '@smithy/eventstream-serde-universal': 2.0.8
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/eventstream-serde-config-resolver@2.0.8:
-    resolution: {integrity: sha512-EyAEj258eMUv9zcMvBbqrInh2eHRYuiwQAjXDMxZFCyP+JePzQB6O++3wFwjQeRKMFFgZipNgnEXfReII4+NAw==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/eventstream-serde-config-resolver@2.0.8':
     dependencies:
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/eventstream-serde-node@2.0.8:
-    resolution: {integrity: sha512-FMBatSUSKwh6aguKVJokXfJaV8nqsuCkCZHb9MP9zah0ZF+ohbTLeeed7DQGeTVBueVIVWEzIsShPxtxBv7MMQ==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/eventstream-serde-node@2.0.8':
     dependencies:
       '@smithy/eventstream-serde-universal': 2.0.8
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/eventstream-serde-universal@2.0.8:
-    resolution: {integrity: sha512-6InMXH8BUKoEDa6CAuxR4Gn8Gf2vBfVtjA9A6zDKZClYHT+ANUJS+2EtOBc5wECJJGk4KLn5ajQyrt9MBv5lcw==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/eventstream-serde-universal@2.0.8':
     dependencies:
       '@smithy/eventstream-codec': 2.0.8
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/fetch-http-handler@2.1.4:
-    resolution: {integrity: sha512-SL24M9W5ERByoXaVicRx+bj9GJVujDnPn+QO7GY7adhY0mPGa6DSF58pVKsgIh4r5Tx/k3SWCPlH4BxxSxA/fQ==}
+  '@smithy/fetch-http-handler@2.1.4':
     dependencies:
       '@smithy/protocol-http': 3.0.10
       '@smithy/querystring-builder': 2.0.14
       '@smithy/types': 2.6.0
       '@smithy/util-base64': 2.0.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/hash-blob-browser@2.0.8:
-    resolution: {integrity: sha512-IgvRlBMfg/qLg321a59T1yTdEEbaizLrEVsU3DHj65DAO4lFRMF5f+l7vuV+je6m1G9wSD5GQXLturX8qlGb4g==}
+  '@smithy/hash-blob-browser@2.0.8':
     dependencies:
       '@smithy/chunked-blob-reader': 2.0.0
       '@smithy/chunked-blob-reader-native': 2.0.0
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/hash-node@2.0.8:
-    resolution: {integrity: sha512-yZL/nmxZzjZV5/QX5JWSgXlt0HxuMTwFO89CS++jOMMPiCMZngf6VYmtNdccs8IIIAMmfQeTzwu07XgUE/Zd3Q==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/hash-node@2.0.8':
     dependencies:
       '@smithy/types': 2.6.0
       '@smithy/util-buffer-from': 2.0.0
       '@smithy/util-utf8': 2.0.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/hash-stream-node@2.0.8:
-    resolution: {integrity: sha512-82zC6I9ZJycbEZH8TVyXyBx9c2ZIPQDgBvM0x5AFPUl/i1AxwKKX+lwYRnzgkF//cYhIIoJaCfJ9mjSMPRGvCQ==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/hash-stream-node@2.0.8':
     dependencies:
       '@smithy/types': 2.6.0
       '@smithy/util-utf8': 2.0.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/invalid-dependency@2.0.8:
-    resolution: {integrity: sha512-88VOS7W3KzUz/bNRc+Sl/F/CDIasFspEE4G39YZRHIh9YmsXF7GUyVaAKURfMNulTie62ayk6BHC9O0nOBAVgQ==}
+  '@smithy/invalid-dependency@2.0.8':
     dependencies:
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/is-array-buffer@2.0.0:
-    resolution: {integrity: sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/is-array-buffer@2.0.0':
     dependencies:
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/md5-js@2.0.8:
-    resolution: {integrity: sha512-1VVECXEiuJvjXv+mudiaUFKYwgDLOWz5MTTy8RzbrPiU3GiOb3/o5/urdkYpqmgoMfxdvxxOw/Adjv2dV2q2Yg==}
+  '@smithy/md5-js@2.0.8':
     dependencies:
       '@smithy/types': 2.6.0
       '@smithy/util-utf8': 2.0.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/middleware-content-length@2.0.10:
-    resolution: {integrity: sha512-EGSbysyA4jH0p3xI6G0jdXoj9Iz9GUnAta6aEaHtXm3wVWtenRf80y2TeVvNkVSr5jwKOdSCjKIRI2l1A/oZLA==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/middleware-content-length@2.0.10':
     dependencies:
       '@smithy/protocol-http': 3.0.10
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/middleware-endpoint@2.0.8:
-    resolution: {integrity: sha512-yOpogfG2d2V0cbJdAJ6GLAWkNOc9pVsL5hZUfXcxJu408N3CUCsXzIAFF6+70ZKSE+lCfG3GFErcSXv/UfUbjw==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/middleware-endpoint@2.0.8':
     dependencies:
       '@smithy/middleware-serde': 2.0.8
       '@smithy/types': 2.6.0
       '@smithy/url-parser': 2.0.8
       '@smithy/util-middleware': 2.0.1
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/middleware-retry@2.0.11:
-    resolution: {integrity: sha512-pknfokumZ+wvBERSuKAI2vVr+aK3ZgPiWRg6+0ZG4kKJogBRpPmDGWw+Jht0izS9ZaEbIobNzueIb4wD33JJVg==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/middleware-retry@2.0.11':
     dependencies:
       '@smithy/node-config-provider': 2.0.11
       '@smithy/protocol-http': 3.0.10
@@ -5735,96 +14114,74 @@ packages:
       '@smithy/util-retry': 2.0.1
       tslib: 2.6.2
       uuid: 8.3.2
-    dev: false
 
-  /@smithy/middleware-serde@2.0.8:
-    resolution: {integrity: sha512-Is0sm+LiNlgsc0QpstDzifugzL9ehno1wXp109GgBgpnKTK3j+KphiparBDI4hWTtH9/7OUsxuspNqai2yyhcg==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/middleware-serde@2.0.8':
     dependencies:
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/middleware-stack@2.0.1:
-    resolution: {integrity: sha512-UexsfY6/oQZRjTQL56s9AKtMcR60tBNibSgNYX1I2WXaUaXg97W9JCkFyth85TzBWKDBTyhLfenrukS/kyu54A==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/middleware-stack@2.0.1':
     dependencies:
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/node-config-provider@2.0.11:
-    resolution: {integrity: sha512-CaR1dciSSGKttjhcefpytYjsfI/Yd5mqL8am4wfmyFCDxSiPsvnEWHl8UjM/RbcAjX0klt+CeIKPSHEc0wGvJA==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/node-config-provider@2.0.11':
     dependencies:
       '@smithy/property-provider': 2.0.9
       '@smithy/shared-ini-file-loader': 2.0.10
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/node-http-handler@2.1.10:
-    resolution: {integrity: sha512-lkALAwtN6odygIM4nB8aHDahINM6WXXjNrZmWQAh0RSossySRT2qa31cFv0ZBuAYVWeprskRk13AFvvLmf1WLw==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/node-http-handler@2.5.0':
     dependencies:
-      '@smithy/abort-controller': 2.0.14
-      '@smithy/protocol-http': 3.0.10
-      '@smithy/querystring-builder': 2.0.14
-      '@smithy/types': 2.6.0
+      '@smithy/abort-controller': 2.2.0
+      '@smithy/protocol-http': 3.3.0
+      '@smithy/querystring-builder': 2.2.0
+      '@smithy/types': 2.12.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/property-provider@2.0.9:
-    resolution: {integrity: sha512-25pPZ8f8DeRwYI5wbPRZaoMoR+3vrw8DwbA0TjP+GsdiB2KxScndr4HQehiJ5+WJ0giOTWhLz0bd+7Djv1qpUQ==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/property-provider@2.0.9':
     dependencies:
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/protocol-http@3.0.10:
-    resolution: {integrity: sha512-6+tjNk7rXW7YTeGo9qwxXj/2BFpJTe37kTj3EnZCoX/nH+NP/WLA7O83fz8XhkGqsaAhLUPo/bB12vvd47nsmg==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/protocol-http@3.0.10':
     dependencies:
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/querystring-builder@2.0.14:
-    resolution: {integrity: sha512-lQ4pm9vTv9nIhl5jt6uVMPludr6syE2FyJmHsIJJuOD7QPIJnrf9HhUGf1iHh9KJ4CUv21tpOU3X6s0rB6uJ0g==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/protocol-http@3.3.0':
+    dependencies:
+      '@smithy/types': 2.12.0
+      tslib: 2.6.2
+
+  '@smithy/querystring-builder@2.0.14':
     dependencies:
       '@smithy/types': 2.6.0
       '@smithy/util-uri-escape': 2.0.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/querystring-parser@2.0.8:
-    resolution: {integrity: sha512-ArbanNuR7O/MmTd90ZqhDqGOPPDYmxx3huHxD+R3cuCnazcK/1tGQA+SnnR5307T7ZRb5WTpB6qBggERuibVSA==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/querystring-builder@2.2.0':
+    dependencies:
+      '@smithy/types': 2.12.0
+      '@smithy/util-uri-escape': 2.2.0
+      tslib: 2.6.2
+
+  '@smithy/querystring-parser@2.0.8':
     dependencies:
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/service-error-classification@2.0.1:
-    resolution: {integrity: sha512-QHa9+t+v4s0cMuDCcbjIJN67mNZ42/+fc3jKe8P6ZMPXZl5ksKk6a8vhZ/m494GZng5eFTc3OePv+NF9cG83yg==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/service-error-classification@2.0.1':
     dependencies:
       '@smithy/types': 2.6.0
-    dev: false
 
-  /@smithy/shared-ini-file-loader@2.0.10:
-    resolution: {integrity: sha512-jWASteSezRKohJ7GdA7pHDvmr7Q7tw3b5mu3xLHIkZy/ICftJ+O7aqNaF8wklhI7UNFoQ7flFRM3Rd0KA+1BbQ==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/shared-ini-file-loader@2.0.10':
     dependencies:
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/signature-v4@2.0.5:
-    resolution: {integrity: sha512-ABIzXmUDXK4n2c9cXjQLELgH2RdtABpYKT+U131e2I6RbCypFZmxIHmIBufJzU2kdMCQ3+thBGDWorAITFW04A==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/signature-v4@2.0.5':
     dependencies:
       '@smithy/eventstream-codec': 2.0.8
       '@smithy/is-array-buffer': 2.0.0
@@ -5834,83 +14191,59 @@ packages:
       '@smithy/util-uri-escape': 2.0.0
       '@smithy/util-utf8': 2.0.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/smithy-client@2.1.5:
-    resolution: {integrity: sha512-7S865uKzsxApM8W8Q6zkij7tcUFgaG8PuADMFdMt1yL/ku3d0+s6Zwrg3N7iXCPM08Gu/mf0BIfTXIu/9i450Q==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/smithy-client@2.1.5':
     dependencies:
       '@smithy/middleware-stack': 2.0.1
       '@smithy/types': 2.6.0
       '@smithy/util-stream': 2.0.11
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/types@2.6.0:
-    resolution: {integrity: sha512-PgqxJq2IcdMF9iAasxcqZqqoOXBHufEfmbEUdN1pmJrJltT42b0Sc8UiYSWWzKkciIp9/mZDpzYi4qYG1qqg6g==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/types@2.12.0':
     dependencies:
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/url-parser@2.0.8:
-    resolution: {integrity: sha512-wQw7j004ScCrBRJ+oNPXlLE9mtofxyadSZ9D8ov/rHkyurS7z1HTNuyaGRj6OvKsEk0SVQsuY0C9+EfM75XTkw==}
+  '@smithy/types@2.6.0':
+    dependencies:
+      tslib: 2.6.2
+
+  '@smithy/url-parser@2.0.8':
     dependencies:
       '@smithy/querystring-parser': 2.0.8
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/util-base64@2.0.0:
-    resolution: {integrity: sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/util-base64@2.0.0':
     dependencies:
       '@smithy/util-buffer-from': 2.0.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/util-body-length-browser@2.0.0:
-    resolution: {integrity: sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==}
+  '@smithy/util-body-length-browser@2.0.0':
     dependencies:
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/util-body-length-node@2.1.0:
-    resolution: {integrity: sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/util-body-length-node@2.1.0':
     dependencies:
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/util-buffer-from@2.0.0:
-    resolution: {integrity: sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/util-buffer-from@2.0.0':
     dependencies:
       '@smithy/is-array-buffer': 2.0.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/util-config-provider@2.0.0:
-    resolution: {integrity: sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/util-config-provider@2.0.0':
     dependencies:
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/util-defaults-mode-browser@2.0.9:
-    resolution: {integrity: sha512-JONLJVQWT8165XoSV36ERn3SVlZLJJ4D6IeGsCSePv65Uxa93pzSLE0UMSR9Jwm4zix7rst9AS8W5QIypZWP8Q==}
-    engines: {node: '>= 10.0.0'}
+  '@smithy/util-defaults-mode-browser@2.0.9':
     dependencies:
       '@smithy/property-provider': 2.0.9
       '@smithy/smithy-client': 2.1.5
       '@smithy/types': 2.6.0
       bowser: 2.11.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/util-defaults-mode-node@2.0.11:
-    resolution: {integrity: sha512-tmqjNsfj+bgZN6jXBe6efZnukzILA7BUytHkzqikuRLNtR+0VVchQHvawD0w6vManh76rO81ydhioe7i4oBzuA==}
-    engines: {node: '>= 10.0.0'}
+  '@smithy/util-defaults-mode-node@2.0.11':
     dependencies:
       '@smithy/config-resolver': 2.0.9
       '@smithy/credential-provider-imds': 2.0.11
@@ -5919,76 +14252,55 @@ packages:
       '@smithy/smithy-client': 2.1.5
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/util-hex-encoding@2.0.0:
-    resolution: {integrity: sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/util-hex-encoding@2.0.0':
     dependencies:
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/util-middleware@2.0.1:
-    resolution: {integrity: sha512-LnsBMi0Mg3gfz/TpNGLv2Jjcz2ra1OX5HR/4IaCepIYmtPQzqMWDdhX/XTW1LS8OZ0xbQuyQPcHkQ+2XkhWOVQ==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/util-middleware@2.0.1':
     dependencies:
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/util-retry@2.0.1:
-    resolution: {integrity: sha512-naj4X0IafJ9yJnVJ58QgSMkCNLjyQOnyrnKh/T0f+0UOUxJiT8vuFn/hS7B/pNqbo2STY7PyJ4J4f+5YqxwNtA==}
-    engines: {node: '>= 14.0.0'}
+  '@smithy/util-retry@2.0.1':
     dependencies:
       '@smithy/service-error-classification': 2.0.1
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/util-stream@2.0.11:
-    resolution: {integrity: sha512-2MeWfqSpZKdmEJ+tH8CJQSgzLWhH5cmdE24X7JB0hiamXrOmswWGGuPvyj/9sQCTclo57pNxLR2p7KrP8Ahiyg==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/util-stream@2.0.11':
     dependencies:
       '@smithy/fetch-http-handler': 2.1.4
-      '@smithy/node-http-handler': 2.1.10
+      '@smithy/node-http-handler': 2.5.0
       '@smithy/types': 2.6.0
       '@smithy/util-base64': 2.0.0
       '@smithy/util-buffer-from': 2.0.0
       '@smithy/util-hex-encoding': 2.0.0
       '@smithy/util-utf8': 2.0.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/util-uri-escape@2.0.0:
-    resolution: {integrity: sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/util-uri-escape@2.0.0':
     dependencies:
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/util-utf8@2.0.0:
-    resolution: {integrity: sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/util-uri-escape@2.2.0':
+    dependencies:
+      tslib: 2.6.2
+
+  '@smithy/util-utf8@2.0.0':
     dependencies:
       '@smithy/util-buffer-from': 2.0.0
       tslib: 2.6.2
-    dev: false
 
-  /@smithy/util-waiter@2.0.8:
-    resolution: {integrity: sha512-t9yaoofNhdEhNlyDeV5al/JJEFJ62HIQBGktgCUE63MvKn6imnbkh1qISsYMyMYVLwhWCpZ3Xa3R1LA+SnWcng==}
-    engines: {node: '>=14.0.0'}
+  '@smithy/util-waiter@2.0.8':
     dependencies:
       '@smithy/abort-controller': 2.0.14
       '@smithy/types': 2.6.0
       tslib: 2.6.2
-    dev: false
 
-  /@sqltools/formatter@1.2.5:
-    resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==}
-    dev: false
+  '@sqltools/formatter@1.2.5': {}
 
-  /@storybook/addon-actions@8.0.9:
-    resolution: {integrity: sha512-+I3VTvlKdj8puHeS2tyaOVv9syDiNLneVZbTfqN+UDOK2i42NwvZr8PVwjTzMlEj9eePJdCZgiipz55xwts5bw==}
+  '@storybook/addon-actions@8.0.9':
     dependencies:
       '@storybook/core-events': 8.0.9
       '@storybook/global': 5.0.0
@@ -5996,20 +14308,16 @@ packages:
       dequal: 2.0.3
       polished: 4.2.2
       uuid: 9.0.1
-    dev: true
 
-  /@storybook/addon-backgrounds@8.0.9:
-    resolution: {integrity: sha512-pCDecACrVyxPaJKEWS0sHsRb8xw+IPCSxDM1TkjaAQ6zZ468A/dcUnqW+LVK8bSXgQwWzn23wqnqPFSy5yptuQ==}
+  '@storybook/addon-backgrounds@8.0.9':
     dependencies:
       '@storybook/global': 5.0.0
       memoizerific: 1.11.3
       ts-dedent: 2.2.0
-    dev: true
 
-  /@storybook/addon-controls@8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-wWdmd62UP/sfPm8M7aJjEA+kEXTUIR/QsYi9PoYBhBZcXiikZ4kNan7oD7GfsnzGGKHrBVfwQhO+TqaENGYytA==}
+  '@storybook/addon-controls@8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
     dependencies:
-      '@storybook/blocks': 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/blocks': 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       lodash: 4.17.21
       ts-dedent: 2.2.0
     transitivePeerDependencies:
@@ -6018,50 +14326,46 @@ packages:
       - react
       - react-dom
       - supports-color
-    dev: true
 
-  /@storybook/addon-docs@8.0.9:
-    resolution: {integrity: sha512-x7hX7UuzJtClu6XwU3SfpyFhuckVcgqgD6BU6Ihxl0zs+i4xp6iKVXYSnHFMRM1sgoeT8TjPxab35Ke8w8BVRw==}
+  '@storybook/addon-docs@8.0.9(encoding@0.1.13)':
     dependencies:
       '@babel/core': 7.24.0
-      '@mdx-js/react': 3.0.1(@types/react@18.0.28)(react@18.2.0)
-      '@storybook/blocks': 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
+      '@mdx-js/react': 3.0.1(@types/react@18.0.28)(react@18.3.1)
+      '@storybook/blocks': 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/client-logger': 8.0.9
-      '@storybook/components': 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/components': 8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/csf-plugin': 8.0.9
       '@storybook/csf-tools': 8.0.9
       '@storybook/global': 5.0.0
       '@storybook/node-logger': 8.0.9
       '@storybook/preview-api': 8.0.9
-      '@storybook/react-dom-shim': 8.0.9(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/theming': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/react-dom-shim': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+      '@storybook/theming': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/types': 8.0.9
       '@types/react': 18.0.28
       fs-extra: 11.1.1
-      react: 18.2.0
-      react-dom: 18.2.0(react@18.2.0)
+      react: 18.3.1
+      react-dom: 18.3.1(react@18.3.1)
       rehype-external-links: 3.0.0
       rehype-slug: 6.0.0
       ts-dedent: 2.2.0
     transitivePeerDependencies:
       - encoding
       - supports-color
-    dev: true
 
-  /@storybook/addon-essentials@8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-mwAgdfrOsTuTDcagvM7veBh+iayZIWmKOazzkhrIWbhYcrXOsweigD2UOVeHgAiAzJK49znr4FXTCKcE1hOWcw==}
+  '@storybook/addon-essentials@8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
     dependencies:
       '@storybook/addon-actions': 8.0.9
       '@storybook/addon-backgrounds': 8.0.9
-      '@storybook/addon-controls': 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/addon-docs': 8.0.9
+      '@storybook/addon-controls': 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+      '@storybook/addon-docs': 8.0.9(encoding@0.1.13)
       '@storybook/addon-highlight': 8.0.9
       '@storybook/addon-measure': 8.0.9
       '@storybook/addon-outline': 8.0.9
       '@storybook/addon-toolbars': 8.0.9
       '@storybook/addon-viewport': 8.0.9
-      '@storybook/core-common': 8.0.9
-      '@storybook/manager-api': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/core-common': 8.0.9(encoding@0.1.13)
+      '@storybook/manager-api': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/node-logger': 8.0.9
       '@storybook/preview-api': 8.0.9
       ts-dedent: 2.2.0
@@ -6071,20 +14375,16 @@ packages:
       - react
       - react-dom
       - supports-color
-    dev: true
 
-  /@storybook/addon-highlight@8.0.9:
-    resolution: {integrity: sha512-vaRHGDbx7dpNpQECAHk5wczlZO3ntstprGlqnZt0o7ylz6xB5+pTQwTuIFty0hwKv+3TPcskzzifATUyEOEmyg==}
+  '@storybook/addon-highlight@8.0.9':
     dependencies:
       '@storybook/global': 5.0.0
-    dev: true
 
-  /@storybook/addon-interactions@8.0.9(vitest@0.34.6):
-    resolution: {integrity: sha512-AMIdNcyM6DDAWvMitBJMqp1iPZND8AXB4QT4VZHGMKG2ngHNKktriEKpTfcRkfKPGTJs9T+71dWfm6/R4tticw==}
+  '@storybook/addon-interactions@8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))':
     dependencies:
       '@storybook/global': 5.0.0
       '@storybook/instrumenter': 8.0.9
-      '@storybook/test': 8.0.9(vitest@0.34.6)
+      '@storybook/test': 8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
       '@storybook/types': 8.0.9
       polished: 4.2.2
       ts-dedent: 2.2.0
@@ -6094,147 +14394,104 @@ packages:
       - '@types/jest'
       - jest
       - vitest
-    dev: true
 
-  /@storybook/addon-links@8.0.9(react@18.2.0):
-    resolution: {integrity: sha512-FVt+AdW3JFSqbJzkKiqKsMRWqHXqEvCBqFs7lNfk3OW0w0jfv1iREtrxE0dVdJoUFQC9V/2Im/EpJ7UB3C2bNQ==}
-    peerDependencies:
-      react: ^16.8.0 || ^17.0.0 || ^18.0.0
-    peerDependenciesMeta:
-      react:
-        optional: true
+  '@storybook/addon-links@8.0.9(react@18.3.1)':
     dependencies:
       '@storybook/csf': 0.1.6
       '@storybook/global': 5.0.0
-      react: 18.2.0
       ts-dedent: 2.2.0
-    dev: true
+    optionalDependencies:
+      react: 18.3.1
 
-  /@storybook/addon-mdx-gfm@8.0.9:
-    resolution: {integrity: sha512-AoEx+OGKANtVZgKyWKrQhGpMpDuc2S7PnOlNLUiDYzmj8ABAGPmEJmqeb/VHVgqLQSjhOW1fMsQ4fYsecvMxTQ==}
+  '@storybook/addon-mdx-gfm@8.0.9':
     dependencies:
       '@storybook/node-logger': 8.0.9
       remark-gfm: 4.0.0
       ts-dedent: 2.2.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@storybook/addon-measure@8.0.9:
-    resolution: {integrity: sha512-91svOOGEXmGG4USglwXLE3wtlUVgtbKJVxTKX7xRI+AC5JEEaKByVzP17/X8Qn/8HilUL7AfSQ0kCoqtPSJ5cA==}
+  '@storybook/addon-measure@8.0.9':
     dependencies:
       '@storybook/global': 5.0.0
       tiny-invariant: 1.3.1
-    dev: true
 
-  /@storybook/addon-outline@8.0.9:
-    resolution: {integrity: sha512-fQ+jm356TgUnz81IxsC99/aOesbLw3N5OQRJpo/A6kqbLMzlq3ybVzuXYCKC3f0ArgQRNh4NoMeJBMRFMtaWRw==}
+  '@storybook/addon-outline@8.0.9':
     dependencies:
       '@storybook/global': 5.0.0
       ts-dedent: 2.2.0
-    dev: true
 
-  /@storybook/addon-storysource@8.0.9:
-    resolution: {integrity: sha512-5m3K2Rs4fQtKtqwrq4CDS1jK2wzWOlnxhE2ArX5XTWytb1am65CEPxfYTEQkvZH9oPGwX3cXytPCziynqysFMQ==}
+  '@storybook/addon-storysource@8.0.9':
     dependencies:
       '@storybook/source-loader': 8.0.9
       estraverse: 5.3.0
       tiny-invariant: 1.3.1
-    dev: true
 
-  /@storybook/addon-toolbars@8.0.9:
-    resolution: {integrity: sha512-nNSBnnBOhQ+EJwkrIkK4ZBYPcozNmEH770CZ/6NK85SUJ6WEBZapE6ru33jIUokFGEvlOlNCeai0GUc++cQP8w==}
-    dev: true
+  '@storybook/addon-toolbars@8.0.9': {}
 
-  /@storybook/addon-viewport@8.0.9:
-    resolution: {integrity: sha512-Ao4+D56cO7biaw+iTlMU1FBec1idX0cmdosDeCFZin06MSawcPkeBlRBeruaSQYdLes8TBMdZPFgfuqI5yIk6g==}
+  '@storybook/addon-viewport@8.0.9':
     dependencies:
       memoizerific: 1.11.3
-    dev: true
 
-  /@storybook/blocks@8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-F2zSrfSwzTFN7qW3zB80tG+EXtmfmCDC6Ird0F7tolszb6tOqJcAcBOwQbE2O0wI63sLu21qxzXgaKBMkiWvJg==}
-    peerDependencies:
-      react: ^16.8.0 || ^17.0.0 || ^18.0.0
-      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
-    peerDependenciesMeta:
-      react:
-        optional: true
-      react-dom:
-        optional: true
+  '@storybook/blocks@8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
     dependencies:
       '@storybook/channels': 8.0.9
       '@storybook/client-logger': 8.0.9
-      '@storybook/components': 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/components': 8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/core-events': 8.0.9
       '@storybook/csf': 0.1.6
-      '@storybook/docs-tools': 8.0.9
+      '@storybook/docs-tools': 8.0.9(encoding@0.1.13)
       '@storybook/global': 5.0.0
-      '@storybook/icons': 1.2.5(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/manager-api': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/icons': 1.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+      '@storybook/manager-api': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/preview-api': 8.0.9
-      '@storybook/theming': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/theming': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/types': 8.0.9
       '@types/lodash': 4.14.191
       color-convert: 2.0.1
       dequal: 2.0.3
       lodash: 4.17.21
-      markdown-to-jsx: 7.3.2(react@18.2.0)
+      markdown-to-jsx: 7.3.2(react@18.3.1)
       memoizerific: 1.11.3
       polished: 4.2.2
-      react: 18.2.0
-      react-colorful: 5.6.1(react-dom@18.2.0)(react@18.2.0)
-      react-dom: 18.2.0(react@18.2.0)
+      react-colorful: 5.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       telejson: 7.2.0
       tocbot: 4.21.1
       ts-dedent: 2.2.0
       util-deprecate: 1.0.2
+    optionalDependencies:
+      react: 18.3.1
+      react-dom: 18.3.1(react@18.3.1)
     transitivePeerDependencies:
       - '@types/react'
       - encoding
       - supports-color
-    dev: true
 
-  /@storybook/builder-manager@8.0.9:
-    resolution: {integrity: sha512-/PxDwZIfMc/PSRZcasb6SIdGr3azIlenzx7dBF7Imt8i4jLHiAf1t00GvghlfJsvsrn4DNp95rbRbXTDyTj7tQ==}
+  '@storybook/builder-manager@8.0.9(encoding@0.1.13)':
     dependencies:
       '@fal-works/esbuild-plugin-global-externals': 2.1.2
-      '@storybook/core-common': 8.0.9
+      '@storybook/core-common': 8.0.9(encoding@0.1.13)
       '@storybook/manager': 8.0.9
       '@storybook/node-logger': 8.0.9
       '@types/ejs': 3.1.2
-      '@yarnpkg/esbuild-plugin-pnp': 3.0.0-rc.15(esbuild@0.19.11)
+      '@yarnpkg/esbuild-plugin-pnp': 3.0.0-rc.15(esbuild@0.20.2)
       browser-assert: 1.2.1
       ejs: 3.1.9
-      esbuild: 0.19.11
+      esbuild: 0.20.2
       esbuild-plugin-alias: 0.2.1
-      express: 4.18.2
+      express: 4.19.2
       fs-extra: 11.1.1
       process: 0.11.10
       util: 0.12.5
     transitivePeerDependencies:
       - encoding
       - supports-color
-    dev: true
 
-  /@storybook/builder-vite@8.0.9(typescript@5.3.3)(vite@5.1.4):
-    resolution: {integrity: sha512-7hEQFZIIz7VvxdySDpPE96iMvZxQvRZcRdhaNGeE+8Y2pyc3DgYE4WY3sjr+LUoB0a6TYLpAIKqbXwtLz0R+PQ==}
-    peerDependencies:
-      '@preact/preset-vite': '*'
-      typescript: '>= 4.3.x'
-      vite: ^4.0.0 || ^5.0.0
-      vite-plugin-glimmerx: '*'
-    peerDependenciesMeta:
-      '@preact/preset-vite':
-        optional: true
-      typescript:
-        optional: true
-      vite-plugin-glimmerx:
-        optional: true
+  '@storybook/builder-vite@8.0.9(encoding@0.1.13)(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))':
     dependencies:
       '@storybook/channels': 8.0.9
       '@storybook/client-logger': 8.0.9
-      '@storybook/core-common': 8.0.9
+      '@storybook/core-common': 8.0.9(encoding@0.1.13)
       '@storybook/core-events': 8.0.9
       '@storybook/csf-plugin': 8.0.9
       '@storybook/node-logger': 8.0.9
@@ -6249,37 +14506,33 @@ packages:
       fs-extra: 11.1.1
       magic-string: 0.30.7
       ts-dedent: 2.2.0
-      typescript: 5.3.3
-      vite: 5.1.4(@types/node@20.11.22)(sass@1.71.1)(terser@5.28.1)
+      vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
+    optionalDependencies:
+      typescript: 5.4.5
     transitivePeerDependencies:
       - encoding
       - supports-color
-    dev: true
 
-  /@storybook/channels@8.0.9:
-    resolution: {integrity: sha512-7Lcfyy5CsLWWGhMPO9WG4jZ/Alzp0AjepFhEreYHRPtQrfttp6qMAjE/g1aHgun0qHCYWxwqIG4NLR/hqDNrXQ==}
+  '@storybook/channels@8.0.9':
     dependencies:
       '@storybook/client-logger': 8.0.9
       '@storybook/core-events': 8.0.9
       '@storybook/global': 5.0.0
       telejson: 7.2.0
       tiny-invariant: 1.3.1
-    dev: true
 
-  /@storybook/cli@8.0.9(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-lilYTKn8F5YOePijqfRYFa5v2mHVIJxPCIgTn+OXAmAFbcizZ6P8P6niU4J/NXulgx68Ln1M7hYhFtTP25hVTw==}
-    hasBin: true
+  '@storybook/cli@8.0.9(@babel/preset-env@7.23.5(@babel/core@7.24.0))(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/types': 7.24.0
       '@ndelangen/get-tarball': 3.0.7
       '@storybook/codemod': 8.0.9
-      '@storybook/core-common': 8.0.9
+      '@storybook/core-common': 8.0.9(encoding@0.1.13)
       '@storybook/core-events': 8.0.9
-      '@storybook/core-server': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/core-server': 8.0.9(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)
       '@storybook/csf-tools': 8.0.9
       '@storybook/node-logger': 8.0.9
-      '@storybook/telemetry': 8.0.9
+      '@storybook/telemetry': 8.0.9(encoding@0.1.13)
       '@storybook/types': 8.0.9
       '@types/semver': 7.5.8
       '@yarnpkg/fslib': 2.10.3
@@ -6295,7 +14548,7 @@ packages:
       get-npm-tarball-url: 2.0.3
       giget: 1.1.2
       globby: 11.1.0
-      jscodeshift: 0.15.1(@babel/preset-env@7.23.5)
+      jscodeshift: 0.15.1(@babel/preset-env@7.23.5(@babel/core@7.24.0))
       leven: 3.1.0
       ora: 5.4.1
       prettier: 3.2.5
@@ -6314,16 +14567,12 @@ packages:
       - react-dom
       - supports-color
       - utf-8-validate
-    dev: true
 
-  /@storybook/client-logger@8.0.9:
-    resolution: {integrity: sha512-LzV/RHkbf07sRc1Jc0ff36RlapKf9Ul7/+9VMvVbI3hshH1CpmrZK4t/tsIdpX/EVOdJ1Gg5cES06PnleOAIPA==}
+  '@storybook/client-logger@8.0.9':
     dependencies:
       '@storybook/global': 5.0.0
-    dev: true
 
-  /@storybook/codemod@8.0.9:
-    resolution: {integrity: sha512-VBeGpSZSQpL6iyLLqceJSNGhdCqcNwv+xC/aWdDFOkmuE1YfbmNNwpa9QYv4ZFJ2QjUsm4iTWG60qK+9NXeSKA==}
+  '@storybook/codemod@8.0.9':
     dependencies:
       '@babel/core': 7.24.0
       '@babel/preset-env': 7.23.5(@babel/core@7.24.0)
@@ -6335,38 +14584,31 @@ packages:
       '@types/cross-spawn': 6.0.2
       cross-spawn: 7.0.3
       globby: 11.1.0
-      jscodeshift: 0.15.1(@babel/preset-env@7.23.5)
+      jscodeshift: 0.15.1(@babel/preset-env@7.23.5(@babel/core@7.24.0))
       lodash: 4.17.21
       prettier: 3.2.5
       recast: 0.23.6
       tiny-invariant: 1.3.1
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@storybook/components@8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-JcwBGADzIJs0PSzqykrrD2KHzNG9wtexUOKuidt+FSv9szpUhe3qBAXIHpdfBRl7mOJ9TRZ5rt+mukEnfncdzA==}
-    peerDependencies:
-      react: ^16.8.0 || ^17.0.0 || ^18.0.0
-      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+  '@storybook/components@8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
     dependencies:
-      '@radix-ui/react-slot': 1.0.2(@types/react@18.0.28)(react@18.2.0)
+      '@radix-ui/react-slot': 1.0.2(@types/react@18.0.28)(react@18.3.1)
       '@storybook/client-logger': 8.0.9
       '@storybook/csf': 0.1.6
       '@storybook/global': 5.0.0
-      '@storybook/icons': 1.2.5(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/theming': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/icons': 1.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+      '@storybook/theming': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/types': 8.0.9
       memoizerific: 1.11.3
-      react: 18.2.0
-      react-dom: 18.2.0(react@18.2.0)
+      react: 18.3.1
+      react-dom: 18.3.1(react@18.3.1)
       util-deprecate: 1.0.2
     transitivePeerDependencies:
       - '@types/react'
-    dev: true
 
-  /@storybook/core-common@8.0.9:
-    resolution: {integrity: sha512-Jmue+sfHFb4GTYBzyWYw1MygoJiQSfISIrKmNIzAmZ+oR9EOr+jpu/i/bH+uetZ2Hqg1AGhj1VB7OtJp9HQyWw==}
+  '@storybook/core-common@8.0.9(encoding@0.1.13)':
     dependencies:
       '@storybook/core-events': 8.0.9
       '@storybook/csf-tools': 8.0.9
@@ -6376,17 +14618,17 @@ packages:
       '@yarnpkg/libzip': 2.3.0
       chalk: 4.1.2
       cross-spawn: 7.0.3
-      esbuild: 0.19.11
-      esbuild-register: 3.5.0(esbuild@0.19.11)
+      esbuild: 0.20.2
+      esbuild-register: 3.5.0(esbuild@0.20.2)
       execa: 5.1.1
       file-system-cache: 2.3.0
       find-cache-dir: 3.3.2
       find-up: 5.0.0
       fs-extra: 11.1.1
-      glob: 10.3.10
+      glob: 10.3.12
       handlebars: 4.7.7
       lazy-universal-dotenv: 4.0.0
-      node-fetch: 2.7.0
+      node-fetch: 2.7.0(encoding@0.1.13)
       picomatch: 2.3.1
       pkg-dir: 5.0.0
       pretty-hrtime: 1.0.3
@@ -6399,33 +14641,29 @@ packages:
     transitivePeerDependencies:
       - encoding
       - supports-color
-    dev: true
 
-  /@storybook/core-events@8.0.9:
-    resolution: {integrity: sha512-DxSUx7wG9Qe3OFUBnv3OrYq48J8UWNo2DUR5/JecJCtp3n++L4fAEW3J0IF5FfxpQDMQSp1yTNjZ2PaWCMd2ag==}
+  '@storybook/core-events@8.0.9':
     dependencies:
       ts-dedent: 2.2.0
-    dev: true
 
-  /@storybook/core-server@8.0.9(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-BIe1T5YUBl0GYxEjRoTQsvXD2pyuzL8rPTUD41zlzSQM0R8U6Iant9SzRms4u0+rKUm2mGxxKuODlUo5ewqaGA==}
+  '@storybook/core-server@8.0.9(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)':
     dependencies:
       '@aw-web-design/x-default-browser': 1.4.126
       '@babel/core': 7.24.0
       '@discoveryjs/json-ext': 0.5.7
-      '@storybook/builder-manager': 8.0.9
+      '@storybook/builder-manager': 8.0.9(encoding@0.1.13)
       '@storybook/channels': 8.0.9
-      '@storybook/core-common': 8.0.9
+      '@storybook/core-common': 8.0.9(encoding@0.1.13)
       '@storybook/core-events': 8.0.9
       '@storybook/csf': 0.1.6
       '@storybook/csf-tools': 8.0.9
       '@storybook/docs-mdx': 3.0.0
       '@storybook/global': 5.0.0
       '@storybook/manager': 8.0.9
-      '@storybook/manager-api': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/manager-api': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/node-logger': 8.0.9
       '@storybook/preview-api': 8.0.9
-      '@storybook/telemetry': 8.0.9
+      '@storybook/telemetry': 8.0.9(encoding@0.1.13)
       '@storybook/types': 8.0.9
       '@types/detect-port': 1.3.2
       '@types/node': 18.17.15
@@ -6452,7 +14690,7 @@ packages:
       util: 0.12.5
       util-deprecate: 1.0.2
       watchpack: 2.4.0
-      ws: 8.16.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
+      ws: 8.17.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
     transitivePeerDependencies:
       - bufferutil
       - encoding
@@ -6460,19 +14698,15 @@ packages:
       - react-dom
       - supports-color
       - utf-8-validate
-    dev: true
 
-  /@storybook/csf-plugin@8.0.9:
-    resolution: {integrity: sha512-pXaNCNi++kxKsqSWwvx215fPx8cNqvepLVxQ7B69qXLHj80DHn0Q3DFBO3sLXNiQMJ2JK4OYcTxMfuOiyzszKw==}
+  '@storybook/csf-plugin@8.0.9':
     dependencies:
       '@storybook/csf-tools': 8.0.9
       unplugin: 1.4.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@storybook/csf-tools@8.0.9:
-    resolution: {integrity: sha512-PiNMhL97giLytTdQwuhsZ92buVk4gy9H/8DtrDhUc45/1OmF95gogm6T2Yap729SIFwgpOcuq/U3aVo6d6swVQ==}
+  '@storybook/csf-tools@8.0.9':
     dependencies:
       '@babel/generator': 7.23.6
       '@babel/parser': 7.24.0
@@ -6485,22 +14719,16 @@ packages:
       ts-dedent: 2.2.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@storybook/csf@0.1.6:
-    resolution: {integrity: sha512-JjWnBptVhBYJ14yq+cHs66BXjykRUWQ5TlD1RhPxMOtavynYyV/Q+QR98/N+XB+mcPtFMm5I2DvNkpj0/Dk8Mw==}
+  '@storybook/csf@0.1.6':
     dependencies:
       type-fest: 2.19.0
-    dev: true
 
-  /@storybook/docs-mdx@3.0.0:
-    resolution: {integrity: sha512-NmiGXl2HU33zpwTv1XORe9XG9H+dRUC1Jl11u92L4xr062pZtrShLmD4VKIsOQujxhhOrbxpwhNOt+6TdhyIdQ==}
-    dev: true
+  '@storybook/docs-mdx@3.0.0': {}
 
-  /@storybook/docs-tools@8.0.9:
-    resolution: {integrity: sha512-OzogAeOmeHea/MxSPKRBWtOQVNSpoq+OOpimO9YRA5h5GBRJ2TUOGT44Gny6QT4ll5AvQA8fIiq9KezKcLekAg==}
+  '@storybook/docs-tools@8.0.9(encoding@0.1.13)':
     dependencies:
-      '@storybook/core-common': 8.0.9
+      '@storybook/core-common': 8.0.9(encoding@0.1.13)
       '@storybook/core-events': 8.0.9
       '@storybook/preview-api': 8.0.9
       '@storybook/types': 8.0.9
@@ -6511,46 +14739,34 @@ packages:
     transitivePeerDependencies:
       - encoding
       - supports-color
-    dev: true
 
-  /@storybook/global@5.0.0:
-    resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==}
-    dev: true
+  '@storybook/global@5.0.0': {}
 
-  /@storybook/icons@1.2.5(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-m3jnuE+zmkZy6K+cdUDzAoUuCJyl0fWCAXPCji7VZCH1TzFohyvnPqhc9JMkQpanej2TOW3wWXaplPzHghcBSg==}
-    engines: {node: '>=14.0.0'}
-    peerDependencies:
-      react: ^16.8.0 || ^17.0.0 || ^18.0.0
-      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+  '@storybook/icons@1.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
     dependencies:
-      react: 18.2.0
-      react-dom: 18.2.0(react@18.2.0)
-    dev: true
+      react: 18.3.1
+      react-dom: 18.3.1(react@18.3.1)
 
-  /@storybook/instrumenter@8.0.9:
-    resolution: {integrity: sha512-Gw74dgpTU/2p7FG0s7DuVdqCbJ2MEcSuRJjDo7HcXRYcvWp7I6Ly+C0v7N5VaoS+kbBVerAhLKIHZgG/LZf1og==}
+  '@storybook/instrumenter@8.0.9':
     dependencies:
       '@storybook/channels': 8.0.9
       '@storybook/client-logger': 8.0.9
       '@storybook/core-events': 8.0.9
       '@storybook/global': 5.0.0
       '@storybook/preview-api': 8.0.9
-      '@vitest/utils': 1.5.3
+      '@vitest/utils': 1.6.0
       util: 0.12.5
-    dev: true
 
-  /@storybook/manager-api@8.0.9(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-99b3yKArDSvfabXL7QE3nA95e4DdW/5H/ZCcr6/E2qCQJayZ6G1v/WWamKXbiaTpkndulFmcb/+ZmnDXcweIIQ==}
+  '@storybook/manager-api@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
     dependencies:
       '@storybook/channels': 8.0.9
       '@storybook/client-logger': 8.0.9
       '@storybook/core-events': 8.0.9
       '@storybook/csf': 0.1.6
       '@storybook/global': 5.0.0
-      '@storybook/icons': 1.2.5(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/icons': 1.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/router': 8.0.9
-      '@storybook/theming': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/theming': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/types': 8.0.9
       dequal: 2.0.3
       lodash: 4.17.21
@@ -6561,18 +14777,12 @@ packages:
     transitivePeerDependencies:
       - react
       - react-dom
-    dev: true
 
-  /@storybook/manager@8.0.9:
-    resolution: {integrity: sha512-+NnRo+5JQFGNqveKrLtC0b+Z08Tae4m44iq292bPeZMpr9OkFsIkU0PBPsHTHPkrqC/zZXRNsCsTEgvu3p2OIA==}
-    dev: true
+  '@storybook/manager@8.0.9': {}
 
-  /@storybook/node-logger@8.0.9:
-    resolution: {integrity: sha512-5ajMdZFrYrjGLJOVDq7dlEQNFsgeLHymt4dCK9MulL/ciXykmXUZXE3Bye0wFy+I2qqDVvrvR8uzCvSFvm5MAQ==}
-    dev: true
+  '@storybook/node-logger@8.0.9': {}
 
-  /@storybook/preview-api@8.0.9:
-    resolution: {integrity: sha512-zHfX34bkAMzzmE7vbDzaqFwSW6ExiBD0HiO1L/IsHF55f0f7xV7IH8uJyFRrDTvAoW3ReSxZDMvvPpeydFPKGA==}
+  '@storybook/preview-api@8.0.9':
     dependencies:
       '@storybook/channels': 8.0.9
       '@storybook/client-logger': 8.0.9
@@ -6588,43 +14798,29 @@ packages:
       tiny-invariant: 1.3.1
       ts-dedent: 2.2.0
       util-deprecate: 1.0.2
-    dev: true
 
-  /@storybook/preview@8.0.9:
-    resolution: {integrity: sha512-tFsR8xc8AYBZZrZw8enklFbSQt7ZAV+rv20BoxwDhd3q7fjXyK7O4moGPqUwBZ7rukTG13nPoISxr+VXAk/HYA==}
-    dev: true
+  '@storybook/preview@8.0.9': {}
 
-  /@storybook/react-dom-shim@8.0.9(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-8011KlRuG3obr5pZZ7bcEyYYNWF3tR596YadoMd267NPoHKvwAbKL1L/DNgb6kiYjZDUf9QfaKSCWW31k0kcRQ==}
-    peerDependencies:
-      react: ^16.8.0 || ^17.0.0 || ^18.0.0
-      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+  '@storybook/react-dom-shim@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
     dependencies:
-      react: 18.2.0
-      react-dom: 18.2.0(react@18.2.0)
-    dev: true
+      react: 18.3.1
+      react-dom: 18.3.1(react@18.3.1)
 
-  /@storybook/react-vite@8.0.9(react-dom@18.2.0)(react@18.2.0)(rollup@4.12.0)(typescript@5.3.3)(vite@5.1.4):
-    resolution: {integrity: sha512-FT5KeulUH6grfzOJOxJCxpv9+81UVDrT9UPcgiFhQT9rKtsgmltezThwbHknByZNw3WWnf+ieidMLEis9hd73A==}
-    engines: {node: '>=18.0.0'}
-    peerDependencies:
-      react: ^16.8.0 || ^17.0.0 || ^18.0.0
-      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
-      vite: ^4.0.0 || ^5.0.0
+  '@storybook/react-vite@8.0.9(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.17.2)(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))':
     dependencies:
-      '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.3.3)(vite@5.1.4)
-      '@rollup/pluginutils': 5.1.0(rollup@4.12.0)
-      '@storybook/builder-vite': 8.0.9(typescript@5.3.3)(vite@5.1.4)
+      '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))
+      '@rollup/pluginutils': 5.1.0(rollup@4.17.2)
+      '@storybook/builder-vite': 8.0.9(encoding@0.1.13)(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))
       '@storybook/node-logger': 8.0.9
-      '@storybook/react': 8.0.9(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)
+      '@storybook/react': 8.0.9(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
       find-up: 5.0.0
       magic-string: 0.30.7
-      react: 18.2.0
+      react: 18.3.1
       react-docgen: 7.0.1
-      react-dom: 18.2.0(react@18.2.0)
+      react-dom: 18.3.1(react@18.3.1)
       resolve: 1.22.8
       tsconfig-paths: 4.2.0
-      vite: 5.1.4(@types/node@20.11.22)(sass@1.71.1)(terser@5.28.1)
+      vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
     transitivePeerDependencies:
       - '@preact/preset-vite'
       - encoding
@@ -6632,24 +14828,14 @@ packages:
       - supports-color
       - typescript
       - vite-plugin-glimmerx
-    dev: true
 
-  /@storybook/react@8.0.9(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3):
-    resolution: {integrity: sha512-NeQ6suZG3HKikwe3Tx9cAIaRx7uP8FKCmlVvIiBg4LTTI5orCt94PPakvuZukZcbkqvcCnEBkebAzwUpn8PiJw==}
-    engines: {node: '>=18.0.0'}
-    peerDependencies:
-      react: ^16.8.0 || ^17.0.0 || ^18.0.0
-      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
-      typescript: '>= 4.2.x'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
+  '@storybook/react@8.0.9(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)':
     dependencies:
       '@storybook/client-logger': 8.0.9
-      '@storybook/docs-tools': 8.0.9
+      '@storybook/docs-tools': 8.0.9(encoding@0.1.13)
       '@storybook/global': 5.0.0
       '@storybook/preview-api': 8.0.9
-      '@storybook/react-dom-shim': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/react-dom-shim': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/types': 8.0.9
       '@types/escodegen': 0.0.6
       '@types/estree': 0.0.51
@@ -6661,42 +14847,37 @@ packages:
       html-tags: 3.2.0
       lodash: 4.17.21
       prop-types: 15.8.1
-      react: 18.2.0
-      react-dom: 18.2.0(react@18.2.0)
-      react-element-to-jsx-string: 15.0.0(react-dom@18.2.0)(react@18.2.0)
+      react: 18.3.1
+      react-dom: 18.3.1(react@18.3.1)
+      react-element-to-jsx-string: 15.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       semver: 7.6.0
       ts-dedent: 2.2.0
       type-fest: 2.19.0
-      typescript: 5.3.3
       util-deprecate: 1.0.2
+    optionalDependencies:
+      typescript: 5.4.5
     transitivePeerDependencies:
       - encoding
       - supports-color
-    dev: true
 
-  /@storybook/router@8.0.9:
-    resolution: {integrity: sha512-aAOWxbM9J4mt+cp4o88T2PB29mgBBTOzU37/pUsTHYnKnR9XI4npXEXdN8Gv+ryqM0kj0AbBpz/llFlnR2MNNA==}
+  '@storybook/router@8.0.9':
     dependencies:
       '@storybook/client-logger': 8.0.9
       memoizerific: 1.11.3
       qs: 6.11.1
-    dev: true
 
-  /@storybook/source-loader@8.0.9:
-    resolution: {integrity: sha512-FDnpxIGE5nIYT15pvYe6rz95TSBrdLcDll7lOHNyZisWt19MI3wZU3YkVsFNRBuFrebo+FjVU3wHyoV81ur1Qw==}
+  '@storybook/source-loader@8.0.9':
     dependencies:
       '@storybook/csf': 0.1.6
       '@storybook/types': 8.0.9
       estraverse: 5.3.0
       lodash: 4.17.21
       prettier: 3.2.5
-    dev: true
 
-  /@storybook/telemetry@8.0.9:
-    resolution: {integrity: sha512-AGGfcup06t+wxhBIkHd0iybieOh9PDVZQJ9oPct5JGB39+ni9wvs0WOD+MYlHbsjp8id7+aGkh6mYuYOvfck+Q==}
+  '@storybook/telemetry@8.0.9(encoding@0.1.13)':
     dependencies:
       '@storybook/client-logger': 8.0.9
-      '@storybook/core-common': 8.0.9
+      '@storybook/core-common': 8.0.9(encoding@0.1.13)
       '@storybook/csf-tools': 8.0.9
       chalk: 4.1.2
       detect-package-manager: 2.0.1
@@ -6706,20 +14887,18 @@ packages:
     transitivePeerDependencies:
       - encoding
       - supports-color
-    dev: true
 
-  /@storybook/test@8.0.9(vitest@0.34.6):
-    resolution: {integrity: sha512-bRd5tBJnPzR6UKbDXONWnFWtdkNOY99HMLDUWe5fTRo50GwkrpFBVqPflhdkruEeof0kAbBUbnoN2CIYgtnAFw==}
+  '@storybook/test@8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))':
     dependencies:
       '@storybook/client-logger': 8.0.9
       '@storybook/core-events': 8.0.9
       '@storybook/instrumenter': 8.0.9
       '@storybook/preview-api': 8.0.9
       '@testing-library/dom': 9.3.4
-      '@testing-library/jest-dom': 6.4.2(vitest@0.34.6)
+      '@testing-library/jest-dom': 6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
       '@testing-library/user-event': 14.5.2(@testing-library/dom@9.3.4)
       '@vitest/expect': 1.3.1
-      '@vitest/spy': 1.5.3
+      '@vitest/spy': 1.6.0
       util: 0.12.5
     transitivePeerDependencies:
       - '@jest/globals'
@@ -6727,50 +14906,34 @@ packages:
       - '@types/jest'
       - jest
       - vitest
-    dev: true
 
-  /@storybook/theming@8.0.9(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-jgfDuYoiNMMirQiASN3Eg0hGDXsEtpdAcMxyShqYGwu9elxgD9yUnYC2nSckYsM74a3ZQ3JaViZ9ZFSe2FHmeQ==}
-    peerDependencies:
-      react: ^16.8.0 || ^17.0.0 || ^18.0.0
-      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
-    peerDependenciesMeta:
-      react:
-        optional: true
-      react-dom:
-        optional: true
+  '@storybook/theming@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
     dependencies:
-      '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.2.0)
+      '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.3.1)
       '@storybook/client-logger': 8.0.9
       '@storybook/global': 5.0.0
       memoizerific: 1.11.3
-      react: 18.2.0
-      react-dom: 18.2.0(react@18.2.0)
-    dev: true
+    optionalDependencies:
+      react: 18.3.1
+      react-dom: 18.3.1(react@18.3.1)
 
-  /@storybook/types@8.0.9:
-    resolution: {integrity: sha512-ew0EXzk9k4B557P1qIWYrnvUcgaE0WWA5qQS0AU8l+fRTp5nvl9O3SP/zNIB0SN1qDFO7dXr3idTNTyIikTcEQ==}
+  '@storybook/types@8.0.9':
     dependencies:
       '@storybook/channels': 8.0.9
       '@types/express': 4.17.17
       file-system-cache: 2.3.0
-    dev: true
 
-  /@storybook/vue3-vite@8.0.9(react-dom@18.2.0)(react@18.2.0)(vite@5.1.4)(vue@3.4.21):
-    resolution: {integrity: sha512-IkzYsEyCo5HIvLWbJeGrBu/VIN4u+LvdIAz7vcFqVVXBtTUhy+9/8caLx8fdnM0FWgKcBRQs8HnjBB2V0lOFcg==}
-    engines: {node: '>=18.0.0'}
-    peerDependencies:
-      vite: ^4.0.0 || ^5.0.0
+  '@storybook/vue3-vite@8.0.9(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))(vue@3.4.26(typescript@5.4.5))':
     dependencies:
-      '@storybook/builder-vite': 8.0.9(typescript@5.3.3)(vite@5.1.4)
-      '@storybook/core-server': 8.0.9(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/vue3': 8.0.9(vue@3.4.21)
+      '@storybook/builder-vite': 8.0.9(encoding@0.1.13)(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))
+      '@storybook/core-server': 8.0.9(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)
+      '@storybook/vue3': 8.0.9(encoding@0.1.13)(vue@3.4.26(typescript@5.4.5))
       find-package-json: 1.2.0
       magic-string: 0.30.7
-      typescript: 5.3.3
-      vite: 5.1.4(@types/node@20.11.22)(sass@1.71.1)(terser@5.28.1)
-      vue-component-meta: 2.0.16(typescript@5.3.3)
-      vue-docgen-api: 4.75.1(vue@3.4.21)
+      typescript: 5.4.5
+      vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
+      vue-component-meta: 2.0.16(typescript@5.4.5)
+      vue-docgen-api: 4.75.1(vue@3.4.26(typescript@5.4.5))
     transitivePeerDependencies:
       - '@preact/preset-vite'
       - bufferutil
@@ -6781,15 +14944,10 @@ packages:
       - utf-8-validate
       - vite-plugin-glimmerx
       - vue
-    dev: true
 
-  /@storybook/vue3@8.0.9(vue@3.4.21):
-    resolution: {integrity: sha512-EqVdS62YbOCAE0wJrQKW0sHpM90be8N8Mvmj+HzB0QYhJNtFqP9ehwbcTfwEKtaVGudisHgGBOzNoSKDlxFaag==}
-    engines: {node: '>=18.0.0'}
-    peerDependencies:
-      vue: ^3.0.0
+  '@storybook/vue3@8.0.9(encoding@0.1.13)(vue@3.4.26(typescript@5.4.5))':
     dependencies:
-      '@storybook/docs-tools': 8.0.9
+      '@storybook/docs-tools': 8.0.9(encoding@0.1.13)
       '@storybook/global': 5.0.0
       '@storybook/preview-api': 8.0.9
       '@storybook/types': 8.0.9
@@ -6797,344 +14955,167 @@ packages:
       lodash: 4.17.21
       ts-dedent: 2.2.0
       type-fest: 2.19.0
-      vue: 3.4.21(typescript@5.3.3)
+      vue: 3.4.26(typescript@5.4.5)
       vue-component-type-helpers: 2.0.16
     transitivePeerDependencies:
       - encoding
       - supports-color
-    dev: true
 
-  /@swc/cli@0.1.63(@swc/core@1.3.107)(chokidar@3.5.3):
-    resolution: {integrity: sha512-EM9oxxHzmmsprYRbGqsS2M4M/Gr5Gkcl0ROYYIdlUyTkhOiX822EQiRCpPCwdutdnzH2GyaTN7wc6i0Y+CKd3A==}
-    engines: {node: '>= 12.13'}
-    hasBin: true
-    peerDependencies:
-      '@swc/core': ^1.2.66
-      chokidar: 3.5.3
-    peerDependenciesMeta:
-      chokidar:
-        optional: true
+  '@swc/cli@0.3.12(@swc/core@1.4.17)(chokidar@3.5.3)':
     dependencies:
       '@mole-inc/bin-wrapper': 8.0.1
-      '@swc/core': 1.3.107
-      chokidar: 3.5.3
-      commander: 7.2.0
+      '@swc/core': 1.4.17
+      '@swc/counter': 0.1.3
+      commander: 8.3.0
       fast-glob: 3.3.2
-      semver: 7.5.4
+      minimatch: 9.0.3
+      piscina: 4.4.0
+      semver: 7.6.0
       slash: 3.0.0
       source-map: 0.7.4
-    dev: false
+    optionalDependencies:
+      chokidar: 3.5.3
 
-  /@swc/core-android-arm64@1.3.11:
-    resolution: {integrity: sha512-M7FamR3kFpVTyTw73FzKcOZmS7/TWHX75eqtwBTaU9fW4shf0KTLr/h9DnMxNKAnwUMeub/lqlINUe5EKFIKwQ==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [android]
-    requiresBuild: true
+  '@swc/core-android-arm64@1.3.11':
     dependencies:
       '@swc/wasm': 1.2.130
-    dev: false
     optional: true
 
-  /@swc/core-darwin-arm64@1.3.107:
-    resolution: {integrity: sha512-47tD/5vSXWxPd0j/ZllyQUg4bqalbQTsmqSw0J4dDdS82MWqCAwUErUrAZPRjBkjNQ6Kmrf5rpCWaGTtPw+ngw==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
+  '@swc/core-darwin-arm64@1.3.56':
     optional: true
 
-  /@swc/core-darwin-arm64@1.3.56:
-    resolution: {integrity: sha512-DZcu7BzDaLEdWHabz9DRTP0yEBLqkrWmskFcD5BX0lGAvoIvE4duMnAqi5F2B3X7630QioHRCYFoRw2WkeE3Cw==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
-    dev: false
+  '@swc/core-darwin-arm64@1.4.17':
     optional: true
 
-  /@swc/core-darwin-x64@1.3.107:
-    resolution: {integrity: sha512-hwiLJ2ulNkBGAh1m1eTfeY1417OAYbRGcb/iGsJ+LuVLvKAhU/itzsl535CvcwAlt2LayeCFfcI8gdeOLeZa9A==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
+  '@swc/core-darwin-x64@1.3.56':
     optional: true
 
-  /@swc/core-darwin-x64@1.3.56:
-    resolution: {integrity: sha512-VH5saqYFasdRXJy6RAT+MXm0+IjkMZvOkohJwUei+oA65cKJofQwrJ1jZro8yOJFYvUSI3jgNRGsdBkmo/4hMw==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
-    dev: false
+  '@swc/core-darwin-x64@1.4.17':
     optional: true
 
-  /@swc/core-freebsd-x64@1.3.11:
-    resolution: {integrity: sha512-02uqYktPp6WmZfZ2Crc/yIVOcgANtjo8ciHcT7yLHvz7v+S7gx1I2tyNGUFtTX5hcR2IFNGrL8Yj4DvpTABFHg==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [freebsd]
-    requiresBuild: true
+  '@swc/core-freebsd-x64@1.3.11':
     dependencies:
       '@swc/wasm': 1.2.130
-    dev: false
     optional: true
 
-  /@swc/core-linux-arm-gnueabihf@1.3.107:
-    resolution: {integrity: sha512-I2wzcC0KXqh0OwymCmYwNRgZ9nxX7DWnOOStJXV3pS0uB83TXAkmqd7wvMBuIl9qu4Hfomi9aDM7IlEEn9tumQ==}
-    engines: {node: '>=10'}
-    cpu: [arm]
-    os: [linux]
-    requiresBuild: true
+  '@swc/core-linux-arm-gnueabihf@1.3.56':
     optional: true
 
-  /@swc/core-linux-arm-gnueabihf@1.3.56:
-    resolution: {integrity: sha512-LWwPo6NnJkH01+ukqvkoNIOpMdw+Zundm4vBeicwyVrkP+mC3kwVfi03TUFpQUz3kRKdw/QEnxGTj+MouCPbtw==}
-    engines: {node: '>=10'}
-    cpu: [arm]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  '@swc/core-linux-arm-gnueabihf@1.4.17':
     optional: true
 
-  /@swc/core-linux-arm64-gnu@1.3.107:
-    resolution: {integrity: sha512-HWgnn7JORYlOYnGsdunpSF8A+BCZKPLzLtEUA27/M/ZuANcMZabKL9Zurt7XQXq888uJFAt98Gy+59PU90aHKg==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
+  '@swc/core-linux-arm64-gnu@1.3.56':
     optional: true
 
-  /@swc/core-linux-arm64-gnu@1.3.56:
-    resolution: {integrity: sha512-GzsUy/4egJ4cMlxbM+Ub7AMi5CKAc+pxBxrh8MUPQbyStW8jGgnQsJouTnGy0LHawtdEnsCOl6PcO6OgvktXuQ==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  '@swc/core-linux-arm64-gnu@1.4.17':
     optional: true
 
-  /@swc/core-linux-arm64-musl@1.3.107:
-    resolution: {integrity: sha512-vfPF74cWfAm8hyhS8yvYI94ucMHIo8xIYU+oFOW9uvDlGQRgnUf/6DEVbLyt/3yfX5723Ln57U8uiMALbX5Pyw==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
+  '@swc/core-linux-arm64-musl@1.3.56':
     optional: true
 
-  /@swc/core-linux-arm64-musl@1.3.56:
-    resolution: {integrity: sha512-9gxL09BIiAv8zY0DjfnFf19bo8+P4T9tdhzPwcm+1yPJcY5yr1+YFWLNFzz01agtOj6VlZ2/wUJTaOfdjjtc+A==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  '@swc/core-linux-arm64-musl@1.4.17':
     optional: true
 
-  /@swc/core-linux-x64-gnu@1.3.107:
-    resolution: {integrity: sha512-uBVNhIg0ip8rH9OnOsCARUFZ3Mq3tbPHxtmWk9uAa5u8jQwGWeBx5+nTHpDOVd3YxKb6+5xDEI/edeeLpha/9g==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
+  '@swc/core-linux-x64-gnu@1.3.56':
     optional: true
 
-  /@swc/core-linux-x64-gnu@1.3.56:
-    resolution: {integrity: sha512-n0ORNknl50vMRkll3BDO1E4WOqY6iISlPV1ZQCRLWQ6YQ2q8/WAryBxc2OAybcGHBUFkxyACpJukeU1QZ/9tNw==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  '@swc/core-linux-x64-gnu@1.4.17':
     optional: true
 
-  /@swc/core-linux-x64-musl@1.3.107:
-    resolution: {integrity: sha512-mvACkUvzSIB12q1H5JtabWATbk3AG+pQgXEN95AmEX2ZA5gbP9+B+mijsg7Sd/3tboHr7ZHLz/q3SHTvdFJrEw==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
+  '@swc/core-linux-x64-musl@1.3.56':
     optional: true
 
-  /@swc/core-linux-x64-musl@1.3.56:
-    resolution: {integrity: sha512-r+D34WLAOAlJtfw1gaVWpHRwCncU9nzW9i7w9kSw4HpWYnHJOz54jLGSEmNsrhdTCz1VK2ar+V2ktFUsrlGlDA==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  '@swc/core-linux-x64-musl@1.4.17':
     optional: true
 
-  /@swc/core-win32-arm64-msvc@1.3.107:
-    resolution: {integrity: sha512-J3P14Ngy/1qtapzbguEH41kY109t6DFxfbK4Ntz9dOWNuVY3o9/RTB841ctnJk0ZHEG+BjfCJjsD2n8H5HcaOA==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [win32]
-    requiresBuild: true
+  '@swc/core-win32-arm64-msvc@1.3.56':
     optional: true
 
-  /@swc/core-win32-arm64-msvc@1.3.56:
-    resolution: {integrity: sha512-29Yt75Is6X24z3x8h/xZC1HnDPkPpyLH9mDQiM6Cuc0I9mVr1XSriPEUB2N/awf5IE4SA8c+3IVq1DtKWbkJIw==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [win32]
-    requiresBuild: true
-    dev: false
+  '@swc/core-win32-arm64-msvc@1.4.17':
     optional: true
 
-  /@swc/core-win32-ia32-msvc@1.3.107:
-    resolution: {integrity: sha512-ZBUtgyjTHlz8TPJh7kfwwwFma+ktr6OccB1oXC8fMSopD0AxVnQasgun3l3099wIsAB9eEsJDQ/3lDkOLs1gBA==}
-    engines: {node: '>=10'}
-    cpu: [ia32]
-    os: [win32]
-    requiresBuild: true
+  '@swc/core-win32-ia32-msvc@1.3.56':
     optional: true
 
-  /@swc/core-win32-ia32-msvc@1.3.56:
-    resolution: {integrity: sha512-mplp0zbYDrcHtfvkniXlXdB04e2qIjz2Gq/XHKr4Rnc6xVORJjjXF91IemXKpavx2oZYJws+LNJL7UFQ8jyCdQ==}
-    engines: {node: '>=10'}
-    cpu: [ia32]
-    os: [win32]
-    requiresBuild: true
-    dev: false
+  '@swc/core-win32-ia32-msvc@1.4.17':
     optional: true
 
-  /@swc/core-win32-x64-msvc@1.3.107:
-    resolution: {integrity: sha512-Eyzo2XRqWOxqhE1gk9h7LWmUf4Bp4Xn2Ttb0ayAXFp6YSTxQIThXcT9kipXZqcpxcmDwoq8iWbbf2P8XL743EA==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [win32]
-    requiresBuild: true
+  '@swc/core-win32-x64-msvc@1.3.56':
     optional: true
 
-  /@swc/core-win32-x64-msvc@1.3.56:
-    resolution: {integrity: sha512-zp8MBnrw/bjdLenO/ifYzHrImSjKunqL0C2IF4LXYNRfcbYFh2NwobsVQMZ20IT0474lKRdlP8Oxdt+bHuXrzA==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [win32]
-    requiresBuild: true
-    dev: false
+  '@swc/core-win32-x64-msvc@1.4.17':
     optional: true
 
-  /@swc/core@1.3.107:
-    resolution: {integrity: sha512-zKhqDyFcTsyLIYK1iEmavljZnf4CCor5pF52UzLAz4B6Nu/4GLU+2LQVAf+oRHjusG39PTPjd2AlRT3f3QWfsQ==}
-    engines: {node: '>=10'}
-    requiresBuild: true
-    peerDependencies:
-      '@swc/helpers': ^0.5.0
-    peerDependenciesMeta:
-      '@swc/helpers':
-        optional: true
+  '@swc/core@1.4.17':
     dependencies:
-      '@swc/counter': 0.1.1
+      '@swc/counter': 0.1.3
       '@swc/types': 0.1.5
     optionalDependencies:
-      '@swc/core-darwin-arm64': 1.3.107
-      '@swc/core-darwin-x64': 1.3.107
-      '@swc/core-linux-arm-gnueabihf': 1.3.107
-      '@swc/core-linux-arm64-gnu': 1.3.107
-      '@swc/core-linux-arm64-musl': 1.3.107
-      '@swc/core-linux-x64-gnu': 1.3.107
-      '@swc/core-linux-x64-musl': 1.3.107
-      '@swc/core-win32-arm64-msvc': 1.3.107
-      '@swc/core-win32-ia32-msvc': 1.3.107
-      '@swc/core-win32-x64-msvc': 1.3.107
+      '@swc/core-darwin-arm64': 1.4.17
+      '@swc/core-darwin-x64': 1.4.17
+      '@swc/core-linux-arm-gnueabihf': 1.4.17
+      '@swc/core-linux-arm64-gnu': 1.4.17
+      '@swc/core-linux-arm64-musl': 1.4.17
+      '@swc/core-linux-x64-gnu': 1.4.17
+      '@swc/core-linux-x64-musl': 1.4.17
+      '@swc/core-win32-arm64-msvc': 1.4.17
+      '@swc/core-win32-ia32-msvc': 1.4.17
+      '@swc/core-win32-x64-msvc': 1.4.17
 
-  /@swc/counter@0.1.1:
-    resolution: {integrity: sha512-xVRaR4u9hcYjFvcSg71Lz5Bo4//CyjAAfMxa7UsaDSYxAshflUkVJWiyVWrfxC59z2kP1IzI4/1BEpnhI9o3Mw==}
+  '@swc/counter@0.1.3': {}
 
-  /@swc/jest@0.2.31(@swc/core@1.3.107):
-    resolution: {integrity: sha512-Gh0Ste380O8KUY1IqsKr+aOvqqs2Loa+WcWWVNwl+lhXqOWK1iTFAP1K0IDfLqAuFP68+D/PxcpBJn21e6Quvw==}
-    engines: {npm: '>= 7.0.0'}
-    peerDependencies:
-      '@swc/core': '*'
+  '@swc/jest@0.2.36(@swc/core@1.4.17)':
     dependencies:
       '@jest/create-cache-key-function': 29.7.0
-      '@swc/core': 1.3.107
+      '@swc/core': 1.4.17
+      '@swc/counter': 0.1.3
       jsonc-parser: 3.2.0
-    dev: true
 
-  /@swc/types@0.1.5:
-    resolution: {integrity: sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==}
+  '@swc/types@0.1.5': {}
 
-  /@swc/wasm@1.2.130:
-    resolution: {integrity: sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==}
-    requiresBuild: true
-    dev: false
+  '@swc/wasm@1.2.130':
     optional: true
 
-  /@syuilo/aiscript@0.18.0:
-    resolution: {integrity: sha512-/iY9Vv4LLjtW/KUzId1QwXC4BlpIEPCMcoT7dyRhYdyxtwhS3Hx4b/4j1HYP+n3Pq9XKyW5zvkY72/+DNu4g6Q==}
+  '@syuilo/aiscript@0.18.0':
     dependencies:
       seedrandom: 3.0.5
       stringz: 2.1.0
       uuid: 9.0.1
-    dev: false
 
-  /@szmarczak/http-timer@4.0.6:
-    resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==}
-    engines: {node: '>=10'}
-    dependencies:
-      defer-to-connect: 2.0.1
-    dev: false
-
-  /@szmarczak/http-timer@5.0.1:
-    resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==}
-    engines: {node: '>=14.16'}
+  '@szmarczak/http-timer@4.0.6':
     dependencies:
       defer-to-connect: 2.0.1
 
-  /@tabler/icons-webfont@2.44.0:
-    resolution: {integrity: sha512-E5+CYnZXKTUGFhpb0KGiRR4s+Tylbsq6/CA88QKn44xaBfU3ui/zVwKc1vaTKBL9kxZIxNz7qLkne+lUd/Hvzw==}
+  '@szmarczak/http-timer@5.0.1':
     dependencies:
-      '@tabler/icons': 2.44.0
-    dev: false
+      defer-to-connect: 2.0.1
 
-  /@tabler/icons@2.44.0:
-    resolution: {integrity: sha512-WPPtihDcAwEm1QZM9MXQw6+r/R2/qx7KMU1eegsi9DsqBLAb0W2kbt6e/syvd6j9c+6XNpRVBW1ziGqSWQAWOg==}
-    dev: false
-
-  /@tensorflow/tfjs-backend-cpu@4.4.0(@tensorflow/tfjs-core@4.4.0):
-    resolution: {integrity: sha512-d4eln500/qNym78z9IrUUzF0ITBoJGLrxV8xd92kLVoXhg35Mm+zqUXShjFcrH8joOHOFuST0qZ0TbDDqcPzPA==}
-    engines: {yarn: '>= 1.3.2'}
-    requiresBuild: true
-    peerDependencies:
-      '@tensorflow/tfjs-core': 4.4.0
+  '@tabler/icons-webfont@3.3.0':
     dependencies:
-      '@tensorflow/tfjs-core': 4.4.0
+      '@tabler/icons': 3.3.0
+
+  '@tabler/icons@3.3.0': {}
+
+  '@tensorflow/tfjs-backend-cpu@4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))':
+    dependencies:
+      '@tensorflow/tfjs-core': 4.4.0(encoding@0.1.13)
       '@types/seedrandom': 2.4.30
       seedrandom: 3.0.5
-    dev: false
 
-  /@tensorflow/tfjs-backend-webgl@4.4.0(@tensorflow/tfjs-core@4.4.0):
-    resolution: {integrity: sha512-TzQKvfAPgGt9cMG+5bVoTckoG1xr/PVJM/uODkPvzcMqi3j97kuWDXwkYJIgXldStmfiKkU7f5CmyD3Cq3E6BA==}
-    engines: {yarn: '>= 1.3.2'}
-    requiresBuild: true
-    peerDependencies:
-      '@tensorflow/tfjs-core': 4.4.0
+  '@tensorflow/tfjs-backend-webgl@4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))':
     dependencies:
-      '@tensorflow/tfjs-backend-cpu': 4.4.0(@tensorflow/tfjs-core@4.4.0)
-      '@tensorflow/tfjs-core': 4.4.0
+      '@tensorflow/tfjs-backend-cpu': 4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))
+      '@tensorflow/tfjs-core': 4.4.0(encoding@0.1.13)
       '@types/offscreencanvas': 2019.3.0
       '@types/seedrandom': 2.4.30
       '@types/webgl-ext': 0.0.30
       seedrandom: 3.0.5
-    dev: false
 
-  /@tensorflow/tfjs-converter@4.4.0(@tensorflow/tfjs-core@4.4.0):
-    resolution: {integrity: sha512-JUjpRStrAuw37tgPd5UENu0UjQVuJT09yF7KpOur4BriJ0uQqrbEZHMPHmvUtr5nYzkqlXJTuXIyxvEY/olNpg==}
-    requiresBuild: true
-    peerDependencies:
-      '@tensorflow/tfjs-core': 4.4.0
+  '@tensorflow/tfjs-converter@4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))':
     dependencies:
-      '@tensorflow/tfjs-core': 4.4.0
-    dev: false
+      '@tensorflow/tfjs-core': 4.4.0(encoding@0.1.13)
 
-  /@tensorflow/tfjs-core@4.4.0:
-    resolution: {integrity: sha512-Anxpc7cAOA0Q7EUXdTbQKMg3reFvrdkgDlaYzH9ZfkMq2CgLV4Au6E/s6HmbYn/VrAtWy9mLY5c/lLJqh4764g==}
-    engines: {yarn: '>= 1.3.2'}
-    requiresBuild: true
+  '@tensorflow/tfjs-core@4.4.0(encoding@0.1.13)':
     dependencies:
       '@types/long': 4.0.2
       '@types/offscreencanvas': 2019.7.0
@@ -7142,44 +15123,29 @@ packages:
       '@types/webgl-ext': 0.0.30
       '@webgpu/types': 0.1.30
       long: 4.0.0
-      node-fetch: 2.6.11
+      node-fetch: 2.6.11(encoding@0.1.13)
       seedrandom: 3.0.5
     transitivePeerDependencies:
       - encoding
-    dev: false
 
-  /@tensorflow/tfjs-data@4.4.0(@tensorflow/tfjs-core@4.4.0)(seedrandom@3.0.5):
-    resolution: {integrity: sha512-aY4eq4cgrsrXeBU6ABZAAN3tV0fG4YcHd0z+cYuNXnCo+VEQLJnPmhn+xymZ4VQZQH4GXbVS4dV9pXMclFNRFw==}
-    requiresBuild: true
-    peerDependencies:
-      '@tensorflow/tfjs-core': 4.4.0
-      seedrandom: ^3.0.5
+  '@tensorflow/tfjs-data@4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))(encoding@0.1.13)(seedrandom@3.0.5)':
     dependencies:
-      '@tensorflow/tfjs-core': 4.4.0
+      '@tensorflow/tfjs-core': 4.4.0(encoding@0.1.13)
       '@types/node-fetch': 2.6.4
-      node-fetch: 2.6.11
+      node-fetch: 2.6.11(encoding@0.1.13)
       seedrandom: 3.0.5
       string_decoder: 1.3.0
     transitivePeerDependencies:
       - encoding
-    dev: false
 
-  /@tensorflow/tfjs-layers@4.4.0(@tensorflow/tfjs-core@4.4.0):
-    resolution: {integrity: sha512-OGC7shfiD9Gc698hINHK4y9slOJvu5m54tVNm4xf+WSNrw/avvgpar6yyoL5bakYIZNQvFNK75Yr8VRPR7oPeQ==}
-    requiresBuild: true
-    peerDependencies:
-      '@tensorflow/tfjs-core': 4.4.0
+  '@tensorflow/tfjs-layers@4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))':
     dependencies:
-      '@tensorflow/tfjs-core': 4.4.0
-    dev: false
+      '@tensorflow/tfjs-core': 4.4.0(encoding@0.1.13)
 
-  /@tensorflow/tfjs-node@4.4.0(seedrandom@3.0.5):
-    resolution: {integrity: sha512-+JSAddsupjSQUDZeb7QGOFkL3Tty3kjPHx8ethiYFzwTZJHCMvM7wZJd0Fqnjxym6A0KpsmB7SPZgwRRXVIlPA==}
-    engines: {node: '>=8.11.0'}
-    requiresBuild: true
+  '@tensorflow/tfjs-node@4.4.0(encoding@0.1.13)(seedrandom@3.0.5)':
     dependencies:
-      '@mapbox/node-pre-gyp': 1.0.9
-      '@tensorflow/tfjs': 4.4.0(seedrandom@3.0.5)
+      '@mapbox/node-pre-gyp': 1.0.9(encoding@0.1.13)
+      '@tensorflow/tfjs': 4.4.0(encoding@0.1.13)(seedrandom@3.0.5)
       adm-zip: 0.5.10
       google-protobuf: 3.21.2
       https-proxy-agent: 2.2.4
@@ -7190,20 +15156,16 @@ packages:
       - encoding
       - seedrandom
       - supports-color
-    dev: false
     optional: true
 
-  /@tensorflow/tfjs@4.4.0(seedrandom@3.0.5):
-    resolution: {integrity: sha512-EmCsnzdvawyk4b+4JKaLLuicHcJQRZtL1zSy9AWJLiiHTbDDseYgLxfaCEfLk8v2bUe7SBXwl3n3B7OjgvH11Q==}
-    hasBin: true
-    requiresBuild: true
+  '@tensorflow/tfjs@4.4.0(encoding@0.1.13)(seedrandom@3.0.5)':
     dependencies:
-      '@tensorflow/tfjs-backend-cpu': 4.4.0(@tensorflow/tfjs-core@4.4.0)
-      '@tensorflow/tfjs-backend-webgl': 4.4.0(@tensorflow/tfjs-core@4.4.0)
-      '@tensorflow/tfjs-converter': 4.4.0(@tensorflow/tfjs-core@4.4.0)
-      '@tensorflow/tfjs-core': 4.4.0
-      '@tensorflow/tfjs-data': 4.4.0(@tensorflow/tfjs-core@4.4.0)(seedrandom@3.0.5)
-      '@tensorflow/tfjs-layers': 4.4.0(@tensorflow/tfjs-core@4.4.0)
+      '@tensorflow/tfjs-backend-cpu': 4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))
+      '@tensorflow/tfjs-backend-webgl': 4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))
+      '@tensorflow/tfjs-converter': 4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))
+      '@tensorflow/tfjs-core': 4.4.0(encoding@0.1.13)
+      '@tensorflow/tfjs-data': 4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))(encoding@0.1.13)(seedrandom@3.0.5)
+      '@tensorflow/tfjs-layers': 4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))
       argparse: 1.0.10
       chalk: 4.1.2
       core-js: 3.29.1
@@ -7212,11 +15174,8 @@ packages:
     transitivePeerDependencies:
       - encoding
       - seedrandom
-    dev: false
 
-  /@testing-library/dom@9.3.3:
-    resolution: {integrity: sha512-fB0R+fa3AUqbLHWyxXa2kGVtf1Fe1ZZFr0Zp6AIbIAzXb2mKbEXl+PCQNUOaq5lbTab5tfctfXRNsWXxa2f7Aw==}
-    engines: {node: '>=14'}
+  '@testing-library/dom@9.3.3':
     dependencies:
       '@babel/code-frame': 7.23.5
       '@babel/runtime': 7.23.4
@@ -7226,11 +15185,8 @@ packages:
       dom-accessibility-api: 0.5.16
       lz-string: 1.5.0
       pretty-format: 27.5.1
-    dev: true
 
-  /@testing-library/dom@9.3.4:
-    resolution: {integrity: sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==}
-    engines: {node: '>=14'}
+  '@testing-library/dom@9.3.4':
     dependencies:
       '@babel/code-frame': 7.23.5
       '@babel/runtime': 7.23.4
@@ -7240,28 +15196,8 @@ packages:
       dom-accessibility-api: 0.5.16
       lz-string: 1.5.0
       pretty-format: 27.5.1
-    dev: true
 
-  /@testing-library/jest-dom@6.4.2(vitest@0.34.6):
-    resolution: {integrity: sha512-CzqH0AFymEMG48CpzXFriYYkOjk6ZGPCLMhW9e9jg3KMCn5OfJecF8GtGW7yGfR/IgCe3SX8BSwjdzI6BBbZLw==}
-    engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
-    peerDependencies:
-      '@jest/globals': '>= 28'
-      '@types/bun': latest
-      '@types/jest': '>= 28'
-      jest: '>= 28'
-      vitest: '>= 0.32'
-    peerDependenciesMeta:
-      '@jest/globals':
-        optional: true
-      '@types/bun':
-        optional: true
-      '@types/jest':
-        optional: true
-      jest:
-        optional: true
-      vitest:
-        optional: true
+  '@testing-library/jest-dom@6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))':
     dependencies:
       '@adobe/css-tools': 4.3.3
       '@babel/runtime': 7.23.4
@@ -7271,686 +15207,411 @@ packages:
       dom-accessibility-api: 0.6.3
       lodash: 4.17.21
       redent: 3.0.0
-      vitest: 0.34.6(happy-dom@13.6.2)(sass@1.71.1)(terser@5.28.1)
-    dev: true
+    optionalDependencies:
+      '@jest/globals': 29.7.0
+      '@types/jest': 29.5.12
+      jest: 29.7.0(@types/node@20.12.7)
+      vitest: 0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)
 
-  /@testing-library/user-event@14.5.2(@testing-library/dom@9.3.4):
-    resolution: {integrity: sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==}
-    engines: {node: '>=12', npm: '>=6'}
-    peerDependencies:
-      '@testing-library/dom': '>=7.21.4'
+  '@testing-library/user-event@14.5.2(@testing-library/dom@9.3.4)':
     dependencies:
       '@testing-library/dom': 9.3.4
-    dev: true
 
-  /@testing-library/vue@8.0.2(@vue/compiler-sfc@3.4.21)(vue@3.4.21):
-    resolution: {integrity: sha512-A8wWX+qQn0o0izpQWnGCpwQt8wAdpsVP8vPP2h5Q/jcGhZ5yKXz9PPUqhQv+45LTFaWlyRf8bArTVaB/KFFd5A==}
-    engines: {node: '>=14'}
-    peerDependencies:
-      '@vue/compiler-sfc': '>= 3'
-      vue: '>= 3'
-    peerDependenciesMeta:
-      '@vue/compiler-sfc':
-        optional: true
+  '@testing-library/vue@8.0.3(@vue/compiler-sfc@3.4.26)(@vue/server-renderer@3.4.25(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))':
     dependencies:
       '@babel/runtime': 7.23.4
       '@testing-library/dom': 9.3.3
-      '@vue/compiler-sfc': 3.4.21
-      '@vue/test-utils': 2.4.1(vue@3.4.21)
-      vue: 3.4.21(typescript@5.3.3)
+      '@vue/test-utils': 2.4.1(@vue/server-renderer@3.4.25(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))
+      vue: 3.4.26(typescript@5.4.5)
+    optionalDependencies:
+      '@vue/compiler-sfc': 3.4.26
     transitivePeerDependencies:
       - '@vue/server-renderer'
-    dev: true
 
-  /@tokenizer/token@0.3.0:
-    resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
-    dev: false
+  '@tokenizer/token@0.3.0': {}
 
-  /@trysound/sax@0.2.0:
-    resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
-    engines: {node: '>=10.13.0'}
-    dev: false
+  '@trysound/sax@0.2.0': {}
 
-  /@tsd/typescript@5.3.3:
-    resolution: {integrity: sha512-CQlfzol0ldaU+ftWuG52vH29uRoKboLinLy84wS8TQOu+m+tWoaUfk4svL4ij2V8M5284KymJBlHUusKj6k34w==}
-    engines: {node: '>=14.17'}
-    dev: true
+  '@tsd/typescript@5.3.3': {}
 
-  /@twemoji/parser@15.0.0:
-    resolution: {integrity: sha512-lh9515BNsvKSNvyUqbj5yFu83iIDQ77SwVcsN/SnEGawczhsKU6qWuogewN1GweTi5Imo5ToQ9s+nNTf97IXvg==}
-    dev: false
+  '@twemoji/parser@15.0.0': {}
 
-  /@types/accepts@1.3.7:
-    resolution: {integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==}
+  '@twemoji/parser@15.1.1': {}
+
+  '@types/accepts@1.3.7':
     dependencies:
-      '@types/node': 20.11.22
-    dev: true
+      '@types/node': 20.12.7
 
-  /@types/archiver@6.0.2:
-    resolution: {integrity: sha512-KmROQqbQzKGuaAbmK+ZcytkJ51+YqDa7NmbXjmtC5YBLSyQYo21YaUnQ3HbaPFKL1ooo6RQ6OPYPIDyxfpDDXw==}
+  '@types/archiver@6.0.2':
     dependencies:
       '@types/readdir-glob': 1.1.1
-    dev: true
 
-  /@types/argparse@1.0.38:
-    resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==}
-    dev: true
+  '@types/argparse@1.0.38': {}
 
-  /@types/aria-query@5.0.1:
-    resolution: {integrity: sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==}
-    dev: true
+  '@types/aria-query@5.0.1': {}
 
-  /@types/babel__core@7.20.0:
-    resolution: {integrity: sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==}
+  '@types/babel__core@7.20.0':
     dependencies:
-      '@babel/parser': 7.23.9
-      '@babel/types': 7.23.5
+      '@babel/parser': 7.24.0
+      '@babel/types': 7.24.0
       '@types/babel__generator': 7.6.4
       '@types/babel__template': 7.4.1
       '@types/babel__traverse': 7.20.0
-    dev: true
 
-  /@types/babel__generator@7.6.4:
-    resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==}
+  '@types/babel__generator@7.6.4':
     dependencies:
-      '@babel/types': 7.23.5
-    dev: true
+      '@babel/types': 7.24.0
 
-  /@types/babel__template@7.4.1:
-    resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==}
+  '@types/babel__template@7.4.1':
     dependencies:
-      '@babel/parser': 7.23.9
-      '@babel/types': 7.23.5
-    dev: true
+      '@babel/parser': 7.24.0
+      '@babel/types': 7.24.0
 
-  /@types/babel__traverse@7.20.0:
-    resolution: {integrity: sha512-TBOjqAGf0hmaqRwpii5LLkJLg7c6OMm4nHLmpsUxwk9bBHtoTC6dAHdVWdGv4TBxj2CZOZY8Xfq8WmfoVi7n4Q==}
+  '@types/babel__traverse@7.20.0':
     dependencies:
-      '@babel/types': 7.23.5
-    dev: true
+      '@babel/types': 7.24.0
 
-  /@types/bcryptjs@2.4.6:
-    resolution: {integrity: sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==}
-    dev: true
+  '@types/bcryptjs@2.4.6': {}
 
-  /@types/body-parser@1.19.5:
-    resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
+  '@types/body-parser@1.19.5':
     dependencies:
       '@types/connect': 3.4.35
-      '@types/node': 20.11.22
-    dev: true
+      '@types/node': 20.12.7
 
-  /@types/braces@3.0.1:
-    resolution: {integrity: sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ==}
-    dev: true
+  '@types/braces@3.0.1': {}
 
-  /@types/cacheable-request@6.0.3:
-    resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==}
+  '@types/cacheable-request@6.0.3':
     dependencies:
       '@types/http-cache-semantics': 4.0.4
       '@types/keyv': 3.1.4
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       '@types/responselike': 1.0.0
-    dev: false
 
-  /@types/chai-subset@1.3.5:
-    resolution: {integrity: sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==}
+  '@types/chai-subset@1.3.5':
     dependencies:
       '@types/chai': 4.3.11
-    dev: true
 
-  /@types/chai@4.3.11:
-    resolution: {integrity: sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==}
-    dev: true
+  '@types/chai@4.3.11': {}
 
-  /@types/color-convert@2.0.3:
-    resolution: {integrity: sha512-2Q6wzrNiuEvYxVQqhh7sXM2mhIhvZR/Paq4FdsQkOMgWsCIkKvSGj8Le1/XalulrmgOzPMqNa0ix+ePY4hTrfg==}
+  '@types/color-convert@2.0.3':
     dependencies:
       '@types/color-name': 1.1.1
-    dev: true
 
-  /@types/color-name@1.1.1:
-    resolution: {integrity: sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==}
-    dev: true
+  '@types/color-name@1.1.1': {}
 
-  /@types/connect@3.4.35:
-    resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==}
+  '@types/connect@3.4.35':
     dependencies:
-      '@types/node': 20.11.22
-    dev: true
+      '@types/node': 20.12.7
 
-  /@types/content-disposition@0.5.8:
-    resolution: {integrity: sha512-QVSSvno3dE0MgO76pJhmv4Qyi/j0Yk9pBp0Y7TJ2Tlj+KCgJWY6qX7nnxCOLkZ3VYRSIk1WTxCvwUSdx6CCLdg==}
-    dev: true
+  '@types/content-disposition@0.5.8': {}
 
-  /@types/cookie@0.6.0:
-    resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
-    dev: true
+  '@types/cookie@0.6.0': {}
 
-  /@types/cross-spawn@6.0.2:
-    resolution: {integrity: sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==}
+  '@types/cross-spawn@6.0.2':
     dependencies:
-      '@types/node': 20.11.28
-    dev: true
+      '@types/node': 20.12.7
 
-  /@types/debug@4.1.12:
-    resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
+  '@types/debug@4.1.12':
     dependencies:
       '@types/ms': 0.7.34
-    dev: true
 
-  /@types/detect-port@1.3.2:
-    resolution: {integrity: sha512-xxgAGA2SAU4111QefXPSp5eGbDm/hW6zhvYl9IeEPZEry9F4d66QAHm5qpUXjb6IsevZV/7emAEx5MhP6O192g==}
-    dev: true
+  '@types/detect-port@1.3.2': {}
 
-  /@types/disposable-email-domains@1.0.2:
-    resolution: {integrity: sha512-SDKwyYTjk3y5aZBxxc38yRecpJPjsqn57STz1bNxYYlv4k11bBe7QB8w4llXDTmQXKT1mFvgGmJv+8Zdu3YmJw==}
-    dev: false
+  '@types/disposable-email-domains@1.0.2': {}
 
-  /@types/doctrine@0.0.3:
-    resolution: {integrity: sha512-w5jZ0ee+HaPOaX25X2/2oGR/7rgAQSYII7X7pp0m9KgBfMP7uKfMfTvcpl5Dj+eDBbpxKGiqE+flqDr6XTd2RA==}
-    dev: true
+  '@types/doctrine@0.0.3': {}
 
-  /@types/doctrine@0.0.9:
-    resolution: {integrity: sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==}
-    dev: true
+  '@types/doctrine@0.0.9': {}
 
-  /@types/ejs@3.1.2:
-    resolution: {integrity: sha512-ZmiaE3wglXVWBM9fyVC17aGPkLo/UgaOjEiI2FXQfyczrCefORPxIe+2dVmnmk3zkVIbizjrlQzmPGhSYGXG5g==}
-    dev: true
+  '@types/ejs@3.1.2': {}
 
-  /@types/emscripten@1.39.7:
-    resolution: {integrity: sha512-tLqYV94vuqDrXh515F/FOGtBcRMTPGvVV1LzLbtYDcQmmhtpf/gLYf+hikBbQk8MzOHNz37wpFfJbYAuSn8HqA==}
-    dev: true
+  '@types/emscripten@1.39.7': {}
 
-  /@types/escape-regexp@0.0.3:
-    resolution: {integrity: sha512-FQMYUxaf1dVeWLUzJFSvfdDugfOpDyM13p67QfyMdagxSkBa689opkr/q9uR/VWyrWrl0jAyQaSPKxX9MpAXFw==}
-    dev: true
+  '@types/escape-regexp@0.0.3': {}
 
-  /@types/escodegen@0.0.6:
-    resolution: {integrity: sha512-AjwI4MvWx3HAOaZqYsjKWyEObT9lcVV0Y0V8nXo6cXzN8ZiMxVhf6F3d/UNvXVGKrEzL/Dluc5p+y9GkzlTWig==}
-    dev: true
+  '@types/escodegen@0.0.6': {}
 
-  /@types/eslint@7.29.0:
-    resolution: {integrity: sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==}
+  '@types/eslint@7.29.0':
     dependencies:
       '@types/estree': 1.0.5
       '@types/json-schema': 7.0.12
-    dev: true
 
-  /@types/estree@0.0.51:
-    resolution: {integrity: sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==}
-    dev: true
+  '@types/estree@0.0.51': {}
 
-  /@types/estree@1.0.5:
-    resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
+  '@types/estree@1.0.5': {}
 
-  /@types/express-serve-static-core@4.17.33:
-    resolution: {integrity: sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==}
+  '@types/express-serve-static-core@4.17.33':
     dependencies:
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       '@types/qs': 6.9.7
       '@types/range-parser': 1.2.4
-    dev: true
 
-  /@types/express@4.17.17:
-    resolution: {integrity: sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==}
+  '@types/express@4.17.17':
     dependencies:
       '@types/body-parser': 1.19.5
       '@types/express-serve-static-core': 4.17.33
       '@types/qs': 6.9.7
       '@types/serve-static': 1.15.1
-    dev: true
 
-  /@types/find-cache-dir@3.2.1:
-    resolution: {integrity: sha512-frsJrz2t/CeGifcu/6uRo4b+SzAwT4NYCVPu1GN8IB9XTzrpPkGuV0tmh9mN+/L0PklAlsC3u5Fxt0ju00LXIw==}
-    dev: true
+  '@types/find-cache-dir@3.2.1': {}
 
-  /@types/fluent-ffmpeg@2.1.24:
-    resolution: {integrity: sha512-g5oQO8Jgi2kFS3tTub7wLvfLztr1s8tdXmRd8PiL/hLMLzTIAyMR2sANkTggM/rdEDAg3d63nYRRVepwBiCw5A==}
+  '@types/fluent-ffmpeg@2.1.24':
     dependencies:
-      '@types/node': 20.11.22
-    dev: true
+      '@types/node': 20.12.7
 
-  /@types/glob@7.2.0:
-    resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
+  '@types/glob@7.2.0':
     dependencies:
       '@types/minimatch': 5.1.2
-      '@types/node': 20.11.28
-    dev: true
+      '@types/node': 20.12.7
 
-  /@types/graceful-fs@4.1.6:
-    resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==}
+  '@types/graceful-fs@4.1.6':
     dependencies:
-      '@types/node': 20.11.28
-    dev: true
+      '@types/node': 20.12.7
 
-  /@types/hast@3.0.4:
-    resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
+  '@types/hast@3.0.4':
     dependencies:
       '@types/unist': 3.0.2
-    dev: true
 
-  /@types/htmlescape@1.1.3:
-    resolution: {integrity: sha512-tuC81YJXGUe0q8WRtBNW+uyx79rkkzWK651ALIXXYq5/u/IxjX4iHneGF2uUqzsNp+F+9J2mFZOv9jiLTtIq0w==}
-    dev: true
+  '@types/htmlescape@1.1.3': {}
 
-  /@types/http-cache-semantics@4.0.4:
-    resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
+  '@types/http-cache-semantics@4.0.4': {}
 
-  /@types/http-link-header@1.0.5:
-    resolution: {integrity: sha512-AxhIKR8UbyoqCTNp9rRepkktHuUOw3DjfOfDCaO9kwI8AYzjhxyrvZq4+mRw/2daD3hYDknrtSeV6SsPwmc71w==}
+  '@types/http-link-header@1.0.5':
     dependencies:
-      '@types/node': 20.11.22
-    dev: true
+      '@types/node': 20.12.7
 
-  /@types/istanbul-lib-coverage@2.0.4:
-    resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==}
-    dev: true
+  '@types/istanbul-lib-coverage@2.0.4': {}
 
-  /@types/istanbul-lib-report@3.0.0:
-    resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==}
+  '@types/istanbul-lib-report@3.0.0':
     dependencies:
       '@types/istanbul-lib-coverage': 2.0.4
-    dev: true
 
-  /@types/istanbul-reports@3.0.1:
-    resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==}
+  '@types/istanbul-reports@3.0.1':
     dependencies:
       '@types/istanbul-lib-report': 3.0.0
-    dev: true
 
-  /@types/jest@29.5.11:
-    resolution: {integrity: sha512-S2mHmYIVe13vrm6q4kN6fLYYAka15ALQki/vgDC3mIukEOx8WJlv0kQPM+d4w8Gp6u0uSdKND04IlTXBv0rwnQ==}
+  '@types/jest@29.5.12':
     dependencies:
       expect: 29.7.0
       pretty-format: 29.7.0
-    dev: true
 
-  /@types/jest@29.5.12:
-    resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==}
+  '@types/js-yaml@4.0.9': {}
+
+  '@types/jsdom@21.1.6':
     dependencies:
-      expect: 29.7.0
-      pretty-format: 29.7.0
-    dev: true
-
-  /@types/js-yaml@4.0.9:
-    resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==}
-    dev: true
-
-  /@types/jsdom@21.1.6:
-    resolution: {integrity: sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw==}
-    dependencies:
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       '@types/tough-cookie': 4.0.2
       parse5: 7.1.2
-    dev: true
 
-  /@types/json-schema@7.0.12:
-    resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==}
-    dev: true
+  '@types/json-schema@7.0.12': {}
 
-  /@types/json5@0.0.29:
-    resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
-    dev: true
+  '@types/json-schema@7.0.15': {}
 
-  /@types/jsonld@1.5.13:
-    resolution: {integrity: sha512-n7fUU6W4kSYK8VQlf/LsE9kddBHPKhODoVOjsZswmve+2qLwBy6naWxs/EiuSZN9NU0N06Ra01FR+j87C62T0A==}
-    dev: true
+  '@types/json5@0.0.29': {}
 
-  /@types/jsrsasign@10.5.12:
-    resolution: {integrity: sha512-sOA+eVnHU+FziThpMhuqs/tjFKe5gHVJKIS7g1BzhXP+e2FS8OvtzM0K3IzFxVksDOr98Gz5FJiZVxZ9uFoHhw==}
-    dev: true
+  '@types/jsonld@1.5.13': {}
 
-  /@types/keyv@3.1.4:
-    resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
+  '@types/jsrsasign@10.5.14': {}
+
+  '@types/keyv@3.1.4':
     dependencies:
-      '@types/node': 20.11.22
-    dev: false
+      '@types/node': 20.12.7
 
-  /@types/lodash@4.14.191:
-    resolution: {integrity: sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==}
-    dev: true
+  '@types/lodash@4.14.191': {}
 
-  /@types/long@4.0.2:
-    resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==}
-    requiresBuild: true
-    dev: false
+  '@types/long@4.0.2': {}
 
-  /@types/matter-js@0.19.6:
-    resolution: {integrity: sha512-ffk6tqJM5scla+ThXmnox+mdfCo3qYk6yMjQsNcrbo6eQ5DqorVdtnaL+1agCoYzxUjmHeiNB7poBMAmhuLY7w==}
-    dev: true
+  '@types/matter-js@0.19.6': {}
 
-  /@types/mdast@4.0.3:
-    resolution: {integrity: sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==}
+  '@types/mdast@4.0.3':
     dependencies:
       '@types/unist': 3.0.2
-    dev: true
 
-  /@types/mdx@2.0.3:
-    resolution: {integrity: sha512-IgHxcT3RC8LzFLhKwP3gbMPeaK7BM9eBH46OdapPA7yvuIUJ8H6zHZV53J8hGZcTSnt95jANt+rTBNUUc22ACQ==}
-    dev: true
+  '@types/mdx@2.0.3': {}
 
-  /@types/micromatch@4.0.6:
-    resolution: {integrity: sha512-2eulCHWqjEpk9/vyic4tBhI8a9qQEl6DaK2n/sF7TweX9YESlypgKyhXMDGt4DAOy/jhLPvVrZc8pTDAMsplJA==}
+  '@types/micromatch@4.0.7':
     dependencies:
       '@types/braces': 3.0.1
-    dev: true
 
-  /@types/mime-types@2.1.4:
-    resolution: {integrity: sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==}
-    dev: true
+  '@types/mime-types@2.1.4': {}
 
-  /@types/mime@3.0.1:
-    resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==}
-    dev: true
+  '@types/mime@3.0.1': {}
 
-  /@types/minimatch@5.1.2:
-    resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==}
-    dev: true
+  '@types/minimatch@5.1.2': {}
 
-  /@types/minimist@1.2.2:
-    resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==}
-    dev: true
+  '@types/minimist@1.2.2': {}
 
-  /@types/ms@0.7.34:
-    resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==}
-    dev: true
+  '@types/ms@0.7.34': {}
 
-  /@types/node-fetch@2.6.4:
-    resolution: {integrity: sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==}
-    requiresBuild: true
+  '@types/mute-stream@0.0.4':
     dependencies:
-      '@types/node': 20.11.22
-      form-data: 3.0.1
-    dev: false
+      '@types/node': 20.12.7
 
-  /@types/node-fetch@3.0.3:
-    resolution: {integrity: sha512-HhggYPH5N+AQe/OmN6fmhKmRRt2XuNJow+R3pQwJxOOF9GuwM7O2mheyGeIrs5MOIeNjDEdgdoyHBOrFeJBR3g==}
-    deprecated: This is a stub types definition. node-fetch provides its own type definitions, so you do not need this installed.
+  '@types/node-fetch@2.6.4':
+    dependencies:
+      '@types/node': 20.12.7
+      form-data: 3.0.1
+
+  '@types/node-fetch@3.0.3':
     dependencies:
       node-fetch: 3.3.2
-    dev: true
 
-  /@types/node@18.17.15:
-    resolution: {integrity: sha512-2yrWpBk32tvV/JAd3HNHWuZn/VDN1P+72hWirHnvsvTGSqbANi+kSeuQR9yAHnbvaBvHDsoTdXV0Fe+iRtHLKA==}
-    dev: true
+  '@types/node@18.17.15': {}
 
-  /@types/node@20.11.22:
-    resolution: {integrity: sha512-/G+IxWxma6V3E+pqK1tSl2Fo1kl41pK1yeCyDsgkF9WlVAme4j5ISYM2zR11bgLFJGLN5sVK40T4RJNuiZbEjA==}
+  '@types/node@20.11.5':
     dependencies:
       undici-types: 5.26.5
 
-  /@types/node@20.11.28:
-    resolution: {integrity: sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==}
+  '@types/node@20.12.7':
     dependencies:
       undici-types: 5.26.5
-    dev: true
 
-  /@types/node@20.11.5:
-    resolution: {integrity: sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==}
+  '@types/node@20.9.1':
     dependencies:
       undici-types: 5.26.5
-    dev: true
 
-  /@types/node@20.9.1:
-    resolution: {integrity: sha512-HhmzZh5LSJNS5O8jQKpJ/3ZcrrlG6L70hpGqMIAoM9YVD0YBRNWYsfwcXq8VnSjlNpCpgLzMXdiPo+dxcvSmiA==}
+  '@types/nodemailer@6.4.15':
     dependencies:
-      undici-types: 5.26.5
-    dev: true
+      '@types/node': 20.12.7
 
-  /@types/nodemailer@6.4.14:
-    resolution: {integrity: sha512-fUWthHO9k9DSdPCSPRqcu6TWhYyxTBg382vlNIttSe9M7XfsT06y0f24KHXtbnijPGGRIcVvdKHTNikOI6qiHA==}
+  '@types/normalize-package-data@2.4.1': {}
+
+  '@types/oauth2orize-pkce@0.1.2':
     dependencies:
-      '@types/node': 20.11.22
-    dev: true
+      '@types/oauth2orize': 1.11.5
 
-  /@types/normalize-package-data@2.4.1:
-    resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
-    dev: true
-
-  /@types/oauth2orize-pkce@0.1.2:
-    resolution: {integrity: sha512-g5rDzqQTTUIJJpY7UWxb0EU1WyURIwOj3TndKC2krEEEmaKrnZXgoEBkR72QY2kp4cJ6N9cF2AqTPJ0Qyg+caA==}
-    dependencies:
-      '@types/oauth2orize': 1.11.3
-    dev: true
-
-  /@types/oauth2orize@1.11.3:
-    resolution: {integrity: sha512-Ali0fUUn+zgr4Yy/pCTFbuiaiJpq7l7OQwFnxYVchNbNGIx0c4Wkcdje6WO89I91RAaYF+gVc1pOaizA4YKZmA==}
+  '@types/oauth2orize@1.11.5':
     dependencies:
       '@types/express': 4.17.17
-      '@types/node': 20.11.22
-    dev: true
+      '@types/node': 20.12.7
 
-  /@types/oauth@0.9.4:
-    resolution: {integrity: sha512-qk9orhti499fq5XxKCCEbd0OzdPZuancneyse3KtR+vgMiHRbh+mn8M4G6t64ob/Fg+GZGpa565MF/2dKWY32A==}
+  '@types/oauth@0.9.4':
     dependencies:
-      '@types/node': 20.11.22
-    dev: true
+      '@types/node': 20.12.7
 
-  /@types/offscreencanvas@2019.3.0:
-    resolution: {integrity: sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==}
-    requiresBuild: true
-    dev: false
+  '@types/offscreencanvas@2019.3.0': {}
 
-  /@types/offscreencanvas@2019.7.0:
-    resolution: {integrity: sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==}
-    requiresBuild: true
-    dev: false
+  '@types/offscreencanvas@2019.7.0': {}
 
-  /@types/pg@8.11.2:
-    resolution: {integrity: sha512-G2Mjygf2jFMU/9hCaTYxJrwdObdcnuQde1gndooZSOHsNSaCehAuwc7EIuSA34Do8Jx2yZ19KtvW8P0j4EuUXw==}
+  '@types/pg@8.11.5':
     dependencies:
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       pg-protocol: 1.6.0
       pg-types: 4.0.1
-    dev: true
 
-  /@types/pretty-hrtime@1.0.1:
-    resolution: {integrity: sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ==}
-    dev: true
+  '@types/pretty-hrtime@1.0.1': {}
 
-  /@types/prop-types@15.7.5:
-    resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
-    dev: true
+  '@types/prop-types@15.7.5': {}
 
-  /@types/pug@2.0.10:
-    resolution: {integrity: sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==}
-    dev: true
+  '@types/pug@2.0.10': {}
 
-  /@types/punycode@2.1.4:
-    resolution: {integrity: sha512-trzh6NzBnq8yw5e35f8xe8VTYjqM3NE7bohBtvDVf/dtUer3zYTLK1Ka3DG3p7bdtoaOHZucma6FfVKlQ134pQ==}
-    dev: true
+  '@types/punycode@2.1.4': {}
 
-  /@types/qrcode@1.5.5:
-    resolution: {integrity: sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==}
+  '@types/qrcode@1.5.5':
     dependencies:
-      '@types/node': 20.11.22
-    dev: true
+      '@types/node': 20.12.7
 
-  /@types/qs@6.9.7:
-    resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==}
-    dev: true
+  '@types/qs@6.9.7': {}
 
-  /@types/random-seed@0.3.5:
-    resolution: {integrity: sha512-CftxcDPAHgs0SLHU2dt+ZlDPJfGqLW3sZlC/ATr5vJDSe5tRLeOne7HMvCOJnFyF8e1U41wqzs3h6AMC613xtA==}
-    dev: true
+  '@types/random-seed@0.3.5': {}
 
-  /@types/range-parser@1.2.4:
-    resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==}
-    dev: true
+  '@types/range-parser@1.2.4': {}
 
-  /@types/ratelimiter@3.4.6:
-    resolution: {integrity: sha512-Bv6WLSXPGLVsBjkizXtn+ef78R92e36/DFQo2wXPTHtp1cYXF6rCULMqf9WcZPAtyMZMvQAtIPeYMA1xAyxghw==}
-    dev: true
+  '@types/ratelimiter@3.4.6': {}
 
-  /@types/react@18.0.28:
-    resolution: {integrity: sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==}
+  '@types/react@18.0.28':
     dependencies:
       '@types/prop-types': 15.7.5
       '@types/scheduler': 0.16.2
       csstype: 3.1.3
-    dev: true
 
-  /@types/readdir-glob@1.1.1:
-    resolution: {integrity: sha512-ImM6TmoF8bgOwvehGviEj3tRdRBbQujr1N+0ypaln/GWjaerOB26jb93vsRHmdMtvVQZQebOlqt2HROark87mQ==}
+  '@types/readdir-glob@1.1.1':
     dependencies:
-      '@types/node': 20.11.22
-    dev: true
+      '@types/node': 20.12.7
 
-  /@types/rename@1.0.7:
-    resolution: {integrity: sha512-E9qapfghUGfBMi3jNhsmCKPIp3f2zvNKpaX1BDGLGJNjzpgsZ/RTx7NaNksFjGoJ+r9NvWF1NSM5vVecnNjVmw==}
-    dev: true
+  '@types/rename@1.0.7': {}
 
-  /@types/resolve@1.20.3:
-    resolution: {integrity: sha512-NH5oErHOtHZYcjCtg69t26aXEk4BN2zLWqf7wnDZ+dpe0iR7Rds1SPGEItl3fca21oOe0n3OCnZ4W7jBxu7FOw==}
-    dev: true
+  '@types/resolve@1.20.3': {}
 
-  /@types/responselike@1.0.0:
-    resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
+  '@types/responselike@1.0.0':
     dependencies:
-      '@types/node': 20.11.22
-    dev: false
+      '@types/node': 20.12.7
 
-  /@types/sanitize-html@2.11.0:
-    resolution: {integrity: sha512-7oxPGNQHXLHE48r/r/qjn7q0hlrs3kL7oZnGj0Wf/h9tj/6ibFyRkNbsDxaBBZ4XUZ0Dx5LGCyDJ04ytSofacQ==}
+  '@types/sanitize-html@2.11.0':
     dependencies:
       htmlparser2: 8.0.1
-    dev: true
 
-  /@types/scheduler@0.16.2:
-    resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
-    dev: true
+  '@types/scheduler@0.16.2': {}
 
-  /@types/seedrandom@2.4.30:
-    resolution: {integrity: sha512-AnxLHewubLVzoF/A4qdxBGHCKifw8cY32iro3DQX9TPcetE95zBeVt3jnsvtvAUf1vwzMfwzp4t/L2yqPlnjkQ==}
-    requiresBuild: true
-    dev: false
+  '@types/seedrandom@2.4.30': {}
 
-  /@types/seedrandom@3.0.8:
-    resolution: {integrity: sha512-TY1eezMU2zH2ozQoAFAQFOPpvP15g+ZgSfTZt31AUUH/Rxtnz3H+A/Sv1Snw2/amp//omibc+AEkTaA8KUeOLQ==}
-    dev: true
+  '@types/seedrandom@3.0.8': {}
 
-  /@types/semver@7.5.8:
-    resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==}
-    dev: true
+  '@types/semver@7.5.8': {}
 
-  /@types/serve-static@1.15.1:
-    resolution: {integrity: sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==}
+  '@types/serve-static@1.15.1':
     dependencies:
       '@types/mime': 3.0.1
-      '@types/node': 20.11.22
-    dev: true
+      '@types/node': 20.12.7
 
-  /@types/serviceworker@0.0.67:
-    resolution: {integrity: sha512-7TCH7iNsCSNb+aUD9M/36TekrWFSLCjNK8zw/3n5kOtRjbLtDfGYMXTrDnGhSfqXNwpqmt9Vd90w5C/ad1tX6Q==}
-    dev: true
+  '@types/serviceworker@0.0.67': {}
 
-  /@types/simple-oauth2@5.0.7:
-    resolution: {integrity: sha512-8JbWVJbiTSBQP/7eiyGKyXWAqp3dKQZpaA+pdW16FCi32ujkzRMG8JfjoAzdWt6W8U591ZNdHcPtP2D7ILTKuA==}
-    dev: true
+  '@types/simple-oauth2@5.0.7': {}
 
-  /@types/sinon@10.0.13:
-    resolution: {integrity: sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ==}
+  '@types/sinon@10.0.13':
     dependencies:
       '@types/sinonjs__fake-timers': 8.1.5
-    dev: true
 
-  /@types/sinonjs__fake-timers@8.1.1:
-    resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==}
-    dev: true
+  '@types/sinonjs__fake-timers@8.1.1': {}
 
-  /@types/sinonjs__fake-timers@8.1.5:
-    resolution: {integrity: sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==}
-    dev: true
+  '@types/sinonjs__fake-timers@8.1.5': {}
 
-  /@types/sizzle@2.3.3:
-    resolution: {integrity: sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==}
-    dev: true
+  '@types/sizzle@2.3.3': {}
 
-  /@types/stack-utils@2.0.1:
-    resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==}
-    dev: true
+  '@types/stack-utils@2.0.1': {}
 
-  /@types/statuses@2.0.4:
-    resolution: {integrity: sha512-eqNDvZsCNY49OAXB0Firg/Sc2BgoWsntsLUdybGFOhAfCD6QJ2n9HXUIHGqt5qjrxmMv4wS8WLAw43ZkKcJ8Pw==}
-    dev: true
+  '@types/statuses@2.0.4': {}
 
-  /@types/throttle-debounce@5.0.2:
-    resolution: {integrity: sha512-pDzSNulqooSKvSNcksnV72nk8p7gRqN8As71Sp28nov1IgmPKWbOEIwAWvBME5pPTtaXJAvG3O4oc76HlQ4kqQ==}
-    dev: true
+  '@types/throttle-debounce@5.0.2': {}
 
-  /@types/tinycolor2@1.4.6:
-    resolution: {integrity: sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==}
-    dev: true
+  '@types/tinycolor2@1.4.6': {}
 
-  /@types/tmp@0.2.6:
-    resolution: {integrity: sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==}
-    dev: true
+  '@types/tmp@0.2.6': {}
 
-  /@types/tough-cookie@4.0.2:
-    resolution: {integrity: sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==}
-    dev: true
+  '@types/tough-cookie@4.0.2': {}
 
-  /@types/unist@3.0.2:
-    resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==}
-    dev: true
+  '@types/unist@3.0.2': {}
 
-  /@types/uuid@9.0.8:
-    resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==}
-    dev: true
+  '@types/uuid@9.0.8': {}
 
-  /@types/vary@1.1.3:
-    resolution: {integrity: sha512-XJT8/ZQCL7NUut9QDLf6l24JfAEl7bnNdgxfj50cHIpEPRJLHHDDFOAq6i+GsEmeFfH7NamhBE4c4Thtb2egWg==}
+  '@types/vary@1.1.3':
     dependencies:
-      '@types/node': 20.11.22
-    dev: true
+      '@types/node': 20.12.7
 
-  /@types/web-push@3.6.3:
-    resolution: {integrity: sha512-v3oT4mMJsHeJ/rraliZ+7TbZtr5bQQuxcgD7C3/1q/zkAj29c8RE0F9lVZVu3hiQe5Z9fYcBreV7TLnfKR+4mg==}
+  '@types/web-push@3.6.3':
     dependencies:
-      '@types/node': 20.11.22
-    dev: true
+      '@types/node': 20.12.7
 
-  /@types/webgl-ext@0.0.30:
-    resolution: {integrity: sha512-LKVgNmBxN0BbljJrVUwkxwRYqzsAEPcZOe6S2T6ZaBDIrFp0qu4FNlpc5sM1tGbXUYFgdVQIoeLk1Y1UoblyEg==}
-    requiresBuild: true
-    dev: false
+  '@types/webgl-ext@0.0.30': {}
 
-  /@types/ws@8.5.10:
-    resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==}
+  '@types/wrap-ansi@3.0.0': {}
+
+  '@types/ws@8.5.10':
     dependencies:
-      '@types/node': 20.11.22
-    dev: true
+      '@types/node': 20.12.7
 
-  /@types/yargs-parser@21.0.0:
-    resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==}
-    dev: true
+  '@types/yargs-parser@21.0.0': {}
 
-  /@types/yargs@17.0.19:
-    resolution: {integrity: sha512-cAx3qamwaYX9R0fzOIZAlFpo4A+1uBVCxqpKz9D26uTF4srRXaGTTsikQmaotCtNdbhzyUH7ft6p9ktz9s6UNQ==}
+  '@types/yargs@17.0.19':
     dependencies:
       '@types/yargs-parser': 21.0.0
-    dev: true
 
-  /@types/yauzl@2.10.0:
-    resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==}
-    requiresBuild: true
+  '@types/yauzl@2.10.0':
     dependencies:
-      '@types/node': 20.11.22
-    dev: true
+      '@types/node': 20.12.7
     optional: true
 
-  /@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.3):
-    resolution: {integrity: sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha
-      eslint: ^7.0.0 || ^8.0.0
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
+  '@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0)(typescript@5.3.3)':
     dependencies:
       '@eslint-community/regexpp': 4.6.2
       '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
@@ -7965,21 +15626,12 @@ packages:
       natural-compare: 1.4.0
       semver: 7.5.4
       ts-api-utils: 1.0.1(typescript@5.3.3)
+    optionalDependencies:
       typescript: 5.3.3
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3):
-    resolution: {integrity: sha512-j6vT/kCulhG5wBmGtstKeiVr1rdXE4nk+DT1k6trYkwlrvW9eOF5ZbgKnd/YR6PcM4uTEXa0h6Fcvf6X7Dxl0w==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      '@typescript-eslint/parser': ^7.0.0
-      eslint: ^8.56.0
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
+  '@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3)':
     dependencies:
       '@eslint-community/regexpp': 4.6.2
       '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3)
@@ -7994,20 +15646,32 @@ packages:
       natural-compare: 1.4.0
       semver: 7.6.0
       ts-api-utils: 1.0.1(typescript@5.3.3)
+    optionalDependencies:
       typescript: 5.3.3
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3):
-    resolution: {integrity: sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      eslint: ^7.0.0 || ^8.0.0
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
+  '@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)':
+    dependencies:
+      '@eslint-community/regexpp': 4.10.0
+      '@typescript-eslint/parser': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
+      '@typescript-eslint/scope-manager': 7.7.1
+      '@typescript-eslint/type-utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
+      '@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
+      '@typescript-eslint/visitor-keys': 7.7.1
+      debug: 4.3.4(supports-color@8.1.1)
+      eslint: 8.57.0
+      graphemer: 1.4.0
+      ignore: 5.3.1
+      natural-compare: 1.4.0
+      semver: 7.6.0
+      ts-api-utils: 1.3.0(typescript@5.4.5)
+    optionalDependencies:
+      typescript: 5.4.5
+    transitivePeerDependencies:
+      - supports-color
+
+  '@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3)':
     dependencies:
       '@typescript-eslint/scope-manager': 6.11.0
       '@typescript-eslint/types': 6.11.0
@@ -8015,20 +15679,12 @@ packages:
       '@typescript-eslint/visitor-keys': 6.11.0
       debug: 4.3.4(supports-color@8.1.1)
       eslint: 8.53.0
+    optionalDependencies:
       typescript: 5.3.3
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3):
-    resolution: {integrity: sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      eslint: ^8.56.0
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
+  '@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3)':
     dependencies:
       '@typescript-eslint/scope-manager': 7.1.0
       '@typescript-eslint/types': 7.1.0
@@ -8036,85 +15692,82 @@ packages:
       '@typescript-eslint/visitor-keys': 7.1.0
       debug: 4.3.4(supports-color@8.1.1)
       eslint: 8.57.0
+    optionalDependencies:
       typescript: 5.3.3
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@typescript-eslint/scope-manager@6.11.0:
-    resolution: {integrity: sha512-0A8KoVvIURG4uhxAdjSaxy8RdRE//HztaZdG8KiHLP8WOXSk0vlF7Pvogv+vlJA5Rnjj/wDcFENvDaHb+gKd1A==}
-    engines: {node: ^16.0.0 || >=18.0.0}
+  '@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5)':
+    dependencies:
+      '@typescript-eslint/scope-manager': 7.7.1
+      '@typescript-eslint/types': 7.7.1
+      '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5)
+      '@typescript-eslint/visitor-keys': 7.7.1
+      debug: 4.3.4(supports-color@8.1.1)
+      eslint: 8.57.0
+    optionalDependencies:
+      typescript: 5.4.5
+    transitivePeerDependencies:
+      - supports-color
+
+  '@typescript-eslint/scope-manager@6.11.0':
     dependencies:
       '@typescript-eslint/types': 6.11.0
       '@typescript-eslint/visitor-keys': 6.11.0
-    dev: true
 
-  /@typescript-eslint/scope-manager@7.1.0:
-    resolution: {integrity: sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==}
-    engines: {node: ^16.0.0 || >=18.0.0}
+  '@typescript-eslint/scope-manager@7.1.0':
     dependencies:
       '@typescript-eslint/types': 7.1.0
       '@typescript-eslint/visitor-keys': 7.1.0
-    dev: true
 
-  /@typescript-eslint/type-utils@6.11.0(eslint@8.53.0)(typescript@5.3.3):
-    resolution: {integrity: sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      eslint: ^7.0.0 || ^8.0.0
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
+  '@typescript-eslint/scope-manager@7.7.1':
+    dependencies:
+      '@typescript-eslint/types': 7.7.1
+      '@typescript-eslint/visitor-keys': 7.7.1
+
+  '@typescript-eslint/type-utils@6.11.0(eslint@8.53.0)(typescript@5.3.3)':
     dependencies:
       '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.3)
       '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
       debug: 4.3.4(supports-color@8.1.1)
       eslint: 8.53.0
       ts-api-utils: 1.0.1(typescript@5.3.3)
+    optionalDependencies:
       typescript: 5.3.3
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@typescript-eslint/type-utils@7.1.0(eslint@8.57.0)(typescript@5.3.3):
-    resolution: {integrity: sha512-UZIhv8G+5b5skkcuhgvxYWHjk7FW7/JP5lPASMEUoliAPwIH/rxoUSQPia2cuOj9AmDZmwUl1usKm85t5VUMew==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      eslint: ^8.56.0
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
+  '@typescript-eslint/type-utils@7.1.0(eslint@8.57.0)(typescript@5.3.3)':
     dependencies:
       '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3)
       '@typescript-eslint/utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3)
       debug: 4.3.4(supports-color@8.1.1)
       eslint: 8.57.0
       ts-api-utils: 1.0.1(typescript@5.3.3)
+    optionalDependencies:
       typescript: 5.3.3
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@typescript-eslint/types@6.11.0:
-    resolution: {integrity: sha512-ZbEzuD4DwEJxwPqhv3QULlRj8KYTAnNsXxmfuUXFCxZmO6CF2gM/y+ugBSAQhrqaJL3M+oe4owdWunaHM6beqA==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    dev: true
+  '@typescript-eslint/type-utils@7.7.1(eslint@8.57.0)(typescript@5.4.5)':
+    dependencies:
+      '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5)
+      '@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
+      debug: 4.3.4(supports-color@8.1.1)
+      eslint: 8.57.0
+      ts-api-utils: 1.3.0(typescript@5.4.5)
+    optionalDependencies:
+      typescript: 5.4.5
+    transitivePeerDependencies:
+      - supports-color
 
-  /@typescript-eslint/types@7.1.0:
-    resolution: {integrity: sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    dev: true
+  '@typescript-eslint/types@6.11.0': {}
 
-  /@typescript-eslint/typescript-estree@6.11.0(typescript@5.3.3):
-    resolution: {integrity: sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
+  '@typescript-eslint/types@7.1.0': {}
+
+  '@typescript-eslint/types@7.7.1': {}
+
+  '@typescript-eslint/typescript-estree@6.11.0(typescript@5.3.3)':
     dependencies:
       '@typescript-eslint/types': 6.11.0
       '@typescript-eslint/visitor-keys': 6.11.0
@@ -8123,19 +15776,12 @@ packages:
       is-glob: 4.0.3
       semver: 7.5.4
       ts-api-utils: 1.0.1(typescript@5.3.3)
+    optionalDependencies:
       typescript: 5.3.3
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@typescript-eslint/typescript-estree@7.1.0(typescript@5.3.3):
-    resolution: {integrity: sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
+  '@typescript-eslint/typescript-estree@7.1.0(typescript@5.3.3)':
     dependencies:
       '@typescript-eslint/types': 7.1.0
       '@typescript-eslint/visitor-keys': 7.1.0
@@ -8145,16 +15791,27 @@ packages:
       minimatch: 9.0.3
       semver: 7.6.0
       ts-api-utils: 1.0.1(typescript@5.3.3)
+    optionalDependencies:
       typescript: 5.3.3
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@typescript-eslint/utils@6.11.0(eslint@8.53.0)(typescript@5.3.3):
-    resolution: {integrity: sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      eslint: ^7.0.0 || ^8.0.0
+  '@typescript-eslint/typescript-estree@7.7.1(typescript@5.4.5)':
+    dependencies:
+      '@typescript-eslint/types': 7.7.1
+      '@typescript-eslint/visitor-keys': 7.7.1
+      debug: 4.3.4(supports-color@8.1.1)
+      globby: 11.1.0
+      is-glob: 4.0.3
+      minimatch: 9.0.4
+      semver: 7.6.0
+      ts-api-utils: 1.3.0(typescript@5.4.5)
+    optionalDependencies:
+      typescript: 5.4.5
+    transitivePeerDependencies:
+      - supports-color
+
+  '@typescript-eslint/utils@6.11.0(eslint@8.53.0)(typescript@5.3.3)':
     dependencies:
       '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0)
       '@types/json-schema': 7.0.12
@@ -8167,13 +15824,8 @@ packages:
     transitivePeerDependencies:
       - supports-color
       - typescript
-    dev: true
 
-  /@typescript-eslint/utils@7.1.0(eslint@8.57.0)(typescript@5.3.3):
-    resolution: {integrity: sha512-WUFba6PZC5OCGEmbweGpnNJytJiLG7ZvDBJJoUcX4qZYf1mGZ97mO2Mps6O2efxJcJdRNpqweCistDbZMwIVHw==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      eslint: ^8.56.0
+  '@typescript-eslint/utils@7.1.0(eslint@8.57.0)(typescript@5.3.3)':
     dependencies:
       '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
       '@types/json-schema': 7.0.12
@@ -8186,43 +15838,44 @@ packages:
     transitivePeerDependencies:
       - supports-color
       - typescript
-    dev: true
 
-  /@typescript-eslint/visitor-keys@6.11.0:
-    resolution: {integrity: sha512-+SUN/W7WjBr05uRxPggJPSzyB8zUpaYo2hByKasWbqr3PM8AXfZt8UHdNpBS1v9SA62qnSSMF3380SwDqqprgQ==}
-    engines: {node: ^16.0.0 || >=18.0.0}
+  '@typescript-eslint/utils@7.7.1(eslint@8.57.0)(typescript@5.4.5)':
+    dependencies:
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+      '@types/json-schema': 7.0.15
+      '@types/semver': 7.5.8
+      '@typescript-eslint/scope-manager': 7.7.1
+      '@typescript-eslint/types': 7.7.1
+      '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5)
+      eslint: 8.57.0
+      semver: 7.6.0
+    transitivePeerDependencies:
+      - supports-color
+      - typescript
+
+  '@typescript-eslint/visitor-keys@6.11.0':
     dependencies:
       '@typescript-eslint/types': 6.11.0
       eslint-visitor-keys: 3.4.3
-    dev: true
 
-  /@typescript-eslint/visitor-keys@7.1.0:
-    resolution: {integrity: sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==}
-    engines: {node: ^16.0.0 || >=18.0.0}
+  '@typescript-eslint/visitor-keys@7.1.0':
     dependencies:
       '@typescript-eslint/types': 7.1.0
       eslint-visitor-keys: 3.4.3
-    dev: true
 
-  /@ungap/structured-clone@1.2.0:
-    resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
-    dev: true
-
-  /@vitejs/plugin-vue@5.0.4(vite@5.1.4)(vue@3.4.21):
-    resolution: {integrity: sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==}
-    engines: {node: ^18.0.0 || >=20.0.0}
-    peerDependencies:
-      vite: ^5.0.0
-      vue: ^3.2.25
+  '@typescript-eslint/visitor-keys@7.7.1':
     dependencies:
-      vite: 5.1.4(@types/node@20.11.22)(sass@1.71.1)(terser@5.28.1)
-      vue: 3.4.21(typescript@5.3.3)
-    dev: false
+      '@typescript-eslint/types': 7.7.1
+      eslint-visitor-keys: 3.4.3
 
-  /@vitest/coverage-v8@0.34.6(vitest@0.34.6):
-    resolution: {integrity: sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw==}
-    peerDependencies:
-      vitest: '>=0.32.0 <1'
+  '@ungap/structured-clone@1.2.0': {}
+
+  '@vitejs/plugin-vue@5.0.4(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))(vue@3.4.26(typescript@5.4.5))':
+    dependencies:
+      vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
+      vue: 3.4.26(typescript@5.4.5)
+
+  '@vitest/coverage-v8@0.34.6(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))':
     dependencies:
       '@ampproject/remapping': 2.2.1
       '@bcoe/v8-coverage': 0.2.3
@@ -8235,641 +15888,424 @@ packages:
       std-env: 3.7.0
       test-exclude: 6.0.0
       v8-to-istanbul: 9.2.0
-      vitest: 0.34.6(happy-dom@13.6.2)(sass@1.71.1)(terser@5.28.1)
+      vitest: 0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@vitest/expect@0.34.6:
-    resolution: {integrity: sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==}
+  '@vitest/expect@0.34.6':
     dependencies:
       '@vitest/spy': 0.34.6
       '@vitest/utils': 0.34.6
       chai: 4.3.10
-    dev: true
 
-  /@vitest/expect@1.3.1:
-    resolution: {integrity: sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==}
+  '@vitest/expect@1.3.1':
     dependencies:
       '@vitest/spy': 1.3.1
       '@vitest/utils': 1.3.1
       chai: 4.3.10
-    dev: true
 
-  /@vitest/runner@0.34.6:
-    resolution: {integrity: sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==}
+  '@vitest/runner@0.34.6':
     dependencies:
       '@vitest/utils': 0.34.6
       p-limit: 4.0.0
       pathe: 1.1.2
-    dev: true
 
-  /@vitest/snapshot@0.34.6:
-    resolution: {integrity: sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==}
+  '@vitest/snapshot@0.34.6':
     dependencies:
       magic-string: 0.30.7
       pathe: 1.1.2
       pretty-format: 29.7.0
-    dev: true
 
-  /@vitest/spy@0.34.6:
-    resolution: {integrity: sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==}
+  '@vitest/spy@0.34.6':
     dependencies:
       tinyspy: 2.2.0
-    dev: true
 
-  /@vitest/spy@1.3.1:
-    resolution: {integrity: sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==}
+  '@vitest/spy@1.3.1':
     dependencies:
       tinyspy: 2.2.0
-    dev: true
 
-  /@vitest/spy@1.5.3:
-    resolution: {integrity: sha512-Llj7Jgs6lbnL55WoshJUUacdJfjU2honvGcAJBxhra5TPEzTJH8ZuhI3p/JwqqfnTr4PmP7nDmOXP53MS7GJlg==}
+  '@vitest/spy@1.6.0':
     dependencies:
       tinyspy: 2.2.0
-    dev: true
 
-  /@vitest/utils@0.34.6:
-    resolution: {integrity: sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==}
+  '@vitest/utils@0.34.6':
     dependencies:
       diff-sequences: 29.6.3
       loupe: 2.3.7
       pretty-format: 29.7.0
-    dev: true
 
-  /@vitest/utils@1.3.1:
-    resolution: {integrity: sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==}
+  '@vitest/utils@1.3.1':
     dependencies:
       diff-sequences: 29.6.3
       estree-walker: 3.0.3
       loupe: 2.3.7
       pretty-format: 29.7.0
-    dev: true
 
-  /@vitest/utils@1.5.3:
-    resolution: {integrity: sha512-rE9DTN1BRhzkzqNQO+kw8ZgfeEBCLXiHJwetk668shmNBpSagQxneT5eSqEBLP+cqSiAeecvQmbpFfdMyLcIQA==}
+  '@vitest/utils@1.6.0':
     dependencies:
       diff-sequences: 29.6.3
       estree-walker: 3.0.3
       loupe: 2.3.7
       pretty-format: 29.7.0
-    dev: true
 
-  /@volar/language-core@1.11.1:
-    resolution: {integrity: sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==}
-    dependencies:
-      '@volar/source-map': 1.11.1
-    dev: true
-
-  /@volar/language-core@2.2.0:
-    resolution: {integrity: sha512-a8WG9+4OdeNDW4ywABZIM6S6UN7em8uIlM/BZ2pWQUYrVmX+m8sj/X+QadvO+Li/t/LjAqbWJQtVgxdpEWLALQ==}
+  '@volar/language-core@2.2.0':
     dependencies:
       '@volar/source-map': 2.2.0
-    dev: true
 
-  /@volar/source-map@1.11.1:
-    resolution: {integrity: sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==}
-    dependencies:
-      muggle-string: 0.3.1
-    dev: true
-
-  /@volar/source-map@2.2.0:
-    resolution: {integrity: sha512-HQlPRlHOVqCCHK8wI76ZldHkEwKsjp7E6idUc36Ekni+KJDNrqgSqPvyHQixybXPHNU7CI9Uxd9/IkxO7LuNBw==}
+  '@volar/source-map@2.2.0':
     dependencies:
       muggle-string: 0.4.1
-    dev: true
 
-  /@volar/typescript@1.11.1:
-    resolution: {integrity: sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==}
-    dependencies:
-      '@volar/language-core': 1.11.1
-      path-browserify: 1.0.1
-    dev: true
-
-  /@volar/typescript@2.2.0:
-    resolution: {integrity: sha512-wC6l4zLiiCLxF+FGaHCbWlQYf4vMsnRxYhcI6WgvaNppOD6r1g+Ef1RKRJUApALWU46Yy/JDU/TbdV6w/X6Liw==}
+  '@volar/typescript@2.2.0':
     dependencies:
       '@volar/language-core': 2.2.0
       path-browserify: 1.0.1
-    dev: true
 
-  /@vue/compiler-core@3.4.18:
-    resolution: {integrity: sha512-F7YK8lMK0iv6b9/Gdk15A67wM0KKZvxDxed0RR60C1z9tIJTKta+urs4j0RTN5XqHISzI3etN3mX0uHhjmoqjQ==}
+  '@vue/compiler-core@3.4.21':
     dependencies:
-      '@babel/parser': 7.23.9
-      '@vue/shared': 3.4.18
-      entities: 4.5.0
-      estree-walker: 2.0.2
-      source-map-js: 1.0.2
-    dev: true
-
-  /@vue/compiler-core@3.4.21:
-    resolution: {integrity: sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==}
-    dependencies:
-      '@babel/parser': 7.23.9
+      '@babel/parser': 7.24.0
       '@vue/shared': 3.4.21
       entities: 4.5.0
       estree-walker: 2.0.2
       source-map-js: 1.0.2
 
-  /@vue/compiler-dom@3.4.18:
-    resolution: {integrity: sha512-24Eb8lcMfInefvQ6YlEVS18w5Q66f4+uXWVA+yb7praKbyjHRNuKVWGuinfSSjM0ZIiPi++QWukhkgznBaqpEA==}
+  '@vue/compiler-core@3.4.25':
     dependencies:
-      '@vue/compiler-core': 3.4.18
-      '@vue/shared': 3.4.18
-    dev: true
-
-  /@vue/compiler-dom@3.4.21:
-    resolution: {integrity: sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==}
-    dependencies:
-      '@vue/compiler-core': 3.4.21
-      '@vue/shared': 3.4.21
-
-  /@vue/compiler-sfc@3.4.21:
-    resolution: {integrity: sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==}
-    dependencies:
-      '@babel/parser': 7.23.9
-      '@vue/compiler-core': 3.4.21
-      '@vue/compiler-dom': 3.4.21
-      '@vue/compiler-ssr': 3.4.21
-      '@vue/shared': 3.4.21
+      '@babel/parser': 7.24.5
+      '@vue/shared': 3.4.25
+      entities: 4.5.0
       estree-walker: 2.0.2
-      magic-string: 0.30.7
-      postcss: 8.4.35
-      source-map-js: 1.0.2
+      source-map-js: 1.2.0
 
-  /@vue/compiler-ssr@3.4.21:
-    resolution: {integrity: sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==}
+  '@vue/compiler-core@3.4.26':
     dependencies:
-      '@vue/compiler-dom': 3.4.21
+      '@babel/parser': 7.24.5
+      '@vue/shared': 3.4.26
+      entities: 4.5.0
+      estree-walker: 2.0.2
+      source-map-js: 1.2.0
+
+  '@vue/compiler-dom@3.4.21':
+    dependencies:
+      '@vue/compiler-core': 3.4.21
       '@vue/shared': 3.4.21
 
-  /@vue/language-core@1.8.27(typescript@5.3.3):
-    resolution: {integrity: sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==}
-    peerDependencies:
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
+  '@vue/compiler-dom@3.4.25':
     dependencies:
-      '@volar/language-core': 1.11.1
-      '@volar/source-map': 1.11.1
-      '@vue/compiler-dom': 3.4.18
-      '@vue/shared': 3.3.12
-      computeds: 0.0.1
-      minimatch: 9.0.3
-      muggle-string: 0.3.1
-      path-browserify: 1.0.1
-      typescript: 5.3.3
-      vue-template-compiler: 2.7.14
-    dev: true
+      '@vue/compiler-core': 3.4.25
+      '@vue/shared': 3.4.25
 
-  /@vue/language-core@2.0.16(typescript@5.3.3):
-    resolution: {integrity: sha512-Bc2sexRH99pznOph8mLw2BlRZ9edm7tW51kcBXgx8adAoOcZUWJj3UNSsdQ6H9Y8meGz7BoazVrVo/jUukIsPw==}
-    peerDependencies:
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
+  '@vue/compiler-dom@3.4.26':
+    dependencies:
+      '@vue/compiler-core': 3.4.26
+      '@vue/shared': 3.4.26
+
+  '@vue/compiler-sfc@3.4.26':
+    dependencies:
+      '@babel/parser': 7.24.5
+      '@vue/compiler-core': 3.4.26
+      '@vue/compiler-dom': 3.4.26
+      '@vue/compiler-ssr': 3.4.26
+      '@vue/shared': 3.4.26
+      estree-walker: 2.0.2
+      magic-string: 0.30.10
+      postcss: 8.4.38
+      source-map-js: 1.2.0
+
+  '@vue/compiler-ssr@3.4.25':
+    dependencies:
+      '@vue/compiler-dom': 3.4.25
+      '@vue/shared': 3.4.25
+    optional: true
+
+  '@vue/compiler-ssr@3.4.26':
+    dependencies:
+      '@vue/compiler-dom': 3.4.26
+      '@vue/shared': 3.4.26
+
+  '@vue/devtools-api@6.6.1': {}
+
+  '@vue/language-core@2.0.16(typescript@5.4.5)':
     dependencies:
       '@volar/language-core': 2.2.0
-      '@vue/compiler-dom': 3.4.21
-      '@vue/shared': 3.4.21
+      '@vue/compiler-dom': 3.4.25
+      '@vue/shared': 3.4.25
       computeds: 0.0.1
-      minimatch: 9.0.3
+      minimatch: 9.0.4
       path-browserify: 1.0.1
-      typescript: 5.3.3
       vue-template-compiler: 2.7.14
-    dev: true
+    optionalDependencies:
+      typescript: 5.4.5
 
-  /@vue/reactivity@3.4.21:
-    resolution: {integrity: sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==}
+  '@vue/reactivity@3.4.26':
     dependencies:
-      '@vue/shared': 3.4.21
+      '@vue/shared': 3.4.26
 
-  /@vue/runtime-core@3.4.21:
-    resolution: {integrity: sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==}
+  '@vue/runtime-core@3.4.26':
     dependencies:
-      '@vue/reactivity': 3.4.21
-      '@vue/shared': 3.4.21
+      '@vue/reactivity': 3.4.26
+      '@vue/shared': 3.4.26
 
-  /@vue/runtime-dom@3.4.21:
-    resolution: {integrity: sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==}
+  '@vue/runtime-dom@3.4.26':
     dependencies:
-      '@vue/runtime-core': 3.4.21
-      '@vue/shared': 3.4.21
+      '@vue/runtime-core': 3.4.26
+      '@vue/shared': 3.4.26
       csstype: 3.1.3
 
-  /@vue/server-renderer@3.4.21(vue@3.4.21):
-    resolution: {integrity: sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==}
-    peerDependencies:
-      vue: 3.4.21
+  '@vue/server-renderer@3.4.25(vue@3.4.26(typescript@5.4.5))':
     dependencies:
-      '@vue/compiler-ssr': 3.4.21
-      '@vue/shared': 3.4.21
-      vue: 3.4.21(typescript@5.3.3)
+      '@vue/compiler-ssr': 3.4.25
+      '@vue/shared': 3.4.25
+      vue: 3.4.26(typescript@5.4.5)
+    optional: true
 
-  /@vue/shared@3.3.12:
-    resolution: {integrity: sha512-6p0Yin0pclvnER7BLNOQuod9Z+cxSYh8pSh7CzHnWNjAIP6zrTlCdHRvSCb1aYEx6i3Q3kvfuWU7nG16CgG1ag==}
-    dev: true
+  '@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.4.5))':
+    dependencies:
+      '@vue/compiler-ssr': 3.4.26
+      '@vue/shared': 3.4.26
+      vue: 3.4.26(typescript@5.4.5)
 
-  /@vue/shared@3.4.18:
-    resolution: {integrity: sha512-CxouGFxxaW5r1WbrSmWwck3No58rApXgRSBxrqgnY1K+jk20F6DrXJkHdH9n4HVT+/B6G2CAn213Uq3npWiy8Q==}
-    dev: true
+  '@vue/shared@3.4.21': {}
 
-  /@vue/shared@3.4.21:
-    resolution: {integrity: sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==}
+  '@vue/shared@3.4.25': {}
 
-  /@vue/test-utils@2.4.1(vue@3.4.21):
-    resolution: {integrity: sha512-VO8nragneNzUZUah6kOjiFmD/gwRjUauG9DROh6oaOeFwX1cZRUNHhdeogE8635cISigXFTtGLUQWx5KCb0xeg==}
-    peerDependencies:
-      '@vue/server-renderer': ^3.0.1
-      vue: ^3.0.1
-    peerDependenciesMeta:
-      '@vue/server-renderer':
-        optional: true
+  '@vue/shared@3.4.26': {}
+
+  '@vue/test-utils@2.4.1(@vue/server-renderer@3.4.25(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))':
     dependencies:
       js-beautify: 1.14.9
-      vue: 3.4.21(typescript@5.3.3)
+      vue: 3.4.26(typescript@5.4.5)
       vue-component-type-helpers: 1.8.4
-    dev: true
+    optionalDependencies:
+      '@vue/server-renderer': 3.4.25(vue@3.4.26(typescript@5.4.5))
 
-  /@webgpu/types@0.1.30:
-    resolution: {integrity: sha512-9AXJSmL3MzY8ZL//JjudA//q+2kBRGhLBFpkdGksWIuxrMy81nFrCzj2Am+mbh8WoU6rXmv7cY5E3rdlyru2Qg==}
-    requiresBuild: true
-    dev: false
+  '@webgpu/types@0.1.30': {}
 
-  /@yarnpkg/esbuild-plugin-pnp@3.0.0-rc.15(esbuild@0.19.11):
-    resolution: {integrity: sha512-kYzDJO5CA9sy+on/s2aIW0411AklfCi8Ck/4QDivOqsMKpStZA2SsR+X27VTggGwpStWaLrjJcDcdDMowtG8MA==}
-    engines: {node: '>=14.15.0'}
-    peerDependencies:
-      esbuild: '>=0.10.0'
+  '@yarnpkg/esbuild-plugin-pnp@3.0.0-rc.15(esbuild@0.20.2)':
     dependencies:
-      esbuild: 0.19.11
+      esbuild: 0.20.2
       tslib: 2.6.2
-    dev: true
 
-  /@yarnpkg/fslib@2.10.3:
-    resolution: {integrity: sha512-41H+Ga78xT9sHvWLlFOZLIhtU6mTGZ20pZ29EiZa97vnxdohJD2AF42rCoAoWfqUz486xY6fhjMH+DYEM9r14A==}
-    engines: {node: '>=12 <14 || 14.2 - 14.9 || >14.10.0'}
+  '@yarnpkg/fslib@2.10.3':
     dependencies:
       '@yarnpkg/libzip': 2.3.0
       tslib: 1.14.1
-    dev: true
 
-  /@yarnpkg/libzip@2.3.0:
-    resolution: {integrity: sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==}
-    engines: {node: '>=12 <14 || 14.2 - 14.9 || >14.10.0'}
+  '@yarnpkg/libzip@2.3.0':
     dependencies:
       '@types/emscripten': 1.39.7
       tslib: 1.14.1
-    dev: true
 
-  /abbrev@1.1.1:
-    resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
+  abbrev@1.1.1: {}
 
-  /abbrev@2.0.0:
-    resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==}
-    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-    dev: false
+  abbrev@2.0.0: {}
 
-  /abort-controller@3.0.0:
-    resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
-    engines: {node: '>=6.5'}
+  abort-controller@3.0.0:
     dependencies:
       event-target-shim: 5.0.1
-    dev: false
 
-  /abstract-logging@2.0.1:
-    resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==}
-    dev: false
+  abstract-logging@2.0.1: {}
 
-  /accepts@1.3.8:
-    resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
-    engines: {node: '>= 0.6'}
+  accepts@1.3.8:
     dependencies:
       mime-types: 2.1.35
       negotiator: 0.6.3
 
-  /acorn-jsx@5.3.2(acorn@7.4.1):
-    resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
-    peerDependencies:
-      acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+  acorn-jsx@5.3.2(acorn@7.4.1):
     dependencies:
       acorn: 7.4.1
-    dev: true
 
-  /acorn-jsx@5.3.2(acorn@8.11.3):
-    resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
-    peerDependencies:
-      acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+  acorn-jsx@5.3.2(acorn@8.11.3):
     dependencies:
       acorn: 8.11.3
-    dev: true
 
-  /acorn-walk@7.2.0:
-    resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==}
-    engines: {node: '>=0.4.0'}
-    dev: true
+  acorn-walk@7.2.0: {}
 
-  /acorn-walk@8.3.2:
-    resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==}
-    engines: {node: '>=0.4.0'}
-    dev: true
+  acorn-walk@8.3.2: {}
 
-  /acorn@7.4.1:
-    resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==}
-    engines: {node: '>=0.4.0'}
-    hasBin: true
+  acorn@7.4.1: {}
 
-  /acorn@8.11.3:
-    resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==}
-    engines: {node: '>=0.4.0'}
-    hasBin: true
+  acorn@8.11.3: {}
 
-  /address@1.2.2:
-    resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==}
-    engines: {node: '>= 10.0.0'}
-    dev: true
+  address@1.2.2: {}
 
-  /adm-zip@0.5.10:
-    resolution: {integrity: sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==}
-    engines: {node: '>=6.0'}
-    requiresBuild: true
-    dev: false
+  adm-zip@0.5.10:
     optional: true
 
-  /agent-base@4.3.0:
-    resolution: {integrity: sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==}
-    engines: {node: '>= 4.0.0'}
-    requiresBuild: true
+  agent-base@4.3.0:
     dependencies:
       es6-promisify: 5.0.0
-    dev: false
     optional: true
 
-  /agent-base@6.0.2:
-    resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
-    engines: {node: '>= 6.0.0'}
-    requiresBuild: true
+  agent-base@6.0.2:
     dependencies:
       debug: 4.3.4(supports-color@8.1.1)
     transitivePeerDependencies:
       - supports-color
 
-  /agent-base@7.1.0:
-    resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==}
-    engines: {node: '>= 14'}
+  agent-base@7.1.0:
     dependencies:
       debug: 4.3.4(supports-color@8.1.1)
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /aggregate-error@3.1.0:
-    resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
-    engines: {node: '>=8'}
+  aggregate-error@3.1.0:
     dependencies:
       clean-stack: 2.2.0
       indent-string: 4.0.0
 
-  /aggregate-error@5.0.0:
-    resolution: {integrity: sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==}
-    engines: {node: '>=18'}
+  aggregate-error@5.0.0:
     dependencies:
       clean-stack: 5.2.0
       indent-string: 5.0.0
-    dev: true
 
-  /ajv-draft-04@1.0.0(ajv@8.12.0):
-    resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==}
-    peerDependencies:
-      ajv: ^8.5.0
-    peerDependenciesMeta:
-      ajv:
-        optional: true
+  aiscript-vscode@https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/3f79d6f0550369267220aa67702287948d885424:
     dependencies:
-      ajv: 8.12.0
-    dev: true
+      '@aiscript-dev/aiscript-languageserver': https://github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz
+      vscode-languageclient: 9.0.1
 
-  /ajv-formats@2.1.1(ajv@8.12.0):
-    resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
-    peerDependencies:
-      ajv: ^8.0.0
-    peerDependenciesMeta:
-      ajv:
-        optional: true
-    dependencies:
-      ajv: 8.12.0
-    dev: false
+  ajv-draft-04@1.0.0(ajv@8.13.0):
+    optionalDependencies:
+      ajv: 8.13.0
 
-  /ajv@6.12.6:
-    resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+  ajv-formats@2.1.1(ajv@8.13.0):
+    optionalDependencies:
+      ajv: 8.13.0
+
+  ajv@6.12.6:
     dependencies:
       fast-deep-equal: 3.1.3
       fast-json-stable-stringify: 2.1.0
       json-schema-traverse: 0.4.1
       uri-js: 4.4.1
 
-  /ajv@8.12.0:
-    resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==}
+  ajv@8.13.0:
     dependencies:
       fast-deep-equal: 3.1.3
       json-schema-traverse: 1.0.0
       require-from-string: 2.0.2
       uri-js: 4.4.1
 
-  /ansi-colors@4.1.3:
-    resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
-    engines: {node: '>=6'}
-    dev: true
+  ansi-colors@4.1.3: {}
 
-  /ansi-escapes@4.3.2:
-    resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
-    engines: {node: '>=8'}
+  ansi-escapes@4.3.2:
     dependencies:
       type-fest: 0.21.3
-    dev: true
 
-  /ansi-regex@5.0.1:
-    resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
-    engines: {node: '>=8'}
+  ansi-regex@5.0.1: {}
 
-  /ansi-regex@6.0.1:
-    resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
-    engines: {node: '>=12'}
+  ansi-regex@6.0.1: {}
 
-  /ansi-styles@3.2.1:
-    resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
-    engines: {node: '>=4'}
+  ansi-styles@3.2.1:
     dependencies:
       color-convert: 1.9.3
-    dev: true
 
-  /ansi-styles@4.3.0:
-    resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
-    engines: {node: '>=8'}
+  ansi-styles@4.3.0:
     dependencies:
       color-convert: 2.0.1
 
-  /ansi-styles@5.2.0:
-    resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
-    engines: {node: '>=10'}
-    dev: true
+  ansi-styles@5.2.0: {}
 
-  /ansi-styles@6.2.1:
-    resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
-    engines: {node: '>=12'}
+  ansi-styles@6.2.1: {}
 
-  /any-promise@1.3.0:
-    resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
-    dev: false
+  any-promise@1.3.0: {}
 
-  /anymatch@3.1.3:
-    resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
-    engines: {node: '>= 8'}
+  anymatch@3.1.3:
     dependencies:
       normalize-path: 3.0.0
       picomatch: 2.3.1
 
-  /app-root-dir@1.0.2:
-    resolution: {integrity: sha512-jlpIfsOoNoafl92Sz//64uQHGSyMrD2vYG5d8o2a4qGvyNCvXur7bzIsWtAC/6flI2RYAp3kv8rsfBtaLm7w0g==}
-    dev: true
+  app-root-dir@1.0.2: {}
 
-  /app-root-path@3.1.0:
-    resolution: {integrity: sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==}
-    engines: {node: '>= 6.0.0'}
-    dev: false
+  app-root-path@3.1.0: {}
 
-  /append-field@1.0.0:
-    resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==}
+  append-field@1.0.0: {}
 
-  /aproba@2.0.0:
-    resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==}
-    requiresBuild: true
-    dev: false
+  aproba@2.0.0:
     optional: true
 
-  /arch@2.2.0:
-    resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==}
+  arch@2.2.0: {}
 
-  /archiver-utils@4.0.1:
-    resolution: {integrity: sha512-Q4Q99idbvzmgCTEAAhi32BkOyq8iVI5EwdO0PmBDSGIzzjYNdcFn7Q7k3OzbLy4kLUPXfJtG6fO2RjftXbobBg==}
-    engines: {node: '>= 12.0.0'}
+  archiver-utils@5.0.2:
     dependencies:
-      glob: 8.1.0
+      glob: 10.3.12
       graceful-fs: 4.2.11
+      is-stream: 2.0.1
       lazystream: 1.0.1
       lodash: 4.17.21
       normalize-path: 3.0.0
-      readable-stream: 3.6.0
-    dev: false
+      readable-stream: 4.3.0
 
-  /archiver@6.0.1:
-    resolution: {integrity: sha512-CXGy4poOLBKptiZH//VlWdFuUC1RESbdZjGjILwBuZ73P7WkAUN0htfSfBq/7k6FRFlpu7bg4JOkj1vU9G6jcQ==}
-    engines: {node: '>= 12.0.0'}
+  archiver@7.0.1:
     dependencies:
-      archiver-utils: 4.0.1
+      archiver-utils: 5.0.2
       async: 3.2.4
-      buffer-crc32: 0.2.13
-      readable-stream: 3.6.0
+      buffer-crc32: 1.0.0
+      readable-stream: 4.3.0
       readdir-glob: 1.1.2
       tar-stream: 3.1.6
-      zip-stream: 5.0.1
-    dev: false
+      zip-stream: 6.0.1
 
-  /archy@1.0.0:
-    resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==}
-    dev: false
+  archy@1.0.0: {}
 
-  /are-we-there-yet@2.0.0:
-    resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==}
-    engines: {node: '>=10'}
-    requiresBuild: true
+  are-we-there-yet@2.0.0:
     dependencies:
       delegates: 1.0.0
       readable-stream: 3.6.0
-    dev: false
     optional: true
 
-  /arg@5.0.2:
-    resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
-    dev: true
+  arg@5.0.2: {}
 
-  /argparse@1.0.10:
-    resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
+  argparse@1.0.10:
     dependencies:
       sprintf-js: 1.0.3
 
-  /argparse@2.0.1:
-    resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+  argparse@2.0.1: {}
 
-  /aria-query@5.1.3:
-    resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==}
+  aria-query@5.1.3:
     dependencies:
       deep-equal: 2.2.0
-    dev: true
 
-  /array-buffer-byte-length@1.0.0:
-    resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==}
+  array-buffer-byte-length@1.0.0:
     dependencies:
       call-bind: 1.0.2
       is-array-buffer: 3.0.2
-    dev: true
 
-  /array-flatten@1.1.1:
-    resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
+  array-flatten@1.1.1: {}
 
-  /array-includes@3.1.7:
-    resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==}
-    engines: {node: '>= 0.4'}
+  array-includes@3.1.7:
     dependencies:
       call-bind: 1.0.2
       define-properties: 1.2.0
       es-abstract: 1.22.1
       get-intrinsic: 1.2.1
       is-string: 1.0.7
-    dev: true
 
-  /array-union@2.1.0:
-    resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
-    engines: {node: '>=8'}
+  array-union@2.1.0: {}
 
-  /array.prototype.findlastindex@1.2.3:
-    resolution: {integrity: sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==}
-    engines: {node: '>= 0.4'}
+  array.prototype.findlastindex@1.2.3:
     dependencies:
       call-bind: 1.0.2
       define-properties: 1.2.0
       es-abstract: 1.22.1
       es-shim-unscopables: 1.0.0
       get-intrinsic: 1.2.1
-    dev: true
 
-  /array.prototype.flat@1.3.2:
-    resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==}
-    engines: {node: '>= 0.4'}
+  array.prototype.flat@1.3.2:
     dependencies:
       call-bind: 1.0.2
       define-properties: 1.2.0
       es-abstract: 1.22.1
       es-shim-unscopables: 1.0.0
-    dev: true
 
-  /array.prototype.flatmap@1.3.2:
-    resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==}
-    engines: {node: '>= 0.4'}
+  array.prototype.flatmap@1.3.2:
     dependencies:
       call-bind: 1.0.2
       define-properties: 1.2.0
       es-abstract: 1.22.1
       es-shim-unscopables: 1.0.0
-    dev: true
 
-  /arraybuffer.prototype.slice@1.0.1:
-    resolution: {integrity: sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==}
-    engines: {node: '>= 0.4'}
+  arraybuffer.prototype.slice@1.0.1:
     dependencies:
       array-buffer-byte-length: 1.0.0
       call-bind: 1.0.2
@@ -8877,163 +16313,104 @@ packages:
       get-intrinsic: 1.2.1
       is-array-buffer: 3.0.2
       is-shared-array-buffer: 1.0.2
-    dev: true
 
-  /arrify@1.0.1:
-    resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==}
-    engines: {node: '>=0.10.0'}
-    dev: true
+  arrify@1.0.1: {}
 
-  /asap@2.0.6:
-    resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
+  asap@2.0.6: {}
 
-  /asn1.js@5.4.1:
-    resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==}
+  asn1.js@5.4.1:
     dependencies:
       bn.js: 4.12.0
       inherits: 2.0.4
       minimalistic-assert: 1.0.1
       safer-buffer: 2.1.2
-    dev: false
 
-  /asn1@0.2.6:
-    resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
+  asn1@0.2.6:
     dependencies:
       safer-buffer: 2.1.2
 
-  /asn1js@3.0.5:
-    resolution: {integrity: sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==}
-    engines: {node: '>=12.0.0'}
+  asn1js@3.0.5:
     dependencies:
       pvtsutils: 1.3.5
       pvutils: 1.1.3
       tslib: 2.6.2
-    dev: false
 
-  /assert-never@1.2.1:
-    resolution: {integrity: sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==}
+  assert-never@1.2.1: {}
 
-  /assert-plus@1.0.0:
-    resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==}
-    engines: {node: '>=0.8'}
+  assert-plus@1.0.0: {}
 
-  /assert@2.1.0:
-    resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==}
+  assert@2.1.0:
     dependencies:
       call-bind: 1.0.2
       is-nan: 1.3.2
       object-is: 1.1.5
       object.assign: 4.1.4
       util: 0.12.5
-    dev: true
 
-  /assertion-error@1.1.0:
-    resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
-    dev: true
+  assertion-error@1.1.0: {}
 
-  /ast-types@0.16.1:
-    resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==}
-    engines: {node: '>=4'}
+  ast-types@0.16.1:
     dependencies:
       tslib: 2.6.2
-    dev: true
 
-  /astral-regex@2.0.0:
-    resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
-    engines: {node: '>=8'}
-    dev: true
+  astral-regex@2.0.0: {}
 
-  /astring@1.8.6:
-    resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==}
-    hasBin: true
-    dev: false
+  astring@1.8.6: {}
 
-  /async-mutex@0.4.1:
-    resolution: {integrity: sha512-WfoBo4E/TbCX1G95XTjbWTE3X2XLG0m1Xbv2cwOtuPdyH9CZvnaA5nCt1ucjaKEgW2A5IF71hxrRhr83Je5xjA==}
+  async-mutex@0.5.0:
     dependencies:
       tslib: 2.6.2
-    dev: false
 
-  /async@3.2.4:
-    resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==}
+  async@3.2.4: {}
 
-  /asynckit@0.4.0:
-    resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+  asynckit@0.4.0: {}
 
-  /at-least-node@1.0.0:
-    resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
-    engines: {node: '>= 4.0.0'}
-    dev: true
+  at-least-node@1.0.0: {}
 
-  /atomic-sleep@1.0.0:
-    resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==}
-    engines: {node: '>=8.0.0'}
-    dev: false
+  atomic-sleep@1.0.0: {}
 
-  /available-typed-arrays@1.0.5:
-    resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
-    engines: {node: '>= 0.4'}
-    dev: true
+  available-typed-arrays@1.0.5: {}
 
-  /avvio@8.2.1:
-    resolution: {integrity: sha512-TAlMYvOuwGyLK3PfBb5WKBXZmXz2fVCgv23d6zZFdle/q3gPjmxBaeuC0pY0Dzs5PWMSgfqqEZkrye19GlDTgw==}
+  avvio@8.3.0:
     dependencies:
+      '@fastify/error': 3.4.0
       archy: 1.0.0
       debug: 4.3.4(supports-color@8.1.1)
-      fastq: 1.15.0
+      fastq: 1.17.1
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /aws-sdk-client-mock@3.0.1:
-    resolution: {integrity: sha512-9VAzJLl8mz99KP9HjOm/93d8vznRRUTpJooPBOunRdUAnVYopCe9xmMuu7eVemu8fQ+w6rP7o5bBK1kAFkB2KQ==}
+  aws-sdk-client-mock@3.0.1:
     dependencies:
       '@types/sinon': 10.0.13
       sinon: 16.1.3
       tslib: 2.6.2
-    dev: true
 
-  /aws-sign2@0.7.0:
-    resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==}
+  aws-sign2@0.7.0: {}
 
-  /aws4@1.12.0:
-    resolution: {integrity: sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==}
+  aws4@1.12.0: {}
 
-  /axios@0.24.0:
-    resolution: {integrity: sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==}
+  axios@0.24.0:
     dependencies:
       follow-redirects: 1.15.2(debug@4.3.4)
     transitivePeerDependencies:
       - debug
-    dev: false
 
-  /axios@1.6.2(debug@4.3.4):
-    resolution: {integrity: sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==}
+  axios@1.6.2(debug@4.3.4):
     dependencies:
       follow-redirects: 1.15.2(debug@4.3.4)
       form-data: 4.0.0
       proxy-from-env: 1.1.0
     transitivePeerDependencies:
       - debug
-    dev: true
 
-  /b4a@1.6.4:
-    resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==}
-    dev: false
+  b4a@1.6.4: {}
 
-  /babel-core@7.0.0-bridge.0(@babel/core@7.24.0):
-    resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
+  babel-core@7.0.0-bridge.0(@babel/core@7.24.0):
     dependencies:
       '@babel/core': 7.24.0
-    dev: true
 
-  /babel-jest@29.7.0(@babel/core@7.23.5):
-    resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-    peerDependencies:
-      '@babel/core': ^7.8.0
+  babel-jest@29.7.0(@babel/core@7.23.5):
     dependencies:
       '@babel/core': 7.23.5
       '@jest/transform': 29.7.0
@@ -9045,11 +16422,8 @@ packages:
       slash: 3.0.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /babel-plugin-istanbul@6.1.1:
-    resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==}
-    engines: {node: '>=8'}
+  babel-plugin-istanbul@6.1.1:
     dependencies:
       '@babel/helper-plugin-utils': 7.22.5
       '@istanbuljs/load-nyc-config': 1.1.0
@@ -9058,22 +16432,15 @@ packages:
       test-exclude: 6.0.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /babel-plugin-jest-hoist@29.6.3:
-    resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  babel-plugin-jest-hoist@29.6.3:
     dependencies:
-      '@babel/template': 7.22.15
-      '@babel/types': 7.23.5
+      '@babel/template': 7.24.0
+      '@babel/types': 7.24.0
       '@types/babel__core': 7.20.0
       '@types/babel__traverse': 7.20.0
-    dev: true
 
-  /babel-plugin-polyfill-corejs2@0.4.6(@babel/core@7.24.0):
-    resolution: {integrity: sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==}
-    peerDependencies:
-      '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
+  babel-plugin-polyfill-corejs2@0.4.6(@babel/core@7.24.0):
     dependencies:
       '@babel/compat-data': 7.23.5
       '@babel/core': 7.24.0
@@ -9081,35 +16448,23 @@ packages:
       semver: 6.3.1
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /babel-plugin-polyfill-corejs3@0.8.6(@babel/core@7.24.0):
-    resolution: {integrity: sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==}
-    peerDependencies:
-      '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
+  babel-plugin-polyfill-corejs3@0.8.6(@babel/core@7.24.0):
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.24.0)
       core-js-compat: 3.33.3
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /babel-plugin-polyfill-regenerator@0.5.3(@babel/core@7.24.0):
-    resolution: {integrity: sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==}
-    peerDependencies:
-      '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
+  babel-plugin-polyfill-regenerator@0.5.3(@babel/core@7.24.0):
     dependencies:
       '@babel/core': 7.24.0
       '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.24.0)
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.5):
-    resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==}
-    peerDependencies:
-      '@babel/core': ^7.0.0
+  babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.5):
     dependencies:
       '@babel/core': 7.23.5
       '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.5)
@@ -9124,118 +16479,68 @@ packages:
       '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.5)
       '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.5)
       '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.5)
-    dev: true
 
-  /babel-preset-jest@29.6.3(@babel/core@7.23.5):
-    resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-    peerDependencies:
-      '@babel/core': ^7.0.0
+  babel-preset-jest@29.6.3(@babel/core@7.23.5):
     dependencies:
       '@babel/core': 7.23.5
       babel-plugin-jest-hoist: 29.6.3
       babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.5)
-    dev: true
 
-  /babel-walk@3.0.0-canary-5:
-    resolution: {integrity: sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==}
-    engines: {node: '>= 10.0.0'}
+  babel-walk@3.0.0-canary-5:
     dependencies:
       '@babel/types': 7.23.5
 
-  /bail@2.0.2:
-    resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
-    dev: true
+  bail@2.0.2: {}
 
-  /balanced-match@1.0.2:
-    resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+  balanced-match@1.0.2: {}
 
-  /base64-js@1.5.1:
-    resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+  base64-js@1.5.1: {}
 
-  /bcrypt-pbkdf@1.0.2:
-    resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==}
+  bcrypt-pbkdf@1.0.2:
     dependencies:
       tweetnacl: 0.14.5
 
-  /bcryptjs@2.4.3:
-    resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==}
-    dev: false
+  bcryptjs@2.4.3: {}
 
-  /better-opn@3.0.2:
-    resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==}
-    engines: {node: '>=12.0.0'}
+  better-opn@3.0.2:
     dependencies:
       open: 8.4.2
-    dev: true
 
-  /bidi-js@1.0.3:
-    resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==}
-    dependencies:
-      require-from-string: 2.0.2
-    dev: false
+  big-integer@1.6.51: {}
 
-  /big-integer@1.6.51:
-    resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==}
-    engines: {node: '>=0.6'}
-    dev: true
-
-  /bin-check@4.1.0:
-    resolution: {integrity: sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==}
-    engines: {node: '>=4'}
+  bin-check@4.1.0:
     dependencies:
       execa: 0.7.0
       executable: 4.1.1
-    dev: false
 
-  /bin-version-check@5.0.0:
-    resolution: {integrity: sha512-Q3FMQnS5eZmrBGqmDXLs4dbAn/f+52voP6ykJYmweSA60t6DyH4UTSwZhtbK5UH+LBoWvDljILUQMLRUtsynsA==}
-    engines: {node: '>=12'}
+  bin-version-check@5.0.0:
     dependencies:
       bin-version: 6.0.0
-      semver: 7.5.4
+      semver: 7.6.0
       semver-truncate: 2.0.0
-    dev: false
 
-  /bin-version@6.0.0:
-    resolution: {integrity: sha512-nk5wEsP4RiKjG+vF+uG8lFsEn4d7Y6FVDamzzftSunXOoOcOOkzcWdKVlGgFFwlUQCj63SgnUkLLGF8v7lufhw==}
-    engines: {node: '>=12'}
+  bin-version@6.0.0:
     dependencies:
       execa: 5.1.1
       find-versions: 5.1.0
-    dev: false
 
-  /binary-extensions@2.2.0:
-    resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
-    engines: {node: '>=8'}
+  binary-extensions@2.2.0: {}
 
-  /bl@4.1.0:
-    resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
+  bl@4.1.0:
     dependencies:
       buffer: 5.7.1
       inherits: 2.0.4
       readable-stream: 3.6.0
-    dev: true
 
-  /blob-util@2.0.2:
-    resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==}
-    dev: true
+  blob-util@2.0.2: {}
 
-  /bluebird@3.7.2:
-    resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
-    dev: true
+  bluebird@3.7.2: {}
 
-  /blurhash@2.0.5:
-    resolution: {integrity: sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w==}
-    dev: false
+  blurhash@2.0.5: {}
 
-  /bn.js@4.12.0:
-    resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==}
-    dev: false
+  bn.js@4.12.0: {}
 
-  /body-parser@1.20.1:
-    resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==}
-    engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+  body-parser@1.20.1:
     dependencies:
       bytes: 3.1.2
       content-type: 1.0.5
@@ -9252,9 +16557,7 @@ packages:
     transitivePeerDependencies:
       - supports-color
 
-  /body-parser@1.20.2:
-    resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==}
-    engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+  body-parser@1.20.2:
     dependencies:
       bytes: 3.1.2
       content-type: 1.0.5
@@ -9271,174 +16574,115 @@ packages:
     transitivePeerDependencies:
       - supports-color
 
-  /boolbase@1.0.0:
-    resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
+  boolbase@1.0.0: {}
 
-  /bowser@2.11.0:
-    resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==}
-    dev: false
+  bowser@2.11.0: {}
 
-  /bplist-parser@0.2.0:
-    resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==}
-    engines: {node: '>= 5.10.0'}
+  bplist-parser@0.2.0:
     dependencies:
       big-integer: 1.6.51
-    dev: true
 
-  /brace-expansion@1.1.11:
-    resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+  brace-expansion@1.1.11:
     dependencies:
       balanced-match: 1.0.2
       concat-map: 0.0.1
 
-  /brace-expansion@2.0.1:
-    resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+  brace-expansion@2.0.1:
     dependencies:
       balanced-match: 1.0.2
 
-  /braces@3.0.2:
-    resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
-    engines: {node: '>=8'}
+  braces@3.0.2:
     dependencies:
       fill-range: 7.0.1
 
-  /broadcast-channel@7.0.0:
-    resolution: {integrity: sha512-a2tW0Ia1pajcPBOGUF2jXlDnvE9d5/dg6BG9h60OmRUcZVr/veUrU8vEQFwwQIhwG3KVzYwSk3v2nRRGFgQDXQ==}
+  broadcast-channel@7.0.0:
     dependencies:
       '@babel/runtime': 7.23.4
       oblivious-set: 1.4.0
       p-queue: 6.6.2
       unload: 2.4.1
-    dev: false
 
-  /browser-assert@1.2.1:
-    resolution: {integrity: sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==}
-    dev: true
+  browser-assert@1.2.1: {}
 
-  /browserify-zlib@0.1.4:
-    resolution: {integrity: sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ==}
+  browserify-zlib@0.1.4:
     dependencies:
       pako: 0.2.9
-    dev: true
 
-  /browserslist@4.22.2:
-    resolution: {integrity: sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==}
-    engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
-    hasBin: true
+  browserslist@4.22.2:
     dependencies:
       caniuse-lite: 1.0.30001566
       electron-to-chromium: 1.4.601
       node-releases: 2.0.14
       update-browserslist-db: 1.0.13(browserslist@4.22.2)
-    dev: true
 
-  /browserslist@4.23.0:
-    resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==}
-    engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
-    hasBin: true
+  browserslist@4.23.0:
     dependencies:
       caniuse-lite: 1.0.30001591
       electron-to-chromium: 1.4.686
       node-releases: 2.0.14
       update-browserslist-db: 1.0.13(browserslist@4.23.0)
 
-  /bser@2.1.1:
-    resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
+  bser@2.1.1:
     dependencies:
       node-int64: 0.4.0
-    dev: true
 
-  /buffer-crc32@0.2.13:
-    resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
+  buffer-crc32@0.2.13: {}
 
-  /buffer-equal-constant-time@1.0.1:
-    resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
-    dev: false
+  buffer-crc32@1.0.0: {}
 
-  /buffer-from@1.1.2:
-    resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
+  buffer-equal-constant-time@1.0.1: {}
 
-  /buffer-writer@2.0.0:
-    resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==}
-    engines: {node: '>=4'}
-    dev: false
+  buffer-from@1.1.2: {}
 
-  /buffer@5.6.0:
-    resolution: {integrity: sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==}
+  buffer@5.6.0:
     dependencies:
       base64-js: 1.5.1
       ieee754: 1.2.1
-    dev: false
 
-  /buffer@5.7.1:
-    resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
+  buffer@5.7.1:
     dependencies:
       base64-js: 1.5.1
       ieee754: 1.2.1
-    dev: true
 
-  /buffer@6.0.3:
-    resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
+  buffer@6.0.3:
     dependencies:
       base64-js: 1.5.1
       ieee754: 1.2.1
-    dev: false
 
-  /bufferutil@4.0.7:
-    resolution: {integrity: sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==}
-    engines: {node: '>=6.14.2'}
-    requiresBuild: true
+  bufferutil@4.0.7:
     dependencies:
       node-gyp-build: 4.6.0
+    optional: true
 
-  /bullmq@5.4.0:
-    resolution: {integrity: sha512-QNOT+Vp/OFctwKa1/LYvrfIMXqb6Hu8a1VwXxQpa/JXoFAQ9E4ZcqW4fyEjx9iYrXakpV6cAGPbmdgWaKTGXOQ==}
+  bullmq@5.7.8:
     dependencies:
       cron-parser: 4.8.1
-      fast-glob: 3.3.2
-      ioredis: 5.3.2
-      lodash: 4.17.21
-      minimatch: 9.0.3
+      ioredis: 5.4.1
       msgpackr: 1.10.1
       node-abort-controller: 3.1.1
-      semver: 7.5.4
+      semver: 7.6.0
       tslib: 2.6.2
       uuid: 9.0.1
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /buraha@0.0.1:
-    resolution: {integrity: sha512-G563A0mTbzknm2jDaNxfZuNKIdeArs8T+XQN6t+KbmgnOoevXSXhKDkyf8Md/36Jrx99ikwbCag37VGe3myExQ==}
-    dev: false
+  buraha@0.0.1: {}
 
-  /busboy@1.6.0:
-    resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
-    engines: {node: '>=10.16.0'}
+  busboy@1.6.0:
     dependencies:
       streamsearch: 1.1.0
 
-  /bytes@3.0.0:
-    resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==}
-    engines: {node: '>= 0.8'}
-    dev: true
+  bytes@3.0.0: {}
 
-  /bytes@3.1.2:
-    resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
-    engines: {node: '>= 0.8'}
+  bytes@3.1.2: {}
 
-  /cac@6.7.14:
-    resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
-    engines: {node: '>=8'}
-    dev: true
+  cac@6.7.14: {}
 
-  /cacache@18.0.0:
-    resolution: {integrity: sha512-I7mVOPl3PUCeRub1U8YoGz2Lqv9WOBpobZ8RyWFXmReuILz+3OAyTa5oH3QPdtKZD7N0Yk00aLfzn0qvp8dZ1w==}
-    engines: {node: ^16.14.0 || >=18.0.0}
+  cacache@18.0.0:
     dependencies:
       '@npmcli/fs': 3.1.0
       fs-minipass: 3.0.2
-      glob: 10.3.10
+      glob: 10.3.12
       lru-cache: 10.0.2
       minipass: 7.0.4
       minipass-collect: 1.0.2
@@ -9446,22 +16690,14 @@ packages:
       minipass-pipeline: 1.2.4
       p-map: 4.0.0
       ssri: 10.0.4
-      tar: 6.2.0
+      tar: 6.2.1
       unique-filename: 3.0.0
-    dev: false
 
-  /cacheable-lookup@5.0.4:
-    resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==}
-    engines: {node: '>=10.6.0'}
-    dev: false
+  cacheable-lookup@5.0.4: {}
 
-  /cacheable-lookup@7.0.0:
-    resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==}
-    engines: {node: '>=14.16'}
+  cacheable-lookup@7.0.0: {}
 
-  /cacheable-request@10.2.14:
-    resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==}
-    engines: {node: '>=14.16'}
+  cacheable-request@10.2.14:
     dependencies:
       '@types/http-cache-semantics': 4.0.4
       get-stream: 6.0.1
@@ -9471,9 +16707,7 @@ packages:
       normalize-url: 8.0.0
       responselike: 3.0.0
 
-  /cacheable-request@7.0.2:
-    resolution: {integrity: sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==}
-    engines: {node: '>=8'}
+  cacheable-request@7.0.2:
     dependencies:
       clone-response: 1.0.3
       get-stream: 5.2.0
@@ -9482,86 +16716,52 @@ packages:
       lowercase-keys: 2.0.0
       normalize-url: 6.1.0
       responselike: 2.0.1
-    dev: false
 
-  /cachedir@2.3.0:
-    resolution: {integrity: sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==}
-    engines: {node: '>=6'}
-    dev: true
+  cachedir@2.3.0: {}
 
-  /call-bind@1.0.2:
-    resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
+  call-bind@1.0.2:
     dependencies:
       function-bind: 1.1.2
       get-intrinsic: 1.2.1
 
-  /call-me-maybe@1.0.2:
-    resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==}
-    dev: true
+  call-me-maybe@1.0.2: {}
 
-  /callsites@3.1.0:
-    resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
-    engines: {node: '>=6'}
-    dev: true
+  callsites@3.1.0: {}
 
-  /camelcase-keys@6.2.2:
-    resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==}
-    engines: {node: '>=8'}
+  camelcase-keys@6.2.2:
     dependencies:
       camelcase: 5.3.1
       map-obj: 4.3.0
       quick-lru: 4.0.1
-    dev: true
 
-  /camelcase@5.3.1:
-    resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
-    engines: {node: '>=6'}
+  camelcase@5.3.1: {}
 
-  /camelcase@6.3.0:
-    resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
-    engines: {node: '>=10'}
-    dev: true
+  camelcase@6.3.0: {}
 
-  /caniuse-api@3.0.0:
-    resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==}
+  caniuse-api@3.0.0:
     dependencies:
       browserslist: 4.23.0
-      caniuse-lite: 1.0.30001566
+      caniuse-lite: 1.0.30001591
       lodash.memoize: 4.1.2
       lodash.uniq: 4.5.0
-    dev: false
 
-  /caniuse-lite@1.0.30001566:
-    resolution: {integrity: sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==}
+  caniuse-lite@1.0.30001566: {}
 
-  /caniuse-lite@1.0.30001591:
-    resolution: {integrity: sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==}
+  caniuse-lite@1.0.30001591: {}
 
-  /canonicalize@1.0.8:
-    resolution: {integrity: sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==}
-    dev: false
+  canonicalize@1.0.8: {}
 
-  /canvas-confetti@1.9.2:
-    resolution: {integrity: sha512-6Xi7aHHzKwxZsem4mCKoqP6YwUG3HamaHHAlz1hTNQPCqXhARFpSXnkC9TWlahHY5CG6hSL5XexNjxK8irVErg==}
-    dev: false
+  canvas-confetti@1.9.3: {}
 
-  /caseless@0.12.0:
-    resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
+  caseless@0.12.0: {}
 
-  /cbor@9.0.2:
-    resolution: {integrity: sha512-JPypkxsB10s9QOWwa6zwPzqE1Md3vqpPc+cai4sAecuCsRyAtAl/pMyhPlMbT/xtPnm2dznJZYRLui57qiRhaQ==}
-    engines: {node: '>=16'}
+  cbor@9.0.2:
     dependencies:
       nofilter: 3.1.0
-    dev: false
 
-  /ccount@2.0.1:
-    resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
-    dev: true
+  ccount@2.0.1: {}
 
-  /chai@4.3.10:
-    resolution: {integrity: sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==}
-    engines: {node: '>=4'}
+  chai@4.3.10:
     dependencies:
       assertion-error: 1.1.0
       check-error: 1.0.3
@@ -9570,116 +16770,66 @@ packages:
       loupe: 2.3.7
       pathval: 1.1.1
       type-detect: 4.0.8
-    dev: true
 
-  /chalk-template@1.1.0:
-    resolution: {integrity: sha512-T2VJbcDuZQ0Tb2EWwSotMPJjgpy1/tGee1BTpUNsGZ/qgNjV2t7Mvu+d4600U564nbLesN1x2dPL+xii174Ekg==}
-    engines: {node: '>=14.16'}
+  chalk-template@1.1.0:
     dependencies:
       chalk: 5.3.0
-    dev: false
 
-  /chalk@2.4.2:
-    resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
-    engines: {node: '>=4'}
+  chalk@2.4.2:
     dependencies:
       ansi-styles: 3.2.1
       escape-string-regexp: 1.0.5
       supports-color: 5.5.0
-    dev: true
 
-  /chalk@3.0.0:
-    resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==}
-    engines: {node: '>=8'}
-    dependencies:
-      ansi-styles: 4.3.0
-      supports-color: 7.2.0
-    dev: true
-
-  /chalk@4.1.2:
-    resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
-    engines: {node: '>=10'}
+  chalk@3.0.0:
     dependencies:
       ansi-styles: 4.3.0
       supports-color: 7.2.0
 
-  /chalk@5.3.0:
-    resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
-    engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
-    dev: false
+  chalk@4.1.2:
+    dependencies:
+      ansi-styles: 4.3.0
+      supports-color: 7.2.0
 
-  /char-regex@1.0.2:
-    resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
-    engines: {node: '>=10'}
+  chalk@5.3.0: {}
 
-  /character-entities@2.0.2:
-    resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==}
-    dev: true
+  char-regex@1.0.2: {}
 
-  /character-parser@2.2.0:
-    resolution: {integrity: sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==}
+  character-entities@2.0.2: {}
+
+  character-parser@2.2.0:
     dependencies:
       is-regex: 1.1.4
 
-  /chardet@0.7.0:
-    resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
-    dev: true
-
-  /chart.js@4.4.2:
-    resolution: {integrity: sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==}
-    engines: {pnpm: '>=8'}
+  chart.js@4.4.2:
     dependencies:
       '@kurkle/color': 0.3.2
-    dev: false
 
-  /chartjs-adapter-date-fns@3.0.0(chart.js@4.4.2)(date-fns@2.30.0):
-    resolution: {integrity: sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==}
-    peerDependencies:
-      chart.js: '>=2.8.0'
-      date-fns: '>=2.0.0'
+  chartjs-adapter-date-fns@3.0.0(chart.js@4.4.2)(date-fns@2.30.0):
     dependencies:
       chart.js: 4.4.2
       date-fns: 2.30.0
-    dev: false
 
-  /chartjs-chart-matrix@2.0.1(chart.js@4.4.2):
-    resolution: {integrity: sha512-BGfeY+/PHnITyDlc7WfnKJ1RyOfgOzIqWp/gxzzl7pUjyoGzHDcw51qd2xJF9gdT9Def7ZwOnOMm8GJUXDxI0w==}
-    peerDependencies:
-      chart.js: '>=3.0.0'
+  chartjs-chart-matrix@2.0.1(chart.js@4.4.2):
     dependencies:
       chart.js: 4.4.2
-    dev: false
 
-  /chartjs-plugin-gradient@0.6.1(chart.js@4.4.2):
-    resolution: {integrity: sha512-TGHNIh8KqQMLdb+UfY80cBHYRyOC47eeokmgkeajRdKGbFt462lJiyiq4ZJ25fiM7BGsmzoBLhmVyEw4B3gQxw==}
-    peerDependencies:
-      chart.js: '>=2.6.0'
+  chartjs-plugin-gradient@0.6.1(chart.js@4.4.2):
     dependencies:
       chart.js: 4.4.2
-    dev: false
 
-  /chartjs-plugin-zoom@2.0.1(chart.js@4.4.2):
-    resolution: {integrity: sha512-ogOmLu6e+Q7E1XWOCOz9YwybMslz9qNfGV2a+qjfmqJYpsw5ZMoRHZBUyW+NGhkpQ5PwwPA/+rikHpBZb7PZuA==}
-    peerDependencies:
-      chart.js: '>=3.2.0'
+  chartjs-plugin-zoom@2.0.1(chart.js@4.4.2):
     dependencies:
       chart.js: 4.4.2
       hammerjs: 2.0.8
-    dev: false
 
-  /check-error@1.0.3:
-    resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==}
+  check-error@1.0.3:
     dependencies:
       get-func-name: 2.0.2
-    dev: true
 
-  /check-more-types@2.24.0:
-    resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==}
-    engines: {node: '>= 0.8.0'}
-    dev: true
+  check-more-types@2.24.0: {}
 
-  /cheerio-select@2.1.0:
-    resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==}
+  cheerio-select@2.1.0:
     dependencies:
       boolbase: 1.0.0
       css-select: 5.1.0
@@ -9688,9 +16838,7 @@ packages:
       domhandler: 5.0.3
       domutils: 3.0.1
 
-  /cheerio@1.0.0-rc.12:
-    resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==}
-    engines: {node: '>= 6'}
+  cheerio@1.0.0-rc.12:
     dependencies:
       cheerio-select: 2.1.0
       dom-serializer: 2.0.0
@@ -9700,9 +16848,7 @@ packages:
       parse5: 7.1.2
       parse5-htmlparser2-tree-adapter: 7.0.0
 
-  /chokidar@3.5.3:
-    resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
-    engines: {node: '>= 8.10.0'}
+  chokidar@3.5.3:
     dependencies:
       anymatch: 3.1.3
       braces: 3.0.2
@@ -9714,58 +16860,27 @@ packages:
     optionalDependencies:
       fsevents: 2.3.3
 
-  /chownr@1.1.4:
-    resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
+  chownr@1.1.4: {}
 
-  /chownr@2.0.0:
-    resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
-    engines: {node: '>=10'}
-    requiresBuild: true
+  chownr@2.0.0: {}
 
-  /chromatic@11.0.0:
-    resolution: {integrity: sha512-utzRVqdMrpzYwZNf7dHWU0z0/rx6SH/FUVNozQxYHDtQfYUdEj+Ro4OSch5+Wsk2FoUmznJyLkaC2J839z1N7A==}
-    hasBin: true
-    peerDependencies:
-      '@chromatic-com/cypress': ^0.5.2 || ^1.0.0
-      '@chromatic-com/playwright': ^0.5.2 || ^1.0.0
-    peerDependenciesMeta:
-      '@chromatic-com/cypress':
-        optional: true
-      '@chromatic-com/playwright':
-        optional: true
-    dev: false
+  chromatic@11.3.0: {}
 
-  /ci-info@3.7.1:
-    resolution: {integrity: sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==}
-    engines: {node: '>=8'}
-    dev: true
+  ci-info@3.7.1: {}
 
-  /cjs-module-lexer@1.2.2:
-    resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==}
-    dev: true
+  cjs-module-lexer@1.2.2: {}
 
-  /clean-stack@2.2.0:
-    resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
-    engines: {node: '>=6'}
+  clean-stack@2.2.0: {}
 
-  /clean-stack@5.2.0:
-    resolution: {integrity: sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==}
-    engines: {node: '>=14.16'}
+  clean-stack@5.2.0:
     dependencies:
       escape-string-regexp: 5.0.0
-    dev: true
 
-  /cli-cursor@3.1.0:
-    resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
-    engines: {node: '>=8'}
+  cli-cursor@3.1.0:
     dependencies:
       restore-cursor: 3.1.0
-    dev: true
 
-  /cli-highlight@2.1.11:
-    resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==}
-    engines: {node: '>=8.0.0', npm: '>=5.0.0'}
-    hasBin: true
+  cli-highlight@2.1.11:
     dependencies:
       chalk: 4.1.2
       highlight.js: 10.7.3
@@ -9773,213 +16888,126 @@ packages:
       parse5: 5.1.1
       parse5-htmlparser2-tree-adapter: 6.0.1
       yargs: 16.2.0
-    dev: false
 
-  /cli-spinners@2.7.0:
-    resolution: {integrity: sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==}
-    engines: {node: '>=6'}
-    dev: true
+  cli-spinners@2.7.0: {}
 
-  /cli-table3@0.6.3:
-    resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==}
-    engines: {node: 10.* || >= 12.*}
+  cli-spinners@2.9.2: {}
+
+  cli-table3@0.6.3:
     dependencies:
       string-width: 4.2.3
     optionalDependencies:
       '@colors/colors': 1.5.0
-    dev: true
 
-  /cli-truncate@2.1.0:
-    resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==}
-    engines: {node: '>=8'}
+  cli-truncate@2.1.0:
     dependencies:
       slice-ansi: 3.0.0
       string-width: 4.2.3
-    dev: true
 
-  /cli-width@3.0.0:
-    resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==}
-    engines: {node: '>= 10'}
-    dev: true
+  cli-width@4.1.0: {}
 
-  /cliui@6.0.0:
-    resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
+  cliui@6.0.0:
     dependencies:
       string-width: 4.2.3
       strip-ansi: 6.0.1
       wrap-ansi: 6.2.0
-    dev: false
 
-  /cliui@7.0.4:
-    resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==}
-    dependencies:
-      string-width: 4.2.3
-      strip-ansi: 6.0.1
-      wrap-ansi: 7.0.0
-    dev: false
-
-  /cliui@8.0.1:
-    resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
-    engines: {node: '>=12'}
+  cliui@7.0.4:
     dependencies:
       string-width: 4.2.3
       strip-ansi: 6.0.1
       wrap-ansi: 7.0.0
 
-  /clone-deep@4.0.1:
-    resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==}
-    engines: {node: '>=6'}
+  cliui@8.0.1:
+    dependencies:
+      string-width: 4.2.3
+      strip-ansi: 6.0.1
+      wrap-ansi: 7.0.0
+
+  clone-deep@4.0.1:
     dependencies:
       is-plain-object: 2.0.4
       kind-of: 6.0.3
       shallow-clone: 3.0.1
-    dev: true
 
-  /clone-response@1.0.3:
-    resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==}
+  clone-response@1.0.3:
     dependencies:
       mimic-response: 1.0.1
-    dev: false
 
-  /clone@1.0.4:
-    resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
-    engines: {node: '>=0.8'}
-    dev: true
+  clone@1.0.4: {}
 
-  /cluster-key-slot@1.1.2:
-    resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
-    engines: {node: '>=0.10.0'}
-    dev: false
+  cluster-key-slot@1.1.2: {}
 
-  /co@4.6.0:
-    resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
-    engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
-    dev: true
+  co@4.6.0: {}
 
-  /code-error-fragment@0.0.230:
-    resolution: {integrity: sha512-cadkfKp6932H8UkhzE/gcUqhRMNf8jHzkAN7+5Myabswaghu4xABTgPHDCjW+dBAJxj/SpkTYokpzDqY4pCzQw==}
-    engines: {node: '>= 4'}
-    dev: true
+  code-error-fragment@0.0.230: {}
 
-  /collect-v8-coverage@1.0.1:
-    resolution: {integrity: sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==}
-    dev: true
+  collect-v8-coverage@1.0.1: {}
 
-  /color-convert@1.9.3:
-    resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
+  color-convert@1.9.3:
     dependencies:
       color-name: 1.1.3
-    dev: true
 
-  /color-convert@2.0.1:
-    resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
-    engines: {node: '>=7.0.0'}
+  color-convert@2.0.1:
     dependencies:
       color-name: 1.1.4
 
-  /color-name@1.1.3:
-    resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
-    dev: true
+  color-name@1.1.3: {}
 
-  /color-name@1.1.4:
-    resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+  color-name@1.1.4: {}
 
-  /color-string@1.9.1:
-    resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
+  color-string@1.9.1:
     dependencies:
       color-name: 1.1.4
       simple-swizzle: 0.2.2
-    dev: false
 
-  /color-support@1.1.3:
-    resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
-    hasBin: true
-    requiresBuild: true
-    dev: false
+  color-support@1.1.3:
     optional: true
 
-  /color@4.2.3:
-    resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
-    engines: {node: '>=12.5.0'}
+  color@4.2.3:
     dependencies:
       color-convert: 2.0.1
       color-string: 1.9.1
-    dev: false
 
-  /colord@2.9.3:
-    resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
-    dev: false
+  colord@2.9.3: {}
 
-  /colorette@2.0.19:
-    resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==}
-    dev: true
+  colorette@2.0.19: {}
 
-  /colors@1.2.5:
-    resolution: {integrity: sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==}
-    engines: {node: '>=0.1.90'}
-    dev: true
-
-  /combined-stream@1.0.8:
-    resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
-    engines: {node: '>= 0.8'}
+  combined-stream@1.0.8:
     dependencies:
       delayed-stream: 1.0.0
 
-  /commander@10.0.1:
-    resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
-    engines: {node: '>=14'}
-    dev: true
+  commander@10.0.1: {}
 
-  /commander@2.20.3:
-    resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
+  commander@2.20.3: {}
 
-  /commander@6.2.1:
-    resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==}
-    engines: {node: '>= 6'}
-    dev: true
+  commander@6.2.1: {}
 
-  /commander@7.2.0:
-    resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
-    engines: {node: '>= 10'}
-    dev: false
+  commander@7.2.0: {}
 
-  /commander@9.5.0:
-    resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
-    engines: {node: ^12.20.0 || >=14}
+  commander@8.3.0: {}
 
-  /common-tags@1.8.2:
-    resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==}
-    engines: {node: '>=4.0.0'}
-    dev: true
+  commander@9.5.0: {}
 
-  /commondir@1.0.1:
-    resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
-    dev: true
+  common-tags@1.8.2: {}
 
-  /compare-versions@6.1.0:
-    resolution: {integrity: sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==}
-    dev: false
+  commondir@1.0.1: {}
 
-  /compress-commons@5.0.1:
-    resolution: {integrity: sha512-MPh//1cERdLtqwO3pOFLeXtpuai0Y2WCd5AhtKxznqM7WtaMYaOEMSgn45d9D10sIHSfIKE603HlOp8OPGrvag==}
-    engines: {node: '>= 12.0.0'}
+  compare-versions@6.1.0: {}
+
+  compress-commons@6.0.2:
     dependencies:
       crc-32: 1.2.2
-      crc32-stream: 5.0.0
+      crc32-stream: 6.0.0
+      is-stream: 2.0.1
       normalize-path: 3.0.0
-      readable-stream: 3.6.0
-    dev: false
+      readable-stream: 4.3.0
 
-  /compressible@2.0.18:
-    resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==}
-    engines: {node: '>= 0.6'}
+  compressible@2.0.18:
     dependencies:
       mime-db: 1.52.0
-    dev: true
 
-  /compression@1.7.4:
-    resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==}
-    engines: {node: '>= 0.8.0'}
+  compression@1.7.4:
     dependencies:
       accepts: 1.3.8
       bytes: 3.0.0
@@ -9990,120 +17018,78 @@ packages:
       vary: 1.1.2
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /computeds@0.0.1:
-    resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==}
-    dev: true
+  computeds@0.0.1: {}
 
-  /concat-map@0.0.1:
-    resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+  concat-map@0.0.1: {}
 
-  /concat-stream@1.6.2:
-    resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==}
-    engines: {'0': node >= 0.8}
+  concat-stream@1.6.2:
     dependencies:
       buffer-from: 1.1.2
       inherits: 2.0.4
       readable-stream: 2.3.7
       typedarray: 0.0.6
 
-  /config-chain@1.1.13:
-    resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
+  config-chain@1.1.13:
     dependencies:
       ini: 1.3.8
       proto-list: 1.2.4
-    dev: true
 
-  /consola@2.15.3:
-    resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==}
+  consola@2.15.3: {}
 
-  /console-control-strings@1.1.0:
-    resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==}
-    requiresBuild: true
-    dev: false
+  console-control-strings@1.1.0:
     optional: true
 
-  /constantinople@4.0.1:
-    resolution: {integrity: sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==}
+  constantinople@4.0.1:
     dependencies:
       '@babel/parser': 7.23.9
       '@babel/types': 7.23.5
 
-  /content-disposition@0.5.4:
-    resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
-    engines: {node: '>= 0.6'}
+  content-disposition@0.5.4:
     dependencies:
       safe-buffer: 5.2.1
 
-  /content-type@1.0.5:
-    resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
-    engines: {node: '>= 0.6'}
+  content-type@1.0.5: {}
 
-  /convert-source-map@2.0.0:
-    resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
-    dev: true
+  convert-source-map@2.0.0: {}
 
-  /cookie-signature@1.0.6:
-    resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
+  cookie-signature@1.0.6: {}
 
-  /cookie-signature@1.2.1:
-    resolution: {integrity: sha512-78KWk9T26NhzXtuL26cIJ8/qNHANyJ/ZYrmEXFzUmhZdjpBv+DlWlOANRTGBt48YcyslsLrj0bMLFTmXvLRCOw==}
-    engines: {node: '>=6.6.0'}
-    dev: false
+  cookie-signature@1.2.1: {}
 
-  /cookie@0.5.0:
-    resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
-    engines: {node: '>= 0.6'}
+  cookie@0.5.0: {}
 
-  /core-js-compat@3.33.3:
-    resolution: {integrity: sha512-cNzGqFsh3Ot+529GIXacjTJ7kegdt5fPXxCBVS1G0iaZpuo/tBz399ymceLJveQhFFZ8qThHiP3fzuoQjKN2ow==}
+  cookie@0.6.0: {}
+
+  core-js-compat@3.33.3:
     dependencies:
       browserslist: 4.23.0
-    dev: true
 
-  /core-js@3.29.1:
-    resolution: {integrity: sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw==}
-    requiresBuild: true
-    dev: false
+  core-js@3.29.1: {}
 
-  /core-util-is@1.0.2:
-    resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
+  core-util-is@1.0.2: {}
 
-  /core-util-is@1.0.3:
-    resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
+  core-util-is@1.0.3: {}
 
-  /cors@2.8.5:
-    resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
-    engines: {node: '>= 0.10'}
+  cors@2.8.5:
     dependencies:
       object-assign: 4.1.1
       vary: 1.1.2
 
-  /crc-32@1.2.2:
-    resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==}
-    engines: {node: '>=0.8'}
-    hasBin: true
-    dev: false
+  crc-32@1.2.2: {}
 
-  /crc32-stream@5.0.0:
-    resolution: {integrity: sha512-B0EPa1UK+qnpBZpG+7FgPCu0J2ETLpXq09o9BkLkEAhdB6Z61Qo4pJ3JYu0c+Qi+/SAL7QThqnzS06pmSSyZaw==}
-    engines: {node: '>= 12.0.0'}
+  crc32-stream@6.0.0:
     dependencies:
       crc-32: 1.2.2
-      readable-stream: 3.6.0
-    dev: false
+      readable-stream: 4.3.0
 
-  /create-jest@29.7.0(@types/node@20.11.22):
-    resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-    hasBin: true
+  create-jest@29.7.0(@types/node@20.12.7):
     dependencies:
       '@jest/types': 29.6.3
       chalk: 4.1.2
       exit: 0.1.2
       graceful-fs: 4.2.11
-      jest-config: 29.7.0(@types/node@20.11.22)
+      jest-config: 29.7.0(@types/node@20.12.7)
       jest-util: 29.7.0
       prompts: 2.4.2
     transitivePeerDependencies:
@@ -10111,77 +17097,51 @@ packages:
       - babel-plugin-macros
       - supports-color
       - ts-node
-    dev: true
 
-  /cron-parser@4.8.1:
-    resolution: {integrity: sha512-jbokKWGcyU4gl6jAfX97E1gDpY12DJ1cLJZmoDzaAln/shZ+S3KBFBuA2Q6WeUN4gJf/8klnV1EfvhA2lK5IRQ==}
-    engines: {node: '>=12.0.0'}
+  cron-parser@4.8.1:
     dependencies:
       luxon: 3.3.0
-    dev: false
 
-  /cropperjs@2.0.0-beta.4:
-    resolution: {integrity: sha512-tWIQnvbou6eJvQkajwhGLOOEw03dM/i23FmnUQtMKjuzbTDSMP61kcwM77Uit8MXEWcUb5PH8n4jawyrFvj5ag==}
+  cropperjs@2.0.0-beta.5:
     dependencies:
-      '@cropper/elements': 2.0.0-beta.4
-      '@cropper/utils': 2.0.0-beta.4
-    dev: false
+      '@cropper/elements': 2.0.0-beta.5
+      '@cropper/utils': 2.0.0-beta.5
 
-  /cross-env@7.0.3:
-    resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==}
-    engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'}
-    hasBin: true
+  cross-env@7.0.3:
     dependencies:
       cross-spawn: 7.0.3
-    dev: true
 
-  /cross-fetch@3.1.6:
-    resolution: {integrity: sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==}
+  cross-fetch@3.1.6(encoding@0.1.13):
     dependencies:
-      node-fetch: 2.7.0
+      node-fetch: 2.7.0(encoding@0.1.13)
     transitivePeerDependencies:
       - encoding
 
-  /cross-fetch@4.0.0:
-    resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==}
+  cross-fetch@4.0.0(encoding@0.1.13):
     dependencies:
-      node-fetch: 2.7.0
+      node-fetch: 2.7.0(encoding@0.1.13)
     transitivePeerDependencies:
       - encoding
-    dev: false
 
-  /cross-spawn@5.1.0:
-    resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}
+  cross-spawn@5.1.0:
     dependencies:
       lru-cache: 4.1.5
       shebang-command: 1.2.0
       which: 1.3.1
-    dev: false
 
-  /cross-spawn@7.0.3:
-    resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
-    engines: {node: '>= 8'}
+  cross-spawn@7.0.3:
     dependencies:
       path-key: 3.1.1
       shebang-command: 2.0.0
       which: 2.0.2
 
-  /crypto-random-string@2.0.0:
-    resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==}
-    engines: {node: '>=8'}
-    dev: true
+  crypto-random-string@2.0.0: {}
 
-  /css-declaration-sorter@7.1.1(postcss@8.4.35):
-    resolution: {integrity: sha512-dZ3bVTEEc1vxr3Bek9vGwfB5Z6ESPULhcRvO472mfjVnj8jRcTnKO8/JTczlvxM10Myb+wBM++1MtdO76eWcaQ==}
-    engines: {node: ^14 || ^16 || >=18}
-    peerDependencies:
-      postcss: ^8.0.9
+  css-declaration-sorter@7.2.0(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
-    dev: false
+      postcss: 8.4.38
 
-  /css-select@5.1.0:
-    resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
+  css-select@5.1.0:
     dependencies:
       boolbase: 1.0.0
       css-what: 6.1.0
@@ -10189,120 +17149,81 @@ packages:
       domutils: 3.0.1
       nth-check: 2.1.1
 
-  /css-tree@2.2.1:
-    resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==}
-    engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
+  css-tree@2.2.1:
     dependencies:
       mdn-data: 2.0.28
       source-map-js: 1.0.2
-    dev: false
 
-  /css-tree@2.3.1:
-    resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
-    engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
+  css-tree@2.3.1:
     dependencies:
       mdn-data: 2.0.30
       source-map-js: 1.0.2
-    dev: false
 
-  /css-what@6.1.0:
-    resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
-    engines: {node: '>= 6'}
+  css-what@6.1.0: {}
 
-  /css.escape@1.5.1:
-    resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
+  css.escape@1.5.1: {}
 
-  /cssesc@3.0.0:
-    resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
-    engines: {node: '>=4'}
-    hasBin: true
+  cssesc@3.0.0: {}
 
-  /cssnano-preset-default@6.0.5(postcss@8.4.35):
-    resolution: {integrity: sha512-M+qRDEr5QZrfNl0B2ySdbTLGyNb8kBcSjuwR7WBamYBOEREH9t2efnB/nblekqhdGLZdkf4oZNetykG2JWRdZQ==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  cssnano-preset-default@6.1.2(postcss@8.4.38):
     dependencies:
-      css-declaration-sorter: 7.1.1(postcss@8.4.35)
-      cssnano-utils: 4.0.1(postcss@8.4.35)
-      postcss: 8.4.35
-      postcss-calc: 9.0.1(postcss@8.4.35)
-      postcss-colormin: 6.0.3(postcss@8.4.35)
-      postcss-convert-values: 6.0.4(postcss@8.4.35)
-      postcss-discard-comments: 6.0.1(postcss@8.4.35)
-      postcss-discard-duplicates: 6.0.2(postcss@8.4.35)
-      postcss-discard-empty: 6.0.2(postcss@8.4.35)
-      postcss-discard-overridden: 6.0.1(postcss@8.4.35)
-      postcss-merge-longhand: 6.0.3(postcss@8.4.35)
-      postcss-merge-rules: 6.0.4(postcss@8.4.35)
-      postcss-minify-font-values: 6.0.2(postcss@8.4.35)
-      postcss-minify-gradients: 6.0.2(postcss@8.4.35)
-      postcss-minify-params: 6.0.3(postcss@8.4.35)
-      postcss-minify-selectors: 6.0.2(postcss@8.4.35)
-      postcss-normalize-charset: 6.0.1(postcss@8.4.35)
-      postcss-normalize-display-values: 6.0.1(postcss@8.4.35)
-      postcss-normalize-positions: 6.0.1(postcss@8.4.35)
-      postcss-normalize-repeat-style: 6.0.1(postcss@8.4.35)
-      postcss-normalize-string: 6.0.1(postcss@8.4.35)
-      postcss-normalize-timing-functions: 6.0.1(postcss@8.4.35)
-      postcss-normalize-unicode: 6.0.3(postcss@8.4.35)
-      postcss-normalize-url: 6.0.1(postcss@8.4.35)
-      postcss-normalize-whitespace: 6.0.1(postcss@8.4.35)
-      postcss-ordered-values: 6.0.1(postcss@8.4.35)
-      postcss-reduce-initial: 6.0.3(postcss@8.4.35)
-      postcss-reduce-transforms: 6.0.1(postcss@8.4.35)
-      postcss-svgo: 6.0.2(postcss@8.4.35)
-      postcss-unique-selectors: 6.0.2(postcss@8.4.35)
-    dev: false
+      browserslist: 4.23.0
+      css-declaration-sorter: 7.2.0(postcss@8.4.38)
+      cssnano-utils: 4.0.2(postcss@8.4.38)
+      postcss: 8.4.38
+      postcss-calc: 9.0.1(postcss@8.4.38)
+      postcss-colormin: 6.1.0(postcss@8.4.38)
+      postcss-convert-values: 6.1.0(postcss@8.4.38)
+      postcss-discard-comments: 6.0.2(postcss@8.4.38)
+      postcss-discard-duplicates: 6.0.3(postcss@8.4.38)
+      postcss-discard-empty: 6.0.3(postcss@8.4.38)
+      postcss-discard-overridden: 6.0.2(postcss@8.4.38)
+      postcss-merge-longhand: 6.0.5(postcss@8.4.38)
+      postcss-merge-rules: 6.1.1(postcss@8.4.38)
+      postcss-minify-font-values: 6.1.0(postcss@8.4.38)
+      postcss-minify-gradients: 6.0.3(postcss@8.4.38)
+      postcss-minify-params: 6.1.0(postcss@8.4.38)
+      postcss-minify-selectors: 6.0.4(postcss@8.4.38)
+      postcss-normalize-charset: 6.0.2(postcss@8.4.38)
+      postcss-normalize-display-values: 6.0.2(postcss@8.4.38)
+      postcss-normalize-positions: 6.0.2(postcss@8.4.38)
+      postcss-normalize-repeat-style: 6.0.2(postcss@8.4.38)
+      postcss-normalize-string: 6.0.2(postcss@8.4.38)
+      postcss-normalize-timing-functions: 6.0.2(postcss@8.4.38)
+      postcss-normalize-unicode: 6.1.0(postcss@8.4.38)
+      postcss-normalize-url: 6.0.2(postcss@8.4.38)
+      postcss-normalize-whitespace: 6.0.2(postcss@8.4.38)
+      postcss-ordered-values: 6.0.2(postcss@8.4.38)
+      postcss-reduce-initial: 6.1.0(postcss@8.4.38)
+      postcss-reduce-transforms: 6.0.2(postcss@8.4.38)
+      postcss-svgo: 6.0.3(postcss@8.4.38)
+      postcss-unique-selectors: 6.0.4(postcss@8.4.38)
 
-  /cssnano-utils@4.0.1(postcss@8.4.35):
-    resolution: {integrity: sha512-6qQuYDqsGoiXssZ3zct6dcMxiqfT6epy7x4R0TQJadd4LWO3sPR6JH6ZByOvVLoZ6EdwPGgd7+DR1EmX3tiXQQ==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  cssnano-utils@4.0.2(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
-    dev: false
+      postcss: 8.4.38
 
-  /cssnano@6.0.5(postcss@8.4.35):
-    resolution: {integrity: sha512-tpTp/ukgrElwu3ESFY4IvWnGn8eTt8cJhC2aAbtA3lvUlxp6t6UPv8YCLjNnEGiFreT1O0LiOM1U3QyTBVFl2A==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  cssnano@6.1.2(postcss@8.4.38):
     dependencies:
-      cssnano-preset-default: 6.0.5(postcss@8.4.35)
+      cssnano-preset-default: 6.1.2(postcss@8.4.38)
       lilconfig: 3.1.1
-      postcss: 8.4.35
-    dev: false
+      postcss: 8.4.38
 
-  /csso@5.0.5:
-    resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==}
-    engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
+  csso@5.0.5:
     dependencies:
       css-tree: 2.2.1
-    dev: false
 
-  /cssstyle@4.0.1:
-    resolution: {integrity: sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==}
-    engines: {node: '>=18'}
+  cssstyle@4.0.1:
     dependencies:
       rrweb-cssom: 0.6.0
-    dev: false
 
-  /csstype@3.1.3:
-    resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+  csstype@3.1.3: {}
 
-  /cwise-compiler@1.1.3:
-    resolution: {integrity: sha512-WXlK/m+Di8DMMcCjcWr4i+XzcQra9eCdXIJrgh4TUgh0pIS/yJduLxS9JgefsHJ/YVLdgPtXm9r62W92MvanEQ==}
+  cwise-compiler@1.1.3:
     dependencies:
       uniq: 1.0.1
-    dev: false
 
-  /cypress@13.6.6:
-    resolution: {integrity: sha512-S+2S9S94611hXimH9a3EAYt81QM913ZVA03pUmGDfLTFa5gyp85NJ8dJGSlEAEmyRsYkioS1TtnWtbv/Fzt11A==}
-    engines: {node: ^16.0.0 || ^18.0.0 || >=20.0.0}
-    hasBin: true
-    requiresBuild: true
+  cypress@13.7.3:
     dependencies:
       '@cypress/request': 3.0.0
       '@cypress/xvfb': 1.2.4(supports-color@8.1.1)
@@ -10341,151 +17262,131 @@ packages:
       process: 0.11.10
       proxy-from-env: 1.0.0
       request-progress: 3.0.0
-      semver: 7.5.4
+      semver: 7.6.0
       supports-color: 8.1.1
-      tmp: 0.2.2
+      tmp: 0.2.3
       untildify: 4.0.0
       yauzl: 2.10.0
-    dev: true
 
-  /dashdash@1.14.1:
-    resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==}
-    engines: {node: '>=0.10'}
+  cypress@13.8.1:
+    dependencies:
+      '@cypress/request': 3.0.0
+      '@cypress/xvfb': 1.2.4(supports-color@8.1.1)
+      '@types/sinonjs__fake-timers': 8.1.1
+      '@types/sizzle': 2.3.3
+      arch: 2.2.0
+      blob-util: 2.0.2
+      bluebird: 3.7.2
+      buffer: 5.7.1
+      cachedir: 2.3.0
+      chalk: 4.1.2
+      check-more-types: 2.24.0
+      cli-cursor: 3.1.0
+      cli-table3: 0.6.3
+      commander: 6.2.1
+      common-tags: 1.8.2
+      dayjs: 1.11.10
+      debug: 4.3.4(supports-color@8.1.1)
+      enquirer: 2.3.6
+      eventemitter2: 6.4.7
+      execa: 4.1.0
+      executable: 4.1.1
+      extract-zip: 2.0.1(supports-color@8.1.1)
+      figures: 3.2.0
+      fs-extra: 9.1.0
+      getos: 3.2.1
+      is-ci: 3.0.1
+      is-installed-globally: 0.4.0
+      lazy-ass: 1.6.0
+      listr2: 3.14.0(enquirer@2.3.6)
+      lodash: 4.17.21
+      log-symbols: 4.1.0
+      minimist: 1.2.8
+      ospath: 1.2.2
+      pretty-bytes: 5.6.0
+      process: 0.11.10
+      proxy-from-env: 1.0.0
+      request-progress: 3.0.0
+      semver: 7.6.0
+      supports-color: 8.1.1
+      tmp: 0.2.3
+      untildify: 4.0.0
+      yauzl: 2.10.0
+
+  dashdash@1.14.1:
     dependencies:
       assert-plus: 1.0.0
 
-  /data-uri-to-buffer@0.0.3:
-    resolution: {integrity: sha512-Cp+jOa8QJef5nXS5hU7M1DWzXPEIoVR3kbV0dQuVGwROZg8bGf1DcCnkmajBTnvghTtSNMUdRrPjgaT6ZQucbw==}
-    dev: false
+  data-uri-to-buffer@0.0.3: {}
 
-  /data-uri-to-buffer@4.0.0:
-    resolution: {integrity: sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==}
-    engines: {node: '>= 12'}
+  data-uri-to-buffer@4.0.0: {}
 
-  /data-urls@5.0.0:
-    resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
-    engines: {node: '>=18'}
+  data-urls@5.0.0:
     dependencies:
       whatwg-mimetype: 4.0.0
       whatwg-url: 14.0.0
-    dev: false
 
-  /date-fns@2.30.0:
-    resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
-    engines: {node: '>=0.11'}
+  date-fns@2.30.0:
     dependencies:
       '@babel/runtime': 7.23.4
-    dev: false
 
-  /dayjs@1.11.10:
-    resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==}
+  dayjs@1.11.10: {}
 
-  /de-indent@1.0.2:
-    resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
-    dev: true
+  de-indent@1.0.2: {}
 
-  /debug@2.6.9:
-    resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
-    peerDependencies:
-      supports-color: '*'
-    peerDependenciesMeta:
-      supports-color:
-        optional: true
+  debug@2.6.9:
     dependencies:
       ms: 2.0.0
 
-  /debug@3.2.7(supports-color@8.1.1):
-    resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
-    peerDependencies:
-      supports-color: '*'
-    peerDependenciesMeta:
-      supports-color:
-        optional: true
+  debug@3.2.7(supports-color@8.1.1):
     dependencies:
       ms: 2.1.3
+    optionalDependencies:
       supports-color: 8.1.1
 
-  /debug@4.3.4(supports-color@5.5.0):
-    resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
-    engines: {node: '>=6.0'}
-    peerDependencies:
-      supports-color: '*'
-    peerDependenciesMeta:
-      supports-color:
-        optional: true
+  debug@4.3.4(supports-color@5.5.0):
     dependencies:
       ms: 2.1.2
+    optionalDependencies:
       supports-color: 5.5.0
-    dev: true
 
-  /debug@4.3.4(supports-color@8.1.1):
-    resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
-    engines: {node: '>=6.0'}
-    peerDependencies:
-      supports-color: '*'
-    peerDependenciesMeta:
-      supports-color:
-        optional: true
+  debug@4.3.4(supports-color@8.1.1):
     dependencies:
       ms: 2.1.2
+    optionalDependencies:
       supports-color: 8.1.1
 
-  /decamelize-keys@1.1.1:
-    resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==}
-    engines: {node: '>=0.10.0'}
+  decamelize-keys@1.1.1:
     dependencies:
       decamelize: 1.2.0
       map-obj: 1.0.1
-    dev: true
 
-  /decamelize@1.2.0:
-    resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
-    engines: {node: '>=0.10.0'}
+  decamelize@1.2.0: {}
 
-  /decimal.js@10.4.3:
-    resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
-    dev: false
+  decimal.js@10.4.3: {}
 
-  /decode-bmp@0.2.1:
-    resolution: {integrity: sha512-NiOaGe+GN0KJqi2STf24hfMkFitDUaIoUU3eKvP/wAbLe8o6FuW5n/x7MHPR0HKvBokp6MQY/j7w8lewEeVCIA==}
-    engines: {node: '>=8.6.0'}
+  decode-bmp@0.2.1:
     dependencies:
       '@canvas/image-data': 1.0.0
       to-data-view: 1.1.0
-    dev: false
 
-  /decode-ico@0.4.1:
-    resolution: {integrity: sha512-69NZfbKIzux1vBOd31al3XnMnH+2mqDhEgLdpygErm4d60N+UwA5Sq5WFjmEDQzumgB9fElojGwWG0vybVfFmA==}
-    engines: {node: '>=8.6'}
+  decode-ico@0.4.1:
     dependencies:
       '@canvas/image-data': 1.0.0
       decode-bmp: 0.2.1
       to-data-view: 1.1.0
-    dev: false
 
-  /decode-named-character-reference@1.0.2:
-    resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==}
+  decode-named-character-reference@1.0.2:
     dependencies:
       character-entities: 2.0.2
-    dev: true
 
-  /decompress-response@6.0.0:
-    resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
-    engines: {node: '>=10'}
+  decompress-response@6.0.0:
     dependencies:
       mimic-response: 3.1.0
 
-  /dedent@1.3.0:
-    resolution: {integrity: sha512-7glNLfvdsMzZm3FpRY1CHuI2lbYDR+71YmrhmTZjYFD5pfT0ACgnGRdrrC9Mk2uICnzkcdelCx5at787UDGOvg==}
-    peerDependencies:
-      babel-plugin-macros: ^3.1.0
-    peerDependenciesMeta:
-      babel-plugin-macros:
-        optional: true
-    dev: true
+  dedent@1.3.0: {}
 
-  /deep-email-validator@0.1.21:
-    resolution: {integrity: sha512-DBAmMzbr+MAubXQ+TS9tZuPwLcdKscb8YzKZiwoLqF3NmaeEgXvSSHhZ0EXOFeKFE2FNWC4mNXCyiQ/JdFXUwg==}
+  deep-email-validator@0.1.21:
     dependencies:
       '@types/disposable-email-domains': 1.0.2
       axios: 0.24.0
@@ -10493,17 +17394,12 @@ packages:
       mailcheck: 1.1.1
     transitivePeerDependencies:
       - debug
-    dev: false
 
-  /deep-eql@4.1.3:
-    resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==}
-    engines: {node: '>=6'}
+  deep-eql@4.1.3:
     dependencies:
       type-detect: 4.0.8
-    dev: true
 
-  /deep-equal@2.2.0:
-    resolution: {integrity: sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==}
+  deep-equal@2.2.0:
     dependencies:
       call-bind: 1.0.2
       es-get-iterator: 1.1.3
@@ -10522,54 +17418,32 @@ packages:
       which-boxed-primitive: 1.0.2
       which-collection: 1.0.1
       which-typed-array: 1.1.11
-    dev: true
 
-  /deep-is@0.1.4:
-    resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
-    dev: true
+  deep-is@0.1.4: {}
 
-  /deepmerge@4.2.2:
-    resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==}
-    engines: {node: '>=0.10.0'}
+  deepmerge@4.2.2: {}
 
-  /default-browser-id@3.0.0:
-    resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==}
-    engines: {node: '>=12'}
+  default-browser-id@3.0.0:
     dependencies:
       bplist-parser: 0.2.0
       untildify: 4.0.0
-    dev: true
 
-  /defaults@1.0.4:
-    resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
+  defaults@1.0.4:
     dependencies:
       clone: 1.0.4
-    dev: true
 
-  /defer-to-connect@2.0.1:
-    resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==}
-    engines: {node: '>=10'}
+  defer-to-connect@2.0.1: {}
 
-  /define-lazy-prop@2.0.0:
-    resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==}
-    engines: {node: '>=8'}
-    dev: true
+  define-lazy-prop@2.0.0: {}
 
-  /define-properties@1.2.0:
-    resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==}
-    engines: {node: '>= 0.4'}
+  define-properties@1.2.0:
     dependencies:
       has-property-descriptors: 1.0.0
       object-keys: 1.1.1
-    dev: true
 
-  /defu@6.1.4:
-    resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
-    dev: true
+  defu@6.1.4: {}
 
-  /del@6.1.1:
-    resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==}
-    engines: {node: '>=10'}
+  del@6.1.1:
     dependencies:
       globby: 11.1.0
       graceful-fs: 4.2.11
@@ -10579,285 +17453,169 @@ packages:
       p-map: 4.0.0
       rimraf: 3.0.2
       slash: 3.0.0
-    dev: true
 
-  /delayed-stream@1.0.0:
-    resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
-    engines: {node: '>=0.4.0'}
+  delayed-stream@1.0.0: {}
 
-  /delegates@1.0.0:
-    resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
-    requiresBuild: true
-    dev: false
+  delegates@1.0.0:
     optional: true
 
-  /denque@2.1.0:
-    resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
-    engines: {node: '>=0.10'}
-    dev: false
+  denque@2.1.0: {}
 
-  /depd@2.0.0:
-    resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
-    engines: {node: '>= 0.8'}
+  depd@2.0.0: {}
 
-  /dequal@2.0.3:
-    resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
-    engines: {node: '>=6'}
-    dev: true
+  dequal@2.0.3: {}
 
-  /destroy@1.2.0:
-    resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
-    engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+  destroy@1.2.0: {}
 
-  /detect-indent@6.1.0:
-    resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==}
-    engines: {node: '>=8'}
-    dev: true
+  detect-indent@6.1.0: {}
 
-  /detect-libc@2.0.2:
-    resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
-    engines: {node: '>=8'}
-    dev: false
+  detect-libc@2.0.2:
+    optional: true
 
-  /detect-newline@3.1.0:
-    resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
-    engines: {node: '>=8'}
-    dev: true
+  detect-libc@2.0.3: {}
 
-  /detect-package-manager@2.0.1:
-    resolution: {integrity: sha512-j/lJHyoLlWi6G1LDdLgvUtz60Zo5GEj+sVYtTVXnYLDPuzgC3llMxonXym9zIwhhUII8vjdw0LXxavpLqTbl1A==}
-    engines: {node: '>=12'}
+  detect-newline@3.1.0: {}
+
+  detect-package-manager@2.0.1:
     dependencies:
       execa: 5.1.1
-    dev: true
 
-  /detect-port@1.5.1:
-    resolution: {integrity: sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==}
-    hasBin: true
+  detect-port@1.5.1:
     dependencies:
       address: 1.2.2
       debug: 4.3.4(supports-color@8.1.1)
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /devlop@1.1.0:
-    resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
+  devlop@1.1.0:
     dependencies:
       dequal: 2.0.3
-    dev: true
 
-  /diff-match-patch@1.0.5:
-    resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==}
-    dev: false
+  diff-match-patch@1.0.5: {}
 
-  /diff-sequences@29.6.3:
-    resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-    dev: true
+  diff-sequences@29.6.3: {}
 
-  /diff@5.1.0:
-    resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==}
-    engines: {node: '>=0.3.1'}
+  diff@5.1.0: {}
 
-  /dijkstrajs@1.0.2:
-    resolution: {integrity: sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==}
-    dev: false
+  dijkstrajs@1.0.2: {}
 
-  /dir-glob@3.0.1:
-    resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
-    engines: {node: '>=8'}
+  dir-glob@3.0.1:
     dependencies:
       path-type: 4.0.0
 
-  /disposable-email-domains@1.0.62:
-    resolution: {integrity: sha512-LBQvhRw7mznQTPoyZbsmYeNOZt1pN5aCsx4BAU/3siVFuiM9f2oyKzUaB8v1jbxFjE3aYqYiMo63kAL4pHgfWQ==}
-    dev: false
+  disposable-email-domains@1.0.62: {}
 
-  /doctrine@2.1.0:
-    resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
-    engines: {node: '>=0.10.0'}
+  doctrine@2.1.0:
     dependencies:
       esutils: 2.0.3
-    dev: true
 
-  /doctrine@3.0.0:
-    resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
-    engines: {node: '>=6.0.0'}
+  doctrine@3.0.0:
     dependencies:
       esutils: 2.0.3
-    dev: true
 
-  /doctypes@1.1.0:
-    resolution: {integrity: sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==}
+  doctypes@1.1.0: {}
 
-  /dom-accessibility-api@0.5.16:
-    resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==}
-    dev: true
+  dom-accessibility-api@0.5.16: {}
 
-  /dom-accessibility-api@0.6.3:
-    resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==}
-    dev: true
+  dom-accessibility-api@0.6.3: {}
 
-  /dom-serializer@2.0.0:
-    resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
+  dom-serializer@2.0.0:
     dependencies:
       domelementtype: 2.3.0
       domhandler: 5.0.3
       entities: 4.5.0
 
-  /domelementtype@2.3.0:
-    resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
+  domelementtype@2.3.0: {}
 
-  /domhandler@5.0.3:
-    resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
-    engines: {node: '>= 4'}
+  domhandler@5.0.3:
     dependencies:
       domelementtype: 2.3.0
 
-  /domutils@3.0.1:
-    resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==}
+  domutils@3.0.1:
     dependencies:
       dom-serializer: 2.0.0
       domelementtype: 2.3.0
       domhandler: 5.0.3
 
-  /dotenv-expand@10.0.0:
-    resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==}
-    engines: {node: '>=12'}
-    dev: true
+  dotenv-expand@10.0.0: {}
 
-  /dotenv@16.0.3:
-    resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==}
-    engines: {node: '>=12'}
+  dotenv@16.0.3: {}
 
-  /duplexer@0.1.2:
-    resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
-    dev: true
+  duplexer@0.1.2: {}
 
-  /duplexify@3.7.1:
-    resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==}
+  duplexify@3.7.1:
     dependencies:
       end-of-stream: 1.4.4
       inherits: 2.0.4
       readable-stream: 2.3.7
       stream-shift: 1.0.1
-    dev: true
 
-  /eastasianwidth@0.2.0:
-    resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+  eastasianwidth@0.2.0: {}
 
-  /ecc-jsbn@0.1.2:
-    resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==}
+  ecc-jsbn@0.1.2:
     dependencies:
       jsbn: 0.1.1
       safer-buffer: 2.1.2
 
-  /ecdsa-sig-formatter@1.0.11:
-    resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
+  ecdsa-sig-formatter@1.0.11:
     dependencies:
       safe-buffer: 5.2.1
-    dev: false
 
-  /editorconfig@1.0.4:
-    resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==}
-    engines: {node: '>=14'}
-    hasBin: true
+  editorconfig@1.0.4:
     dependencies:
       '@one-ini/wasm': 0.1.1
       commander: 10.0.1
       minimatch: 9.0.1
       semver: 7.6.0
-    dev: true
 
-  /ee-first@1.1.1:
-    resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
+  ee-first@1.1.1: {}
 
-  /ejs@3.1.9:
-    resolution: {integrity: sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==}
-    engines: {node: '>=0.10.0'}
-    hasBin: true
+  ejs@3.1.9:
     dependencies:
       jake: 10.8.5
 
-  /electron-to-chromium@1.4.601:
-    resolution: {integrity: sha512-SpwUMDWe9tQu8JX5QCO1+p/hChAi9AE9UpoC3rcHVc+gdCGlbT3SGb5I1klgb952HRIyvt9wZhSz9bNBYz9swA==}
-    dev: true
+  electron-to-chromium@1.4.601: {}
 
-  /electron-to-chromium@1.4.686:
-    resolution: {integrity: sha512-3avY1B+vUzNxEgkBDpKOP8WarvUAEwpRaiCL0He5OKWEFxzaOFiq4WoZEZe7qh0ReS7DiWoHMnYoQCKxNZNzSg==}
+  electron-to-chromium@1.4.686: {}
 
-  /emittery@0.13.1:
-    resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
-    engines: {node: '>=12'}
-    dev: true
+  emittery@0.13.1: {}
 
-  /emoji-regex@8.0.0:
-    resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+  emoji-regex@8.0.0: {}
 
-  /emoji-regex@9.2.2:
-    resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+  emoji-regex@9.2.2: {}
 
-  /encode-utf8@1.0.3:
-    resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==}
-    dev: false
+  encode-utf8@1.0.3: {}
 
-  /encodeurl@1.0.2:
-    resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
-    engines: {node: '>= 0.8'}
+  encodeurl@1.0.2: {}
 
-  /encoding@0.1.13:
-    resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==}
-    requiresBuild: true
+  encoding@0.1.13:
     dependencies:
       iconv-lite: 0.6.3
-    dev: false
     optional: true
 
-  /end-of-stream@1.4.4:
-    resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
+  end-of-stream@1.4.4:
     dependencies:
       once: 1.4.0
 
-  /enquirer@2.3.6:
-    resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==}
-    engines: {node: '>=8.6'}
+  enquirer@2.3.6:
     dependencies:
       ansi-colors: 4.1.3
-    dev: true
 
-  /entities@2.2.0:
-    resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==}
-    dev: false
+  entities@2.2.0: {}
 
-  /entities@4.5.0:
-    resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
-    engines: {node: '>=0.12'}
+  entities@4.5.0: {}
 
-  /env-paths@2.2.1:
-    resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
-    engines: {node: '>=6'}
-    dev: false
+  env-paths@2.2.1: {}
 
-  /envinfo@7.8.1:
-    resolution: {integrity: sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==}
-    engines: {node: '>=4'}
-    hasBin: true
-    dev: true
+  envinfo@7.8.1: {}
 
-  /err-code@2.0.3:
-    resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==}
-    dev: false
+  err-code@2.0.3: {}
 
-  /error-ex@1.3.2:
-    resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
+  error-ex@1.3.2:
     dependencies:
       is-arrayish: 0.2.1
-    dev: true
 
-  /es-abstract@1.22.1:
-    resolution: {integrity: sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==}
-    engines: {node: '>= 0.4'}
+  es-abstract@1.22.1:
     dependencies:
       array-buffer-byte-length: 1.0.0
       arraybuffer.prototype.slice: 1.0.1
@@ -10898,10 +17656,8 @@ packages:
       typed-array-length: 1.0.4
       unbox-primitive: 1.0.2
       which-typed-array: 1.1.11
-    dev: true
 
-  /es-get-iterator@1.1.3:
-    resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==}
+  es-get-iterator@1.1.3:
     dependencies:
       call-bind: 1.0.2
       get-intrinsic: 1.2.1
@@ -10912,70 +17668,43 @@ packages:
       is-string: 1.0.7
       isarray: 2.0.5
       stop-iteration-iterator: 1.0.0
-    dev: true
 
-  /es-module-lexer@0.9.3:
-    resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==}
-    dev: true
+  es-module-lexer@0.9.3: {}
 
-  /es-set-tostringtag@2.0.1:
-    resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==}
-    engines: {node: '>= 0.4'}
+  es-set-tostringtag@2.0.1:
     dependencies:
       get-intrinsic: 1.2.1
       has: 1.0.3
       has-tostringtag: 1.0.0
-    dev: true
 
-  /es-shim-unscopables@1.0.0:
-    resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==}
+  es-shim-unscopables@1.0.0:
     dependencies:
       has: 1.0.3
-    dev: true
 
-  /es-to-primitive@1.2.1:
-    resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
-    engines: {node: '>= 0.4'}
+  es-to-primitive@1.2.1:
     dependencies:
       is-callable: 1.2.7
       is-date-object: 1.0.5
       is-symbol: 1.0.4
-    dev: true
 
-  /es6-promise@4.2.8:
-    resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==}
-    requiresBuild: true
-    dev: false
+  es6-promise@4.2.8:
     optional: true
 
-  /es6-promisify@5.0.0:
-    resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==}
-    requiresBuild: true
+  es6-promisify@5.0.0:
     dependencies:
       es6-promise: 4.2.8
-    dev: false
     optional: true
 
-  /esbuild-plugin-alias@0.2.1:
-    resolution: {integrity: sha512-jyfL/pwPqaFXyKnj8lP8iLk6Z0m099uXR45aSN8Av1XD4vhvQutxxPzgA2bTcAwQpa1zCXDcWOlhFgyP3GKqhQ==}
-    dev: true
+  esbuild-plugin-alias@0.2.1: {}
 
-  /esbuild-register@3.5.0(esbuild@0.19.11):
-    resolution: {integrity: sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==}
-    peerDependencies:
-      esbuild: '>=0.12 <1'
+  esbuild-register@3.5.0(esbuild@0.20.2):
     dependencies:
       debug: 4.3.4(supports-color@8.1.1)
-      esbuild: 0.19.11
+      esbuild: 0.20.2
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /esbuild@0.18.20:
-    resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==}
-    engines: {node: '>=12'}
-    hasBin: true
-    requiresBuild: true
+  esbuild@0.18.20:
     optionalDependencies:
       '@esbuild/android-arm': 0.18.20
       '@esbuild/android-arm64': 0.18.20
@@ -10999,13 +17728,8 @@ packages:
       '@esbuild/win32-arm64': 0.18.20
       '@esbuild/win32-ia32': 0.18.20
       '@esbuild/win32-x64': 0.18.20
-    dev: true
 
-  /esbuild@0.19.11:
-    resolution: {integrity: sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==}
-    engines: {node: '>=12'}
-    hasBin: true
-    requiresBuild: true
+  esbuild@0.19.11:
     optionalDependencies:
       '@esbuild/aix-ppc64': 0.19.11
       '@esbuild/android-arm': 0.19.11
@@ -11031,49 +17755,55 @@ packages:
       '@esbuild/win32-ia32': 0.19.11
       '@esbuild/win32-x64': 0.19.11
 
-  /escalade@3.1.1:
-    resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
-    engines: {node: '>=6'}
+  esbuild@0.20.2:
+    optionalDependencies:
+      '@esbuild/aix-ppc64': 0.20.2
+      '@esbuild/android-arm': 0.20.2
+      '@esbuild/android-arm64': 0.20.2
+      '@esbuild/android-x64': 0.20.2
+      '@esbuild/darwin-arm64': 0.20.2
+      '@esbuild/darwin-x64': 0.20.2
+      '@esbuild/freebsd-arm64': 0.20.2
+      '@esbuild/freebsd-x64': 0.20.2
+      '@esbuild/linux-arm': 0.20.2
+      '@esbuild/linux-arm64': 0.20.2
+      '@esbuild/linux-ia32': 0.20.2
+      '@esbuild/linux-loong64': 0.20.2
+      '@esbuild/linux-mips64el': 0.20.2
+      '@esbuild/linux-ppc64': 0.20.2
+      '@esbuild/linux-riscv64': 0.20.2
+      '@esbuild/linux-s390x': 0.20.2
+      '@esbuild/linux-x64': 0.20.2
+      '@esbuild/netbsd-x64': 0.20.2
+      '@esbuild/openbsd-x64': 0.20.2
+      '@esbuild/sunos-x64': 0.20.2
+      '@esbuild/win32-arm64': 0.20.2
+      '@esbuild/win32-ia32': 0.20.2
+      '@esbuild/win32-x64': 0.20.2
 
-  /escape-html@1.0.3:
-    resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
+  escalade@3.1.1: {}
 
-  /escape-regexp@0.0.1:
-    resolution: {integrity: sha512-jVgdsYRa7RKxTT6MKNC3gdT+BF0Gfhpel19+HMRZJC2L0PufB0XOBuXBoXj29NKHwuktnAXd1Z1lyiH/8vOTpw==}
+  escape-html@1.0.3: {}
 
-  /escape-string-regexp@1.0.5:
-    resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
-    engines: {node: '>=0.8.0'}
-    dev: true
+  escape-regexp@0.0.1: {}
 
-  /escape-string-regexp@2.0.0:
-    resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
-    engines: {node: '>=8'}
-    dev: true
+  escape-string-regexp@1.0.5: {}
 
-  /escape-string-regexp@4.0.0:
-    resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
-    engines: {node: '>=10'}
+  escape-string-regexp@2.0.0: {}
 
-  /escape-string-regexp@5.0.0:
-    resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
-    engines: {node: '>=12'}
+  escape-string-regexp@4.0.0: {}
 
-  /escodegen@2.1.0:
-    resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==}
-    engines: {node: '>=6.0'}
-    hasBin: true
+  escape-string-regexp@5.0.0: {}
+
+  escodegen@2.1.0:
     dependencies:
       esprima: 4.0.1
       estraverse: 5.3.0
       esutils: 2.0.3
     optionalDependencies:
       source-map: 0.6.1
-    dev: true
 
-  /eslint-formatter-pretty@4.1.0:
-    resolution: {integrity: sha512-IsUTtGxF1hrH6lMWiSl1WbGaiP01eT6kzywdY1U+zLc0MP+nwEnUiS9UI8IaOTUhTeQJLlCEWIbXINBH4YJbBQ==}
-    engines: {node: '>=10'}
+  eslint-formatter-pretty@4.1.0:
     dependencies:
       '@types/eslint': 7.29.0
       ansi-escapes: 4.3.2
@@ -11083,87 +17813,47 @@ packages:
       plur: 4.0.0
       string-width: 4.2.3
       supports-hyperlinks: 2.3.0
-    dev: true
 
-  /eslint-import-resolver-node@0.3.9:
-    resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
+  eslint-import-resolver-node@0.3.9:
     dependencies:
       debug: 3.2.7(supports-color@8.1.1)
       is-core-module: 2.13.1
       resolve: 1.22.8
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.11.0)(eslint-import-resolver-node@0.3.9)(eslint@8.53.0):
-    resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==}
-    engines: {node: '>=4'}
-    peerDependencies:
-      '@typescript-eslint/parser': '*'
-      eslint: '*'
-      eslint-import-resolver-node: '*'
-      eslint-import-resolver-typescript: '*'
-      eslint-import-resolver-webpack: '*'
-    peerDependenciesMeta:
-      '@typescript-eslint/parser':
-        optional: true
-      eslint:
-        optional: true
-      eslint-import-resolver-node:
-        optional: true
-      eslint-import-resolver-typescript:
-        optional: true
-      eslint-import-resolver-webpack:
-        optional: true
+  eslint-module-utils@2.8.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@8.53.0):
     dependencies:
-      '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
       debug: 3.2.7(supports-color@8.1.1)
+    optionalDependencies:
+      '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
       eslint: 8.53.0
       eslint-import-resolver-node: 0.3.9
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /eslint-module-utils@2.8.0(@typescript-eslint/parser@7.1.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0):
-    resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==}
-    engines: {node: '>=4'}
-    peerDependencies:
-      '@typescript-eslint/parser': '*'
-      eslint: '*'
-      eslint-import-resolver-node: '*'
-      eslint-import-resolver-typescript: '*'
-      eslint-import-resolver-webpack: '*'
-    peerDependenciesMeta:
-      '@typescript-eslint/parser':
-        optional: true
-      eslint:
-        optional: true
-      eslint-import-resolver-node:
-        optional: true
-      eslint-import-resolver-typescript:
-        optional: true
-      eslint-import-resolver-webpack:
-        optional: true
+  eslint-module-utils@2.8.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0):
     dependencies:
-      '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3)
       debug: 3.2.7(supports-color@8.1.1)
+    optionalDependencies:
+      '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3)
       eslint: 8.57.0
       eslint-import-resolver-node: 0.3.9
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.11.0)(eslint@8.53.0):
-    resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
-    engines: {node: '>=4'}
-    peerDependencies:
-      '@typescript-eslint/parser': '*'
-      eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
-    peerDependenciesMeta:
-      '@typescript-eslint/parser':
-        optional: true
+  eslint-module-utils@2.8.0(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0):
+    dependencies:
+      debug: 3.2.7(supports-color@8.1.1)
+    optionalDependencies:
+      '@typescript-eslint/parser': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
+      eslint: 8.57.0
+      eslint-import-resolver-node: 0.3.9
+    transitivePeerDependencies:
+      - supports-color
+
+  eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0):
     dependencies:
-      '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
       array-includes: 3.1.7
       array.prototype.findlastindex: 1.2.3
       array.prototype.flat: 1.3.2
@@ -11172,7 +17862,7 @@ packages:
       doctrine: 2.1.0
       eslint: 8.53.0
       eslint-import-resolver-node: 0.3.9
-      eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.11.0)(eslint-import-resolver-node@0.3.9)(eslint@8.53.0)
+      eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@8.53.0)
       hasown: 2.0.0
       is-core-module: 2.13.1
       is-glob: 4.0.3
@@ -11182,23 +17872,15 @@ packages:
       object.values: 1.1.7
       semver: 6.3.1
       tsconfig-paths: 3.15.0
+    optionalDependencies:
+      '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
     transitivePeerDependencies:
       - eslint-import-resolver-typescript
       - eslint-import-resolver-webpack
       - supports-color
-    dev: true
 
-  /eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0)(eslint@8.57.0):
-    resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
-    engines: {node: '>=4'}
-    peerDependencies:
-      '@typescript-eslint/parser': '*'
-      eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
-    peerDependenciesMeta:
-      '@typescript-eslint/parser':
-        optional: true
+  eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0):
     dependencies:
-      '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3)
       array-includes: 3.1.7
       array.prototype.findlastindex: 1.2.3
       array.prototype.flat: 1.3.2
@@ -11207,7 +17889,7 @@ packages:
       doctrine: 2.1.0
       eslint: 8.57.0
       eslint-import-resolver-node: 0.3.9
-      eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.1.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0)
+      eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0)
       hasown: 2.0.0
       is-core-module: 2.13.1
       is-glob: 4.0.3
@@ -11217,20 +17899,45 @@ packages:
       object.values: 1.1.7
       semver: 6.3.1
       tsconfig-paths: 3.15.0
+    optionalDependencies:
+      '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3)
     transitivePeerDependencies:
       - eslint-import-resolver-typescript
       - eslint-import-resolver-webpack
       - supports-color
-    dev: true
 
-  /eslint-plugin-vue@9.22.0(eslint@8.57.0):
-    resolution: {integrity: sha512-7wCXv5zuVnBtZE/74z4yZ0CM8AjH6bk4MQGm7hZjUC2DBppKU5ioeOk5LGSg/s9a1ZJnIsdPLJpXnu1Rc+cVHg==}
-    engines: {node: ^14.17.0 || >=16.0.0}
-    peerDependencies:
-      eslint: ^6.2.0 || ^7.0.0 || ^8.0.0
+  eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0):
+    dependencies:
+      array-includes: 3.1.7
+      array.prototype.findlastindex: 1.2.3
+      array.prototype.flat: 1.3.2
+      array.prototype.flatmap: 1.3.2
+      debug: 3.2.7(supports-color@8.1.1)
+      doctrine: 2.1.0
+      eslint: 8.57.0
+      eslint-import-resolver-node: 0.3.9
+      eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0)
+      hasown: 2.0.0
+      is-core-module: 2.13.1
+      is-glob: 4.0.3
+      minimatch: 3.1.2
+      object.fromentries: 2.0.7
+      object.groupby: 1.0.1
+      object.values: 1.1.7
+      semver: 6.3.1
+      tsconfig-paths: 3.15.0
+    optionalDependencies:
+      '@typescript-eslint/parser': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
+    transitivePeerDependencies:
+      - eslint-import-resolver-typescript
+      - eslint-import-resolver-webpack
+      - supports-color
+
+  eslint-plugin-vue@9.25.0(eslint@8.57.0):
     dependencies:
       '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
       eslint: 8.57.0
+      globals: 13.24.0
       natural-compare: 1.4.0
       nth-check: 2.1.1
       postcss-selector-parser: 6.0.15
@@ -11239,29 +17946,17 @@ packages:
       xml-name-validator: 4.0.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /eslint-rule-docs@1.1.235:
-    resolution: {integrity: sha512-+TQ+x4JdTnDoFEXXb3fDvfGOwnyNV7duH8fXWTPD1ieaBmB8omj7Gw/pMBBu4uI2uJCCU8APDaQJzWuXnTsH4A==}
-    dev: true
+  eslint-rule-docs@1.1.235: {}
 
-  /eslint-scope@7.2.2:
-    resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
-    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+  eslint-scope@7.2.2:
     dependencies:
       esrecurse: 4.3.0
       estraverse: 5.3.0
-    dev: true
 
-  /eslint-visitor-keys@3.4.3:
-    resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
-    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-    dev: true
+  eslint-visitor-keys@3.4.3: {}
 
-  /eslint@8.53.0:
-    resolution: {integrity: sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==}
-    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-    hasBin: true
+  eslint@8.53.0:
     dependencies:
       '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0)
       '@eslint-community/regexpp': 4.6.2
@@ -11303,12 +17998,8 @@ packages:
       text-table: 0.2.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /eslint@8.57.0:
-    resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==}
-    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-    hasBin: true
+  eslint@8.57.0:
     dependencies:
       '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
       '@eslint-community/regexpp': 4.6.2
@@ -11350,61 +18041,36 @@ packages:
       text-table: 0.2.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /espree@9.6.1:
-    resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
-    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+  espree@9.6.1:
     dependencies:
       acorn: 8.11.3
       acorn-jsx: 5.3.2(acorn@8.11.3)
       eslint-visitor-keys: 3.4.3
-    dev: true
 
-  /esprima@4.0.1:
-    resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
-    engines: {node: '>=4'}
-    hasBin: true
-    dev: true
+  esprima@4.0.1: {}
 
-  /esquery@1.4.2:
-    resolution: {integrity: sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==}
-    engines: {node: '>=0.10'}
+  esquery@1.4.2:
     dependencies:
       estraverse: 5.3.0
-    dev: true
 
-  /esrecurse@4.3.0:
-    resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
-    engines: {node: '>=4.0'}
+  esrecurse@4.3.0:
     dependencies:
       estraverse: 5.3.0
-    dev: true
 
-  /estraverse@5.3.0:
-    resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
-    engines: {node: '>=4.0'}
-    dev: true
+  estraverse@5.3.0: {}
 
-  /estree-walker@2.0.2:
-    resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+  estree-walker@2.0.2: {}
 
-  /estree-walker@3.0.3:
-    resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+  estree-walker@3.0.3:
     dependencies:
       '@types/estree': 1.0.5
 
-  /esutils@2.0.3:
-    resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
-    engines: {node: '>=0.10.0'}
-    dev: true
+  esutils@2.0.3: {}
 
-  /etag@1.8.1:
-    resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
-    engines: {node: '>= 0.6'}
+  etag@1.8.1: {}
 
-  /event-stream@3.3.4:
-    resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==}
+  event-stream@3.3.4:
     dependencies:
       duplexer: 0.1.2
       from: 0.1.7
@@ -11413,33 +18079,18 @@ packages:
       split: 0.3.3
       stream-combiner: 0.0.4
       through: 2.3.8
-    dev: true
 
-  /event-target-shim@5.0.1:
-    resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
-    engines: {node: '>=6'}
-    dev: false
+  event-target-shim@5.0.1: {}
 
-  /eventemitter2@6.4.7:
-    resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==}
-    dev: true
+  eventemitter2@6.4.7: {}
 
-  /eventemitter3@4.0.7:
-    resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
-    dev: false
+  eventemitter3@4.0.7: {}
 
-  /eventemitter3@5.0.1:
-    resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
-    dev: false
+  eventemitter3@5.0.1: {}
 
-  /events@3.3.0:
-    resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
-    engines: {node: '>=0.8.x'}
-    dev: false
+  events@3.3.0: {}
 
-  /execa@0.7.0:
-    resolution: {integrity: sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==}
-    engines: {node: '>=4'}
+  execa@0.7.0:
     dependencies:
       cross-spawn: 5.1.0
       get-stream: 3.0.0
@@ -11448,11 +18099,8 @@ packages:
       p-finally: 1.0.0
       signal-exit: 3.0.7
       strip-eof: 1.0.0
-    dev: false
 
-  /execa@4.1.0:
-    resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==}
-    engines: {node: '>=10'}
+  execa@4.1.0:
     dependencies:
       cross-spawn: 7.0.3
       get-stream: 5.2.0
@@ -11463,11 +18111,8 @@ packages:
       onetime: 5.1.2
       signal-exit: 3.0.7
       strip-final-newline: 2.0.0
-    dev: true
 
-  /execa@5.1.1:
-    resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
-    engines: {node: '>=10'}
+  execa@5.1.1:
     dependencies:
       cross-spawn: 7.0.3
       get-stream: 6.0.1
@@ -11479,9 +18124,7 @@ packages:
       signal-exit: 3.0.7
       strip-final-newline: 2.0.0
 
-  /execa@6.1.0:
-    resolution: {integrity: sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+  execa@6.1.0:
     dependencies:
       cross-spawn: 7.0.3
       get-stream: 6.0.1
@@ -11492,11 +18135,8 @@ packages:
       onetime: 6.0.0
       signal-exit: 3.0.7
       strip-final-newline: 3.0.0
-    dev: true
 
-  /execa@8.0.1:
-    resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
-    engines: {node: '>=16.17'}
+  execa@8.0.1:
     dependencies:
       cross-spawn: 7.0.3
       get-stream: 8.0.1
@@ -11508,35 +18148,23 @@ packages:
       signal-exit: 4.1.0
       strip-final-newline: 3.0.0
 
-  /executable@4.1.1:
-    resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==}
-    engines: {node: '>=4'}
+  executable@4.1.1:
     dependencies:
       pify: 2.3.0
 
-  /exit@0.1.2:
-    resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}
-    engines: {node: '>= 0.8.0'}
-    dev: true
+  exit@0.1.2: {}
 
-  /expect@29.7.0:
-    resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  expect@29.7.0:
     dependencies:
       '@jest/expect-utils': 29.7.0
       jest-get-type: 29.6.3
       jest-matcher-utils: 29.7.0
       jest-message-util: 29.7.0
       jest-util: 29.7.0
-    dev: true
 
-  /exponential-backoff@3.1.1:
-    resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==}
-    dev: false
+  exponential-backoff@3.1.1: {}
 
-  /express@4.18.2:
-    resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==}
-    engines: {node: '>= 0.10.0'}
+  express@4.18.2:
     dependencies:
       accepts: 1.3.8
       array-flatten: 1.1.1
@@ -11572,37 +18200,54 @@ packages:
     transitivePeerDependencies:
       - supports-color
 
-  /ext-list@2.2.2:
-    resolution: {integrity: sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==}
-    engines: {node: '>=0.10.0'}
+  express@4.19.2:
+    dependencies:
+      accepts: 1.3.8
+      array-flatten: 1.1.1
+      body-parser: 1.20.2
+      content-disposition: 0.5.4
+      content-type: 1.0.5
+      cookie: 0.6.0
+      cookie-signature: 1.0.6
+      debug: 2.6.9
+      depd: 2.0.0
+      encodeurl: 1.0.2
+      escape-html: 1.0.3
+      etag: 1.8.1
+      finalhandler: 1.2.0
+      fresh: 0.5.2
+      http-errors: 2.0.0
+      merge-descriptors: 1.0.1
+      methods: 1.1.2
+      on-finished: 2.4.1
+      parseurl: 1.3.3
+      path-to-regexp: 0.1.7
+      proxy-addr: 2.0.7
+      qs: 6.11.0
+      range-parser: 1.2.1
+      safe-buffer: 5.2.1
+      send: 0.18.0
+      serve-static: 1.15.0
+      setprototypeof: 1.2.0
+      statuses: 2.0.1
+      type-is: 1.6.18
+      utils-merge: 1.0.1
+      vary: 1.1.2
+    transitivePeerDependencies:
+      - supports-color
+
+  ext-list@2.2.2:
     dependencies:
       mime-db: 1.52.0
-    dev: false
 
-  /ext-name@5.0.0:
-    resolution: {integrity: sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==}
-    engines: {node: '>=4'}
+  ext-name@5.0.0:
     dependencies:
       ext-list: 2.2.2
       sort-keys-length: 1.0.1
-    dev: false
 
-  /extend@3.0.2:
-    resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
+  extend@3.0.2: {}
 
-  /external-editor@3.1.0:
-    resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
-    engines: {node: '>=4'}
-    dependencies:
-      chardet: 0.7.0
-      iconv-lite: 0.4.24
-      tmp: 0.0.33
-    dev: true
-
-  /extract-zip@2.0.1(supports-color@8.1.1):
-    resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==}
-    engines: {node: '>= 10.17.0'}
-    hasBin: true
+  extract-zip@2.0.1(supports-color@8.1.1):
     dependencies:
       debug: 4.3.4(supports-color@8.1.1)
       get-stream: 5.2.0
@@ -11611,30 +18256,18 @@ packages:
       '@types/yauzl': 2.10.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /extsprintf@1.3.0:
-    resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==}
-    engines: {'0': node >=0.6.0}
+  extsprintf@1.3.0: {}
 
-  /fast-content-type-parse@1.1.0:
-    resolution: {integrity: sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==}
-    dev: false
+  fast-content-type-parse@1.1.0: {}
 
-  /fast-decode-uri-component@1.0.1:
-    resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==}
-    dev: false
+  fast-decode-uri-component@1.0.1: {}
 
-  /fast-deep-equal@3.1.3:
-    resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+  fast-deep-equal@3.1.3: {}
 
-  /fast-fifo@1.3.0:
-    resolution: {integrity: sha512-IgfweLvEpwyA4WgiQe9Nx6VV2QkML2NkvZnk1oKnIzXgXdWxuhF7zw4DvLTPZJn6PIUneiAXPF24QmoEqHTjyw==}
-    dev: false
+  fast-fifo@1.3.0: {}
 
-  /fast-glob@3.3.2:
-    resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
-    engines: {node: '>=8.6.0'}
+  fast-glob@3.3.2:
     dependencies:
       '@nodelib/fs.stat': 2.0.5
       '@nodelib/fs.walk': 1.2.8
@@ -11642,187 +18275,131 @@ packages:
       merge2: 1.4.1
       micromatch: 4.0.5
 
-  /fast-json-stable-stringify@2.1.0:
-    resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+  fast-json-stable-stringify@2.1.0: {}
 
-  /fast-json-stringify@5.8.0:
-    resolution: {integrity: sha512-VVwK8CFMSALIvt14U8AvrSzQAwN/0vaVRiFFUVlpnXSnDGrSkOAO5MtzyN8oQNjLd5AqTW5OZRgyjoNuAuR3jQ==}
+  fast-json-stringify@5.8.0:
     dependencies:
       '@fastify/deepmerge': 1.3.0
-      ajv: 8.12.0
-      ajv-formats: 2.1.1(ajv@8.12.0)
+      ajv: 8.13.0
+      ajv-formats: 2.1.1(ajv@8.13.0)
       fast-deep-equal: 3.1.3
       fast-uri: 2.2.0
       rfdc: 1.3.0
-    dev: false
 
-  /fast-levenshtein@2.0.6:
-    resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
-    dev: true
+  fast-levenshtein@2.0.6: {}
 
-  /fast-querystring@1.1.2:
-    resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==}
+  fast-querystring@1.1.2:
     dependencies:
       fast-decode-uri-component: 1.0.1
-    dev: false
 
-  /fast-redact@3.1.2:
-    resolution: {integrity: sha512-+0em+Iya9fKGfEQGcd62Yv6onjBmmhV1uh86XVfOU8VwAe6kaFdQCWI9s0/Nnugx5Vd9tdbZ7e6gE2tR9dzXdw==}
-    engines: {node: '>=6'}
-    dev: false
+  fast-redact@3.1.2: {}
 
-  /fast-safe-stringify@2.1.1:
-    resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
+  fast-safe-stringify@2.1.1: {}
 
-  /fast-uri@2.2.0:
-    resolution: {integrity: sha512-cIusKBIt/R/oI6z/1nyfe2FvGKVTohVRfvkOhvx0nCEW+xf5NoCXjAHcWp93uOUBchzYcsvPlrapAdX1uW+YGg==}
-    dev: false
+  fast-uri@2.2.0: {}
 
-  /fast-xml-parser@4.2.5:
-    resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==}
-    hasBin: true
+  fast-xml-parser@4.2.5:
     dependencies:
       strnum: 1.0.5
-    dev: false
 
-  /fastify-plugin@4.5.0:
-    resolution: {integrity: sha512-79ak0JxddO0utAXAQ5ccKhvs6vX2MGyHHMMsmZkBANrq3hXc1CHzvNPHOcvTsVMEPl5I+NT+RO4YKMGehOfSIg==}
-    dev: false
+  fastify-plugin@4.5.0: {}
 
-  /fastify-raw-body@4.3.0:
-    resolution: {integrity: sha512-F4o8ZIMVx4YoxGfwrZys6wyjl40gF3Yv6AWWRy62ozFAyZBSS831/uyyCAqKYw3tR73g180ryG98yih6To1PUQ==}
-    engines: {node: '>= 10'}
+  fastify-raw-body@4.3.0:
     dependencies:
       fastify-plugin: 4.5.0
       raw-body: 2.5.2
       secure-json-parse: 2.7.0
-    dev: false
 
-  /fastify@4.25.2:
-    resolution: {integrity: sha512-SywRouGleDHvRh054onj+lEZnbC1sBCLkR0UY3oyJwjD4BdZJUrxBqfkfCaqn74pVCwBaRHGuL3nEWeHbHzAfw==}
+  fastify@4.26.2:
     dependencies:
       '@fastify/ajv-compiler': 3.5.0
       '@fastify/error': 3.4.0
       '@fastify/fast-json-stringify-compiler': 4.3.0
       abstract-logging: 2.0.1
-      avvio: 8.2.1
+      avvio: 8.3.0
       fast-content-type-parse: 1.1.0
       fast-json-stringify: 5.8.0
-      find-my-way: 7.7.0
+      find-my-way: 8.2.0
       light-my-request: 5.11.0
       pino: 8.17.0
       process-warning: 3.0.0
       proxy-addr: 2.0.7
       rfdc: 1.3.0
       secure-json-parse: 2.7.0
-      semver: 7.5.4
+      semver: 7.6.0
       toad-cache: 3.3.0
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /fastq@1.15.0:
-    resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
+  fastq@1.15.0:
     dependencies:
       reusify: 1.0.4
 
-  /fb-watchman@2.0.2:
-    resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
+  fastq@1.17.1:
+    dependencies:
+      reusify: 1.0.4
+
+  fb-watchman@2.0.2:
     dependencies:
       bser: 2.1.1
-    dev: true
 
-  /fd-slicer@1.1.0:
-    resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
+  fd-slicer@1.1.0:
     dependencies:
       pend: 1.2.0
-    dev: true
 
-  /feed@4.2.2:
-    resolution: {integrity: sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==}
-    engines: {node: '>=0.4.0'}
+  feed@4.2.2:
     dependencies:
       xml-js: 1.6.11
-    dev: false
 
-  /fetch-blob@3.2.0:
-    resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
-    engines: {node: ^12.20 || >= 14.13}
+  fetch-blob@3.2.0:
     dependencies:
       node-domexception: 1.0.0
       web-streams-polyfill: 3.2.1
 
-  /fetch-retry@5.0.4:
-    resolution: {integrity: sha512-LXcdgpdcVedccGg0AZqg+S8lX/FCdwXD92WNZ5k5qsb0irRhSFsBOpcJt7oevyqT2/C2nEE0zSFNdBEpj3YOSw==}
-    dev: true
+  fetch-retry@5.0.4: {}
 
-  /figures@3.2.0:
-    resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
-    engines: {node: '>=8'}
+  figures@3.2.0:
     dependencies:
       escape-string-regexp: 1.0.5
-    dev: true
 
-  /file-entry-cache@6.0.1:
-    resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
-    engines: {node: ^10.12.0 || >=12.0.0}
+  file-entry-cache@6.0.1:
     dependencies:
       flat-cache: 3.0.4
-    dev: true
 
-  /file-system-cache@2.3.0:
-    resolution: {integrity: sha512-l4DMNdsIPsVnKrgEXbJwDJsA5mB8rGwHYERMgqQx/xAUtChPJMre1bXBzDEqqVbWv9AIbFezXMxeEkZDSrXUOQ==}
+  file-system-cache@2.3.0:
     dependencies:
       fs-extra: 11.1.1
       ramda: 0.29.0
-    dev: true
 
-  /file-type@17.1.6:
-    resolution: {integrity: sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+  file-type@17.1.6:
     dependencies:
       readable-web-to-node-stream: 3.0.2
       strtok3: 7.0.0
       token-types: 5.0.1
-    dev: false
 
-  /file-type@19.0.0:
-    resolution: {integrity: sha512-s7cxa7/leUWLiXO78DVVfBVse+milos9FitauDLG1pI7lNaJ2+5lzPnr2N24ym+84HVwJL6hVuGfgVE+ALvU8Q==}
-    engines: {node: '>=18'}
+  file-type@19.0.0:
     dependencies:
       readable-web-to-node-stream: 3.0.2
       strtok3: 7.0.0
       token-types: 5.0.1
-    dev: false
 
-  /filelist@1.0.4:
-    resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==}
+  filelist@1.0.4:
     dependencies:
       minimatch: 5.1.2
 
-  /filename-reserved-regex@3.0.0:
-    resolution: {integrity: sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
-    dev: false
+  filename-reserved-regex@3.0.0: {}
 
-  /filenamify@5.1.1:
-    resolution: {integrity: sha512-M45CbrJLGACfrPOkrTp3j2EcO9OBkKUYME0eiqOCa7i2poaklU0jhlIaMlr8ijLorT0uLAzrn3qXOp5684CkfA==}
-    engines: {node: '>=12.20'}
+  filenamify@5.1.1:
     dependencies:
       filename-reserved-regex: 3.0.0
       strip-outer: 2.0.0
       trim-repeated: 2.0.0
-    dev: false
 
-  /fill-range@7.0.1:
-    resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
-    engines: {node: '>=8'}
+  fill-range@7.0.1:
     dependencies:
       to-regex-range: 5.0.1
 
-  /finalhandler@1.2.0:
-    resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==}
-    engines: {node: '>= 0.8'}
+  finalhandler@1.2.0:
     dependencies:
       debug: 2.6.9
       encodeurl: 1.0.2
@@ -11834,69 +18411,45 @@ packages:
     transitivePeerDependencies:
       - supports-color
 
-  /find-cache-dir@2.1.0:
-    resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==}
-    engines: {node: '>=6'}
+  find-cache-dir@2.1.0:
     dependencies:
       commondir: 1.0.1
       make-dir: 2.1.0
       pkg-dir: 3.0.0
-    dev: true
 
-  /find-cache-dir@3.3.2:
-    resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==}
-    engines: {node: '>=8'}
+  find-cache-dir@3.3.2:
     dependencies:
       commondir: 1.0.1
       make-dir: 3.1.0
       pkg-dir: 4.2.0
-    dev: true
 
-  /find-my-way@7.7.0:
-    resolution: {integrity: sha512-+SrHpvQ52Q6W9f3wJoJBbAQULJuNEEQwBvlvYwACDhBTLOTMiQ0HYWh4+vC3OivGP2ENcTI1oKlFA2OepJNjhQ==}
-    engines: {node: '>=14'}
+  find-my-way@8.2.0:
     dependencies:
       fast-deep-equal: 3.1.3
       fast-querystring: 1.1.2
-      safe-regex2: 2.0.0
-    dev: false
+      safe-regex2: 3.1.0
 
-  /find-package-json@1.2.0:
-    resolution: {integrity: sha512-+SOGcLGYDJHtyqHd87ysBhmaeQ95oWspDKnMXBrnQ9Eq4OkLNqejgoaD8xVWu6GPa0B6roa6KinCMEMcVeqONw==}
-    dev: true
+  find-package-json@1.2.0: {}
 
-  /find-up@3.0.0:
-    resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==}
-    engines: {node: '>=6'}
+  find-up@3.0.0:
     dependencies:
       locate-path: 3.0.0
-    dev: true
 
-  /find-up@4.1.0:
-    resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
-    engines: {node: '>=8'}
+  find-up@4.1.0:
     dependencies:
       locate-path: 5.0.0
       path-exists: 4.0.0
 
-  /find-up@5.0.0:
-    resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
-    engines: {node: '>=10'}
+  find-up@5.0.0:
     dependencies:
       locate-path: 6.0.0
       path-exists: 4.0.0
-    dev: true
 
-  /find-versions@5.1.0:
-    resolution: {integrity: sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==}
-    engines: {node: '>=12'}
+  find-versions@5.1.0:
     dependencies:
       semver-regex: 4.0.5
-    dev: false
 
-  /fkill@9.0.0:
-    resolution: {integrity: sha512-MdYSsbdCaIRjzo5edthZtWmEZVMfr1qrtYZUHIdO3swCE+CoZA8S5l0s4jDsYlTa9ZiXv0pTgpzE7s4N8NeUOA==}
-    engines: {node: '>=18'}
+  fkill@9.0.0:
     dependencies:
       aggregate-error: 5.0.0
       execa: 8.0.1
@@ -11904,207 +18457,125 @@ packages:
       process-exists: 5.0.0
       ps-list: 8.1.1
       taskkill: 5.0.0
-    dev: true
 
-  /flat-cache@3.0.4:
-    resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==}
-    engines: {node: ^10.12.0 || >=12.0.0}
+  flat-cache@3.0.4:
     dependencies:
       flatted: 3.2.7
       rimraf: 3.0.2
-    dev: true
 
-  /flatted@3.2.7:
-    resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
-    dev: true
+  flatted@3.2.7: {}
 
-  /flow-parser@0.202.0:
-    resolution: {integrity: sha512-ZiXxSIXK3zPmY3zrzCofFonM2T+/3Jz5QZKJyPVtUERQEJUnYkXBQ+0H3FzyqiyJs+VXqb/UNU6/K6sziVYdxw==}
-    engines: {node: '>=0.4.0'}
-    dev: true
+  flow-parser@0.202.0: {}
 
-  /fluent-ffmpeg@2.1.2:
-    resolution: {integrity: sha512-IZTB4kq5GK0DPp7sGQ0q/BWurGHffRtQQwVkiqDgeO6wYJLLV5ZhgNOQ65loZxxuPMKZKZcICCUnaGtlxBiR0Q==}
-    engines: {node: '>=0.8.0'}
+  fluent-ffmpeg@2.1.2:
     dependencies:
       async: 3.2.4
       which: 1.3.1
-    dev: false
 
-  /follow-redirects@1.15.2(debug@4.3.4):
-    resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
-    engines: {node: '>=4.0'}
-    peerDependencies:
-      debug: '*'
-    peerDependenciesMeta:
-      debug:
-        optional: true
-    dependencies:
+  follow-redirects@1.15.2(debug@4.3.4):
+    optionalDependencies:
       debug: 4.3.4(supports-color@8.1.1)
 
-  /for-each@0.3.3:
-    resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
+  for-each@0.3.3:
     dependencies:
       is-callable: 1.2.7
-    dev: true
 
-  /foreground-child@3.1.1:
-    resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
-    engines: {node: '>=14'}
+  foreground-child@3.1.1:
     dependencies:
       cross-spawn: 7.0.3
       signal-exit: 4.1.0
 
-  /forever-agent@0.6.1:
-    resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==}
+  forever-agent@0.6.1: {}
 
-  /form-data-encoder@2.1.4:
-    resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==}
-    engines: {node: '>= 14.17'}
+  form-data-encoder@2.1.4: {}
 
-  /form-data-encoder@4.0.2:
-    resolution: {integrity: sha512-KQVhvhK8ZkWzxKxOr56CPulAhH3dobtuQ4+hNQ+HekH/Wp5gSOafqRAeTphQUJAIk0GBvHZgJ2ZGRWd5kphMuw==}
-    engines: {node: '>= 18'}
-    dev: false
+  form-data-encoder@4.0.2: {}
 
-  /form-data@2.3.3:
-    resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==}
-    engines: {node: '>= 0.12'}
+  form-data@2.3.3:
     dependencies:
       asynckit: 0.4.0
       combined-stream: 1.0.8
       mime-types: 2.1.35
 
-  /form-data@3.0.1:
-    resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==}
-    engines: {node: '>= 6'}
-    requiresBuild: true
-    dependencies:
-      asynckit: 0.4.0
-      combined-stream: 1.0.8
-      mime-types: 2.1.35
-    dev: false
-
-  /form-data@4.0.0:
-    resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
-    engines: {node: '>= 6'}
+  form-data@3.0.1:
     dependencies:
       asynckit: 0.4.0
       combined-stream: 1.0.8
       mime-types: 2.1.35
 
-  /formdata-polyfill@4.0.10:
-    resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
-    engines: {node: '>=12.20.0'}
+  form-data@4.0.0:
+    dependencies:
+      asynckit: 0.4.0
+      combined-stream: 1.0.8
+      mime-types: 2.1.35
+
+  formdata-polyfill@4.0.10:
     dependencies:
       fetch-blob: 3.2.0
 
-  /forwarded@0.2.0:
-    resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
-    engines: {node: '>= 0.6'}
+  forwarded@0.2.0: {}
 
-  /fresh@0.5.2:
-    resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
-    engines: {node: '>= 0.6'}
+  fresh@0.5.2: {}
 
-  /from@0.1.7:
-    resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==}
-    dev: true
+  from@0.1.7: {}
 
-  /fs-constants@1.0.0:
-    resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
-    dev: true
+  fs-constants@1.0.0: {}
 
-  /fs-extra@11.1.1:
-    resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==}
-    engines: {node: '>=14.14'}
+  fs-extra@11.1.1:
     dependencies:
       graceful-fs: 4.2.11
       jsonfile: 6.1.0
       universalify: 2.0.0
-    dev: true
 
-  /fs-extra@7.0.1:
-    resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
-    engines: {node: '>=6 <7 || >=8'}
+  fs-extra@7.0.1:
     dependencies:
       graceful-fs: 4.2.11
       jsonfile: 4.0.0
       universalify: 0.1.2
-    dev: true
 
-  /fs-extra@8.1.0:
-    resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==}
-    engines: {node: '>=6 <7 || >=8'}
+  fs-extra@8.1.0:
     dependencies:
       graceful-fs: 4.2.11
       jsonfile: 4.0.0
       universalify: 0.1.2
-    dev: false
 
-  /fs-extra@9.1.0:
-    resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==}
-    engines: {node: '>=10'}
+  fs-extra@9.1.0:
     dependencies:
       at-least-node: 1.0.0
       graceful-fs: 4.2.11
       jsonfile: 6.1.0
       universalify: 2.0.0
-    dev: true
 
-  /fs-minipass@1.2.7:
-    resolution: {integrity: sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==}
-    requiresBuild: true
+  fs-minipass@1.2.7:
     dependencies:
       minipass: 2.9.0
-    dev: false
     optional: true
 
-  /fs-minipass@2.1.0:
-    resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
-    engines: {node: '>= 8'}
-    requiresBuild: true
+  fs-minipass@2.1.0:
     dependencies:
       minipass: 3.3.6
 
-  /fs-minipass@3.0.2:
-    resolution: {integrity: sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g==}
-    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+  fs-minipass@3.0.2:
     dependencies:
       minipass: 5.0.0
-    dev: false
 
-  /fs.realpath@1.0.0:
-    resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+  fs.realpath@1.0.0: {}
 
-  /fsevents@2.3.3:
-    resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
-    engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
-    os: [darwin]
-    requiresBuild: true
+  fsevents@2.3.3:
     optional: true
 
-  /function-bind@1.1.2:
-    resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+  function-bind@1.1.2: {}
 
-  /function.prototype.name@1.1.5:
-    resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==}
-    engines: {node: '>= 0.4'}
+  function.prototype.name@1.1.5:
     dependencies:
       call-bind: 1.0.2
       define-properties: 1.2.0
       es-abstract: 1.22.1
       functions-have-names: 1.2.3
-    dev: true
 
-  /functions-have-names@1.2.3:
-    resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
-    dev: true
+  functions-have-names@1.2.3: {}
 
-  /gauge@3.0.2:
-    resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==}
-    engines: {node: '>=10'}
-    requiresBuild: true
+  gauge@3.0.2:
     dependencies:
       aproba: 2.0.0
       color-support: 1.1.3
@@ -12115,42 +18586,26 @@ packages:
       string-width: 4.2.3
       strip-ansi: 6.0.1
       wide-align: 1.1.5
-    dev: false
     optional: true
 
-  /gensync@1.0.0-beta.2:
-    resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
-    engines: {node: '>=6.9.0'}
-    dev: true
+  gensync@1.0.0-beta.2: {}
 
-  /get-caller-file@2.0.5:
-    resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
-    engines: {node: 6.* || 8.* || >= 10.*}
+  get-caller-file@2.0.5: {}
 
-  /get-func-name@2.0.2:
-    resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
-    dev: true
+  get-func-name@2.0.2: {}
 
-  /get-intrinsic@1.2.1:
-    resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==}
+  get-intrinsic@1.2.1:
     dependencies:
       function-bind: 1.1.2
       has: 1.0.3
       has-proto: 1.0.1
       has-symbols: 1.0.3
 
-  /get-npm-tarball-url@2.0.3:
-    resolution: {integrity: sha512-R/PW6RqyaBQNWYaSyfrh54/qtcnOp22FHCCiRhSSZj0FP3KQWCsxxt0DzIdVTbwTqe9CtQfvl/FPD4UIPt4pqw==}
-    engines: {node: '>=12.17'}
-    dev: true
+  get-npm-tarball-url@2.0.3: {}
 
-  /get-package-type@0.1.0:
-    resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
-    engines: {node: '>=8.0.0'}
-    dev: true
+  get-package-type@0.1.0: {}
 
-  /get-pixels-frame-info-update@3.3.2:
-    resolution: {integrity: sha512-LzVij57X/gK4Y6LpcDdqj+R9WCpD6Sv3ZH85GMA+S3xgPGCz81mHql4GiSnF4GijRjk7TE0ja2sDr8FFYKLe2g==}
+  get-pixels-frame-info-update@3.3.2:
     dependencies:
       data-uri-to-buffer: 0.0.3
       jpeg-js: 0.3.7
@@ -12163,62 +18618,39 @@ packages:
       pngjs: 3.4.0
       request: 2.88.2
       through: 2.3.8
-    dev: false
 
-  /get-stream@3.0.0:
-    resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==}
-    engines: {node: '>=4'}
-    dev: false
+  get-stream@3.0.0: {}
 
-  /get-stream@5.2.0:
-    resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
-    engines: {node: '>=8'}
+  get-stream@5.2.0:
     dependencies:
       pump: 3.0.0
 
-  /get-stream@6.0.1:
-    resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
-    engines: {node: '>=10'}
+  get-stream@6.0.1: {}
 
-  /get-stream@8.0.1:
-    resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
-    engines: {node: '>=16'}
+  get-stream@8.0.1: {}
 
-  /get-symbol-description@1.0.0:
-    resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
-    engines: {node: '>= 0.4'}
+  get-symbol-description@1.0.0:
     dependencies:
       call-bind: 1.0.2
       get-intrinsic: 1.2.1
-    dev: true
 
-  /get-tsconfig@4.7.2:
-    resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==}
+  get-tsconfig@4.7.2:
     dependencies:
       resolve-pkg-maps: 1.0.0
-    dev: true
 
-  /getos@3.2.1:
-    resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==}
+  getos@3.2.1:
     dependencies:
       async: 3.2.4
-    dev: true
 
-  /getpass@0.1.7:
-    resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==}
+  getpass@0.1.7:
     dependencies:
       assert-plus: 1.0.0
 
-  /gif-encoder@0.4.1:
-    resolution: {integrity: sha512-++rNGpDBgWQ9eXj9JfTBLHMUEd7lDOdzIvFyHQM9yL8ffxkcg4G6jWmsgu/r59Uq6nHc3wcVwtgy3geLnIWunQ==}
-    engines: {node: '>= 0.8.0'}
+  gif-encoder@0.4.1:
     dependencies:
       readable-stream: 1.1.14
-    dev: false
 
-  /giget@1.1.2:
-    resolution: {integrity: sha512-HsLoS07HiQ5oqvObOI+Qb2tyZH4Gj5nYGfF9qQcZNrPw+uEFhdXtgJr01aO2pWadGHucajYDLxxbtQkm97ON2A==}
-    hasBin: true
+  giget@1.1.2:
     dependencies:
       colorette: 2.0.19
       defu: 6.1.4
@@ -12226,46 +18658,28 @@ packages:
       mri: 1.2.0
       node-fetch-native: 1.0.2
       pathe: 1.1.2
-      tar: 6.2.0
+      tar: 6.2.1
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /github-slugger@2.0.0:
-    resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==}
-    dev: true
+  github-slugger@2.0.0: {}
 
-  /glob-parent@5.1.2:
-    resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
-    engines: {node: '>= 6'}
+  glob-parent@5.1.2:
     dependencies:
       is-glob: 4.0.3
 
-  /glob-parent@6.0.2:
-    resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
-    engines: {node: '>=10.13.0'}
+  glob-parent@6.0.2:
     dependencies:
       is-glob: 4.0.3
-    dev: true
 
-  /glob-promise@4.2.2(glob@7.2.3):
-    resolution: {integrity: sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw==}
-    engines: {node: '>=12'}
-    peerDependencies:
-      glob: ^7.1.6
+  glob-promise@4.2.2(glob@7.2.3):
     dependencies:
       '@types/glob': 7.2.0
       glob: 7.2.3
-    dev: true
 
-  /glob-to-regexp@0.4.1:
-    resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
-    dev: true
+  glob-to-regexp@0.4.1: {}
 
-  /glob@10.3.10:
-    resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==}
-    engines: {node: '>=16 || 14 >=14.17'}
-    hasBin: true
+  glob@10.3.10:
     dependencies:
       foreground-child: 3.1.1
       jackspeak: 2.3.6
@@ -12273,8 +18687,15 @@ packages:
       minipass: 7.0.4
       path-scurry: 1.10.1
 
-  /glob@7.2.3:
-    resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+  glob@10.3.12:
+    dependencies:
+      foreground-child: 3.1.1
+      jackspeak: 2.3.6
+      minimatch: 9.0.3
+      minipass: 7.0.4
+      path-scurry: 1.10.2
+
+  glob@7.2.3:
     dependencies:
       fs.realpath: 1.0.0
       inflight: 1.0.6
@@ -12283,9 +18704,7 @@ packages:
       once: 1.4.0
       path-is-absolute: 1.0.1
 
-  /glob@8.1.0:
-    resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
-    engines: {node: '>=12'}
+  glob@8.1.0:
     dependencies:
       fs.realpath: 1.0.0
       inflight: 1.0.6
@@ -12293,35 +18712,25 @@ packages:
       minimatch: 5.1.2
       once: 1.4.0
 
-  /global-dirs@3.0.1:
-    resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==}
-    engines: {node: '>=10'}
+  global-dirs@3.0.1:
     dependencies:
       ini: 2.0.0
-    dev: true
 
-  /globals@11.12.0:
-    resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
-    engines: {node: '>=4'}
-    dev: true
+  globals@11.12.0: {}
 
-  /globals@13.19.0:
-    resolution: {integrity: sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==}
-    engines: {node: '>=8'}
+  globals@13.19.0:
     dependencies:
       type-fest: 0.20.2
-    dev: true
 
-  /globalthis@1.0.3:
-    resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
-    engines: {node: '>= 0.4'}
+  globals@13.24.0:
+    dependencies:
+      type-fest: 0.20.2
+
+  globalthis@1.0.3:
     dependencies:
       define-properties: 1.2.0
-    dev: true
 
-  /globby@11.1.0:
-    resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
-    engines: {node: '>=10'}
+  globby@11.1.0:
     dependencies:
       array-union: 2.1.0
       dir-glob: 3.0.1
@@ -12330,21 +18739,14 @@ packages:
       merge2: 1.4.1
       slash: 3.0.0
 
-  /google-protobuf@3.21.2:
-    resolution: {integrity: sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==}
-    requiresBuild: true
-    dev: false
+  google-protobuf@3.21.2:
     optional: true
 
-  /gopd@1.0.1:
-    resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
+  gopd@1.0.1:
     dependencies:
       get-intrinsic: 1.2.1
-    dev: true
 
-  /got@11.8.5:
-    resolution: {integrity: sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==}
-    engines: {node: '>=10.19.0'}
+  got@11.8.5:
     dependencies:
       '@sindresorhus/is': 4.6.0
       '@szmarczak/http-timer': 4.0.6
@@ -12357,11 +18759,8 @@ packages:
       lowercase-keys: 2.0.0
       p-cancelable: 2.1.1
       responselike: 2.0.1
-    dev: false
 
-  /got@12.6.1:
-    resolution: {integrity: sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==}
-    engines: {node: '>=14.16'}
+  got@12.6.1:
     dependencies:
       '@sindresorhus/is': 5.3.0
       '@szmarczak/http-timer': 5.0.1
@@ -12375,9 +18774,7 @@ packages:
       p-cancelable: 3.0.0
       responselike: 3.0.0
 
-  /got@14.2.0:
-    resolution: {integrity: sha512-dBq2KkHcQl3AwPoIWsLsQScCPpUgRulz1qZVthjPYKYOPmYfBnekR3vxecjZbm91Vc3JUGnV9mqFX7B+Fe2quw==}
-    engines: {node: '>=20'}
+  got@14.2.1:
     dependencies:
       '@sindresorhus/is': 6.1.0
       '@szmarczak/http-timer': 5.0.1
@@ -12390,27 +18787,16 @@ packages:
       lowercase-keys: 3.0.0
       p-cancelable: 4.0.1
       responselike: 3.0.0
-    dev: false
 
-  /graceful-fs@4.2.11:
-    resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+  graceful-fs@4.2.11: {}
 
-  /grapheme-splitter@1.0.4:
-    resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==}
-    dev: true
+  grapheme-splitter@1.0.4: {}
 
-  /graphemer@1.4.0:
-    resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
-    dev: true
+  graphemer@1.4.0: {}
 
-  /graphql@16.8.1:
-    resolution: {integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==}
-    engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0}
-    dev: true
+  graphql@16.8.1: {}
 
-  /gunzip-maybe@1.4.2:
-    resolution: {integrity: sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==}
-    hasBin: true
+  gunzip-maybe@1.4.2:
     dependencies:
       browserify-zlib: 0.1.4
       is-deflate: 1.0.0
@@ -12418,17 +18804,10 @@ packages:
       peek-stream: 1.1.3
       pumpify: 1.5.1
       through2: 2.0.5
-    dev: true
 
-  /hammerjs@2.0.8:
-    resolution: {integrity: sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==}
-    engines: {node: '>=0.8.0'}
-    dev: false
+  hammerjs@2.0.8: {}
 
-  /handlebars@4.7.7:
-    resolution: {integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==}
-    engines: {node: '>=0.4.7'}
-    hasBin: true
+  handlebars@4.7.7:
     dependencies:
       minimist: 1.2.8
       neo-async: 2.6.2
@@ -12436,196 +18815,105 @@ packages:
       wordwrap: 1.0.0
     optionalDependencies:
       uglify-js: 3.17.4
-    dev: true
 
-  /happy-dom@10.0.3:
-    resolution: {integrity: sha512-WkCP+Z5fX6U5PY+yHP3ElV5D9PoxRAHRWPFq3pG9rg/6Hjf5ak7dozAgSCywsTRUq2qfa8vV8OQvUy5pRXy8EQ==}
-    dependencies:
-      css.escape: 1.5.1
-      entities: 4.5.0
-      iconv-lite: 0.6.3
-      webidl-conversions: 7.0.0
-      whatwg-encoding: 2.0.0
-      whatwg-mimetype: 3.0.0
-    dev: false
-
-  /happy-dom@13.6.2:
-    resolution: {integrity: sha512-Ku+wDqcF/KwFA0dI+xIMZd9Jn020RXjuSil/Vz7gu2yhDC3FsDYZ55qqV9k+SGC4opwb4acisXqVSRxUJMlPbQ==}
-    engines: {node: '>=16.0.0'}
+  happy-dom@14.7.1:
     dependencies:
       entities: 4.5.0
       webidl-conversions: 7.0.0
       whatwg-mimetype: 3.0.0
-    dev: true
 
-  /har-schema@2.0.0:
-    resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==}
-    engines: {node: '>=4'}
-    dev: false
+  har-schema@2.0.0: {}
 
-  /har-validator@5.1.5:
-    resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==}
-    engines: {node: '>=6'}
-    deprecated: this library is no longer supported
+  har-validator@5.1.5:
     dependencies:
       ajv: 6.12.6
       har-schema: 2.0.0
-    dev: false
 
-  /hard-rejection@2.1.0:
-    resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==}
-    engines: {node: '>=6'}
-    dev: true
+  hard-rejection@2.1.0: {}
 
-  /has-bigints@1.0.2:
-    resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
-    dev: true
+  has-bigints@1.0.2: {}
 
-  /has-flag@3.0.0:
-    resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
-    engines: {node: '>=4'}
-    dev: true
+  has-flag@3.0.0: {}
 
-  /has-flag@4.0.0:
-    resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
-    engines: {node: '>=8'}
+  has-flag@4.0.0: {}
 
-  /has-property-descriptors@1.0.0:
-    resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
+  has-property-descriptors@1.0.0:
     dependencies:
       get-intrinsic: 1.2.1
-    dev: true
 
-  /has-proto@1.0.1:
-    resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
-    engines: {node: '>= 0.4'}
+  has-proto@1.0.1: {}
 
-  /has-symbols@1.0.3:
-    resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
-    engines: {node: '>= 0.4'}
+  has-symbols@1.0.3: {}
 
-  /has-tostringtag@1.0.0:
-    resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==}
-    engines: {node: '>= 0.4'}
+  has-tostringtag@1.0.0:
     dependencies:
       has-symbols: 1.0.3
 
-  /has-unicode@2.0.1:
-    resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
-    requiresBuild: true
-    dev: false
+  has-unicode@2.0.1:
     optional: true
 
-  /has@1.0.3:
-    resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
-    engines: {node: '>= 0.4.0'}
+  has@1.0.3:
     dependencies:
       function-bind: 1.1.2
 
-  /hash-sum@2.0.0:
-    resolution: {integrity: sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==}
-    dev: true
+  hash-sum@2.0.0: {}
 
-  /hashlru@2.3.0:
-    resolution: {integrity: sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A==}
-    dev: false
+  hashlru@2.3.0: {}
 
-  /hasown@2.0.0:
-    resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==}
-    engines: {node: '>= 0.4'}
+  hasown@2.0.0:
     dependencies:
       function-bind: 1.1.2
 
-  /hast-util-heading-rank@3.0.0:
-    resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==}
+  hast-util-heading-rank@3.0.0:
     dependencies:
       '@types/hast': 3.0.4
-    dev: true
 
-  /hast-util-is-element@3.0.0:
-    resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==}
+  hast-util-is-element@3.0.0:
     dependencies:
       '@types/hast': 3.0.4
-    dev: true
 
-  /hast-util-to-string@3.0.0:
-    resolution: {integrity: sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==}
+  hast-util-to-string@3.0.0:
     dependencies:
       '@types/hast': 3.0.4
-    dev: true
 
-  /he@1.2.0:
-    resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
-    hasBin: true
-    dev: true
+  he@1.2.0: {}
 
-  /headers-polyfill@4.0.2:
-    resolution: {integrity: sha512-EWGTfnTqAO2L/j5HZgoM/3z82L7necsJ0pO9Tp0X1wil3PDLrkypTBRgVO2ExehEEvUycejZD3FuRaXpZZc3kw==}
-    dev: true
+  headers-polyfill@4.0.2: {}
 
-  /highlight.js@10.7.3:
-    resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==}
-    dev: false
+  highlight.js@10.7.3: {}
 
-  /highlight.js@11.9.0:
-    resolution: {integrity: sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==}
-    engines: {node: '>=12.0.0'}
-    dev: false
+  highlight.js@11.9.0: {}
 
-  /hosted-git-info@2.8.9:
-    resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
-    dev: true
+  hosted-git-info@2.8.9: {}
 
-  /hosted-git-info@4.1.0:
-    resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==}
-    engines: {node: '>=10'}
+  hosted-git-info@4.1.0:
     dependencies:
       lru-cache: 6.0.0
-    dev: true
 
-  /hpagent@1.2.0:
-    resolution: {integrity: sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==}
-    engines: {node: '>=14'}
-    dev: false
+  hpagent@1.2.0: {}
 
-  /html-encoding-sniffer@4.0.0:
-    resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
-    engines: {node: '>=18'}
+  html-encoding-sniffer@4.0.0:
     dependencies:
       whatwg-encoding: 3.1.1
-    dev: false
 
-  /html-entities@2.3.2:
-    resolution: {integrity: sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==}
+  html-entities@2.3.2: {}
 
-  /html-escaper@2.0.2:
-    resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
-    dev: true
+  html-escaper@2.0.2: {}
 
-  /html-tags@3.2.0:
-    resolution: {integrity: sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==}
-    engines: {node: '>=8'}
-    dev: true
+  html-tags@3.2.0: {}
 
-  /htmlescape@1.1.1:
-    resolution: {integrity: sha512-eVcrzgbR4tim7c7soKQKtxa/kQM4TzjnlU83rcZ9bHU6t31ehfV7SktN6McWgwPWg+JYMA/O3qpGxBvFq1z2Jg==}
-    engines: {node: '>=0.10'}
-    dev: false
+  htmlescape@1.1.1: {}
 
-  /htmlparser2@8.0.1:
-    resolution: {integrity: sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==}
+  htmlparser2@8.0.1:
     dependencies:
       domelementtype: 2.3.0
       domhandler: 5.0.3
       domutils: 3.0.1
       entities: 4.5.0
 
-  /http-cache-semantics@4.1.1:
-    resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
+  http-cache-semantics@4.1.1: {}
 
-  /http-errors@2.0.0:
-    resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
-    engines: {node: '>= 0.8'}
+  http-errors@2.0.0:
     dependencies:
       depd: 2.0.0
       inherits: 2.0.4
@@ -12633,244 +18921,135 @@ packages:
       statuses: 2.0.1
       toidentifier: 1.0.1
 
-  /http-link-header@1.1.2:
-    resolution: {integrity: sha512-6qz1XhMq/ryde52SZGzVhzi3jcG2KqO16KITkupyQxvW6u7iylm0Fq7r3OpCYsc0S0ELlCiFpuxDcccUwjbEqA==}
-    engines: {node: '>=6.0.0'}
-    dev: false
+  http-link-header@1.1.3: {}
 
-  /http-proxy-agent@7.0.0:
-    resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==}
-    engines: {node: '>= 14'}
+  http-proxy-agent@7.0.0:
     dependencies:
       agent-base: 7.1.0
       debug: 4.3.4(supports-color@8.1.1)
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /http-signature@1.2.0:
-    resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==}
-    engines: {node: '>=0.8', npm: '>=1.3.7'}
+  http-signature@1.2.0:
     dependencies:
       assert-plus: 1.0.0
       jsprim: 1.4.2
       sshpk: 1.17.0
-    dev: false
 
-  /http-signature@1.3.6:
-    resolution: {integrity: sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==}
-    engines: {node: '>=0.10'}
+  http-signature@1.3.6:
     dependencies:
       assert-plus: 1.0.0
       jsprim: 2.0.2
       sshpk: 1.17.0
-    dev: true
 
-  /http2-wrapper@1.0.3:
-    resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==}
-    engines: {node: '>=10.19.0'}
-    dependencies:
-      quick-lru: 5.1.1
-      resolve-alpn: 1.2.1
-    dev: false
-
-  /http2-wrapper@2.2.1:
-    resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==}
-    engines: {node: '>=10.19.0'}
+  http2-wrapper@1.0.3:
     dependencies:
       quick-lru: 5.1.1
       resolve-alpn: 1.2.1
 
-  /http_ece@1.2.0:
-    resolution: {integrity: sha512-JrF8SSLVmcvc5NducxgyOrKXe3EsyHMgBFgSaIUGmArKe+rwr0uphRkRXvwiom3I+fpIfoItveHrfudL8/rxuA==}
-    engines: {node: '>=16'}
-    dev: false
+  http2-wrapper@2.2.1:
+    dependencies:
+      quick-lru: 5.1.1
+      resolve-alpn: 1.2.1
 
-  /https-proxy-agent@2.2.4:
-    resolution: {integrity: sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==}
-    engines: {node: '>= 4.5.0'}
-    requiresBuild: true
+  http_ece@1.2.0: {}
+
+  https-proxy-agent@2.2.4:
     dependencies:
       agent-base: 4.3.0
       debug: 3.2.7(supports-color@8.1.1)
     transitivePeerDependencies:
       - supports-color
-    dev: false
     optional: true
 
-  /https-proxy-agent@5.0.1:
-    resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
-    engines: {node: '>= 6'}
+  https-proxy-agent@5.0.1:
     dependencies:
       agent-base: 6.0.2
       debug: 4.3.4(supports-color@8.1.1)
     transitivePeerDependencies:
       - supports-color
 
-  /https-proxy-agent@7.0.2:
-    resolution: {integrity: sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==}
-    engines: {node: '>= 14'}
+  https-proxy-agent@7.0.2:
     dependencies:
       agent-base: 7.1.0
       debug: 4.3.4(supports-color@8.1.1)
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /human-signals@1.1.1:
-    resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==}
-    engines: {node: '>=8.12.0'}
-    dev: true
+  human-signals@1.1.1: {}
 
-  /human-signals@2.1.0:
-    resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
-    engines: {node: '>=10.17.0'}
+  human-signals@2.1.0: {}
 
-  /human-signals@3.0.1:
-    resolution: {integrity: sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==}
-    engines: {node: '>=12.20.0'}
-    dev: true
+  human-signals@3.0.1: {}
 
-  /human-signals@5.0.0:
-    resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
-    engines: {node: '>=16.17.0'}
+  human-signals@5.0.0: {}
 
-  /iconv-lite@0.4.24:
-    resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
-    engines: {node: '>=0.10.0'}
+  iconv-lite@0.4.24:
     dependencies:
       safer-buffer: 2.1.2
 
-  /iconv-lite@0.6.3:
-    resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
-    engines: {node: '>=0.10.0'}
+  iconv-lite@0.6.3:
     dependencies:
       safer-buffer: 2.1.2
 
-  /idb-keyval@6.2.1:
-    resolution: {integrity: sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==}
-    dev: false
+  idb-keyval@6.2.1: {}
 
-  /ieee754@1.2.1:
-    resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+  ieee754@1.2.1: {}
 
-  /ignore-by-default@1.0.1:
-    resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
-    dev: true
+  ignore-by-default@1.0.1: {}
 
-  /ignore-walk@6.0.4:
-    resolution: {integrity: sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==}
-    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+  ignore-walk@6.0.4:
     dependencies:
       minimatch: 9.0.3
-    dev: false
 
-  /ignore@5.2.4:
-    resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
-    engines: {node: '>= 4'}
+  ignore@5.2.4: {}
 
-  /immutable@4.2.2:
-    resolution: {integrity: sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og==}
+  ignore@5.3.1: {}
 
-  /import-fresh@3.3.0:
-    resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
-    engines: {node: '>=6'}
+  immutable@4.2.2: {}
+
+  import-fresh@3.3.0:
     dependencies:
       parent-module: 1.0.1
       resolve-from: 4.0.0
-    dev: true
 
-  /import-lazy@4.0.0:
-    resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==}
-    engines: {node: '>=8'}
-    dev: true
+  import-lazy@4.0.0: {}
 
-  /import-local@3.1.0:
-    resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==}
-    engines: {node: '>=8'}
-    hasBin: true
+  import-local@3.1.0:
     dependencies:
       pkg-dir: 4.2.0
       resolve-cwd: 3.0.0
-    dev: true
 
-  /imurmurhash@0.1.4:
-    resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
-    engines: {node: '>=0.8.19'}
+  imurmurhash@0.1.4: {}
 
-  /indent-string@4.0.0:
-    resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
-    engines: {node: '>=8'}
+  indent-string@4.0.0: {}
 
-  /indent-string@5.0.0:
-    resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==}
-    engines: {node: '>=12'}
-    dev: true
+  indent-string@5.0.0: {}
 
-  /inflight@1.0.6:
-    resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+  inflight@1.0.6:
     dependencies:
       once: 1.4.0
       wrappy: 1.0.2
 
-  /inherits@2.0.4:
-    resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+  inherits@2.0.4: {}
 
-  /ini@1.3.8:
-    resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
-    dev: true
+  ini@1.3.8: {}
 
-  /ini@2.0.0:
-    resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==}
-    engines: {node: '>=10'}
-    dev: true
+  ini@2.0.0: {}
 
-  /inquirer@8.2.5:
-    resolution: {integrity: sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==}
-    engines: {node: '>=12.0.0'}
-    dependencies:
-      ansi-escapes: 4.3.2
-      chalk: 4.1.2
-      cli-cursor: 3.1.0
-      cli-width: 3.0.0
-      external-editor: 3.1.0
-      figures: 3.2.0
-      lodash: 4.17.21
-      mute-stream: 0.0.8
-      ora: 5.4.1
-      run-async: 2.4.1
-      rxjs: 7.8.1
-      string-width: 4.2.3
-      strip-ansi: 6.0.1
-      through: 2.3.8
-      wrap-ansi: 7.0.0
-    dev: true
+  insert-text-at-cursor@0.3.0: {}
 
-  /insert-text-at-cursor@0.3.0:
-    resolution: {integrity: sha512-/nPtyeX9xPUvxZf+r0518B7uqNKlP+LqNJqSiXFEaa2T71rWIwTVXGH7hB9xO/EVdwa5/pWlFCPwShOW81XIxQ==}
-    dev: false
+  install-artifact-from-github@1.3.5: {}
 
-  /install-artifact-from-github@1.3.5:
-    resolution: {integrity: sha512-gZHC7f/cJgXz7MXlHFBxPVMsvIbev1OQN1uKQYKVJDydGNm9oYf9JstbU4Atnh/eSvk41WtEovoRm+8IF686xg==}
-    hasBin: true
-    dev: false
-
-  /internal-slot@1.0.5:
-    resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==}
-    engines: {node: '>= 0.4'}
+  internal-slot@1.0.5:
     dependencies:
       get-intrinsic: 1.2.1
       has: 1.0.3
       side-channel: 1.0.4
-    dev: true
 
-  /intersection-observer@0.12.2:
-    resolution: {integrity: sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==}
-    dev: true
+  intersection-observer@0.12.2: {}
 
-  /ioredis@5.3.2:
-    resolution: {integrity: sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==}
-    engines: {node: '>=12.22.0'}
+  ioredis@5.4.1:
     dependencies:
       '@ioredis/commands': 1.2.0
       cluster-key-slot: 1.1.2
@@ -12883,492 +19062,289 @@ packages:
       standard-as-callback: 2.1.0
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /iota-array@1.0.0:
-    resolution: {integrity: sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==}
-    dev: false
+  iota-array@1.0.0: {}
 
-  /ip-address@7.1.0:
-    resolution: {integrity: sha512-V9pWC/VJf2lsXqP7IWJ+pe3P1/HCYGBMZrrnT62niLGjAfCbeiwXMUxaeHvnVlz19O27pvXP4azs+Pj/A0x+SQ==}
-    engines: {node: '>= 10'}
+  ip-address@7.1.0:
     dependencies:
       jsbn: 1.1.0
       sprintf-js: 1.1.2
-    dev: false
 
-  /ip-cidr@3.1.0:
-    resolution: {integrity: sha512-HUCn4snshEX1P8cja/IyU3qk8FVDW8T5zZcegDFbu4w7NojmAhk5NcOgj3M8+0fmumo1afJTPDtJlzsxLdOjtg==}
-    engines: {node: '>=10.0.0'}
+  ip-cidr@3.1.0:
     dependencies:
       ip-address: 7.1.0
       jsbn: 1.1.0
-    dev: false
 
-  /ip-regex@4.3.0:
-    resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==}
-    engines: {node: '>=8'}
+  ip-regex@4.3.0: {}
 
-  /ip@2.0.0:
-    resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==}
-    dev: false
+  ip@2.0.1: {}
 
-  /ip@2.0.1:
-    resolution: {integrity: sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==}
-    dev: true
+  ipaddr.js@1.9.1: {}
 
-  /ipaddr.js@1.9.1:
-    resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
-    engines: {node: '>= 0.10'}
+  ipaddr.js@2.2.0: {}
 
-  /ipaddr.js@2.1.0:
-    resolution: {integrity: sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==}
-    engines: {node: '>= 10'}
+  irregular-plurals@3.5.0: {}
 
-  /irregular-plurals@3.5.0:
-    resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==}
-    engines: {node: '>=8'}
-    dev: true
+  is-absolute-url@4.0.1: {}
 
-  /is-absolute-url@4.0.1:
-    resolution: {integrity: sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
-    dev: true
-
-  /is-arguments@1.1.1:
-    resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==}
-    engines: {node: '>= 0.4'}
+  is-arguments@1.1.1:
     dependencies:
       call-bind: 1.0.2
       has-tostringtag: 1.0.0
-    dev: true
 
-  /is-array-buffer@3.0.2:
-    resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==}
+  is-array-buffer@3.0.2:
     dependencies:
       call-bind: 1.0.2
       get-intrinsic: 1.2.1
       is-typed-array: 1.1.10
-    dev: true
 
-  /is-arrayish@0.2.1:
-    resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
-    dev: true
+  is-arrayish@0.2.1: {}
 
-  /is-arrayish@0.3.2:
-    resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
-    dev: false
+  is-arrayish@0.3.2: {}
 
-  /is-bigint@1.0.4:
-    resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
+  is-bigint@1.0.4:
     dependencies:
       has-bigints: 1.0.2
-    dev: true
 
-  /is-binary-path@2.1.0:
-    resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
-    engines: {node: '>=8'}
+  is-binary-path@2.1.0:
     dependencies:
       binary-extensions: 2.2.0
 
-  /is-boolean-object@1.1.2:
-    resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
-    engines: {node: '>= 0.4'}
+  is-boolean-object@1.1.2:
     dependencies:
       call-bind: 1.0.2
       has-tostringtag: 1.0.0
-    dev: true
 
-  /is-buffer@1.1.6:
-    resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
-    dev: false
+  is-buffer@1.1.6: {}
 
-  /is-callable@1.2.7:
-    resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
-    engines: {node: '>= 0.4'}
-    dev: true
+  is-callable@1.2.7: {}
 
-  /is-ci@3.0.1:
-    resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==}
-    hasBin: true
+  is-ci@3.0.1:
     dependencies:
       ci-info: 3.7.1
-    dev: true
 
-  /is-core-module@2.13.1:
-    resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
+  is-core-module@2.13.1:
     dependencies:
       hasown: 2.0.0
 
-  /is-date-object@1.0.5:
-    resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
-    engines: {node: '>= 0.4'}
+  is-date-object@1.0.5:
     dependencies:
       has-tostringtag: 1.0.0
-    dev: true
 
-  /is-deflate@1.0.0:
-    resolution: {integrity: sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ==}
-    dev: true
+  is-deflate@1.0.0: {}
 
-  /is-docker@2.2.1:
-    resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==}
-    engines: {node: '>=8'}
-    hasBin: true
-    dev: true
+  is-docker@2.2.1: {}
 
-  /is-expression@4.0.0:
-    resolution: {integrity: sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==}
+  is-expression@4.0.0:
     dependencies:
       acorn: 7.4.1
       object-assign: 4.1.1
 
-  /is-extglob@2.1.1:
-    resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
-    engines: {node: '>=0.10.0'}
+  is-extglob@2.1.1: {}
 
-  /is-file-animated@1.0.2:
-    resolution: {integrity: sha512-TAYDUkvyBmxqneRU26zzpeHLAgtzEOIsRQWrtDidPT/tFK3Yc0WKgtF3u4oOEAiN0kAuVfl7MTgbD0vXdFDztA==}
-    dev: false
+  is-file-animated@1.0.2: {}
 
-  /is-fullwidth-code-point@3.0.0:
-    resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
-    engines: {node: '>=8'}
+  is-fullwidth-code-point@3.0.0: {}
 
-  /is-generator-fn@2.1.0:
-    resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
-    engines: {node: '>=6'}
-    dev: true
+  is-generator-fn@2.1.0: {}
 
-  /is-generator-function@1.0.10:
-    resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==}
-    engines: {node: '>= 0.4'}
+  is-generator-function@1.0.10:
     dependencies:
       has-tostringtag: 1.0.0
-    dev: true
 
-  /is-glob@4.0.3:
-    resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
-    engines: {node: '>=0.10.0'}
+  is-glob@4.0.3:
     dependencies:
       is-extglob: 2.1.1
 
-  /is-gzip@1.0.0:
-    resolution: {integrity: sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ==}
-    engines: {node: '>=0.10.0'}
-    dev: true
+  is-gzip@1.0.0: {}
 
-  /is-installed-globally@0.4.0:
-    resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==}
-    engines: {node: '>=10'}
+  is-installed-globally@0.4.0:
     dependencies:
       global-dirs: 3.0.1
       is-path-inside: 3.0.3
-    dev: true
 
-  /is-interactive@1.0.0:
-    resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==}
-    engines: {node: '>=8'}
-    dev: true
+  is-interactive@1.0.0: {}
 
-  /is-ip@3.1.0:
-    resolution: {integrity: sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==}
-    engines: {node: '>=8'}
+  is-ip@3.1.0:
     dependencies:
       ip-regex: 4.3.0
 
-  /is-lambda@1.0.1:
-    resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==}
-    dev: false
+  is-lambda@1.0.1: {}
 
-  /is-map@2.0.2:
-    resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==}
-    dev: true
+  is-map@2.0.2: {}
 
-  /is-nan@1.3.2:
-    resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==}
-    engines: {node: '>= 0.4'}
+  is-nan@1.3.2:
     dependencies:
       call-bind: 1.0.2
       define-properties: 1.2.0
-    dev: true
 
-  /is-negative-zero@2.0.2:
-    resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==}
-    engines: {node: '>= 0.4'}
-    dev: true
+  is-negative-zero@2.0.2: {}
 
-  /is-node-process@1.2.0:
-    resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==}
-    dev: true
+  is-node-process@1.2.0: {}
 
-  /is-number-object@1.0.7:
-    resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
-    engines: {node: '>= 0.4'}
+  is-number-object@1.0.7:
     dependencies:
       has-tostringtag: 1.0.0
-    dev: true
 
-  /is-number@7.0.0:
-    resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
-    engines: {node: '>=0.12.0'}
+  is-number@7.0.0: {}
 
-  /is-path-cwd@2.2.0:
-    resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==}
-    engines: {node: '>=6'}
-    dev: true
+  is-path-cwd@2.2.0: {}
 
-  /is-path-inside@3.0.3:
-    resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
-    engines: {node: '>=8'}
-    dev: true
+  is-path-inside@3.0.3: {}
 
-  /is-plain-obj@1.1.0:
-    resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==}
-    engines: {node: '>=0.10.0'}
+  is-plain-obj@1.1.0: {}
 
-  /is-plain-obj@4.1.0:
-    resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
-    engines: {node: '>=12'}
-    dev: true
+  is-plain-obj@4.1.0: {}
 
-  /is-plain-object@2.0.4:
-    resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
-    engines: {node: '>=0.10.0'}
+  is-plain-object@2.0.4:
     dependencies:
       isobject: 3.0.1
-    dev: true
 
-  /is-plain-object@5.0.0:
-    resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
-    engines: {node: '>=0.10.0'}
+  is-plain-object@5.0.0: {}
 
-  /is-potential-custom-element-name@1.0.1:
-    resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
-    dev: false
+  is-potential-custom-element-name@1.0.1: {}
 
-  /is-promise@2.2.2:
-    resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==}
+  is-promise@2.2.2: {}
 
-  /is-regex@1.1.4:
-    resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
-    engines: {node: '>= 0.4'}
+  is-regex@1.1.4:
     dependencies:
       call-bind: 1.0.2
       has-tostringtag: 1.0.0
 
-  /is-set@2.0.2:
-    resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==}
-    dev: true
+  is-set@2.0.2: {}
 
-  /is-shared-array-buffer@1.0.2:
-    resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==}
+  is-shared-array-buffer@1.0.2:
     dependencies:
       call-bind: 1.0.2
-    dev: true
 
-  /is-stream@1.1.0:
-    resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==}
-    engines: {node: '>=0.10.0'}
-    dev: false
+  is-stream@1.1.0: {}
 
-  /is-stream@2.0.1:
-    resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
-    engines: {node: '>=8'}
+  is-stream@2.0.1: {}
 
-  /is-stream@3.0.0:
-    resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+  is-stream@3.0.0: {}
 
-  /is-string@1.0.7:
-    resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
-    engines: {node: '>= 0.4'}
+  is-string@1.0.7:
     dependencies:
       has-tostringtag: 1.0.0
-    dev: true
 
-  /is-svg@5.0.0:
-    resolution: {integrity: sha512-sRl7J0oX9yUNamSdc8cwgzh9KBLnQXNzGmW0RVHwg/jEYjGNYHC6UvnYD8+hAeut9WwxRvhG9biK7g/wDGxcMw==}
-    engines: {node: '>=14.16'}
+  is-svg@5.0.0:
     dependencies:
       fast-xml-parser: 4.2.5
-    dev: false
 
-  /is-symbol@1.0.4:
-    resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==}
-    engines: {node: '>= 0.4'}
+  is-symbol@1.0.4:
     dependencies:
       has-symbols: 1.0.3
-    dev: true
 
-  /is-typed-array@1.1.10:
-    resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==}
-    engines: {node: '>= 0.4'}
+  is-typed-array@1.1.10:
     dependencies:
       available-typed-arrays: 1.0.5
       call-bind: 1.0.2
       for-each: 0.3.3
       gopd: 1.0.1
       has-tostringtag: 1.0.0
-    dev: true
 
-  /is-typedarray@1.0.0:
-    resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}
+  is-typedarray@1.0.0: {}
 
-  /is-unicode-supported@0.1.0:
-    resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
-    engines: {node: '>=10'}
-    dev: true
+  is-unicode-supported@0.1.0: {}
 
-  /is-weakmap@2.0.1:
-    resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==}
-    dev: true
+  is-weakmap@2.0.1: {}
 
-  /is-weakref@1.0.2:
-    resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
+  is-weakref@1.0.2:
     dependencies:
       call-bind: 1.0.2
-    dev: true
 
-  /is-weakset@2.0.2:
-    resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==}
+  is-weakset@2.0.2:
     dependencies:
       call-bind: 1.0.2
       get-intrinsic: 1.2.1
-    dev: true
 
-  /is-wsl@2.2.0:
-    resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
-    engines: {node: '>=8'}
+  is-wsl@2.2.0:
     dependencies:
       is-docker: 2.2.1
-    dev: true
 
-  /isarray@0.0.1:
-    resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==}
+  isarray@0.0.1: {}
 
-  /isarray@1.0.0:
-    resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
+  isarray@1.0.0: {}
 
-  /isarray@2.0.5:
-    resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
-    dev: true
+  isarray@2.0.5: {}
 
-  /isexe@2.0.0:
-    resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+  isexe@2.0.0: {}
 
-  /isexe@3.1.1:
-    resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==}
-    engines: {node: '>=16'}
-    dev: false
+  isexe@3.1.1: {}
 
-  /isobject@3.0.1:
-    resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==}
-    engines: {node: '>=0.10.0'}
-    dev: true
+  isobject@3.0.1: {}
 
-  /isstream@0.1.2:
-    resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==}
+  isstream@0.1.2: {}
 
-  /istanbul-lib-coverage@3.2.2:
-    resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
-    engines: {node: '>=8'}
-    dev: true
+  istanbul-lib-coverage@3.2.2: {}
 
-  /istanbul-lib-instrument@5.2.1:
-    resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==}
-    engines: {node: '>=8'}
+  istanbul-lib-instrument@5.2.1:
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/parser': 7.23.9
+      '@babel/core': 7.24.0
+      '@babel/parser': 7.24.0
       '@istanbuljs/schema': 0.1.3
       istanbul-lib-coverage: 3.2.2
       semver: 6.3.1
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /istanbul-lib-instrument@6.0.0:
-    resolution: {integrity: sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==}
-    engines: {node: '>=10'}
+  istanbul-lib-instrument@6.0.0:
     dependencies:
-      '@babel/core': 7.23.5
-      '@babel/parser': 7.23.9
+      '@babel/core': 7.24.0
+      '@babel/parser': 7.24.0
       '@istanbuljs/schema': 0.1.3
       istanbul-lib-coverage: 3.2.2
       semver: 7.6.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /istanbul-lib-report@3.0.1:
-    resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
-    engines: {node: '>=10'}
+  istanbul-lib-report@3.0.1:
     dependencies:
       istanbul-lib-coverage: 3.2.2
       make-dir: 4.0.0
       supports-color: 7.2.0
-    dev: true
 
-  /istanbul-lib-source-maps@4.0.1:
-    resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
-    engines: {node: '>=10'}
+  istanbul-lib-source-maps@4.0.1:
     dependencies:
       debug: 4.3.4(supports-color@8.1.1)
       istanbul-lib-coverage: 3.2.2
       source-map: 0.6.1
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /istanbul-reports@3.1.6:
-    resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==}
-    engines: {node: '>=8'}
+  istanbul-reports@3.1.6:
     dependencies:
       html-escaper: 2.0.2
       istanbul-lib-report: 3.0.1
-    dev: true
 
-  /iterare@1.2.1:
-    resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==}
-    engines: {node: '>=6'}
+  iterare@1.2.1: {}
 
-  /jackspeak@2.3.6:
-    resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
-    engines: {node: '>=14'}
+  jackspeak@2.3.6:
     dependencies:
       '@isaacs/cliui': 8.0.2
     optionalDependencies:
       '@pkgjs/parseargs': 0.11.0
 
-  /jake@10.8.5:
-    resolution: {integrity: sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==}
-    engines: {node: '>=10'}
-    hasBin: true
+  jake@10.8.5:
     dependencies:
       async: 3.2.4
       chalk: 4.1.2
       filelist: 1.0.4
       minimatch: 3.1.2
 
-  /jest-changed-files@29.7.0:
-    resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-changed-files@29.7.0:
     dependencies:
       execa: 5.1.1
       jest-util: 29.7.0
       p-limit: 3.1.0
-    dev: true
 
-  /jest-circus@29.7.0:
-    resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-circus@29.7.0:
     dependencies:
       '@jest/environment': 29.7.0
       '@jest/expect': 29.7.0
       '@jest/test-result': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       chalk: 4.1.2
       co: 4.6.0
       dedent: 1.3.0
@@ -13387,26 +19363,17 @@ packages:
     transitivePeerDependencies:
       - babel-plugin-macros
       - supports-color
-    dev: true
 
-  /jest-cli@29.7.0(@types/node@20.11.22):
-    resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-    hasBin: true
-    peerDependencies:
-      node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
-    peerDependenciesMeta:
-      node-notifier:
-        optional: true
+  jest-cli@29.7.0(@types/node@20.12.7):
     dependencies:
       '@jest/core': 29.7.0
       '@jest/test-result': 29.7.0
       '@jest/types': 29.6.3
       chalk: 4.1.2
-      create-jest: 29.7.0(@types/node@20.11.22)
+      create-jest: 29.7.0(@types/node@20.12.7)
       exit: 0.1.2
       import-local: 3.1.0
-      jest-config: 29.7.0(@types/node@20.11.22)
+      jest-config: 29.7.0(@types/node@20.12.7)
       jest-util: 29.7.0
       jest-validate: 29.7.0
       yargs: 17.7.2
@@ -13415,24 +19382,12 @@ packages:
       - babel-plugin-macros
       - supports-color
       - ts-node
-    dev: true
 
-  /jest-config@29.7.0(@types/node@20.11.22):
-    resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-    peerDependencies:
-      '@types/node': '*'
-      ts-node: '>=9.0.0'
-    peerDependenciesMeta:
-      '@types/node':
-        optional: true
-      ts-node:
-        optional: true
+  jest-config@29.7.0(@types/node@20.12.7):
     dependencies:
       '@babel/core': 7.23.5
       '@jest/test-sequencer': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.11.22
       babel-jest: 29.7.0(@babel/core@7.23.5)
       chalk: 4.1.2
       ci-info: 3.7.1
@@ -13452,72 +19407,54 @@ packages:
       pretty-format: 29.7.0
       slash: 3.0.0
       strip-json-comments: 3.1.1
+    optionalDependencies:
+      '@types/node': 20.12.7
     transitivePeerDependencies:
       - babel-plugin-macros
       - supports-color
-    dev: true
 
-  /jest-diff@29.7.0:
-    resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-diff@29.7.0:
     dependencies:
       chalk: 4.1.2
       diff-sequences: 29.6.3
       jest-get-type: 29.6.3
       pretty-format: 29.7.0
-    dev: true
 
-  /jest-docblock@29.7.0:
-    resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-docblock@29.7.0:
     dependencies:
       detect-newline: 3.1.0
-    dev: true
 
-  /jest-each@29.7.0:
-    resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-each@29.7.0:
     dependencies:
       '@jest/types': 29.6.3
       chalk: 4.1.2
       jest-get-type: 29.6.3
       jest-util: 29.7.0
       pretty-format: 29.7.0
-    dev: true
 
-  /jest-environment-node@29.7.0:
-    resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-environment-node@29.7.0:
     dependencies:
       '@jest/environment': 29.7.0
       '@jest/fake-timers': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       jest-mock: 29.7.0
       jest-util: 29.7.0
-    dev: true
 
-  /jest-fetch-mock@3.0.3:
-    resolution: {integrity: sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==}
+  jest-fetch-mock@3.0.3(encoding@0.1.13):
     dependencies:
-      cross-fetch: 3.1.6
+      cross-fetch: 3.1.6(encoding@0.1.13)
       promise-polyfill: 8.3.0
     transitivePeerDependencies:
       - encoding
-    dev: true
 
-  /jest-get-type@29.6.3:
-    resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-    dev: true
+  jest-get-type@29.6.3: {}
 
-  /jest-haste-map@29.7.0:
-    resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-haste-map@29.7.0:
     dependencies:
       '@jest/types': 29.6.3
       '@types/graceful-fs': 4.1.6
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       anymatch: 3.1.3
       fb-watchman: 2.0.2
       graceful-fs: 4.2.11
@@ -13528,29 +19465,20 @@ packages:
       walker: 1.0.8
     optionalDependencies:
       fsevents: 2.3.3
-    dev: true
 
-  /jest-leak-detector@29.7.0:
-    resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-leak-detector@29.7.0:
     dependencies:
       jest-get-type: 29.6.3
       pretty-format: 29.7.0
-    dev: true
 
-  /jest-matcher-utils@29.7.0:
-    resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-matcher-utils@29.7.0:
     dependencies:
       chalk: 4.1.2
       jest-diff: 29.7.0
       jest-get-type: 29.6.3
       pretty-format: 29.7.0
-    dev: true
 
-  /jest-message-util@29.7.0:
-    resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-message-util@29.7.0:
     dependencies:
       '@babel/code-frame': 7.23.5
       '@jest/types': 29.6.3
@@ -13561,47 +19489,27 @@ packages:
       pretty-format: 29.7.0
       slash: 3.0.0
       stack-utils: 2.0.6
-    dev: true
 
-  /jest-mock@29.7.0:
-    resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-mock@29.7.0:
     dependencies:
       '@jest/types': 29.6.3
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       jest-util: 29.7.0
-    dev: true
 
-  /jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
-    resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==}
-    engines: {node: '>=6'}
-    peerDependencies:
-      jest-resolve: '*'
-    peerDependenciesMeta:
-      jest-resolve:
-        optional: true
-    dependencies:
+  jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
+    optionalDependencies:
       jest-resolve: 29.7.0
-    dev: true
 
-  /jest-regex-util@29.6.3:
-    resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-    dev: true
+  jest-regex-util@29.6.3: {}
 
-  /jest-resolve-dependencies@29.7.0:
-    resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-resolve-dependencies@29.7.0:
     dependencies:
       jest-regex-util: 29.6.3
       jest-snapshot: 29.7.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /jest-resolve@29.7.0:
-    resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-resolve@29.7.0:
     dependencies:
       chalk: 4.1.2
       graceful-fs: 4.2.11
@@ -13612,18 +19520,15 @@ packages:
       resolve: 1.22.8
       resolve.exports: 2.0.0
       slash: 3.0.0
-    dev: true
 
-  /jest-runner@29.7.0:
-    resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-runner@29.7.0:
     dependencies:
       '@jest/console': 29.7.0
       '@jest/environment': 29.7.0
       '@jest/test-result': 29.7.0
       '@jest/transform': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       chalk: 4.1.2
       emittery: 0.13.1
       graceful-fs: 4.2.11
@@ -13641,11 +19546,8 @@ packages:
       source-map-support: 0.5.13
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /jest-runtime@29.7.0:
-    resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-runtime@29.7.0:
     dependencies:
       '@jest/environment': 29.7.0
       '@jest/fake-timers': 29.7.0
@@ -13654,7 +19556,7 @@ packages:
       '@jest/test-result': 29.7.0
       '@jest/transform': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       chalk: 4.1.2
       cjs-module-lexer: 1.2.2
       collect-v8-coverage: 1.0.1
@@ -13671,11 +19573,8 @@ packages:
       strip-bom: 4.0.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /jest-snapshot@29.7.0:
-    resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-snapshot@29.7.0:
     dependencies:
       '@babel/core': 7.23.5
       '@babel/generator': 7.23.5
@@ -13699,23 +19598,17 @@ packages:
       semver: 7.5.4
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /jest-util@29.7.0:
-    resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-util@29.7.0:
     dependencies:
       '@jest/types': 29.6.3
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       chalk: 4.1.2
       ci-info: 3.7.1
       graceful-fs: 4.2.11
       picomatch: 2.3.1
-    dev: true
 
-  /jest-validate@29.7.0:
-    resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-validate@29.7.0:
     dependencies:
       '@jest/types': 29.6.3
       camelcase: 6.3.0
@@ -13723,133 +19616,81 @@ packages:
       jest-get-type: 29.6.3
       leven: 3.1.0
       pretty-format: 29.7.0
-    dev: true
 
-  /jest-watcher@29.7.0:
-    resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-watcher@29.7.0:
     dependencies:
       '@jest/test-result': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       ansi-escapes: 4.3.2
       chalk: 4.1.2
       emittery: 0.13.1
       jest-util: 29.7.0
       string-length: 4.0.2
-    dev: true
 
-  /jest-websocket-mock@2.5.0:
-    resolution: {integrity: sha512-a+UJGfowNIWvtIKIQBHoEWIUqRxxQHFx4CXT+R5KxxKBtEQ5rS3pPOV/5299sHzqbmeCzxxY5qE4+yfXePePig==}
+  jest-websocket-mock@2.5.0:
     dependencies:
       jest-diff: 29.7.0
       mock-socket: 9.3.1
-    dev: true
 
-  /jest-worker@29.7.0:
-    resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  jest-worker@29.7.0:
     dependencies:
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       jest-util: 29.7.0
       merge-stream: 2.0.0
       supports-color: 8.1.1
-    dev: true
 
-  /jest@29.7.0(@types/node@20.11.22):
-    resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-    hasBin: true
-    peerDependencies:
-      node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
-    peerDependenciesMeta:
-      node-notifier:
-        optional: true
+  jest@29.7.0(@types/node@20.12.7):
     dependencies:
       '@jest/core': 29.7.0
       '@jest/types': 29.6.3
       import-local: 3.1.0
-      jest-cli: 29.7.0(@types/node@20.11.22)
+      jest-cli: 29.7.0(@types/node@20.12.7)
     transitivePeerDependencies:
       - '@types/node'
       - babel-plugin-macros
       - supports-color
       - ts-node
-    dev: true
 
-  /jju@1.4.0:
-    resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
-    dev: true
+  jju@1.4.0: {}
 
-  /joi@17.11.0:
-    resolution: {integrity: sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==}
+  joi@17.11.0:
     dependencies:
       '@hapi/hoek': 9.3.0
       '@hapi/topo': 5.1.0
       '@sideway/address': 4.1.4
       '@sideway/formula': 3.0.1
       '@sideway/pinpoint': 2.0.0
-    dev: true
 
-  /jpeg-js@0.3.7:
-    resolution: {integrity: sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ==}
-    dev: false
+  jpeg-js@0.3.7: {}
 
-  /jpeg-js@0.4.4:
-    resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==}
-    dev: false
-
-  /js-beautify@1.14.9:
-    resolution: {integrity: sha512-coM7xq1syLcMyuVGyToxcj2AlzhkDjmfklL8r0JgJ7A76wyGMpJ1oA35mr4APdYNO/o/4YY8H54NQIJzhMbhBg==}
-    engines: {node: '>=12'}
-    hasBin: true
+  js-beautify@1.14.9:
     dependencies:
       config-chain: 1.1.13
       editorconfig: 1.0.4
       glob: 8.1.0
       nopt: 6.0.0
-    dev: true
 
-  /js-stringify@1.0.2:
-    resolution: {integrity: sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==}
+  js-stringify@1.0.2: {}
 
-  /js-tokens@4.0.0:
-    resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
-    dev: true
+  js-tokens@4.0.0: {}
 
-  /js-yaml@3.14.1:
-    resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
-    hasBin: true
+  js-yaml@3.14.1:
     dependencies:
       argparse: 1.0.10
       esprima: 4.0.1
-    dev: true
 
-  /js-yaml@4.1.0:
-    resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
-    hasBin: true
+  js-yaml@4.1.0:
     dependencies:
       argparse: 2.0.1
 
-  /jsbn@0.1.1:
-    resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==}
+  jsbn@0.1.1: {}
 
-  /jsbn@1.1.0:
-    resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==}
-    dev: false
+  jsbn@1.1.0: {}
 
-  /jschardet@3.0.0:
-    resolution: {integrity: sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ==}
-    engines: {node: '>=0.1.90'}
+  jschardet@3.0.0: {}
 
-  /jscodeshift@0.15.1(@babel/preset-env@7.23.5):
-    resolution: {integrity: sha512-hIJfxUy8Rt4HkJn/zZPU9ChKfKZM1342waJ1QC2e2YsPcWhM+3BJ4dcfQCzArTrk1jJeNLB341H+qOcEHRxJZg==}
-    hasBin: true
-    peerDependencies:
-      '@babel/preset-env': ^7.1.6
-    peerDependenciesMeta:
-      '@babel/preset-env':
-        optional: true
+  jscodeshift@0.15.1(@babel/preset-env@7.23.5(@babel/core@7.24.0)):
     dependencies:
       '@babel/core': 7.24.0
       '@babel/parser': 7.24.0
@@ -13858,7 +19699,6 @@ packages:
       '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.24.0)
       '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.24.0)
       '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.24.0)
-      '@babel/preset-env': 7.23.5(@babel/core@7.24.0)
       '@babel/preset-flow': 7.23.3(@babel/core@7.24.0)
       '@babel/preset-typescript': 7.23.3(@babel/core@7.24.0)
       '@babel/register': 7.22.15(@babel/core@7.24.0)
@@ -13872,20 +19712,13 @@ packages:
       recast: 0.23.4
       temp: 0.8.4
       write-file-atomic: 2.4.3
+    optionalDependencies:
+      '@babel/preset-env': 7.23.5(@babel/core@7.24.0)
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /jsdom@23.2.0(bufferutil@4.0.7)(utf-8-validate@6.0.3):
-    resolution: {integrity: sha512-L88oL7D/8ufIES+Zjz7v0aes+oBMh2Xnh3ygWvL0OaICOomKEPKuPnIfBJekiXr+BHbbMjrWn/xqrDQuxFTeyA==}
-    engines: {node: '>=18'}
-    peerDependencies:
-      canvas: ^2.11.2
-    peerDependenciesMeta:
-      canvas:
-        optional: true
+  jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3):
     dependencies:
-      '@asamuzakjp/dom-selector': 2.0.2
       cssstyle: 4.0.1
       data-urls: 5.0.0
       decimal.js: 10.4.3
@@ -13894,6 +19727,7 @@ packages:
       http-proxy-agent: 7.0.0
       https-proxy-agent: 7.0.2
       is-potential-custom-element-name: 1.0.1
+      nwsapi: 2.2.9
       parse5: 7.1.2
       rrweb-cssom: 0.6.0
       saxes: 6.0.0
@@ -13904,463 +19738,283 @@ packages:
       whatwg-encoding: 3.1.1
       whatwg-mimetype: 4.0.0
       whatwg-url: 14.0.0
-      ws: 8.16.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
+      ws: 8.17.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
       xml-name-validator: 5.0.0
     transitivePeerDependencies:
       - bufferutil
       - supports-color
       - utf-8-validate
-    dev: false
 
-  /jsesc@0.5.0:
-    resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==}
-    hasBin: true
-    dev: true
+  jsesc@0.5.0: {}
 
-  /jsesc@2.5.2:
-    resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
-    engines: {node: '>=4'}
-    hasBin: true
-    dev: true
+  jsesc@2.5.2: {}
 
-  /json-buffer@3.0.1:
-    resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+  json-buffer@3.0.1: {}
 
-  /json-parse-even-better-errors@2.3.1:
-    resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
-    dev: true
+  json-parse-even-better-errors@2.3.1: {}
 
-  /json-schema-traverse@0.4.1:
-    resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+  json-schema-traverse@0.4.1: {}
 
-  /json-schema-traverse@1.0.0:
-    resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
+  json-schema-traverse@1.0.0: {}
 
-  /json-schema@0.4.0:
-    resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
+  json-schema@0.4.0: {}
 
-  /json-stable-stringify-without-jsonify@1.0.1:
-    resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
-    dev: true
+  json-stable-stringify-without-jsonify@1.0.1: {}
 
-  /json-stringify-safe@5.0.1:
-    resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
+  json-stringify-safe@5.0.1: {}
 
-  /json-to-ast@2.1.0:
-    resolution: {integrity: sha512-W9Lq347r8tA1DfMvAGn9QNcgYm4Wm7Yc+k8e6vezpMnRT+NHbtlxgNBXRVjXe9YM6eTn6+p/MKOlV/aABJcSnQ==}
-    engines: {node: '>= 4'}
+  json-to-ast@2.1.0:
     dependencies:
       code-error-fragment: 0.0.230
       grapheme-splitter: 1.0.4
-    dev: true
 
-  /json5@1.0.2:
-    resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
-    hasBin: true
+  json5@1.0.2:
     dependencies:
       minimist: 1.2.8
-    dev: true
 
-  /json5@2.2.3:
-    resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
-    engines: {node: '>=6'}
-    hasBin: true
+  json5@2.2.3: {}
 
-  /jsonc-parser@3.2.0:
-    resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==}
-    dev: true
+  jsonc-parser@3.2.0: {}
 
-  /jsonfile@4.0.0:
-    resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
+  jsonfile@4.0.0:
     optionalDependencies:
       graceful-fs: 4.2.11
 
-  /jsonfile@5.0.0:
-    resolution: {integrity: sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==}
+  jsonfile@5.0.0:
     dependencies:
       universalify: 0.1.2
     optionalDependencies:
       graceful-fs: 4.2.11
-    dev: false
 
-  /jsonfile@6.1.0:
-    resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
+  jsonfile@6.1.0:
     dependencies:
       universalify: 2.0.0
     optionalDependencies:
       graceful-fs: 4.2.11
-    dev: true
 
-  /jsonld@8.3.2:
-    resolution: {integrity: sha512-MwBbq95szLwt8eVQ1Bcfwmgju/Y5P2GdtlHE2ncyfuYjIdEhluUVyj1eudacf1mOkWIoS9GpDBTECqhmq7EOaA==}
-    engines: {node: '>=14'}
+  jsonld@8.3.2(web-streams-polyfill@3.2.1):
     dependencies:
-      '@digitalbazaar/http-client': 3.4.1
+      '@digitalbazaar/http-client': 3.4.1(web-streams-polyfill@3.2.1)
       canonicalize: 1.0.8
       lru-cache: 6.0.0
       rdf-canonize: 3.4.0
     transitivePeerDependencies:
       - web-streams-polyfill
-    dev: false
 
-  /jsonpointer@5.0.1:
-    resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==}
-    engines: {node: '>=0.10.0'}
-    dev: true
+  jsonpointer@5.0.1: {}
 
-  /jsprim@1.4.2:
-    resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==}
-    engines: {node: '>=0.6.0'}
+  jsprim@1.4.2:
     dependencies:
       assert-plus: 1.0.0
       extsprintf: 1.3.0
       json-schema: 0.4.0
       verror: 1.10.0
-    dev: false
 
-  /jsprim@2.0.2:
-    resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==}
-    engines: {'0': node >=0.6.0}
+  jsprim@2.0.2:
     dependencies:
       assert-plus: 1.0.0
       extsprintf: 1.3.0
       json-schema: 0.4.0
       verror: 1.10.0
-    dev: true
 
-  /jsrsasign@11.1.0:
-    resolution: {integrity: sha512-Ov74K9GihaK9/9WncTe1mPmvrO7Py665TUfUKvraXBpu+xcTWitrtuOwcjf4KMU9maPaYn0OuaWy0HOzy/GBXg==}
-    dev: false
+  jsrsasign@11.1.0: {}
 
-  /jssha@3.3.1:
-    resolution: {integrity: sha512-VCMZj12FCFMQYcFLPRm/0lOBbLi8uM2BhXPTqw3U4YAfs4AZfiApOoBLoN8cQE60Z50m1MYMTQVCfgF/KaCVhQ==}
-    dev: false
+  jssha@3.3.1: {}
 
-  /jstransformer@1.0.0:
-    resolution: {integrity: sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==}
+  jstransformer@1.0.0:
     dependencies:
       is-promise: 2.2.2
       promise: 7.3.1
 
-  /just-extend@4.2.1:
-    resolution: {integrity: sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==}
-    dev: true
+  just-extend@4.2.1: {}
 
-  /jwa@2.0.0:
-    resolution: {integrity: sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==}
+  jwa@2.0.0:
     dependencies:
       buffer-equal-constant-time: 1.0.1
       ecdsa-sig-formatter: 1.0.11
       safe-buffer: 5.2.1
-    dev: false
 
-  /jws@4.0.0:
-    resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==}
+  jws@4.0.0:
     dependencies:
       jwa: 2.0.0
       safe-buffer: 5.2.1
-    dev: false
 
-  /keyv@4.5.4:
-    resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+  keyv@4.5.4:
     dependencies:
       json-buffer: 3.0.1
 
-  /kind-of@6.0.3:
-    resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
-    engines: {node: '>=0.10.0'}
-    dev: true
+  kind-of@6.0.3: {}
 
-  /kleur@3.0.3:
-    resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
-    engines: {node: '>=6'}
-    dev: true
+  kleur@3.0.3: {}
 
-  /ky-universal@0.11.0(ky@0.33.3):
-    resolution: {integrity: sha512-65KyweaWvk+uKKkCrfAf+xqN2/epw1IJDtlyCPxYffFCMR8u1sp2U65NtWpnozYfZxQ6IUzIlvUcw+hQ82U2Xw==}
-    engines: {node: '>=14.16'}
-    peerDependencies:
-      ky: '>=0.31.4'
-      web-streams-polyfill: '>=3.2.1'
-    peerDependenciesMeta:
-      web-streams-polyfill:
-        optional: true
+  ky-universal@0.11.0(ky@0.33.3)(web-streams-polyfill@3.2.1):
     dependencies:
       abort-controller: 3.0.0
       ky: 0.33.3
       node-fetch: 3.3.2
-    dev: false
+    optionalDependencies:
+      web-streams-polyfill: 3.2.1
 
-  /ky@0.33.3:
-    resolution: {integrity: sha512-CasD9OCEQSFIam2U8efFK81Yeg8vNMTBUqtMOHlrcWQHqUX3HeCl9Dr31u4toV7emlH8Mymk5+9p0lL6mKb/Xw==}
-    engines: {node: '>=14.16'}
-    dev: false
+  ky@0.33.3: {}
 
-  /lazy-ass@1.6.0:
-    resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==}
-    engines: {node: '> 0.8'}
-    dev: true
+  lazy-ass@1.6.0: {}
 
-  /lazy-universal-dotenv@4.0.0:
-    resolution: {integrity: sha512-aXpZJRnTkpK6gQ/z4nk+ZBLd/Qdp118cvPruLSIQzQNRhKwEcdXCOzXuF55VDqIiuAaY3UGZ10DJtvZzDcvsxg==}
-    engines: {node: '>=14.0.0'}
+  lazy-universal-dotenv@4.0.0:
     dependencies:
       app-root-dir: 1.0.2
       dotenv: 16.0.3
       dotenv-expand: 10.0.0
-    dev: true
 
-  /lazystream@1.0.1:
-    resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==}
-    engines: {node: '>= 0.6.3'}
+  lazystream@1.0.1:
     dependencies:
       readable-stream: 2.3.7
-    dev: false
 
-  /leven@3.1.0:
-    resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
-    engines: {node: '>=6'}
-    dev: true
+  leven@3.1.0: {}
 
-  /levn@0.4.1:
-    resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
-    engines: {node: '>= 0.8.0'}
+  levn@0.4.1:
     dependencies:
       prelude-ls: 1.2.1
       type-check: 0.4.0
-    dev: true
 
-  /light-my-request@5.11.0:
-    resolution: {integrity: sha512-qkFCeloXCOMpmEdZ/MV91P8AT4fjwFXWaAFz3lUeStM8RcoM1ks4J/F8r1b3r6y/H4u3ACEJ1T+Gv5bopj7oDA==}
+  light-my-request@5.11.0:
     dependencies:
       cookie: 0.5.0
       process-warning: 2.2.0
       set-cookie-parser: 2.6.0
-    dev: false
 
-  /lilconfig@3.1.1:
-    resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==}
-    engines: {node: '>=14'}
-    dev: false
+  lilconfig@3.1.1: {}
 
-  /lines-and-columns@1.2.4:
-    resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
-    dev: true
+  lines-and-columns@1.2.4: {}
 
-  /listr2@3.14.0(enquirer@2.3.6):
-    resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==}
-    engines: {node: '>=10.0.0'}
-    peerDependencies:
-      enquirer: '>= 2.3.0 < 3'
-    peerDependenciesMeta:
-      enquirer:
-        optional: true
+  listr2@3.14.0(enquirer@2.3.6):
     dependencies:
       cli-truncate: 2.1.0
       colorette: 2.0.19
-      enquirer: 2.3.6
       log-update: 4.0.0
       p-map: 4.0.0
       rfdc: 1.3.0
       rxjs: 7.8.1
       through: 2.3.8
       wrap-ansi: 7.0.0
-    dev: true
+    optionalDependencies:
+      enquirer: 2.3.6
 
-  /local-pkg@0.4.3:
-    resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==}
-    engines: {node: '>=14'}
-    dev: true
+  local-pkg@0.4.3: {}
 
-  /locate-path@3.0.0:
-    resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==}
-    engines: {node: '>=6'}
+  locate-path@3.0.0:
     dependencies:
       p-locate: 3.0.0
       path-exists: 3.0.0
-    dev: true
 
-  /locate-path@5.0.0:
-    resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
-    engines: {node: '>=8'}
+  locate-path@5.0.0:
     dependencies:
       p-locate: 4.1.0
 
-  /locate-path@6.0.0:
-    resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
-    engines: {node: '>=10'}
+  locate-path@6.0.0:
     dependencies:
       p-locate: 5.0.0
-    dev: true
 
-  /lodash.debounce@4.0.8:
-    resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
-    dev: true
+  lodash.debounce@4.0.8: {}
 
-  /lodash.defaults@4.2.0:
-    resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
-    dev: false
+  lodash.defaults@4.2.0: {}
 
-  /lodash.get@4.4.2:
-    resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
-    dev: true
+  lodash.get@4.4.2: {}
 
-  /lodash.isarguments@3.1.0:
-    resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
-    dev: false
+  lodash.isarguments@3.1.0: {}
 
-  /lodash.isequal@4.5.0:
-    resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
-    dev: true
+  lodash.isequal@4.5.0: {}
 
-  /lodash.memoize@4.1.2:
-    resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
-    dev: false
+  lodash.memoize@4.1.2: {}
 
-  /lodash.merge@4.6.2:
-    resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+  lodash.merge@4.6.2: {}
 
-  /lodash.once@4.1.1:
-    resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
-    dev: true
+  lodash.once@4.1.1: {}
 
-  /lodash.uniq@4.5.0:
-    resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==}
-    dev: false
+  lodash.uniq@4.5.0: {}
 
-  /lodash@4.17.21:
-    resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+  lodash@4.17.21: {}
 
-  /log-symbols@4.1.0:
-    resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
-    engines: {node: '>=10'}
+  log-symbols@4.1.0:
     dependencies:
       chalk: 4.1.2
       is-unicode-supported: 0.1.0
-    dev: true
 
-  /log-update@4.0.0:
-    resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==}
-    engines: {node: '>=10'}
+  log-update@4.0.0:
     dependencies:
       ansi-escapes: 4.3.2
       cli-cursor: 3.1.0
       slice-ansi: 4.0.0
       wrap-ansi: 6.2.0
-    dev: true
 
-  /long@4.0.0:
-    resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==}
-    requiresBuild: true
-    dev: false
+  long@4.0.0: {}
 
-  /longest-streak@3.1.0:
-    resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
-    dev: true
+  longest-streak@3.1.0: {}
 
-  /loose-envify@1.4.0:
-    resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
-    hasBin: true
+  loose-envify@1.4.0:
     dependencies:
       js-tokens: 4.0.0
-    dev: true
 
-  /loupe@2.3.7:
-    resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
+  loupe@2.3.7:
     dependencies:
       get-func-name: 2.0.2
-    dev: true
 
-  /lowercase-keys@2.0.0:
-    resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==}
-    engines: {node: '>=8'}
-    dev: false
+  lowercase-keys@2.0.0: {}
 
-  /lowercase-keys@3.0.0:
-    resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+  lowercase-keys@3.0.0: {}
 
-  /lru-cache@10.0.2:
-    resolution: {integrity: sha512-Yj9mA8fPiVgOUpByoTZO5pNrcl5Yk37FcSHsUINpAsaBIEZIuqcCclDZJCVxqQShDsmYX8QG63svJiTbOATZwg==}
-    engines: {node: 14 || >=16.14}
+  lru-cache@10.0.2:
     dependencies:
       semver: 7.6.0
 
-  /lru-cache@4.1.5:
-    resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
+  lru-cache@10.2.2: {}
+
+  lru-cache@4.1.5:
     dependencies:
       pseudomap: 1.0.2
       yallist: 2.1.2
-    dev: false
 
-  /lru-cache@5.1.1:
-    resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+  lru-cache@5.1.1:
     dependencies:
       yallist: 3.1.1
-    dev: true
 
-  /lru-cache@6.0.0:
-    resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
-    engines: {node: '>=10'}
+  lru-cache@6.0.0:
     dependencies:
       yallist: 4.0.0
 
-  /lru-cache@8.0.4:
-    resolution: {integrity: sha512-E9FF6+Oc/uFLqZCuZwRKUzgFt5Raih6LfxknOSAVTjNkrCZkBf7DQCwJxZQgd9l4eHjIJDGR+E+1QKD1RhThPw==}
-    engines: {node: '>=16.14'}
-    dev: true
+  lru-cache@8.0.4: {}
 
-  /luxon@3.3.0:
-    resolution: {integrity: sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==}
-    engines: {node: '>=12'}
-    dev: false
+  luxon@3.3.0: {}
 
-  /lz-string@1.5.0:
-    resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
-    hasBin: true
-    dev: true
+  lz-string@1.5.0: {}
 
-  /magic-string@0.27.0:
-    resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==}
-    engines: {node: '>=12'}
-    dependencies:
-      '@jridgewell/sourcemap-codec': 1.4.15
-    dev: true
-
-  /magic-string@0.30.7:
-    resolution: {integrity: sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==}
-    engines: {node: '>=12'}
+  magic-string@0.27.0:
     dependencies:
       '@jridgewell/sourcemap-codec': 1.4.15
 
-  /mailcheck@1.1.1:
-    resolution: {integrity: sha512-3WjL8+ZDouZwKlyJBMp/4LeziLFXgleOdsYu87piGcMLqhBzCsy2QFdbtAwv757TFC/rtqd738fgJw1tFQCSgA==}
-    dev: false
+  magic-string@0.30.10:
+    dependencies:
+      '@jridgewell/sourcemap-codec': 1.4.15
 
-  /make-dir@2.1.0:
-    resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
-    engines: {node: '>=6'}
+  magic-string@0.30.7:
+    dependencies:
+      '@jridgewell/sourcemap-codec': 1.4.15
+
+  mailcheck@1.1.1: {}
+
+  make-dir@2.1.0:
     dependencies:
       pify: 4.0.1
       semver: 5.7.1
-    dev: true
 
-  /make-dir@3.1.0:
-    resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
-    engines: {node: '>=8'}
+  make-dir@3.1.0:
     dependencies:
       semver: 6.3.1
 
-  /make-dir@4.0.0:
-    resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
-    engines: {node: '>=10'}
+  make-dir@4.0.0:
     dependencies:
       semver: 7.6.0
-    dev: true
 
-  /make-fetch-happen@13.0.0:
-    resolution: {integrity: sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==}
-    engines: {node: ^16.14.0 || >=18.0.0}
+  make-fetch-happen@13.0.0:
     dependencies:
       '@npmcli/agent': 2.2.0
       cacache: 18.0.0
@@ -14375,60 +20029,35 @@ packages:
       ssri: 10.0.4
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /makeerror@1.0.12:
-    resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
+  makeerror@1.0.12:
     dependencies:
       tmpl: 1.0.5
-    dev: true
 
-  /map-obj@1.0.1:
-    resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==}
-    engines: {node: '>=0.10.0'}
-    dev: true
+  map-obj@1.0.1: {}
 
-  /map-obj@4.3.0:
-    resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==}
-    engines: {node: '>=8'}
-    dev: true
+  map-obj@4.3.0: {}
 
-  /map-or-similar@1.5.0:
-    resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==}
-    dev: true
+  map-or-similar@1.5.0: {}
 
-  /map-stream@0.1.0:
-    resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==}
-    dev: true
+  map-stream@0.1.0: {}
 
-  /markdown-table@3.0.3:
-    resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==}
-    dev: true
+  markdown-table@3.0.3: {}
 
-  /markdown-to-jsx@7.3.2(react@18.2.0):
-    resolution: {integrity: sha512-B+28F5ucp83aQm+OxNrPkS8z0tMKaeHiy0lHJs3LqCyDQFtWuenaIrkaVTgAm1pf1AU85LXltva86hlaT17i8Q==}
-    engines: {node: '>= 10'}
-    peerDependencies:
-      react: '>= 0.14.0'
+  markdown-to-jsx@7.3.2(react@18.3.1):
     dependencies:
-      react: 18.2.0
-    dev: true
+      react: 18.3.1
 
-  /matter-js@0.19.0:
-    resolution: {integrity: sha512-v2huwvQGOHTGOkMqtHd2hercCG3f6QAObTisPPHg8TZqq2lz7eIY/5i/5YUV8Ibf3mEioFEmwibcPUF2/fnKKQ==}
-    dev: false
+  matter-js@0.19.0: {}
 
-  /mdast-util-find-and-replace@3.0.1:
-    resolution: {integrity: sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==}
+  mdast-util-find-and-replace@3.0.1:
     dependencies:
       '@types/mdast': 4.0.3
       escape-string-regexp: 5.0.0
       unist-util-is: 6.0.0
       unist-util-visit-parents: 6.0.1
-    dev: true
 
-  /mdast-util-from-markdown@2.0.0:
-    resolution: {integrity: sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==}
+  mdast-util-from-markdown@2.0.0:
     dependencies:
       '@types/mdast': 4.0.3
       '@types/unist': 3.0.2
@@ -14444,20 +20073,16 @@ packages:
       unist-util-stringify-position: 4.0.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /mdast-util-gfm-autolink-literal@2.0.0:
-    resolution: {integrity: sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==}
+  mdast-util-gfm-autolink-literal@2.0.0:
     dependencies:
       '@types/mdast': 4.0.3
       ccount: 2.0.1
       devlop: 1.1.0
       mdast-util-find-and-replace: 3.0.1
       micromark-util-character: 2.1.0
-    dev: true
 
-  /mdast-util-gfm-footnote@2.0.0:
-    resolution: {integrity: sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==}
+  mdast-util-gfm-footnote@2.0.0:
     dependencies:
       '@types/mdast': 4.0.3
       devlop: 1.1.0
@@ -14466,20 +20091,16 @@ packages:
       micromark-util-normalize-identifier: 2.0.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /mdast-util-gfm-strikethrough@2.0.0:
-    resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==}
+  mdast-util-gfm-strikethrough@2.0.0:
     dependencies:
       '@types/mdast': 4.0.3
       mdast-util-from-markdown: 2.0.0
       mdast-util-to-markdown: 2.1.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /mdast-util-gfm-table@2.0.0:
-    resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==}
+  mdast-util-gfm-table@2.0.0:
     dependencies:
       '@types/mdast': 4.0.3
       devlop: 1.1.0
@@ -14488,10 +20109,8 @@ packages:
       mdast-util-to-markdown: 2.1.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /mdast-util-gfm-task-list-item@2.0.0:
-    resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==}
+  mdast-util-gfm-task-list-item@2.0.0:
     dependencies:
       '@types/mdast': 4.0.3
       devlop: 1.1.0
@@ -14499,10 +20118,8 @@ packages:
       mdast-util-to-markdown: 2.1.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /mdast-util-gfm@3.0.0:
-    resolution: {integrity: sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==}
+  mdast-util-gfm@3.0.0:
     dependencies:
       mdast-util-from-markdown: 2.0.0
       mdast-util-gfm-autolink-literal: 2.0.0
@@ -14513,17 +20130,13 @@ packages:
       mdast-util-to-markdown: 2.1.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /mdast-util-phrasing@4.1.0:
-    resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==}
+  mdast-util-phrasing@4.1.0:
     dependencies:
       '@types/mdast': 4.0.3
       unist-util-is: 6.0.0
-    dev: true
 
-  /mdast-util-to-markdown@2.1.0:
-    resolution: {integrity: sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==}
+  mdast-util-to-markdown@2.1.0:
     dependencies:
       '@types/mdast': 4.0.3
       '@types/unist': 3.0.2
@@ -14533,43 +20146,28 @@ packages:
       micromark-util-decode-string: 2.0.0
       unist-util-visit: 5.0.0
       zwitch: 2.0.4
-    dev: true
 
-  /mdast-util-to-string@4.0.0:
-    resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
+  mdast-util-to-string@4.0.0:
     dependencies:
       '@types/mdast': 4.0.3
-    dev: true
 
-  /mdn-data@2.0.28:
-    resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==}
-    dev: false
+  mdn-data@2.0.28: {}
 
-  /mdn-data@2.0.30:
-    resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
-    dev: false
+  mdn-data@2.0.30: {}
 
-  /media-typer@0.3.0:
-    resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
-    engines: {node: '>= 0.6'}
+  media-typer@0.3.0: {}
 
-  /meilisearch@0.37.0:
-    resolution: {integrity: sha512-LdbK6JmRghCawrmWKJSEQF0OiE82md+YqJGE/U2JcCD8ROwlhTx0KM6NX4rQt0u0VpV0QZVG9umYiu3CSSIJAQ==}
+  meilisearch@0.38.0(encoding@0.1.13):
     dependencies:
-      cross-fetch: 3.1.6
+      cross-fetch: 3.1.6(encoding@0.1.13)
     transitivePeerDependencies:
       - encoding
-    dev: false
 
-  /memoizerific@1.11.3:
-    resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==}
+  memoizerific@1.11.3:
     dependencies:
       map-or-similar: 1.5.0
-    dev: true
 
-  /meow@9.0.0:
-    resolution: {integrity: sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==}
-    engines: {node: '>=10'}
+  meow@9.0.0:
     dependencies:
       '@types/minimist': 1.2.2
       camelcase-keys: 6.2.2
@@ -14583,37 +20181,24 @@ packages:
       trim-newlines: 3.0.1
       type-fest: 0.18.1
       yargs-parser: 20.2.9
-    dev: true
 
-  /merge-descriptors@1.0.1:
-    resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
+  merge-descriptors@1.0.1: {}
 
-  /merge-stream@2.0.0:
-    resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+  merge-stream@2.0.0: {}
 
-  /merge2@1.4.1:
-    resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
-    engines: {node: '>= 8'}
+  merge2@1.4.1: {}
 
-  /methods@1.1.2:
-    resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
-    engines: {node: '>= 0.6'}
+  methods@1.1.2: {}
 
-  /mfm-js@0.24.0:
-    resolution: {integrity: sha512-6m8N0ElH9/4CA1izhVqmxTfLj5Z9RspdqM/lMew4xU/UTgm4Pf//VpDunpasxbRFjeJSVW+zoVwL4ZPfPtfiQg==}
+  mfm-js@0.24.0:
     dependencies:
       '@twemoji/parser': 15.0.0
-    dev: false
 
-  /microformats-parser@2.0.2:
-    resolution: {integrity: sha512-tUf9DmN4Jq/tGyp1YH2V6D/Cud+9Uc0WhjjUFirqVeHTRkkfLDacv6BQFT7h7HFsD0Z8wja5eKkRgzZU8bv0Fw==}
-    engines: {node: '>=18'}
+  microformats-parser@2.0.2:
     dependencies:
       parse5: 7.1.2
-    dev: false
 
-  /micromark-core-commonmark@2.0.0:
-    resolution: {integrity: sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==}
+  micromark-core-commonmark@2.0.0:
     dependencies:
       decode-named-character-reference: 1.0.2
       devlop: 1.1.0
@@ -14631,19 +20216,15 @@ packages:
       micromark-util-subtokenize: 2.0.0
       micromark-util-symbol: 2.0.0
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-extension-gfm-autolink-literal@2.0.0:
-    resolution: {integrity: sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==}
+  micromark-extension-gfm-autolink-literal@2.0.0:
     dependencies:
       micromark-util-character: 2.1.0
       micromark-util-sanitize-uri: 2.0.0
       micromark-util-symbol: 2.0.0
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-extension-gfm-footnote@2.0.0:
-    resolution: {integrity: sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==}
+  micromark-extension-gfm-footnote@2.0.0:
     dependencies:
       devlop: 1.1.0
       micromark-core-commonmark: 2.0.0
@@ -14653,10 +20234,8 @@ packages:
       micromark-util-sanitize-uri: 2.0.0
       micromark-util-symbol: 2.0.0
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-extension-gfm-strikethrough@2.0.0:
-    resolution: {integrity: sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==}
+  micromark-extension-gfm-strikethrough@2.0.0:
     dependencies:
       devlop: 1.1.0
       micromark-util-chunked: 2.0.0
@@ -14664,36 +20243,28 @@ packages:
       micromark-util-resolve-all: 2.0.0
       micromark-util-symbol: 2.0.0
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-extension-gfm-table@2.0.0:
-    resolution: {integrity: sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==}
+  micromark-extension-gfm-table@2.0.0:
     dependencies:
       devlop: 1.1.0
       micromark-factory-space: 2.0.0
       micromark-util-character: 2.1.0
       micromark-util-symbol: 2.0.0
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-extension-gfm-tagfilter@2.0.0:
-    resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==}
+  micromark-extension-gfm-tagfilter@2.0.0:
     dependencies:
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-extension-gfm-task-list-item@2.0.1:
-    resolution: {integrity: sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==}
+  micromark-extension-gfm-task-list-item@2.0.1:
     dependencies:
       devlop: 1.1.0
       micromark-factory-space: 2.0.0
       micromark-util-character: 2.1.0
       micromark-util-symbol: 2.0.0
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-extension-gfm@3.0.0:
-    resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==}
+  micromark-extension-gfm@3.0.0:
     dependencies:
       micromark-extension-gfm-autolink-literal: 2.0.0
       micromark-extension-gfm-footnote: 2.0.0
@@ -14703,140 +20274,100 @@ packages:
       micromark-extension-gfm-task-list-item: 2.0.1
       micromark-util-combine-extensions: 2.0.0
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-factory-destination@2.0.0:
-    resolution: {integrity: sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==}
+  micromark-factory-destination@2.0.0:
     dependencies:
       micromark-util-character: 2.1.0
       micromark-util-symbol: 2.0.0
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-factory-label@2.0.0:
-    resolution: {integrity: sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==}
+  micromark-factory-label@2.0.0:
     dependencies:
       devlop: 1.1.0
       micromark-util-character: 2.1.0
       micromark-util-symbol: 2.0.0
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-factory-space@2.0.0:
-    resolution: {integrity: sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==}
+  micromark-factory-space@2.0.0:
     dependencies:
       micromark-util-character: 2.1.0
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-factory-title@2.0.0:
-    resolution: {integrity: sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==}
+  micromark-factory-title@2.0.0:
     dependencies:
       micromark-factory-space: 2.0.0
       micromark-util-character: 2.1.0
       micromark-util-symbol: 2.0.0
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-factory-whitespace@2.0.0:
-    resolution: {integrity: sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==}
+  micromark-factory-whitespace@2.0.0:
     dependencies:
       micromark-factory-space: 2.0.0
       micromark-util-character: 2.1.0
       micromark-util-symbol: 2.0.0
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-util-character@2.1.0:
-    resolution: {integrity: sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==}
+  micromark-util-character@2.1.0:
     dependencies:
       micromark-util-symbol: 2.0.0
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-util-chunked@2.0.0:
-    resolution: {integrity: sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==}
+  micromark-util-chunked@2.0.0:
     dependencies:
       micromark-util-symbol: 2.0.0
-    dev: true
 
-  /micromark-util-classify-character@2.0.0:
-    resolution: {integrity: sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==}
+  micromark-util-classify-character@2.0.0:
     dependencies:
       micromark-util-character: 2.1.0
       micromark-util-symbol: 2.0.0
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-util-combine-extensions@2.0.0:
-    resolution: {integrity: sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==}
+  micromark-util-combine-extensions@2.0.0:
     dependencies:
       micromark-util-chunked: 2.0.0
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-util-decode-numeric-character-reference@2.0.1:
-    resolution: {integrity: sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==}
+  micromark-util-decode-numeric-character-reference@2.0.1:
     dependencies:
       micromark-util-symbol: 2.0.0
-    dev: true
 
-  /micromark-util-decode-string@2.0.0:
-    resolution: {integrity: sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==}
+  micromark-util-decode-string@2.0.0:
     dependencies:
       decode-named-character-reference: 1.0.2
       micromark-util-character: 2.1.0
       micromark-util-decode-numeric-character-reference: 2.0.1
       micromark-util-symbol: 2.0.0
-    dev: true
 
-  /micromark-util-encode@2.0.0:
-    resolution: {integrity: sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==}
-    dev: true
+  micromark-util-encode@2.0.0: {}
 
-  /micromark-util-html-tag-name@2.0.0:
-    resolution: {integrity: sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==}
-    dev: true
+  micromark-util-html-tag-name@2.0.0: {}
 
-  /micromark-util-normalize-identifier@2.0.0:
-    resolution: {integrity: sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==}
+  micromark-util-normalize-identifier@2.0.0:
     dependencies:
       micromark-util-symbol: 2.0.0
-    dev: true
 
-  /micromark-util-resolve-all@2.0.0:
-    resolution: {integrity: sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==}
+  micromark-util-resolve-all@2.0.0:
     dependencies:
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-util-sanitize-uri@2.0.0:
-    resolution: {integrity: sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==}
+  micromark-util-sanitize-uri@2.0.0:
     dependencies:
       micromark-util-character: 2.1.0
       micromark-util-encode: 2.0.0
       micromark-util-symbol: 2.0.0
-    dev: true
 
-  /micromark-util-subtokenize@2.0.0:
-    resolution: {integrity: sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==}
+  micromark-util-subtokenize@2.0.0:
     dependencies:
       devlop: 1.1.0
       micromark-util-chunked: 2.0.0
       micromark-util-symbol: 2.0.0
       micromark-util-types: 2.0.0
-    dev: true
 
-  /micromark-util-symbol@2.0.0:
-    resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==}
-    dev: true
+  micromark-util-symbol@2.0.0: {}
 
-  /micromark-util-types@2.0.0:
-    resolution: {integrity: sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==}
-    dev: true
+  micromark-util-types@2.0.0: {}
 
-  /micromark@4.0.0:
-    resolution: {integrity: sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==}
+  micromark@4.0.0:
     dependencies:
       '@types/debug': 4.1.12
       debug: 4.3.4(supports-color@8.1.1)
@@ -14857,244 +20388,150 @@ packages:
       micromark-util-types: 2.0.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /micromatch@4.0.5:
-    resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
-    engines: {node: '>=8.6'}
+  micromatch@4.0.5:
     dependencies:
       braces: 3.0.2
       picomatch: 2.3.1
 
-  /mime-db@1.52.0:
-    resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
-    engines: {node: '>= 0.6'}
+  mime-db@1.52.0: {}
 
-  /mime-types@2.1.35:
-    resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
-    engines: {node: '>= 0.6'}
+  mime-types@2.1.35:
     dependencies:
       mime-db: 1.52.0
 
-  /mime@1.6.0:
-    resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
-    engines: {node: '>=4'}
-    hasBin: true
+  mime@1.6.0: {}
 
-  /mime@3.0.0:
-    resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==}
-    engines: {node: '>=10.0.0'}
-    hasBin: true
-    dev: false
+  mime@3.0.0: {}
 
-  /mimic-fn@2.1.0:
-    resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
-    engines: {node: '>=6'}
+  mimic-fn@2.1.0: {}
 
-  /mimic-fn@4.0.0:
-    resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
-    engines: {node: '>=12'}
+  mimic-fn@4.0.0: {}
 
-  /mimic-response@1.0.1:
-    resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==}
-    engines: {node: '>=4'}
-    dev: false
+  mimic-response@1.0.1: {}
 
-  /mimic-response@3.1.0:
-    resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
-    engines: {node: '>=10'}
+  mimic-response@3.1.0: {}
 
-  /mimic-response@4.0.0:
-    resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+  mimic-response@4.0.0: {}
 
-  /min-indent@1.0.1:
-    resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
-    engines: {node: '>=4'}
-    dev: true
+  min-indent@1.0.1: {}
 
-  /minimalistic-assert@1.0.1:
-    resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
-    dev: false
+  minimalistic-assert@1.0.1: {}
 
-  /minimatch@3.1.2:
-    resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+  minimatch@3.0.8:
     dependencies:
       brace-expansion: 1.1.11
 
-  /minimatch@5.1.2:
-    resolution: {integrity: sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==}
-    engines: {node: '>=10'}
+  minimatch@3.1.2:
+    dependencies:
+      brace-expansion: 1.1.11
+
+  minimatch@5.1.2:
     dependencies:
       brace-expansion: 2.0.1
 
-  /minimatch@9.0.1:
-    resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==}
-    engines: {node: '>=16 || 14 >=14.17'}
-    dependencies:
-      brace-expansion: 2.0.1
-    dev: true
-
-  /minimatch@9.0.3:
-    resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
-    engines: {node: '>=16 || 14 >=14.17'}
+  minimatch@9.0.1:
     dependencies:
       brace-expansion: 2.0.1
 
-  /minimist-options@4.1.0:
-    resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==}
-    engines: {node: '>= 6'}
+  minimatch@9.0.3:
+    dependencies:
+      brace-expansion: 2.0.1
+
+  minimatch@9.0.4:
+    dependencies:
+      brace-expansion: 2.0.1
+
+  minimist-options@4.1.0:
     dependencies:
       arrify: 1.0.1
       is-plain-obj: 1.1.0
       kind-of: 6.0.3
-    dev: true
 
-  /minimist@1.2.8:
-    resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+  minimist@1.2.8: {}
 
-  /minipass-collect@1.0.2:
-    resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==}
-    engines: {node: '>= 8'}
+  minipass-collect@1.0.2:
     dependencies:
       minipass: 3.3.6
-    dev: false
 
-  /minipass-fetch@3.0.3:
-    resolution: {integrity: sha512-n5ITsTkDqYkYJZjcRWzZt9qnZKCT7nKCosJhHoj7S7zD+BP4jVbWs+odsniw5TA3E0sLomhTKOKjF86wf11PuQ==}
-    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+  minipass-fetch@3.0.3:
     dependencies:
       minipass: 5.0.0
       minipass-sized: 1.0.3
       minizlib: 2.1.2
     optionalDependencies:
       encoding: 0.1.13
-    dev: false
 
-  /minipass-flush@1.0.5:
-    resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==}
-    engines: {node: '>= 8'}
+  minipass-flush@1.0.5:
     dependencies:
       minipass: 3.3.6
-    dev: false
 
-  /minipass-pipeline@1.2.4:
-    resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==}
-    engines: {node: '>=8'}
+  minipass-pipeline@1.2.4:
     dependencies:
       minipass: 3.3.6
-    dev: false
 
-  /minipass-sized@1.0.3:
-    resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==}
-    engines: {node: '>=8'}
+  minipass-sized@1.0.3:
     dependencies:
       minipass: 3.3.6
-    dev: false
 
-  /minipass@2.9.0:
-    resolution: {integrity: sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==}
-    requiresBuild: true
+  minipass@2.9.0:
     dependencies:
       safe-buffer: 5.2.1
       yallist: 3.1.1
-    dev: false
     optional: true
 
-  /minipass@3.3.6:
-    resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
-    engines: {node: '>=8'}
+  minipass@3.3.6:
     dependencies:
       yallist: 4.0.0
 
-  /minipass@5.0.0:
-    resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==}
-    engines: {node: '>=8'}
+  minipass@5.0.0: {}
 
-  /minipass@7.0.4:
-    resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==}
-    engines: {node: '>=16 || 14 >=14.17'}
+  minipass@7.0.4: {}
 
-  /minizlib@1.3.3:
-    resolution: {integrity: sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==}
-    requiresBuild: true
+  minizlib@1.3.3:
     dependencies:
       minipass: 2.9.0
-    dev: false
     optional: true
 
-  /minizlib@2.1.2:
-    resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
-    engines: {node: '>= 8'}
+  minizlib@2.1.2:
     dependencies:
       minipass: 3.3.6
       yallist: 4.0.0
 
-  /mkdirp-classic@0.5.3:
-    resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
-    dev: true
+  mkdirp-classic@0.5.3: {}
 
-  /mkdirp@0.5.6:
-    resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
-    hasBin: true
+  mkdirp@0.5.6:
     dependencies:
       minimist: 1.2.8
 
-  /mkdirp@1.0.4:
-    resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
-    engines: {node: '>=10'}
-    hasBin: true
-    requiresBuild: true
+  mkdirp@1.0.4: {}
 
-  /mkdirp@2.1.6:
-    resolution: {integrity: sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==}
-    engines: {node: '>=10'}
-    hasBin: true
-    dev: false
+  mkdirp@2.1.6: {}
 
-  /mlly@1.5.0:
-    resolution: {integrity: sha512-NPVQvAY1xr1QoVeG0cy8yUYC7FQcOx6evl/RjT1wL5FvzPnzOysoqB/jmx/DhssT2dYa8nxECLAaFI/+gVLhDQ==}
+  mlly@1.5.0:
     dependencies:
       acorn: 8.11.3
       pathe: 1.1.2
       pkg-types: 1.0.3
       ufo: 1.3.2
-    dev: true
 
-  /mnemonist@0.39.6:
-    resolution: {integrity: sha512-A/0v5Z59y63US00cRSLiloEIw3t5G+MiKz4BhX21FI+YBJXBOGW0ohFxTxO08dsOYlzxo87T7vGfZKYp2bcAWA==}
+  mnemonist@0.39.6:
     dependencies:
       obliterator: 2.0.4
-    dev: false
 
-  /mock-socket@9.3.1:
-    resolution: {integrity: sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==}
-    engines: {node: '>= 8'}
-    dev: true
+  mock-socket@9.3.1: {}
 
-  /mri@1.2.0:
-    resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
-    engines: {node: '>=4'}
-    dev: true
+  mri@1.2.0: {}
 
-  /ms@2.0.0:
-    resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
+  ms@2.0.0: {}
 
-  /ms@2.1.2:
-    resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+  ms@2.1.2: {}
 
-  /ms@2.1.3:
-    resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+  ms@2.1.3: {}
 
-  /ms@3.0.0-canary.1:
-    resolution: {integrity: sha512-kh8ARjh8rMN7Du2igDRO9QJnqCb2xYTJxyQYK7vJJS4TvLLmsbyhiKpSW+t+y26gyOyMd0riphX0GeWKU3ky5g==}
-    engines: {node: '>=12.13'}
-    dev: false
+  ms@3.0.0-canary.1: {}
 
-  /msgpackr-extract@3.0.2:
-    resolution: {integrity: sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==}
-    hasBin: true
-    requiresBuild: true
+  msgpackr-extract@3.0.2:
     dependencies:
       node-gyp-build-optional-packages: 5.0.7
     optionalDependencies:
@@ -15104,67 +20541,42 @@ packages:
       '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.2
       '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.2
       '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.2
-    dev: false
     optional: true
 
-  /msgpackr@1.10.1:
-    resolution: {integrity: sha512-r5VRLv9qouXuLiIBrLpl2d5ZvPt8svdQTl5/vMvE4nzDMyEX4sgW5yWhuBBj5UmgwOTWj8CIdSXn5sAfsHAWIQ==}
+  msgpackr@1.10.1:
     optionalDependencies:
       msgpackr-extract: 3.0.2
-    dev: false
 
-  /msw-storybook-addon@2.0.0-beta.1(msw@2.1.7):
-    resolution: {integrity: sha512-DRyIAMK3waEfC+pKTyiIq68OZfiZ4WZGUVAn6J4YwCRpDdoCvLzzoC2spN0Jgegx4dEmJ7589ATnS14NxqeBig==}
-    peerDependencies:
-      msw: ^2.0.0
+  msw-storybook-addon@2.0.1(msw@2.2.14(typescript@5.4.5)):
     dependencies:
       is-node-process: 1.2.0
-      msw: 2.1.7(typescript@5.3.3)
-    dev: true
+      msw: 2.2.14(typescript@5.4.5)
 
-  /msw@2.1.7(typescript@5.3.3):
-    resolution: {integrity: sha512-yTIYqEMqDSrdbVMrfmqP6rTKQsnIbglTvVmAHDWwNegyXPXRcV+RjsaFEqubRS266gwWCDLm9YdOkWSKLdDvJQ==}
-    engines: {node: '>=18'}
-    hasBin: true
-    requiresBuild: true
-    peerDependencies:
-      typescript: '>= 4.7.x <= 5.3.x'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
+  msw@2.2.14(typescript@5.4.5):
     dependencies:
       '@bundled-es-modules/cookie': 2.0.0
       '@bundled-es-modules/statuses': 1.0.1
+      '@inquirer/confirm': 3.1.6
       '@mswjs/cookies': 1.1.0
-      '@mswjs/interceptors': 0.25.16
+      '@mswjs/interceptors': 0.26.15
       '@open-draft/until': 2.1.0
       '@types/cookie': 0.6.0
       '@types/statuses': 2.0.4
       chalk: 4.1.2
-      chokidar: 3.5.3
       graphql: 16.8.1
       headers-polyfill: 4.0.2
-      inquirer: 8.2.5
       is-node-process: 1.2.0
       outvariant: 1.4.2
       path-to-regexp: 6.2.1
       strict-event-emitter: 0.5.1
       type-fest: 4.9.0
-      typescript: 5.3.3
       yargs: 17.7.2
-    dev: true
+    optionalDependencies:
+      typescript: 5.4.5
 
-  /muggle-string@0.3.1:
-    resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==}
-    dev: true
+  muggle-string@0.4.1: {}
 
-  /muggle-string@0.4.1:
-    resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
-    dev: true
-
-  /multer@1.4.4-lts.1:
-    resolution: {integrity: sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==}
-    engines: {node: '>= 6.0.0'}
+  multer@1.4.4-lts.1:
     dependencies:
       append-field: 1.0.0
       busboy: 1.6.0
@@ -15174,219 +20586,138 @@ packages:
       type-is: 1.6.18
       xtend: 4.0.2
 
-  /multi-integer-range@3.0.0:
-    resolution: {integrity: sha512-uQzynjVJ8F7x5wjaK0g4Ybhy2TvO/pk96+YHyS5g1W4GuUEV6HMebZ8HcRwWgKIRCUT2MLbM5uCKwYcAqkS+8Q==}
-    dev: false
+  multi-integer-range@3.0.0: {}
 
-  /mute-stream@0.0.8:
-    resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
-    dev: true
+  mute-stream@1.0.0: {}
 
-  /mylas@2.1.13:
-    resolution: {integrity: sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg==}
-    engines: {node: '>=12.0.0'}
-    dev: false
+  mylas@2.1.13: {}
 
-  /mz@2.7.0:
-    resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
+  mz@2.7.0:
     dependencies:
       any-promise: 1.3.0
       object-assign: 4.1.1
       thenify-all: 1.6.0
-    dev: false
 
-  /nan@2.18.0:
-    resolution: {integrity: sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==}
-    dev: false
+  nan@2.18.0: {}
 
-  /nanoid@3.3.7:
-    resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
-    engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
-    hasBin: true
+  nanoid@3.3.7: {}
 
-  /nanoid@5.0.6:
-    resolution: {integrity: sha512-rRq0eMHoGZxlvaFOUdK1Ev83Bd1IgzzR+WJ3IbDJ7QOSdAxYjlurSPqFs9s4lJg29RT6nPwizFtJhQS6V5xgiA==}
-    engines: {node: ^18 || >=20}
-    hasBin: true
-    dev: false
+  nanoid@5.0.7: {}
 
-  /natural-compare@1.4.0:
-    resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
-    dev: true
+  natural-compare@1.4.0: {}
 
-  /ncp@2.0.0:
-    resolution: {integrity: sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==}
-    hasBin: true
-    dev: true
+  ncp@2.0.0: {}
 
-  /ndarray-ops@1.2.2:
-    resolution: {integrity: sha512-BppWAFRjMYF7N/r6Ie51q6D4fs0iiGmeXIACKY66fLpnwIui3Wc3CXiD/30mgLbDjPpSLrsqcp3Z62+IcHZsDw==}
+  ndarray-ops@1.2.2:
     dependencies:
       cwise-compiler: 1.1.3
-    dev: false
 
-  /ndarray-pack@1.2.1:
-    resolution: {integrity: sha512-51cECUJMT0rUZNQa09EoKsnFeDL4x2dHRT0VR5U2H5ZgEcm95ZDWcMA5JShroXjHOejmAD/fg8+H+OvUnVXz2g==}
+  ndarray-pack@1.2.1:
     dependencies:
       cwise-compiler: 1.1.3
       ndarray: 1.0.19
-    dev: false
 
-  /ndarray@1.0.18:
-    resolution: {integrity: sha512-jUz6G+CIsEsqs2VlB1EvaQSAA0Jkf8YKm7eFBleKyhiQjYWzTxXqHzWEOm3jFoGCpxGh4DnPUYHB4ECWE+n9SQ==}
+  ndarray@1.0.18:
     dependencies:
       iota-array: 1.0.0
       is-buffer: 1.1.6
-    dev: false
 
-  /ndarray@1.0.19:
-    resolution: {integrity: sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ==}
+  ndarray@1.0.19:
     dependencies:
       iota-array: 1.0.0
       is-buffer: 1.1.6
-    dev: false
 
-  /needle@2.9.1:
-    resolution: {integrity: sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==}
-    engines: {node: '>= 4.4.x'}
-    hasBin: true
+  needle@2.9.1:
     dependencies:
       debug: 3.2.7(supports-color@8.1.1)
       iconv-lite: 0.4.24
       sax: 1.2.4
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /negotiator@0.6.3:
-    resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
-    engines: {node: '>= 0.6'}
+  negotiator@0.6.3: {}
 
-  /neo-async@2.6.2:
-    resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
-    dev: true
+  neo-async@2.6.2: {}
 
-  /nested-property@4.0.0:
-    resolution: {integrity: sha512-yFehXNWRs4cM0+dz7QxCd06hTbWbSkV0ISsqBfkntU6TOY4Qm3Q88fRRLOddkGh2Qq6dZvnKVAahfhjcUvLnyA==}
-    dev: false
+  nested-property@4.0.0: {}
 
-  /netmask@2.0.2:
-    resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==}
-    engines: {node: '>= 0.4.0'}
+  netmask@2.0.2: {}
 
-  /nise@5.1.4:
-    resolution: {integrity: sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==}
+  nice-napi@1.0.2:
+    dependencies:
+      node-addon-api: 3.2.1
+      node-gyp-build: 4.6.0
+    optional: true
+
+  nise@5.1.4:
     dependencies:
       '@sinonjs/commons': 2.0.0
       '@sinonjs/fake-timers': 10.3.0
       '@sinonjs/text-encoding': 0.7.2
       just-extend: 4.2.1
       path-to-regexp: 1.8.0
-    dev: true
 
-  /node-abort-controller@3.1.1:
-    resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==}
-    dev: false
+  node-abort-controller@3.1.1: {}
 
-  /node-bitmap@0.0.1:
-    resolution: {integrity: sha512-Jx5lPaaLdIaOsj2mVLWMWulXF6GQVdyLvNSxmiYCvZ8Ma2hfKX0POoR2kgKOqz+oFsRreq0yYZjQ2wjE9VNzCA==}
-    engines: {node: '>=v0.6.5'}
-    dev: false
+  node-addon-api@3.2.1:
+    optional: true
 
-  /node-dir@0.1.17:
-    resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==}
-    engines: {node: '>= 0.10.5'}
+  node-bitmap@0.0.1: {}
+
+  node-dir@0.1.17:
     dependencies:
       minimatch: 3.1.2
-    dev: true
 
-  /node-domexception@1.0.0:
-    resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
-    engines: {node: '>=10.5.0'}
+  node-domexception@1.0.0: {}
 
-  /node-fetch-native@1.0.2:
-    resolution: {integrity: sha512-KIkvH1jl6b3O7es/0ShyCgWLcfXxlBrLBbP3rOr23WArC66IMcU4DeZEeYEOwnopYhawLTn7/y+YtmASe8DFVQ==}
-    dev: true
+  node-fetch-native@1.0.2: {}
 
-  /node-fetch@2.6.11:
-    resolution: {integrity: sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==}
-    engines: {node: 4.x || >=6.0.0}
-    requiresBuild: true
-    peerDependencies:
-      encoding: ^0.1.0
-    peerDependenciesMeta:
-      encoding:
-        optional: true
+  node-fetch@2.6.11(encoding@0.1.13):
     dependencies:
       whatwg-url: 5.0.0
-    dev: false
+    optionalDependencies:
+      encoding: 0.1.13
 
-  /node-fetch@2.7.0:
-    resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
-    engines: {node: 4.x || >=6.0.0}
-    peerDependencies:
-      encoding: ^0.1.0
-    peerDependenciesMeta:
-      encoding:
-        optional: true
+  node-fetch@2.7.0(encoding@0.1.13):
     dependencies:
       whatwg-url: 5.0.0
+    optionalDependencies:
+      encoding: 0.1.13
 
-  /node-fetch@3.3.2:
-    resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+  node-fetch@3.3.2:
     dependencies:
       data-uri-to-buffer: 4.0.0
       fetch-blob: 3.2.0
       formdata-polyfill: 4.0.10
 
-  /node-gyp-build-optional-packages@5.0.7:
-    resolution: {integrity: sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==}
-    hasBin: true
-    requiresBuild: true
-    dev: false
+  node-gyp-build-optional-packages@5.0.7:
     optional: true
 
-  /node-gyp-build@4.6.0:
-    resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==}
-    hasBin: true
-    requiresBuild: true
+  node-gyp-build@4.6.0:
+    optional: true
 
-  /node-gyp@10.0.1:
-    resolution: {integrity: sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==}
-    engines: {node: ^16.14.0 || >=18.0.0}
-    hasBin: true
+  node-gyp@10.0.1:
     dependencies:
       env-paths: 2.2.1
       exponential-backoff: 3.1.1
-      glob: 10.3.10
+      glob: 10.3.12
       graceful-fs: 4.2.11
       make-fetch-happen: 13.0.0
       nopt: 7.2.0
       proc-log: 3.0.0
-      semver: 7.5.4
-      tar: 6.2.0
+      semver: 7.6.0
+      tar: 6.2.1
       which: 4.0.0
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /node-int64@0.4.0:
-    resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
-    dev: true
+  node-int64@0.4.0: {}
 
-  /node-releases@2.0.14:
-    resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
+  node-releases@2.0.14: {}
 
-  /nodemailer@6.9.10:
-    resolution: {integrity: sha512-qtoKfGFhvIFW5kLfrkw2R6Nm6Ur4LNUMykyqu6n9BRKJuyQrqEGwdXXUAbwWEKt33dlWUGXb7rzmJP/p4+O+CA==}
-    engines: {node: '>=6.0.0'}
-    dev: false
+  nodemailer@6.9.13: {}
 
-  /nodemon@3.0.2:
-    resolution: {integrity: sha512-9qIN2LNTrEzpOPBaWHTm4Asy1LxXLSickZStAQ4IZe7zsoIpD/A7LWxhZV3t4Zu352uBcqVnRsDXSMR2Sc3lTA==}
-    engines: {node: '>=10'}
-    hasBin: true
+  nodemon@3.0.2:
     dependencies:
       chokidar: 3.5.3
       debug: 4.3.4(supports-color@5.5.0)
@@ -15398,12 +20729,8 @@ packages:
       supports-color: 5.5.0
       touch: 3.1.0
       undefsafe: 2.0.5
-    dev: true
 
-  /nodemon@3.1.0:
-    resolution: {integrity: sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==}
-    engines: {node: '>=10'}
-    hasBin: true
+  nodemon@3.1.0:
     dependencies:
       chokidar: 3.5.3
       debug: 4.3.4(supports-color@5.5.0)
@@ -15415,267 +20742,165 @@ packages:
       supports-color: 5.5.0
       touch: 3.1.0
       undefsafe: 2.0.5
-    dev: true
 
-  /nofilter@3.1.0:
-    resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==}
-    engines: {node: '>=12.19'}
-    dev: false
+  nofilter@3.1.0: {}
 
-  /nopt@1.0.10:
-    resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==}
-    hasBin: true
+  nopt@1.0.10:
     dependencies:
       abbrev: 1.1.1
-    dev: true
 
-  /nopt@5.0.0:
-    resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==}
-    engines: {node: '>=6'}
-    hasBin: true
-    requiresBuild: true
+  nopt@5.0.0:
     dependencies:
       abbrev: 1.1.1
-    dev: false
     optional: true
 
-  /nopt@6.0.0:
-    resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==}
-    engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
-    hasBin: true
+  nopt@6.0.0:
     dependencies:
       abbrev: 1.1.1
-    dev: true
 
-  /nopt@7.2.0:
-    resolution: {integrity: sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==}
-    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-    hasBin: true
+  nopt@7.2.0:
     dependencies:
       abbrev: 2.0.0
-    dev: false
 
-  /normalize-package-data@2.5.0:
-    resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
+  normalize-package-data@2.5.0:
     dependencies:
       hosted-git-info: 2.8.9
       resolve: 1.22.8
       semver: 5.7.1
       validate-npm-package-license: 3.0.4
-    dev: true
 
-  /normalize-package-data@3.0.3:
-    resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==}
-    engines: {node: '>=10'}
+  normalize-package-data@3.0.3:
     dependencies:
       hosted-git-info: 4.1.0
       is-core-module: 2.13.1
       semver: 7.6.0
       validate-npm-package-license: 3.0.4
-    dev: true
 
-  /normalize-path@3.0.0:
-    resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
-    engines: {node: '>=0.10.0'}
+  normalize-path@3.0.0: {}
 
-  /normalize-url@6.1.0:
-    resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==}
-    engines: {node: '>=10'}
-    dev: false
+  normalize-url@6.1.0: {}
 
-  /normalize-url@8.0.0:
-    resolution: {integrity: sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==}
-    engines: {node: '>=14.16'}
+  normalize-url@8.0.0: {}
 
-  /npm-run-path@2.0.2:
-    resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==}
-    engines: {node: '>=4'}
+  npm-run-path@2.0.2:
     dependencies:
       path-key: 2.0.1
-    dev: false
 
-  /npm-run-path@4.0.1:
-    resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
-    engines: {node: '>=8'}
+  npm-run-path@4.0.1:
     dependencies:
       path-key: 3.1.1
 
-  /npm-run-path@5.1.0:
-    resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+  npm-run-path@5.1.0:
     dependencies:
       path-key: 4.0.0
 
-  /npmlog@5.0.1:
-    resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==}
-    requiresBuild: true
+  npmlog@5.0.1:
     dependencies:
       are-we-there-yet: 2.0.0
       console-control-strings: 1.1.0
       gauge: 3.0.2
       set-blocking: 2.0.0
-    dev: false
     optional: true
 
-  /nsfwjs@2.4.2(@tensorflow/tfjs@4.4.0):
-    resolution: {integrity: sha512-i4Pp2yt59qPQgeZFyg3wXFBX52uSeu/hkDoqdZfe+sILRxNBUu0VDogj7Lmqak0GlrXviS/wLiVeIx40IDUu7A==}
-    peerDependencies:
-      '@tensorflow/tfjs': ^3.18.0
+  nsfwjs@2.4.2(@tensorflow/tfjs@4.4.0(encoding@0.1.13)(seedrandom@3.0.5)):
     dependencies:
       '@nsfw-filter/gif-frames': 1.0.2
-      '@tensorflow/tfjs': 4.4.0(seedrandom@3.0.5)
-    dev: false
+      '@tensorflow/tfjs': 4.4.0(encoding@0.1.13)(seedrandom@3.0.5)
 
-  /nth-check@2.1.1:
-    resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
+  nth-check@2.1.1:
     dependencies:
       boolbase: 1.0.0
 
-  /oauth-sign@0.9.0:
-    resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==}
-    dev: false
+  nwsapi@2.2.9: {}
 
-  /oauth2orize-pkce@0.1.2:
-    resolution: {integrity: sha512-grto2UYhXHi9GLE3IBgBBbV87xci55+bCyjpVuxKyzol6I5Rg0K1MiTuXE+JZk54R86SG2wqXODMiZYHraPpxw==}
-    dev: false
+  oauth-sign@0.9.0: {}
 
-  /oauth2orize@1.12.0:
-    resolution: {integrity: sha512-j4XtFDQUBsvUHPjUmvmNDUDMYed2MphMIJBhyxVVe8hGCjkuYnjIsW+D9qk8c5ciXRdnk6x6tEbiO6PLeOZdCQ==}
-    engines: {node: '>= 0.4.0'}
+  oauth2orize-pkce@0.1.2: {}
+
+  oauth2orize@1.12.0:
     dependencies:
       debug: 2.6.9
       uid2: 0.0.4
       utils-merge: 1.0.1
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /oauth@0.10.0:
-    resolution: {integrity: sha512-1orQ9MT1vHFGQxhuy7E/0gECD3fd2fCC+PIX+/jgmU/gI3EpRocXtmtvxCO5x3WZ443FLTLFWNDjl5MPJf9u+Q==}
-    dev: false
+  oauth@0.10.0: {}
 
-  /object-assign@4.1.1:
-    resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
-    engines: {node: '>=0.10.0'}
+  object-assign@4.1.1: {}
 
-  /object-inspect@1.12.3:
-    resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
+  object-inspect@1.12.3: {}
 
-  /object-is@1.1.5:
-    resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==}
-    engines: {node: '>= 0.4'}
+  object-is@1.1.5:
     dependencies:
       call-bind: 1.0.2
       define-properties: 1.2.0
-    dev: true
 
-  /object-keys@1.1.1:
-    resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
-    engines: {node: '>= 0.4'}
-    dev: true
+  object-keys@1.1.1: {}
 
-  /object.assign@4.1.4:
-    resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==}
-    engines: {node: '>= 0.4'}
+  object.assign@4.1.4:
     dependencies:
       call-bind: 1.0.2
       define-properties: 1.2.0
       has-symbols: 1.0.3
       object-keys: 1.1.1
-    dev: true
 
-  /object.fromentries@2.0.7:
-    resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==}
-    engines: {node: '>= 0.4'}
+  object.fromentries@2.0.7:
     dependencies:
       call-bind: 1.0.2
       define-properties: 1.2.0
       es-abstract: 1.22.1
-    dev: true
 
-  /object.groupby@1.0.1:
-    resolution: {integrity: sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==}
+  object.groupby@1.0.1:
     dependencies:
       call-bind: 1.0.2
       define-properties: 1.2.0
       es-abstract: 1.22.1
       get-intrinsic: 1.2.1
-    dev: true
 
-  /object.values@1.1.7:
-    resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==}
-    engines: {node: '>= 0.4'}
+  object.values@1.1.7:
     dependencies:
       call-bind: 1.0.2
       define-properties: 1.2.0
       es-abstract: 1.22.1
-    dev: true
 
-  /obliterator@2.0.4:
-    resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==}
-    dev: false
+  obliterator@2.0.4: {}
 
-  /oblivious-set@1.4.0:
-    resolution: {integrity: sha512-szyd0ou0T8nsAqHtprRcP3WidfsN1TnAR5yWXf2mFCEr5ek3LEOkT6EZ/92Xfs74HIdyhG5WkGxIssMU0jBaeg==}
-    engines: {node: '>=16'}
-    dev: false
+  oblivious-set@1.4.0: {}
 
-  /obuf@1.1.2:
-    resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==}
-    dev: true
+  obuf@1.1.2: {}
 
-  /omggif@1.0.10:
-    resolution: {integrity: sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==}
-    dev: false
+  omggif@1.0.10: {}
 
-  /on-exit-leak-free@2.1.0:
-    resolution: {integrity: sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==}
-    dev: false
+  on-exit-leak-free@2.1.0: {}
 
-  /on-finished@2.4.1:
-    resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
-    engines: {node: '>= 0.8'}
+  on-finished@2.4.1:
     dependencies:
       ee-first: 1.1.1
 
-  /on-headers@1.0.2:
-    resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==}
-    engines: {node: '>= 0.8'}
-    dev: true
+  on-headers@1.0.2: {}
 
-  /once@1.4.0:
-    resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+  once@1.4.0:
     dependencies:
       wrappy: 1.0.2
 
-  /onetime@5.1.2:
-    resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
-    engines: {node: '>=6'}
+  onetime@5.1.2:
     dependencies:
       mimic-fn: 2.1.0
 
-  /onetime@6.0.0:
-    resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
-    engines: {node: '>=12'}
+  onetime@6.0.0:
     dependencies:
       mimic-fn: 4.0.0
 
-  /open@8.4.2:
-    resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==}
-    engines: {node: '>=12'}
+  open@8.4.2:
     dependencies:
       define-lazy-prop: 2.0.0
       is-docker: 2.2.1
       is-wsl: 2.2.0
-    dev: true
 
-  /openapi-types@12.1.3:
-    resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==}
-    dev: true
+  openapi-types@12.1.3: {}
 
-  /openapi-typescript@6.7.3:
-    resolution: {integrity: sha512-es3mGcDXV6TKPo6n3aohzHm0qxhLyR39MhF6mkD1FwFGjhxnqMqfSIgM0eCpInZvqatve4CxmXcMZw3jnnsaXw==}
-    hasBin: true
+  openapi-typescript@6.7.3:
     dependencies:
       ansi-colors: 4.1.3
       fast-glob: 3.3.2
@@ -15683,16 +20908,8 @@ packages:
       supports-color: 9.4.0
       undici: 5.28.2
       yargs-parser: 21.1.1
-    dev: true
 
-  /opentype.js@0.4.11:
-    resolution: {integrity: sha512-GthxucX/6aftfLdeU5Ho7o7zmQcC8uVtqdcelVq12X++ndxwBZG8Xb5rFEKT7nEcWDD2P1x+TNuJ70jtj1Mbpw==}
-    hasBin: true
-    dev: false
-
-  /optionator@0.9.3:
-    resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
-    engines: {node: '>= 0.8.0'}
+  optionator@0.9.3:
     dependencies:
       '@aashutoshrathi/word-wrap': 1.2.6
       deep-is: 0.1.4
@@ -15700,11 +20917,8 @@ packages:
       levn: 0.4.1
       prelude-ls: 1.2.1
       type-check: 0.4.0
-    dev: true
 
-  /ora@5.4.1:
-    resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==}
-    engines: {node: '>=10'}
+  ora@5.4.1:
     dependencies:
       bl: 4.1.0
       chalk: 4.1.2
@@ -15715,323 +20929,190 @@ packages:
       log-symbols: 4.1.0
       strip-ansi: 6.0.1
       wcwidth: 1.0.1
-    dev: true
 
-  /os-filter-obj@2.0.0:
-    resolution: {integrity: sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==}
-    engines: {node: '>=4'}
+  os-filter-obj@2.0.0:
     dependencies:
       arch: 2.2.0
-    dev: false
 
-  /os-tmpdir@1.0.2:
-    resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
-    engines: {node: '>=0.10.0'}
-    dev: true
+  os-utils@0.0.14: {}
 
-  /os-utils@0.0.14:
-    resolution: {integrity: sha512-ajB8csaHLBvJOYsHJkp8YdO2FvlBbf/ZxaYQwXXRDyQ84UoE+uTuLXxqd0shekXMX6Qr/pt/DDyLMRAMsgfWzg==}
-    dev: false
+  ospath@1.2.2: {}
 
-  /ospath@1.2.2:
-    resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==}
-    dev: true
-
-  /otpauth@9.2.2:
-    resolution: {integrity: sha512-2VcnYRUmq1dNckIfySNYP32ITWp1bvTeAEW0BSCR6G3GBf3a5zb9E+ubY62t3Dma9RjoHlvd7QpmzHfJZRkiNg==}
+  otpauth@9.2.3:
     dependencies:
       jssha: 3.3.1
-    dev: false
 
-  /outvariant@1.4.2:
-    resolution: {integrity: sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ==}
-    dev: true
+  outvariant@1.4.2: {}
 
-  /p-cancelable@2.1.1:
-    resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==}
-    engines: {node: '>=8'}
-    dev: false
+  p-cancelable@2.1.1: {}
 
-  /p-cancelable@3.0.0:
-    resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==}
-    engines: {node: '>=12.20'}
+  p-cancelable@3.0.0: {}
 
-  /p-cancelable@4.0.1:
-    resolution: {integrity: sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==}
-    engines: {node: '>=14.16'}
-    dev: false
+  p-cancelable@4.0.1: {}
 
-  /p-finally@1.0.0:
-    resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==}
-    engines: {node: '>=4'}
-    dev: false
+  p-finally@1.0.0: {}
 
-  /p-limit@2.3.0:
-    resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
-    engines: {node: '>=6'}
+  p-limit@2.3.0:
     dependencies:
       p-try: 2.2.0
 
-  /p-limit@3.1.0:
-    resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
-    engines: {node: '>=10'}
+  p-limit@3.1.0:
     dependencies:
       yocto-queue: 0.1.0
 
-  /p-limit@4.0.0:
-    resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+  p-limit@4.0.0:
     dependencies:
       yocto-queue: 1.0.0
-    dev: true
 
-  /p-locate@3.0.0:
-    resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==}
-    engines: {node: '>=6'}
-    dependencies:
-      p-limit: 2.3.0
-    dev: true
-
-  /p-locate@4.1.0:
-    resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
-    engines: {node: '>=8'}
+  p-locate@3.0.0:
     dependencies:
       p-limit: 2.3.0
 
-  /p-locate@5.0.0:
-    resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
-    engines: {node: '>=10'}
+  p-locate@4.1.0:
+    dependencies:
+      p-limit: 2.3.0
+
+  p-locate@5.0.0:
     dependencies:
       p-limit: 3.1.0
-    dev: true
 
-  /p-map@4.0.0:
-    resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
-    engines: {node: '>=10'}
+  p-map@4.0.0:
     dependencies:
       aggregate-error: 3.1.0
 
-  /p-queue@6.6.2:
-    resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==}
-    engines: {node: '>=8'}
+  p-queue@6.6.2:
     dependencies:
       eventemitter3: 4.0.7
       p-timeout: 3.2.0
-    dev: false
 
-  /p-timeout@3.2.0:
-    resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==}
-    engines: {node: '>=8'}
+  p-timeout@3.2.0:
     dependencies:
       p-finally: 1.0.0
-    dev: false
 
-  /p-try@2.2.0:
-    resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
-    engines: {node: '>=6'}
+  p-try@2.2.0: {}
 
-  /packet-reader@1.0.0:
-    resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==}
-    dev: false
+  pako@0.2.9: {}
 
-  /pako@0.2.9:
-    resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
-    dev: true
-
-  /parent-module@1.0.1:
-    resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
-    engines: {node: '>=6'}
+  parent-module@1.0.1:
     dependencies:
       callsites: 3.1.0
-    dev: true
 
-  /parse-data-uri@0.2.0:
-    resolution: {integrity: sha512-uOtts8NqDcaCt1rIsO3VFDRsAfgE4c6osG4d9z3l4dCBlxYFzni6Di/oNU270SDrjkfZuUvLZx1rxMyqh46Y9w==}
+  parse-data-uri@0.2.0:
     dependencies:
       data-uri-to-buffer: 0.0.3
-    dev: false
 
-  /parse-json@5.2.0:
-    resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
-    engines: {node: '>=8'}
+  parse-json@5.2.0:
     dependencies:
       '@babel/code-frame': 7.23.5
       error-ex: 1.3.2
       json-parse-even-better-errors: 2.3.1
       lines-and-columns: 1.2.4
-    dev: true
 
-  /parse-srcset@1.0.2:
-    resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==}
-    dev: false
+  parse-srcset@1.0.2: {}
 
-  /parse5-htmlparser2-tree-adapter@6.0.1:
-    resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==}
+  parse5-htmlparser2-tree-adapter@6.0.1:
     dependencies:
       parse5: 6.0.1
-    dev: false
 
-  /parse5-htmlparser2-tree-adapter@7.0.0:
-    resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==}
+  parse5-htmlparser2-tree-adapter@7.0.0:
     dependencies:
       domhandler: 5.0.3
       parse5: 7.1.2
 
-  /parse5@5.1.1:
-    resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==}
-    dev: false
+  parse5@5.1.1: {}
 
-  /parse5@6.0.1:
-    resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==}
-    dev: false
+  parse5@6.0.1: {}
 
-  /parse5@7.1.2:
-    resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==}
+  parse5@7.1.2:
     dependencies:
       entities: 4.5.0
 
-  /parseurl@1.3.3:
-    resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
-    engines: {node: '>= 0.8'}
+  parseurl@1.3.3: {}
 
-  /path-browserify@1.0.1:
-    resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
-    dev: true
+  path-browserify@1.0.1: {}
 
-  /path-exists@3.0.0:
-    resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==}
-    engines: {node: '>=4'}
-    dev: true
+  path-exists@3.0.0: {}
 
-  /path-exists@4.0.0:
-    resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
-    engines: {node: '>=8'}
+  path-exists@4.0.0: {}
 
-  /path-is-absolute@1.0.1:
-    resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
-    engines: {node: '>=0.10.0'}
+  path-is-absolute@1.0.1: {}
 
-  /path-key@2.0.1:
-    resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==}
-    engines: {node: '>=4'}
-    dev: false
+  path-key@2.0.1: {}
 
-  /path-key@3.1.1:
-    resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
-    engines: {node: '>=8'}
+  path-key@3.1.1: {}
 
-  /path-key@4.0.0:
-    resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
-    engines: {node: '>=12'}
+  path-key@4.0.0: {}
 
-  /path-parse@1.0.7:
-    resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+  path-parse@1.0.7: {}
 
-  /path-scurry@1.10.1:
-    resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==}
-    engines: {node: '>=16 || 14 >=14.17'}
+  path-scurry@1.10.1:
     dependencies:
       lru-cache: 10.0.2
       minipass: 7.0.4
 
-  /path-to-regexp@0.1.7:
-    resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
+  path-scurry@1.10.2:
+    dependencies:
+      lru-cache: 10.2.2
+      minipass: 7.0.4
 
-  /path-to-regexp@1.8.0:
-    resolution: {integrity: sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==}
+  path-to-regexp@0.1.7: {}
+
+  path-to-regexp@1.8.0:
     dependencies:
       isarray: 0.0.1
-    dev: true
 
-  /path-to-regexp@3.2.0:
-    resolution: {integrity: sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==}
+  path-to-regexp@3.2.0: {}
 
-  /path-to-regexp@6.2.1:
-    resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==}
-    dev: true
+  path-to-regexp@6.2.1: {}
 
-  /path-type@4.0.0:
-    resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
-    engines: {node: '>=8'}
+  path-type@4.0.0: {}
 
-  /pathe@1.1.2:
-    resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
-    dev: true
+  pathe@1.1.2: {}
 
-  /pathval@1.1.1:
-    resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
-    dev: true
+  pathval@1.1.1: {}
 
-  /pause-stream@0.0.11:
-    resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==}
+  pause-stream@0.0.11:
     dependencies:
       through: 2.3.8
-    dev: true
 
-  /peek-readable@5.0.0:
-    resolution: {integrity: sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==}
-    engines: {node: '>=14.16'}
-    dev: false
+  peek-readable@5.0.0: {}
 
-  /peek-stream@1.1.3:
-    resolution: {integrity: sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==}
+  peek-stream@1.1.3:
     dependencies:
       buffer-from: 1.1.2
       duplexify: 3.7.1
       through2: 2.0.5
-    dev: true
 
-  /pend@1.2.0:
-    resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
-    dev: true
+  pend@1.2.0: {}
 
-  /performance-now@2.1.0:
-    resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
+  performance-now@2.1.0: {}
 
-  /pg-cloudflare@1.1.1:
-    resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==}
-    requiresBuild: true
-    dev: false
+  pg-cloudflare@1.1.1:
     optional: true
 
-  /pg-connection-string@2.6.2:
-    resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==}
-    dev: false
+  pg-connection-string@2.6.4: {}
 
-  /pg-int8@1.0.1:
-    resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
-    engines: {node: '>=4.0.0'}
+  pg-int8@1.0.1: {}
 
-  /pg-numeric@1.0.2:
-    resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==}
-    engines: {node: '>=4'}
-    dev: true
+  pg-numeric@1.0.2: {}
 
-  /pg-pool@3.6.1(pg@8.11.3):
-    resolution: {integrity: sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==}
-    peerDependencies:
-      pg: '>=8.0'
+  pg-pool@3.6.2(pg@8.11.5):
     dependencies:
-      pg: 8.11.3
-    dev: false
+      pg: 8.11.5
 
-  /pg-protocol@1.6.0:
-    resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==}
+  pg-protocol@1.6.0: {}
 
-  /pg-types@2.2.0:
-    resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==}
-    engines: {node: '>=4'}
+  pg-protocol@1.6.1: {}
+
+  pg-types@2.2.0:
     dependencies:
       pg-int8: 1.0.1
       postgres-array: 2.0.0
       postgres-bytea: 1.0.0
       postgres-date: 1.0.7
       postgres-interval: 1.2.0
-    dev: false
 
-  /pg-types@4.0.1:
-    resolution: {integrity: sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g==}
-    engines: {node: '>=10'}
+  pg-types@4.0.1:
     dependencies:
       pg-int8: 1.0.1
       pg-numeric: 1.0.2
@@ -16040,76 +21121,43 @@ packages:
       postgres-date: 2.0.1
       postgres-interval: 3.0.0
       postgres-range: 1.1.3
-    dev: true
 
-  /pg@8.11.3:
-    resolution: {integrity: sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==}
-    engines: {node: '>= 8.0.0'}
-    peerDependencies:
-      pg-native: '>=3.0.1'
-    peerDependenciesMeta:
-      pg-native:
-        optional: true
+  pg@8.11.5:
     dependencies:
-      buffer-writer: 2.0.0
-      packet-reader: 1.0.0
-      pg-connection-string: 2.6.2
-      pg-pool: 3.6.1(pg@8.11.3)
-      pg-protocol: 1.6.0
+      pg-connection-string: 2.6.4
+      pg-pool: 3.6.2(pg@8.11.5)
+      pg-protocol: 1.6.1
       pg-types: 2.2.0
       pgpass: 1.0.5
     optionalDependencies:
       pg-cloudflare: 1.1.1
-    dev: false
 
-  /pgpass@1.0.5:
-    resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
+  pgpass@1.0.5:
     dependencies:
       split2: 4.1.0
-    dev: false
 
-  /photoswipe@5.4.3:
-    resolution: {integrity: sha512-9UC6oJBK4oXFZ5HcdlcvGkfEHsVrmE4csUdCQhEjHYb3PvPLO3PG7UhnPuOgjxwmhq5s17Un5NUdum01LgBDng==}
-    engines: {node: '>= 0.12.0'}
-    dev: false
+  photoswipe@5.4.3: {}
 
-  /picocolors@1.0.0:
-    resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
+  picocolors@1.0.0: {}
 
-  /picomatch@2.3.1:
-    resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
-    engines: {node: '>=8.6'}
+  picomatch@2.3.1: {}
 
-  /pid-port@1.0.0:
-    resolution: {integrity: sha512-LSNBeKChRPA4Xlrs6+zV588G1hSrFvANtPV5rt/5MPfSPK3V9XPWxx1d29svsrOjngT9ifLisXWCLS7DvO9ZhQ==}
-    engines: {node: '>=18'}
+  pid-port@1.0.0:
     dependencies:
       execa: 8.0.1
-    dev: true
 
-  /pify@2.3.0:
-    resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
-    engines: {node: '>=0.10.0'}
+  pify@2.3.0: {}
 
-  /pify@4.0.1:
-    resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
-    engines: {node: '>=6'}
-    dev: true
+  pify@4.0.1: {}
 
-  /pino-abstract-transport@1.1.0:
-    resolution: {integrity: sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==}
+  pino-abstract-transport@1.1.0:
     dependencies:
       readable-stream: 4.3.0
       split2: 4.1.0
-    dev: false
 
-  /pino-std-serializers@6.1.0:
-    resolution: {integrity: sha512-KO0m2f1HkrPe9S0ldjx7za9BJjeHqBku5Ch8JyxETxT8dEFGz1PwgrHaOQupVYitpzbFSYm7nnljxD8dik2c+g==}
-    dev: false
+  pino-std-serializers@6.1.0: {}
 
-  /pino@8.17.0:
-    resolution: {integrity: sha512-ey+Mku+PVPhvxglLXMg1l1zQMwSHuNrKC3MD40EDZbkckJmmuY7DYZLIOwwjZ8ix/Nvhe9dZt5H99cgkot9bAw==}
-    hasBin: true
+  pino@8.17.0:
     dependencies:
       atomic-sleep: 1.0.0
       fast-redact: 3.1.2
@@ -16122,611 +21170,344 @@ packages:
       safe-stable-stringify: 2.4.2
       sonic-boom: 3.7.0
       thread-stream: 2.3.0
-    dev: false
 
-  /pirates@4.0.5:
-    resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==}
-    engines: {node: '>= 6'}
-    dev: true
+  pirates@4.0.5: {}
 
-  /pkce-challenge@4.1.0:
-    resolution: {integrity: sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ==}
-    engines: {node: '>=16.20.0'}
-    dev: false
+  piscina@4.4.0:
+    optionalDependencies:
+      nice-napi: 1.0.2
 
-  /pkg-dir@3.0.0:
-    resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==}
-    engines: {node: '>=6'}
+  pkce-challenge@4.1.0: {}
+
+  pkg-dir@3.0.0:
     dependencies:
       find-up: 3.0.0
-    dev: true
 
-  /pkg-dir@4.2.0:
-    resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
-    engines: {node: '>=8'}
+  pkg-dir@4.2.0:
     dependencies:
       find-up: 4.1.0
-    dev: true
 
-  /pkg-dir@5.0.0:
-    resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==}
-    engines: {node: '>=10'}
+  pkg-dir@5.0.0:
     dependencies:
       find-up: 5.0.0
-    dev: true
 
-  /pkg-types@1.0.3:
-    resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==}
+  pkg-types@1.0.3:
     dependencies:
       jsonc-parser: 3.2.0
       mlly: 1.5.0
       pathe: 1.1.2
-    dev: true
 
-  /plimit-lit@1.5.0:
-    resolution: {integrity: sha512-Eb/MqCb1Iv/ok4m1FqIXqvUKPISufcjZ605hl3KM/n8GaX8zfhtgdLwZU3vKjuHGh2O9Rjog/bHTq8ofIShdng==}
+  plimit-lit@1.5.0:
     dependencies:
       queue-lit: 1.5.0
-    dev: false
 
-  /plur@4.0.0:
-    resolution: {integrity: sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==}
-    engines: {node: '>=10'}
+  plur@4.0.0:
     dependencies:
       irregular-plurals: 3.5.0
-    dev: true
 
-  /pngjs-nozlib@1.0.0:
-    resolution: {integrity: sha512-N1PggqLp9xDqwAoKvGohmZ3m4/N9xpY0nDZivFqQLcpLHmliHnCp9BuNCsOeqHWMuEEgFjpEaq9dZq6RZyy0fA==}
-    engines: {iojs: '>= 1.0.0', node: '>=0.10.0'}
-    dev: false
+  pngjs-nozlib@1.0.0: {}
 
-  /pngjs@3.4.0:
-    resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==}
-    engines: {node: '>=4.0.0'}
-    dev: false
+  pngjs@3.4.0: {}
 
-  /pngjs@5.0.0:
-    resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
-    engines: {node: '>=10.13.0'}
-    dev: false
+  pngjs@5.0.0: {}
 
-  /polished@4.2.2:
-    resolution: {integrity: sha512-Sz2Lkdxz6F2Pgnpi9U5Ng/WdWAUZxmHrNPoVlm3aAemxoy2Qy7LGjQg4uf8qKelDAUW94F4np3iH2YPf2qefcQ==}
-    engines: {node: '>=10'}
+  polished@4.2.2:
     dependencies:
       '@babel/runtime': 7.23.4
-    dev: true
 
-  /postcss-calc@9.0.1(postcss@8.4.35):
-    resolution: {integrity: sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.2.2
+  postcss-calc@9.0.1(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
+      postcss: 8.4.38
       postcss-selector-parser: 6.0.15
       postcss-value-parser: 4.2.0
-    dev: false
 
-  /postcss-colormin@6.0.3(postcss@8.4.35):
-    resolution: {integrity: sha512-ECpkS+UZRyAtu/kjive2/1mihP+GNtgC8kcdU8ueWZi1ZVxMNnRziCLdhrWECJhEtSWijfX2Cl9XTTCK/hjGaA==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-colormin@6.1.0(postcss@8.4.38):
     dependencies:
       browserslist: 4.23.0
       caniuse-api: 3.0.0
       colord: 2.9.3
-      postcss: 8.4.35
+      postcss: 8.4.38
       postcss-value-parser: 4.2.0
-    dev: false
 
-  /postcss-convert-values@6.0.4(postcss@8.4.35):
-    resolution: {integrity: sha512-YT2yrGzPXoQD3YeA2kBo/696qNwn7vI+15AOS2puXWEvSWqdCqlOyDWRy5GNnOc9ACRGOkuQ4ESQEqPJBWt/GA==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-convert-values@6.1.0(postcss@8.4.38):
     dependencies:
       browserslist: 4.23.0
-      postcss: 8.4.35
+      postcss: 8.4.38
       postcss-value-parser: 4.2.0
-    dev: false
 
-  /postcss-discard-comments@6.0.1(postcss@8.4.35):
-    resolution: {integrity: sha512-f1KYNPtqYLUeZGCHQPKzzFtsHaRuECe6jLakf/RjSRqvF5XHLZnM2+fXLhb8Qh/HBFHs3M4cSLb1k3B899RYIg==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-discard-comments@6.0.2(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
-    dev: false
+      postcss: 8.4.38
 
-  /postcss-discard-duplicates@6.0.2(postcss@8.4.35):
-    resolution: {integrity: sha512-U2rsj4w6pAGROCCcD13LP2eBIi1whUsXs4kgE6xkIuGfkbxCBSKhkCTWyowFd66WdVlLv0uM1euJKIgmdmZObg==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-discard-duplicates@6.0.3(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
-    dev: false
+      postcss: 8.4.38
 
-  /postcss-discard-empty@6.0.2(postcss@8.4.35):
-    resolution: {integrity: sha512-rj6pVC2dVCJrP0Y2RkYTQEbYaCf4HEm+R/2StQgJqGHxAa3+KcYslNQhcRqjLHtl/4wpzipJluaJLqBj6d5eDQ==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-discard-empty@6.0.3(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
-    dev: false
+      postcss: 8.4.38
 
-  /postcss-discard-overridden@6.0.1(postcss@8.4.35):
-    resolution: {integrity: sha512-qs0ehZMMZpSESbRkw1+inkf51kak6OOzNRaoLd/U7Fatp0aN2HQ1rxGOrJvYcRAN9VpX8kUF13R2ofn8OlvFVA==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-discard-overridden@6.0.2(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
-    dev: false
+      postcss: 8.4.38
 
-  /postcss-merge-longhand@6.0.3(postcss@8.4.35):
-    resolution: {integrity: sha512-kF/y3DU8CRt+SX3tP/aG+2gkZI2Z7OXDsPU7FgxIJmuyhQQ1EHceIYcsp/alvzCm2P4c37Sfdu8nNrHc+YeyLg==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-merge-longhand@6.0.5(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
+      postcss: 8.4.38
       postcss-value-parser: 4.2.0
-      stylehacks: 6.0.3(postcss@8.4.35)
-    dev: false
+      stylehacks: 6.1.1(postcss@8.4.38)
 
-  /postcss-merge-rules@6.0.4(postcss@8.4.35):
-    resolution: {integrity: sha512-97iF3UJ5v8N1BWy38y+0l+Z8o5/9uGlEgtWic2PJPzoRrLB6Gxg8TVG93O0EK52jcLeMsywre26AUlX1YAYeHA==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-merge-rules@6.1.1(postcss@8.4.38):
     dependencies:
       browserslist: 4.23.0
       caniuse-api: 3.0.0
-      cssnano-utils: 4.0.1(postcss@8.4.35)
-      postcss: 8.4.35
-      postcss-selector-parser: 6.0.15
-    dev: false
+      cssnano-utils: 4.0.2(postcss@8.4.38)
+      postcss: 8.4.38
+      postcss-selector-parser: 6.0.16
 
-  /postcss-minify-font-values@6.0.2(postcss@8.4.35):
-    resolution: {integrity: sha512-IedzbVMoX0a7VZWjSYr5qJ6C37rws8kl8diPBeMZLJfWKkgXuMFY5R/OxPegn/q9tK9ztd0XRH3aR0u2t+A7uQ==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-minify-font-values@6.1.0(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
+      postcss: 8.4.38
       postcss-value-parser: 4.2.0
-    dev: false
 
-  /postcss-minify-gradients@6.0.2(postcss@8.4.35):
-    resolution: {integrity: sha512-vP5mF7iI6/5fcpv+rSfwWQekOE+8I1i7/7RjZPGuIjj6eUaZVeG4XZYZrroFuw1WQd51u2V32wyQFZ+oYdE7CA==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-minify-gradients@6.0.3(postcss@8.4.38):
     dependencies:
       colord: 2.9.3
-      cssnano-utils: 4.0.1(postcss@8.4.35)
-      postcss: 8.4.35
+      cssnano-utils: 4.0.2(postcss@8.4.38)
+      postcss: 8.4.38
       postcss-value-parser: 4.2.0
-    dev: false
 
-  /postcss-minify-params@6.0.3(postcss@8.4.35):
-    resolution: {integrity: sha512-j4S74d3AAeCK5eGdQndXSrkxusV2ekOxbXGnlnZthMyZBBvSDiU34CihTASbJxuVB3bugudmwolS7+Dgs5OyOQ==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-minify-params@6.1.0(postcss@8.4.38):
     dependencies:
       browserslist: 4.23.0
-      cssnano-utils: 4.0.1(postcss@8.4.35)
-      postcss: 8.4.35
+      cssnano-utils: 4.0.2(postcss@8.4.38)
+      postcss: 8.4.38
       postcss-value-parser: 4.2.0
-    dev: false
 
-  /postcss-minify-selectors@6.0.2(postcss@8.4.35):
-    resolution: {integrity: sha512-0b+m+w7OAvZejPQdN2GjsXLv5o0jqYHX3aoV0e7RBKPCsB7TYG5KKWBFhGnB/iP3213Ts8c5H4wLPLMm7z28Sg==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-minify-selectors@6.0.4(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
-      postcss-selector-parser: 6.0.15
-    dev: false
+      postcss: 8.4.38
+      postcss-selector-parser: 6.0.16
 
-  /postcss-normalize-charset@6.0.1(postcss@8.4.35):
-    resolution: {integrity: sha512-aW5LbMNRZ+oDV57PF9K+WI1Z8MPnF+A8qbajg/T8PP126YrGX1f9IQx21GI2OlGz7XFJi/fNi0GTbY948XJtXg==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-normalize-charset@6.0.2(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
-    dev: false
+      postcss: 8.4.38
 
-  /postcss-normalize-display-values@6.0.1(postcss@8.4.35):
-    resolution: {integrity: sha512-mc3vxp2bEuCb4LgCcmG1y6lKJu1Co8T+rKHrcbShJwUmKJiEl761qb/QQCfFwlrvSeET3jksolCR/RZuMURudw==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-normalize-display-values@6.0.2(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
+      postcss: 8.4.38
       postcss-value-parser: 4.2.0
-    dev: false
 
-  /postcss-normalize-positions@6.0.1(postcss@8.4.35):
-    resolution: {integrity: sha512-HRsq8u/0unKNvm0cvwxcOUEcakFXqZ41fv3FOdPn916XFUrympjr+03oaLkuZENz3HE9RrQE9yU0Xv43ThWjQg==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-normalize-positions@6.0.2(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
+      postcss: 8.4.38
       postcss-value-parser: 4.2.0
-    dev: false
 
-  /postcss-normalize-repeat-style@6.0.1(postcss@8.4.35):
-    resolution: {integrity: sha512-Gbb2nmCy6tTiA7Sh2MBs3fj9W8swonk6lw+dFFeQT68B0Pzwp1kvisJQkdV6rbbMSd9brMlS8I8ts52tAGWmGQ==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-normalize-repeat-style@6.0.2(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
+      postcss: 8.4.38
       postcss-value-parser: 4.2.0
-    dev: false
 
-  /postcss-normalize-string@6.0.1(postcss@8.4.35):
-    resolution: {integrity: sha512-5Fhx/+xzALJD9EI26Aq23hXwmv97Zfy2VFrt5PLT8lAhnBIZvmaT5pQk+NuJ/GWj/QWaKSKbnoKDGLbV6qnhXg==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-normalize-string@6.0.2(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
+      postcss: 8.4.38
       postcss-value-parser: 4.2.0
-    dev: false
 
-  /postcss-normalize-timing-functions@6.0.1(postcss@8.4.35):
-    resolution: {integrity: sha512-4zcczzHqmCU7L5dqTB9rzeqPWRMc0K2HoR+Bfl+FSMbqGBUcP5LRfgcH4BdRtLuzVQK1/FHdFoGT3F7rkEnY+g==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-normalize-timing-functions@6.0.2(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
+      postcss: 8.4.38
       postcss-value-parser: 4.2.0
-    dev: false
 
-  /postcss-normalize-unicode@6.0.3(postcss@8.4.35):
-    resolution: {integrity: sha512-T2Bb3gXz0ASgc3ori2dzjv6j/P2IantreaC6fT8tWjqYUiqMAh5jGIkdPwEV2FaucjQlCLeFJDJh2BeSugE1ig==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-normalize-unicode@6.1.0(postcss@8.4.38):
     dependencies:
       browserslist: 4.23.0
-      postcss: 8.4.35
+      postcss: 8.4.38
       postcss-value-parser: 4.2.0
-    dev: false
 
-  /postcss-normalize-url@6.0.1(postcss@8.4.35):
-    resolution: {integrity: sha512-jEXL15tXSvbjm0yzUV7FBiEXwhIa9H88JOXDGQzmcWoB4mSjZIsmtto066s2iW9FYuIrIF4k04HA2BKAOpbsaQ==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-normalize-url@6.0.2(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
+      postcss: 8.4.38
       postcss-value-parser: 4.2.0
-    dev: false
 
-  /postcss-normalize-whitespace@6.0.1(postcss@8.4.35):
-    resolution: {integrity: sha512-76i3NpWf6bB8UHlVuLRxG4zW2YykF9CTEcq/9LGAiz2qBuX5cBStadkk0jSkg9a9TCIXbMQz7yzrygKoCW9JuA==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-normalize-whitespace@6.0.2(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
+      postcss: 8.4.38
       postcss-value-parser: 4.2.0
-    dev: false
 
-  /postcss-ordered-values@6.0.1(postcss@8.4.35):
-    resolution: {integrity: sha512-XXbb1O/MW9HdEhnBxitZpPFbIvDgbo9NK4c/5bOfiKpnIGZDoL2xd7/e6jW5DYLsWxBbs+1nZEnVgnjnlFViaA==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-ordered-values@6.0.2(postcss@8.4.38):
     dependencies:
-      cssnano-utils: 4.0.1(postcss@8.4.35)
-      postcss: 8.4.35
+      cssnano-utils: 4.0.2(postcss@8.4.38)
+      postcss: 8.4.38
       postcss-value-parser: 4.2.0
-    dev: false
 
-  /postcss-reduce-initial@6.0.3(postcss@8.4.35):
-    resolution: {integrity: sha512-w4QIR9pEa1N4xMx3k30T1vLZl6udVK2RmNqrDXhBXX9L0mBj2a8ADs8zkbaEH7eUy1m30Wyr5EBgHN31Yq1JvA==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-reduce-initial@6.1.0(postcss@8.4.38):
     dependencies:
       browserslist: 4.23.0
       caniuse-api: 3.0.0
-      postcss: 8.4.35
-    dev: false
+      postcss: 8.4.38
 
-  /postcss-reduce-transforms@6.0.1(postcss@8.4.35):
-    resolution: {integrity: sha512-fUbV81OkUe75JM+VYO1gr/IoA2b/dRiH6HvMwhrIBSUrxq3jNZQZitSnugcTLDi1KkQh1eR/zi+iyxviUNBkcQ==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-reduce-transforms@6.0.2(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
+      postcss: 8.4.38
       postcss-value-parser: 4.2.0
-    dev: false
 
-  /postcss-selector-parser@6.0.15:
-    resolution: {integrity: sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==}
-    engines: {node: '>=4'}
+  postcss-selector-parser@6.0.15:
     dependencies:
       cssesc: 3.0.0
       util-deprecate: 1.0.2
 
-  /postcss-svgo@6.0.2(postcss@8.4.35):
-    resolution: {integrity: sha512-IH5R9SjkTkh0kfFOQDImyy1+mTCb+E830+9SV1O+AaDcoHTvfsvt6WwJeo7KwcHbFnevZVCsXhDmjFiGVuwqFQ==}
-    engines: {node: ^14 || ^16 || >= 18}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-selector-parser@6.0.16:
     dependencies:
-      postcss: 8.4.35
+      cssesc: 3.0.0
+      util-deprecate: 1.0.2
+
+  postcss-svgo@6.0.3(postcss@8.4.38):
+    dependencies:
+      postcss: 8.4.38
       postcss-value-parser: 4.2.0
       svgo: 3.2.0
-    dev: false
 
-  /postcss-unique-selectors@6.0.2(postcss@8.4.35):
-    resolution: {integrity: sha512-8IZGQ94nechdG7Y9Sh9FlIY2b4uS8/k8kdKRX040XHsS3B6d1HrJAkXrBSsSu4SuARruSsUjW3nlSw8BHkaAYQ==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  postcss-unique-selectors@6.0.4(postcss@8.4.38):
     dependencies:
-      postcss: 8.4.35
-      postcss-selector-parser: 6.0.15
-    dev: false
+      postcss: 8.4.38
+      postcss-selector-parser: 6.0.16
 
-  /postcss-value-parser@4.2.0:
-    resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
-    dev: false
+  postcss-value-parser@4.2.0: {}
 
-  /postcss@8.4.35:
-    resolution: {integrity: sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==}
-    engines: {node: ^10 || ^12 || >=14}
+  postcss@8.4.38:
     dependencies:
       nanoid: 3.3.7
       picocolors: 1.0.0
-      source-map-js: 1.0.2
+      source-map-js: 1.2.0
 
-  /postgres-array@2.0.0:
-    resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
-    engines: {node: '>=4'}
-    dev: false
+  postgres-array@2.0.0: {}
 
-  /postgres-array@3.0.2:
-    resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==}
-    engines: {node: '>=12'}
-    dev: true
+  postgres-array@3.0.2: {}
 
-  /postgres-bytea@1.0.0:
-    resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==}
-    engines: {node: '>=0.10.0'}
-    dev: false
+  postgres-bytea@1.0.0: {}
 
-  /postgres-bytea@3.0.0:
-    resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==}
-    engines: {node: '>= 6'}
+  postgres-bytea@3.0.0:
     dependencies:
       obuf: 1.1.2
-    dev: true
 
-  /postgres-date@1.0.7:
-    resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==}
-    engines: {node: '>=0.10.0'}
-    dev: false
+  postgres-date@1.0.7: {}
 
-  /postgres-date@2.0.1:
-    resolution: {integrity: sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw==}
-    engines: {node: '>=12'}
-    dev: true
+  postgres-date@2.0.1: {}
 
-  /postgres-interval@1.2.0:
-    resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
-    engines: {node: '>=0.10.0'}
+  postgres-interval@1.2.0:
     dependencies:
       xtend: 4.0.2
-    dev: false
 
-  /postgres-interval@3.0.0:
-    resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==}
-    engines: {node: '>=12'}
-    dev: true
+  postgres-interval@3.0.0: {}
 
-  /postgres-range@1.1.3:
-    resolution: {integrity: sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==}
-    dev: true
+  postgres-range@1.1.3: {}
 
-  /prelude-ls@1.2.1:
-    resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
-    engines: {node: '>= 0.8.0'}
-    dev: true
+  prelude-ls@1.2.1: {}
 
-  /prettier@3.2.5:
-    resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==}
-    engines: {node: '>=14'}
-    hasBin: true
-    dev: true
+  prettier@3.2.5: {}
 
-  /pretty-bytes@5.6.0:
-    resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==}
-    engines: {node: '>=6'}
-    dev: true
+  pretty-bytes@5.6.0: {}
 
-  /pretty-format@27.5.1:
-    resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}
-    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
+  pretty-format@27.5.1:
     dependencies:
       ansi-regex: 5.0.1
       ansi-styles: 5.2.0
       react-is: 17.0.2
-    dev: true
 
-  /pretty-format@29.7.0:
-    resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+  pretty-format@29.7.0:
     dependencies:
       '@jest/schemas': 29.6.3
       ansi-styles: 5.2.0
       react-is: 18.2.0
-    dev: true
 
-  /pretty-hrtime@1.0.3:
-    resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==}
-    engines: {node: '>= 0.8'}
-    dev: true
+  pretty-hrtime@1.0.3: {}
 
-  /private-ip@2.3.3:
-    resolution: {integrity: sha512-5zyFfekIVUOTVbL92hc8LJOtE/gyGHeREHkJ2yTyByP8Q2YZVoBqLg3EfYLeF0oVvGqtaEX2t2Qovja0/gStXw==}
+  private-ip@2.3.3:
     dependencies:
       ip-regex: 4.3.0
-      ipaddr.js: 2.1.0
+      ipaddr.js: 2.2.0
       is-ip: 3.1.0
       netmask: 2.0.2
 
-  /probe-image-size@7.2.3:
-    resolution: {integrity: sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w==}
+  probe-image-size@7.2.3:
     dependencies:
       lodash.merge: 4.6.2
       needle: 2.9.1
       stream-parser: 0.3.1
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /proc-log@3.0.0:
-    resolution: {integrity: sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==}
-    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-    dev: false
+  proc-log@3.0.0: {}
 
-  /process-exists@5.0.0:
-    resolution: {integrity: sha512-6QPRh5fyHD8MaXr4GYML8K/YY0Sq5dKHGIOrAKS3cYpHQdmygFCcijIu1dVoNKAZ0TWAMoeh8KDK9dF8auBkJA==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+  process-exists@5.0.0:
     dependencies:
       ps-list: 8.1.1
-    dev: true
 
-  /process-nextick-args@2.0.1:
-    resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
+  process-nextick-args@2.0.1: {}
 
-  /process-warning@2.2.0:
-    resolution: {integrity: sha512-/1WZ8+VQjR6avWOgHeEPd7SDQmFQ1B5mC1eRXsCm5TarlNmx/wCsa5GEaxGm05BORRtyG/Ex/3xq3TuRvq57qg==}
-    dev: false
+  process-warning@2.2.0: {}
 
-  /process-warning@3.0.0:
-    resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==}
-    dev: false
+  process-warning@3.0.0: {}
 
-  /process@0.11.10:
-    resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
-    engines: {node: '>= 0.6.0'}
+  process@0.11.10: {}
 
-  /progress@2.0.3:
-    resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
-    engines: {node: '>=0.4.0'}
-    requiresBuild: true
-    dev: false
+  progress@2.0.3:
     optional: true
 
-  /promise-limit@2.7.0:
-    resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==}
-    dev: false
+  promise-limit@2.7.0: {}
 
-  /promise-polyfill@8.3.0:
-    resolution: {integrity: sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg==}
-    dev: true
+  promise-polyfill@8.3.0: {}
 
-  /promise-retry@2.0.1:
-    resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==}
-    engines: {node: '>=10'}
+  promise-retry@2.0.1:
     dependencies:
       err-code: 2.0.3
       retry: 0.12.0
-    dev: false
 
-  /promise@7.3.1:
-    resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==}
+  promise@7.3.1:
     dependencies:
       asap: 2.0.6
 
-  /prompts@2.4.2:
-    resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
-    engines: {node: '>= 6'}
+  prompts@2.4.2:
     dependencies:
       kleur: 3.0.3
       sisteransi: 1.0.5
-    dev: true
 
-  /prop-types@15.8.1:
-    resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
+  prop-types@15.8.1:
     dependencies:
       loose-envify: 1.4.0
       object-assign: 4.1.1
       react-is: 16.13.1
-    dev: true
 
-  /proto-list@1.2.4:
-    resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
-    dev: true
+  proto-list@1.2.4: {}
 
-  /proxy-addr@2.0.7:
-    resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
-    engines: {node: '>= 0.10'}
+  proxy-addr@2.0.7:
     dependencies:
       forwarded: 0.2.0
       ipaddr.js: 1.9.1
 
-  /proxy-from-env@1.0.0:
-    resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==}
-    dev: true
+  proxy-from-env@1.0.0: {}
 
-  /proxy-from-env@1.1.0:
-    resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
-    dev: true
+  proxy-from-env@1.1.0: {}
 
-  /ps-list@8.1.1:
-    resolution: {integrity: sha512-OPS9kEJYVmiO48u/B9qneqhkMvgCxT+Tm28VCEJpheTpl8cJ0ffZRRNgS5mrQRTrX5yRTpaJ+hRDeefXYmmorQ==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
-    dev: true
+  ps-list@8.1.1: {}
 
-  /ps-tree@1.2.0:
-    resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==}
-    engines: {node: '>= 0.10'}
-    hasBin: true
+  ps-tree@1.2.0:
     dependencies:
       event-stream: 3.3.4
-    dev: true
 
-  /pseudomap@1.0.2:
-    resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
-    dev: false
+  pseudomap@1.0.2: {}
 
-  /psl@1.9.0:
-    resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
+  psl@1.9.0: {}
 
-  /pstree.remy@1.1.8:
-    resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==}
-    dev: true
+  pstree.remy@1.1.8: {}
 
-  /pug-attrs@3.0.0:
-    resolution: {integrity: sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==}
+  pug-attrs@3.0.0:
     dependencies:
       constantinople: 4.0.1
       js-stringify: 1.0.2
       pug-runtime: 3.0.1
 
-  /pug-code-gen@3.0.2:
-    resolution: {integrity: sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==}
+  pug-code-gen@3.0.2:
     dependencies:
       constantinople: 4.0.1
       doctypes: 1.1.0
@@ -16737,11 +21518,9 @@ packages:
       void-elements: 3.1.0
       with: 7.0.2
 
-  /pug-error@2.0.0:
-    resolution: {integrity: sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==}
+  pug-error@2.0.0: {}
 
-  /pug-filters@4.0.0:
-    resolution: {integrity: sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==}
+  pug-filters@4.0.0:
     dependencies:
       constantinople: 4.0.1
       jstransformer: 1.0.0
@@ -16749,44 +21528,36 @@ packages:
       pug-walk: 2.0.0
       resolve: 1.22.8
 
-  /pug-lexer@5.0.1:
-    resolution: {integrity: sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==}
+  pug-lexer@5.0.1:
     dependencies:
       character-parser: 2.2.0
       is-expression: 4.0.0
       pug-error: 2.0.0
 
-  /pug-linker@4.0.0:
-    resolution: {integrity: sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==}
+  pug-linker@4.0.0:
     dependencies:
       pug-error: 2.0.0
       pug-walk: 2.0.0
 
-  /pug-load@3.0.0:
-    resolution: {integrity: sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==}
+  pug-load@3.0.0:
     dependencies:
       object-assign: 4.1.1
       pug-walk: 2.0.0
 
-  /pug-parser@6.0.0:
-    resolution: {integrity: sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==}
+  pug-parser@6.0.0:
     dependencies:
       pug-error: 2.0.0
       token-stream: 1.0.0
 
-  /pug-runtime@3.0.1:
-    resolution: {integrity: sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==}
+  pug-runtime@3.0.1: {}
 
-  /pug-strip-comments@2.0.0:
-    resolution: {integrity: sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==}
+  pug-strip-comments@2.0.0:
     dependencies:
       pug-error: 2.0.0
 
-  /pug-walk@2.0.0:
-    resolution: {integrity: sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==}
+  pug-walk@2.0.0: {}
 
-  /pug@3.0.2:
-    resolution: {integrity: sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==}
+  pug@3.0.2:
     dependencies:
       pug-code-gen: 3.0.2
       pug-filters: 4.0.0
@@ -16797,194 +21568,113 @@ packages:
       pug-runtime: 3.0.1
       pug-strip-comments: 2.0.0
 
-  /pump@2.0.1:
-    resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==}
-    dependencies:
-      end-of-stream: 1.4.4
-      once: 1.4.0
-    dev: true
-
-  /pump@3.0.0:
-    resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
+  pump@2.0.1:
     dependencies:
       end-of-stream: 1.4.4
       once: 1.4.0
 
-  /pumpify@1.5.1:
-    resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==}
+  pump@3.0.0:
+    dependencies:
+      end-of-stream: 1.4.4
+      once: 1.4.0
+
+  pumpify@1.5.1:
     dependencies:
       duplexify: 3.7.1
       inherits: 2.0.4
       pump: 2.0.1
-    dev: true
 
-  /punycode@2.3.1:
-    resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
-    engines: {node: '>=6'}
+  punycode@2.3.1: {}
 
-  /pure-rand@6.0.0:
-    resolution: {integrity: sha512-rLSBxJjP+4DQOgcJAx6RZHT2he2pkhQdSnofG5VWyVl6GRq/K02ISOuOLcsMOrtKDIJb8JN2zm3FFzWNbezdPw==}
-    dev: true
+  pure-rand@6.0.0: {}
 
-  /pureimage@0.3.17:
-    resolution: {integrity: sha512-JV4hfYF1BXxDwbSR8hjhVEhVTxwmAXos8uIXQ7Bw2eWrUEpLDJnQoQ8WLlWAO4TMGJ7mp9n6gvLKJ6MSaGUkXQ==}
-    engines: {node: '>=0.8'}
-    dependencies:
-      jpeg-js: 0.4.4
-      opentype.js: 0.4.11
-      pngjs: 3.4.0
-    dev: false
-
-  /pvtsutils@1.3.5:
-    resolution: {integrity: sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==}
+  pvtsutils@1.3.5:
     dependencies:
       tslib: 2.6.2
-    dev: false
 
-  /pvutils@1.1.3:
-    resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==}
-    engines: {node: '>=6.0.0'}
-    dev: false
+  pvutils@1.1.3: {}
 
-  /qrcode@1.5.3:
-    resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==}
-    engines: {node: '>=10.13.0'}
-    hasBin: true
+  qrcode@1.5.3:
     dependencies:
       dijkstrajs: 1.0.2
       encode-utf8: 1.0.3
       pngjs: 5.0.0
       yargs: 15.4.1
-    dev: false
 
-  /qs@6.10.4:
-    resolution: {integrity: sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==}
-    engines: {node: '>=0.6'}
-    dependencies:
-      side-channel: 1.0.4
-    dev: true
-
-  /qs@6.11.0:
-    resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
-    engines: {node: '>=0.6'}
+  qs@6.10.4:
     dependencies:
       side-channel: 1.0.4
 
-  /qs@6.11.1:
-    resolution: {integrity: sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ==}
-    engines: {node: '>=0.6'}
+  qs@6.11.0:
     dependencies:
       side-channel: 1.0.4
-    dev: true
 
-  /qs@6.5.3:
-    resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==}
-    engines: {node: '>=0.6'}
-    dev: false
+  qs@6.11.1:
+    dependencies:
+      side-channel: 1.0.4
 
-  /querystringify@2.2.0:
-    resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
+  qs@6.5.3: {}
 
-  /queue-lit@1.5.0:
-    resolution: {integrity: sha512-IslToJ4eiCEE9xwMzq3viOO5nH8sUWUCwoElrhNMozzr9IIt2qqvB4I+uHu/zJTQVqc9R5DFwok4ijNK1pU3fA==}
-    dev: false
+  querystringify@2.2.0: {}
 
-  /queue-microtask@1.2.3:
-    resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+  queue-lit@1.5.0: {}
 
-  /queue-tick@1.0.1:
-    resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==}
-    dev: false
+  queue-microtask@1.2.3: {}
 
-  /quick-format-unescaped@4.0.4:
-    resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
-    dev: false
+  queue-tick@1.0.1: {}
 
-  /quick-lru@4.0.1:
-    resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==}
-    engines: {node: '>=8'}
-    dev: true
+  quick-format-unescaped@4.0.4: {}
 
-  /quick-lru@5.1.1:
-    resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
-    engines: {node: '>=10'}
+  quick-lru@4.0.1: {}
 
-  /ramda@0.29.0:
-    resolution: {integrity: sha512-BBea6L67bYLtdbOqfp8f58fPMqEwx0doL+pAi8TZyp2YWz8R9G8z9x75CZI8W+ftqhFHCpEX2cRnUUXK130iKA==}
-    dev: true
+  quick-lru@5.1.1: {}
 
-  /random-seed@0.3.0:
-    resolution: {integrity: sha512-y13xtn3kcTlLub3HKWXxJNeC2qK4mB59evwZ5EkeRlolx+Bp2ztF7LbcZmyCnOqlHQrLnfuNbi1sVmm9lPDlDA==}
-    engines: {node: '>= 0.6.0'}
+  ramda@0.29.0: {}
+
+  random-seed@0.3.0:
     dependencies:
       json-stringify-safe: 5.0.1
-    dev: false
 
-  /range-parser@1.2.1:
-    resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
-    engines: {node: '>= 0.6'}
+  range-parser@1.2.1: {}
 
-  /ratelimiter@3.4.1:
-    resolution: {integrity: sha512-5FJbRW/Jkkdk29ksedAfWFkQkhbUrMx3QJGwMKAypeIiQf4yrLW+gtPKZiaWt4zPrtw1uGufOjGO7UGM6VllsQ==}
-    dev: false
+  ratelimiter@3.4.1: {}
 
-  /raw-body@2.5.1:
-    resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==}
-    engines: {node: '>= 0.8'}
+  raw-body@2.5.1:
     dependencies:
       bytes: 3.1.2
       http-errors: 2.0.0
       iconv-lite: 0.4.24
       unpipe: 1.0.0
 
-  /raw-body@2.5.2:
-    resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
-    engines: {node: '>= 0.8'}
+  raw-body@2.5.2:
     dependencies:
       bytes: 3.1.2
       http-errors: 2.0.0
       iconv-lite: 0.4.24
       unpipe: 1.0.0
 
-  /rdf-canonize@3.4.0:
-    resolution: {integrity: sha512-fUeWjrkOO0t1rg7B2fdyDTvngj+9RlUyL92vOdiB7c0FPguWVsniIMjEtHH+meLBO9rzkUlUzBVXgWrjI8P9LA==}
-    engines: {node: '>=12'}
+  rdf-canonize@3.4.0:
     dependencies:
       setimmediate: 1.0.5
-    dev: false
 
-  /re2@1.20.9:
-    resolution: {integrity: sha512-ZYcPTFr5ha2xq3WQjBDTF9CWPSDK1z28MLh5UFRxc//7X8BNQ3A7yR7ITnP0jO346661ertdKVFqw1qoL3FMEQ==}
-    requiresBuild: true
+  re2@1.20.10:
     dependencies:
       install-artifact-from-github: 1.3.5
       nan: 2.18.0
       node-gyp: 10.0.1
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /react-colorful@5.6.1(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==}
-    peerDependencies:
-      react: '>=16.8.0'
-      react-dom: '>=16.8.0'
+  react-colorful@5.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
     dependencies:
-      react: 18.2.0
-      react-dom: 18.2.0(react@18.2.0)
-    dev: true
+      react: 18.3.1
+      react-dom: 18.3.1(react@18.3.1)
 
-  /react-docgen-typescript@2.2.2(typescript@5.3.3):
-    resolution: {integrity: sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==}
-    peerDependencies:
-      typescript: '>= 4.3.x'
+  react-docgen-typescript@2.2.2(typescript@5.4.5):
     dependencies:
-      typescript: 5.3.3
-    dev: true
+      typescript: 5.4.5
 
-  /react-docgen@7.0.1:
-    resolution: {integrity: sha512-rCz0HBIT0LWbIM+///LfRrJoTKftIzzwsYDf0ns5KwaEjejMHQRtphcns+IXFHDNY9pnz6G8l/JbbI6pD4EAIA==}
-    engines: {node: '>=16.14.0'}
+  react-docgen@7.0.1:
     dependencies:
       '@babel/core': 7.24.0
       '@babel/traverse': 7.24.0
@@ -16998,84 +21688,54 @@ packages:
       strip-indent: 4.0.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /react-dom@18.2.0(react@18.2.0):
-    resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
-    peerDependencies:
-      react: ^18.2.0
+  react-dom@18.3.1(react@18.3.1):
     dependencies:
       loose-envify: 1.4.0
-      react: 18.2.0
-      scheduler: 0.23.0
-    dev: true
+      react: 18.3.1
+      scheduler: 0.23.2
 
-  /react-element-to-jsx-string@15.0.0(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-UDg4lXB6BzlobN60P8fHWVPX3Kyw8ORrTeBtClmIlGdkOOE+GYQSFvmEU5iLLpwp/6v42DINwNcwOhOLfQ//FQ==}
-    peerDependencies:
-      react: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0
-      react-dom: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0
+  react-element-to-jsx-string@15.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
     dependencies:
       '@base2/pretty-print-object': 1.0.1
       is-plain-object: 5.0.0
-      react: 18.2.0
-      react-dom: 18.2.0(react@18.2.0)
+      react: 18.3.1
+      react-dom: 18.3.1(react@18.3.1)
       react-is: 18.1.0
-    dev: true
 
-  /react-is@16.13.1:
-    resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
-    dev: true
+  react-is@16.13.1: {}
 
-  /react-is@17.0.2:
-    resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
-    dev: true
+  react-is@17.0.2: {}
 
-  /react-is@18.1.0:
-    resolution: {integrity: sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==}
-    dev: true
+  react-is@18.1.0: {}
 
-  /react-is@18.2.0:
-    resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
-    dev: true
+  react-is@18.2.0: {}
 
-  /react@18.2.0:
-    resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
-    engines: {node: '>=0.10.0'}
+  react@18.3.1:
     dependencies:
       loose-envify: 1.4.0
-    dev: true
 
-  /read-pkg-up@7.0.1:
-    resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==}
-    engines: {node: '>=8'}
+  read-pkg-up@7.0.1:
     dependencies:
       find-up: 4.1.0
       read-pkg: 5.2.0
       type-fest: 0.8.1
-    dev: true
 
-  /read-pkg@5.2.0:
-    resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==}
-    engines: {node: '>=8'}
+  read-pkg@5.2.0:
     dependencies:
       '@types/normalize-package-data': 2.4.1
       normalize-package-data: 2.5.0
       parse-json: 5.2.0
       type-fest: 0.6.0
-    dev: true
 
-  /readable-stream@1.1.14:
-    resolution: {integrity: sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==}
+  readable-stream@1.1.14:
     dependencies:
       core-util-is: 1.0.3
       inherits: 2.0.4
       isarray: 0.0.1
       string_decoder: 0.10.31
-    dev: false
 
-  /readable-stream@2.3.7:
-    resolution: {integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==}
+  readable-stream@2.3.7:
     dependencies:
       core-util-is: 1.0.3
       inherits: 2.0.4
@@ -17085,145 +21745,91 @@ packages:
       string_decoder: 1.1.1
       util-deprecate: 1.0.2
 
-  /readable-stream@3.6.0:
-    resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==}
-    engines: {node: '>= 6'}
+  readable-stream@3.6.0:
     dependencies:
       inherits: 2.0.4
       string_decoder: 1.3.0
       util-deprecate: 1.0.2
 
-  /readable-stream@4.3.0:
-    resolution: {integrity: sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ==}
-    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+  readable-stream@4.3.0:
     dependencies:
       abort-controller: 3.0.0
       buffer: 6.0.3
       events: 3.3.0
       process: 0.11.10
-    dev: false
 
-  /readable-web-to-node-stream@3.0.2:
-    resolution: {integrity: sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==}
-    engines: {node: '>=8'}
+  readable-web-to-node-stream@3.0.2:
     dependencies:
       readable-stream: 3.6.0
-    dev: false
 
-  /readdir-glob@1.1.2:
-    resolution: {integrity: sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA==}
+  readdir-glob@1.1.2:
     dependencies:
       minimatch: 5.1.2
-    dev: false
 
-  /readdirp@3.6.0:
-    resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
-    engines: {node: '>=8.10.0'}
+  readdirp@3.6.0:
     dependencies:
       picomatch: 2.3.1
 
-  /real-require@0.2.0:
-    resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
-    engines: {node: '>= 12.13.0'}
-    dev: false
+  real-require@0.2.0: {}
 
-  /recast@0.23.4:
-    resolution: {integrity: sha512-qtEDqIZGVcSZCHniWwZWbRy79Dc6Wp3kT/UmDA2RJKBPg7+7k51aQBZirHmUGn5uvHf2rg8DkjizrN26k61ATw==}
-    engines: {node: '>= 4'}
+  recast@0.23.4:
     dependencies:
       assert: 2.1.0
       ast-types: 0.16.1
       esprima: 4.0.1
       source-map: 0.6.1
       tslib: 2.6.2
-    dev: true
 
-  /recast@0.23.6:
-    resolution: {integrity: sha512-9FHoNjX1yjuesMwuthAmPKabxYQdOgihFYmT5ebXfYGBcnqXZf3WOVz+5foEZ8Y83P4ZY6yQD5GMmtV+pgCCAQ==}
-    engines: {node: '>= 4'}
+  recast@0.23.6:
     dependencies:
       ast-types: 0.16.1
       esprima: 4.0.1
       source-map: 0.6.1
       tiny-invariant: 1.3.3
       tslib: 2.6.2
-    dev: true
 
-  /reconnecting-websocket@4.4.0:
-    resolution: {integrity: sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==}
-    dev: false
+  reconnecting-websocket@4.4.0: {}
 
-  /redent@3.0.0:
-    resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
-    engines: {node: '>=8'}
+  redent@3.0.0:
     dependencies:
       indent-string: 4.0.0
       strip-indent: 3.0.0
-    dev: true
 
-  /redis-errors@1.2.0:
-    resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==}
-    engines: {node: '>=4'}
-    dev: false
+  redis-errors@1.2.0: {}
 
-  /redis-info@3.1.0:
-    resolution: {integrity: sha512-ER4L9Sh/vm63DkIE0bkSjxluQlioBiBgf5w1UuldaW/3vPcecdljVDisZhmnCMvsxHNiARTTDDHGg9cGwTfrKg==}
+  redis-info@3.1.0:
     dependencies:
       lodash: 4.17.21
-    dev: false
 
-  /redis-lock@0.1.4:
-    resolution: {integrity: sha512-7/+zu86XVQfJVx1nHTzux5reglDiyUCDwmW7TSlvVezfhH2YLc/Rc8NE0ejQG+8/0lwKzm29/u/4+ogKeLosiA==}
-    engines: {node: '>=0.6'}
-    dev: false
+  redis-lock@0.1.4: {}
 
-  /redis-parser@3.0.0:
-    resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==}
-    engines: {node: '>=4'}
+  redis-parser@3.0.0:
     dependencies:
       redis-errors: 1.2.0
-    dev: false
 
-  /reflect-metadata@0.2.1:
-    resolution: {integrity: sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==}
+  reflect-metadata@0.2.2: {}
 
-  /regenerate-unicode-properties@10.1.0:
-    resolution: {integrity: sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==}
-    engines: {node: '>=4'}
+  regenerate-unicode-properties@10.1.0:
     dependencies:
       regenerate: 1.4.2
-    dev: true
 
-  /regenerate@1.4.2:
-    resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==}
-    dev: true
+  regenerate@1.4.2: {}
 
-  /regenerator-runtime@0.13.11:
-    resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
-    requiresBuild: true
-    dev: false
+  regenerator-runtime@0.13.11: {}
 
-  /regenerator-runtime@0.14.0:
-    resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==}
+  regenerator-runtime@0.14.0: {}
 
-  /regenerator-transform@0.15.2:
-    resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==}
+  regenerator-transform@0.15.2:
     dependencies:
       '@babel/runtime': 7.23.4
-    dev: true
 
-  /regexp.prototype.flags@1.5.0:
-    resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==}
-    engines: {node: '>= 0.4'}
+  regexp.prototype.flags@1.5.0:
     dependencies:
       call-bind: 1.0.2
       define-properties: 1.2.0
       functions-have-names: 1.2.3
-    dev: true
 
-  /regexpu-core@5.3.2:
-    resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==}
-    engines: {node: '>=4'}
+  regexpu-core@5.3.2:
     dependencies:
       '@babel/regjsgen': 0.8.0
       regenerate: 1.4.2
@@ -17231,17 +21837,12 @@ packages:
       regjsparser: 0.9.1
       unicode-match-property-ecmascript: 2.0.0
       unicode-match-property-value-ecmascript: 2.1.0
-    dev: true
 
-  /regjsparser@0.9.1:
-    resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==}
-    hasBin: true
+  regjsparser@0.9.1:
     dependencies:
       jsesc: 0.5.0
-    dev: true
 
-  /rehype-external-links@3.0.0:
-    resolution: {integrity: sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==}
+  rehype-external-links@3.0.0:
     dependencies:
       '@types/hast': 3.0.4
       '@ungap/structured-clone': 1.2.0
@@ -17249,20 +21850,16 @@ packages:
       is-absolute-url: 4.0.1
       space-separated-tokens: 2.0.2
       unist-util-visit: 5.0.0
-    dev: true
 
-  /rehype-slug@6.0.0:
-    resolution: {integrity: sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==}
+  rehype-slug@6.0.0:
     dependencies:
       '@types/hast': 3.0.4
       github-slugger: 2.0.0
       hast-util-heading-rank: 3.0.0
       hast-util-to-string: 3.0.0
       unist-util-visit: 5.0.0
-    dev: true
 
-  /remark-gfm@4.0.0:
-    resolution: {integrity: sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==}
+  remark-gfm@4.0.0:
     dependencies:
       '@types/mdast': 4.0.3
       mdast-util-gfm: 3.0.0
@@ -17272,10 +21869,8 @@ packages:
       unified: 11.0.4
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /remark-parse@11.0.0:
-    resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==}
+  remark-parse@11.0.0:
     dependencies:
       '@types/mdast': 4.0.3
       mdast-util-from-markdown: 2.0.0
@@ -17283,34 +21878,24 @@ packages:
       unified: 11.0.4
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /remark-stringify@11.0.0:
-    resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==}
+  remark-stringify@11.0.0:
     dependencies:
       '@types/mdast': 4.0.3
       mdast-util-to-markdown: 2.1.0
       unified: 11.0.4
-    dev: true
 
-  /rename@1.0.4:
-    resolution: {integrity: sha512-YMM6Fn3lrFOCjhORKjj+z/yizj8WSzv3F3YUlpJA20fteWCb0HbJU19nvuRBPUM5dWgxJcHP+kix3M+5NowJyA==}
+  rename@1.0.4:
     dependencies:
       debug: 2.6.9
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /request-progress@3.0.0:
-    resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==}
+  request-progress@3.0.0:
     dependencies:
       throttleit: 1.0.0
-    dev: true
 
-  /request@2.88.2:
-    resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==}
-    engines: {node: '>= 6'}
-    deprecated: request has been deprecated, see https://github.com/request/request/issues/3142
+  request@2.88.2:
     dependencies:
       aws-sign2: 0.7.0
       aws4: 1.12.0
@@ -17332,302 +21917,184 @@ packages:
       tough-cookie: 2.5.0
       tunnel-agent: 0.6.0
       uuid: 3.4.0
-    dev: false
 
-  /require-directory@2.1.1:
-    resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
-    engines: {node: '>=0.10.0'}
+  require-directory@2.1.1: {}
 
-  /require-from-string@2.0.2:
-    resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
-    engines: {node: '>=0.10.0'}
+  require-from-string@2.0.2: {}
 
-  /require-main-filename@2.0.0:
-    resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
-    dev: false
+  require-main-filename@2.0.0: {}
 
-  /requires-port@1.0.0:
-    resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
+  requires-port@1.0.0: {}
 
-  /resolve-alpn@1.2.1:
-    resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
+  resolve-alpn@1.2.1: {}
 
-  /resolve-cwd@3.0.0:
-    resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
-    engines: {node: '>=8'}
+  resolve-cwd@3.0.0:
     dependencies:
       resolve-from: 5.0.0
-    dev: true
 
-  /resolve-from@4.0.0:
-    resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
-    engines: {node: '>=4'}
-    dev: true
+  resolve-from@4.0.0: {}
 
-  /resolve-from@5.0.0:
-    resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
-    engines: {node: '>=8'}
-    dev: true
+  resolve-from@5.0.0: {}
 
-  /resolve-pkg-maps@1.0.0:
-    resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
-    dev: true
+  resolve-pkg-maps@1.0.0: {}
 
-  /resolve.exports@2.0.0:
-    resolution: {integrity: sha512-6K/gDlqgQscOlg9fSRpWstA8sYe8rbELsSTNpx+3kTrsVCzvSl0zIvRErM7fdl9ERWDsKnrLnwB+Ne89918XOg==}
-    engines: {node: '>=10'}
-    dev: true
+  resolve.exports@2.0.0: {}
 
-  /resolve@1.19.0:
-    resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==}
+  resolve@1.19.0:
     dependencies:
       is-core-module: 2.13.1
       path-parse: 1.0.7
-    dev: true
 
-  /resolve@1.22.8:
-    resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
-    hasBin: true
+  resolve@1.22.8:
     dependencies:
       is-core-module: 2.13.1
       path-parse: 1.0.7
       supports-preserve-symlinks-flag: 1.0.0
 
-  /responselike@2.0.1:
-    resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==}
+  responselike@2.0.1:
     dependencies:
       lowercase-keys: 2.0.0
-    dev: false
 
-  /responselike@3.0.0:
-    resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==}
-    engines: {node: '>=14.16'}
+  responselike@3.0.0:
     dependencies:
       lowercase-keys: 3.0.0
 
-  /restore-cursor@3.1.0:
-    resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
-    engines: {node: '>=8'}
+  restore-cursor@3.1.0:
     dependencies:
       onetime: 5.1.2
       signal-exit: 3.0.7
-    dev: true
 
-  /ret@0.2.2:
-    resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==}
-    engines: {node: '>=4'}
-    dev: false
+  ret@0.4.3: {}
 
-  /retry@0.12.0:
-    resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==}
-    engines: {node: '>= 4'}
-    dev: false
+  retry@0.12.0: {}
 
-  /reusify@1.0.4:
-    resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
-    engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+  reusify@1.0.4: {}
 
-  /rfdc@1.3.0:
-    resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==}
+  rfdc@1.3.0: {}
 
-  /rimraf@2.6.3:
-    resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==}
-    hasBin: true
+  rimraf@2.6.3:
     dependencies:
       glob: 7.2.3
-    dev: true
 
-  /rimraf@2.7.1:
-    resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
-    hasBin: true
-    requiresBuild: true
+  rimraf@2.7.1:
     dependencies:
       glob: 7.2.3
-    dev: false
     optional: true
 
-  /rimraf@3.0.2:
-    resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
-    hasBin: true
+  rimraf@3.0.2:
     dependencies:
       glob: 7.2.3
 
-  /rimraf@5.0.5:
-    resolution: {integrity: sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==}
-    engines: {node: '>=14'}
-    hasBin: true
-    dependencies:
-      glob: 10.3.10
-
-  /rollup@4.12.0:
-    resolution: {integrity: sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q==}
-    engines: {node: '>=18.0.0', npm: '>=8.0.0'}
-    hasBin: true
+  rollup@4.17.2:
     dependencies:
       '@types/estree': 1.0.5
     optionalDependencies:
-      '@rollup/rollup-android-arm-eabi': 4.12.0
-      '@rollup/rollup-android-arm64': 4.12.0
-      '@rollup/rollup-darwin-arm64': 4.12.0
-      '@rollup/rollup-darwin-x64': 4.12.0
-      '@rollup/rollup-linux-arm-gnueabihf': 4.12.0
-      '@rollup/rollup-linux-arm64-gnu': 4.12.0
-      '@rollup/rollup-linux-arm64-musl': 4.12.0
-      '@rollup/rollup-linux-riscv64-gnu': 4.12.0
-      '@rollup/rollup-linux-x64-gnu': 4.12.0
-      '@rollup/rollup-linux-x64-musl': 4.12.0
-      '@rollup/rollup-win32-arm64-msvc': 4.12.0
-      '@rollup/rollup-win32-ia32-msvc': 4.12.0
-      '@rollup/rollup-win32-x64-msvc': 4.12.0
+      '@rollup/rollup-android-arm-eabi': 4.17.2
+      '@rollup/rollup-android-arm64': 4.17.2
+      '@rollup/rollup-darwin-arm64': 4.17.2
+      '@rollup/rollup-darwin-x64': 4.17.2
+      '@rollup/rollup-linux-arm-gnueabihf': 4.17.2
+      '@rollup/rollup-linux-arm-musleabihf': 4.17.2
+      '@rollup/rollup-linux-arm64-gnu': 4.17.2
+      '@rollup/rollup-linux-arm64-musl': 4.17.2
+      '@rollup/rollup-linux-powerpc64le-gnu': 4.17.2
+      '@rollup/rollup-linux-riscv64-gnu': 4.17.2
+      '@rollup/rollup-linux-s390x-gnu': 4.17.2
+      '@rollup/rollup-linux-x64-gnu': 4.17.2
+      '@rollup/rollup-linux-x64-musl': 4.17.2
+      '@rollup/rollup-win32-arm64-msvc': 4.17.2
+      '@rollup/rollup-win32-ia32-msvc': 4.17.2
+      '@rollup/rollup-win32-x64-msvc': 4.17.2
       fsevents: 2.3.3
 
-  /rrweb-cssom@0.6.0:
-    resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
-    dev: false
+  rrweb-cssom@0.6.0: {}
 
-  /rss-parser@3.13.0:
-    resolution: {integrity: sha512-7jWUBV5yGN3rqMMj7CZufl/291QAhvrrGpDNE4k/02ZchL0npisiYYqULF71jCEKoIiHvK/Q2e6IkDwPziT7+w==}
+  rss-parser@3.13.0:
     dependencies:
       entities: 2.2.0
       xml2js: 0.5.0
-    dev: false
 
-  /run-async@2.4.1:
-    resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==}
-    engines: {node: '>=0.12.0'}
-    dev: true
-
-  /run-parallel@1.2.0:
-    resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+  run-parallel@1.2.0:
     dependencies:
       queue-microtask: 1.2.3
 
-  /rxjs@7.8.1:
-    resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
+  rxjs@7.8.1:
     dependencies:
       tslib: 2.6.2
 
-  /safe-array-concat@1.0.0:
-    resolution: {integrity: sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==}
-    engines: {node: '>=0.4'}
+  safe-array-concat@1.0.0:
     dependencies:
       call-bind: 1.0.2
       get-intrinsic: 1.2.1
       has-symbols: 1.0.3
       isarray: 2.0.5
-    dev: true
 
-  /safe-buffer@5.1.2:
-    resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
+  safe-buffer@5.1.2: {}
 
-  /safe-buffer@5.2.1:
-    resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+  safe-buffer@5.2.1: {}
 
-  /safe-regex-test@1.0.0:
-    resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
+  safe-regex-test@1.0.0:
     dependencies:
       call-bind: 1.0.2
       get-intrinsic: 1.2.1
       is-regex: 1.1.4
-    dev: true
 
-  /safe-regex2@2.0.0:
-    resolution: {integrity: sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==}
+  safe-regex2@3.1.0:
     dependencies:
-      ret: 0.2.2
-    dev: false
+      ret: 0.4.3
 
-  /safe-stable-stringify@2.4.2:
-    resolution: {integrity: sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==}
-    engines: {node: '>=10'}
-    dev: false
+  safe-stable-stringify@2.4.2: {}
 
-  /safer-buffer@2.1.2:
-    resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+  safer-buffer@2.1.2: {}
 
-  /sanitize-html@2.12.1:
-    resolution: {integrity: sha512-Plh+JAn0UVDpBRP/xEjsk+xDCoOvMBwQUf/K+/cBAVuTbtX8bj2VB7S1sL1dssVpykqp0/KPSesHrqXtokVBpA==}
+  sanitize-html@2.13.0:
     dependencies:
       deepmerge: 4.2.2
       escape-string-regexp: 4.0.0
       htmlparser2: 8.0.1
       is-plain-object: 5.0.0
       parse-srcset: 1.0.2
-      postcss: 8.4.35
-    dev: false
+      postcss: 8.4.38
 
-  /sass@1.71.1:
-    resolution: {integrity: sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==}
-    engines: {node: '>=14.0.0'}
-    hasBin: true
+  sass@1.76.0:
     dependencies:
       chokidar: 3.5.3
       immutable: 4.2.2
-      source-map-js: 1.0.2
+      source-map-js: 1.2.0
 
-  /sax@1.2.4:
-    resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==}
-    dev: false
+  sax@1.2.4: {}
 
-  /saxes@6.0.0:
-    resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
-    engines: {node: '>=v12.22.7'}
+  saxes@6.0.0:
     dependencies:
       xmlchars: 2.2.0
-    dev: false
 
-  /scheduler@0.23.0:
-    resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==}
+  scheduler@0.23.2:
     dependencies:
       loose-envify: 1.4.0
-    dev: true
 
-  /secure-json-parse@2.7.0:
-    resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==}
-    dev: false
+  secure-json-parse@2.7.0: {}
 
-  /seedrandom@3.0.5:
-    resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==}
-    dev: false
+  seedrandom@3.0.5: {}
 
-  /semver-regex@4.0.5:
-    resolution: {integrity: sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==}
-    engines: {node: '>=12'}
-    dev: false
+  semver-regex@4.0.5: {}
 
-  /semver-truncate@2.0.0:
-    resolution: {integrity: sha512-Rh266MLDYNeML5h90ttdMwfXe1+Nc4LAWd9X1KdJe8pPHP4kFmvLZALtsMNHNdvTyQygbEC0D59sIz47DIaq8w==}
-    engines: {node: '>=8'}
+  semver-truncate@2.0.0:
     dependencies:
       semver: 6.3.1
-    dev: false
 
-  /semver@5.7.1:
-    resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
-    hasBin: true
-    dev: true
+  semver@5.7.1: {}
 
-  /semver@6.3.1:
-    resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
-    hasBin: true
+  semver@6.3.1: {}
 
-  /semver@7.5.4:
-    resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
-    engines: {node: '>=10'}
-    hasBin: true
+  semver@7.5.4:
     dependencies:
       lru-cache: 6.0.0
 
-  /semver@7.6.0:
-    resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==}
-    engines: {node: '>=10'}
-    hasBin: true
+  semver@7.6.0:
     dependencies:
       lru-cache: 6.0.0
 
-  /send@0.18.0:
-    resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
-    engines: {node: '>= 0.8.0'}
+  send@0.18.0:
     dependencies:
       debug: 2.6.9
       depd: 2.0.0
@@ -17645,9 +22112,7 @@ packages:
     transitivePeerDependencies:
       - supports-color
 
-  /serve-static@1.15.0:
-    resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==}
-    engines: {node: '>= 0.8.0'}
+  serve-static@1.15.0:
     dependencies:
       encodeurl: 1.0.2
       escape-html: 1.0.3
@@ -17656,114 +22121,78 @@ packages:
     transitivePeerDependencies:
       - supports-color
 
-  /set-blocking@2.0.0:
-    resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
-    dev: false
+  set-blocking@2.0.0: {}
 
-  /set-cookie-parser@2.6.0:
-    resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==}
-    dev: false
+  set-cookie-parser@2.6.0: {}
 
-  /setimmediate@1.0.5:
-    resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
-    dev: false
+  setimmediate@1.0.5: {}
 
-  /setprototypeof@1.2.0:
-    resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+  setprototypeof@1.2.0: {}
 
-  /sha.js@2.4.11:
-    resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==}
-    hasBin: true
+  sha.js@2.4.11:
     dependencies:
       inherits: 2.0.4
       safe-buffer: 5.2.1
-    dev: false
 
-  /shallow-clone@3.0.1:
-    resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==}
-    engines: {node: '>=8'}
+  shallow-clone@3.0.1:
     dependencies:
       kind-of: 6.0.3
-    dev: true
 
-  /sharp@0.33.2:
-    resolution: {integrity: sha512-WlYOPyyPDiiM07j/UO+E720ju6gtNtHjEGg5vovUk1Lgxyjm2LFO+37Nt/UI3MMh2l6hxTWQWi7qk3cXJTutcQ==}
-    engines: {libvips: '>=8.15.1', node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    requiresBuild: true
+  sharp@0.33.3:
     dependencies:
       color: 4.2.3
-      detect-libc: 2.0.2
-      semver: 7.5.4
+      detect-libc: 2.0.3
+      semver: 7.6.0
     optionalDependencies:
-      '@img/sharp-darwin-arm64': 0.33.2
-      '@img/sharp-darwin-x64': 0.33.2
-      '@img/sharp-libvips-darwin-arm64': 1.0.1
-      '@img/sharp-libvips-darwin-x64': 1.0.1
-      '@img/sharp-libvips-linux-arm': 1.0.1
-      '@img/sharp-libvips-linux-arm64': 1.0.1
-      '@img/sharp-libvips-linux-s390x': 1.0.1
-      '@img/sharp-libvips-linux-x64': 1.0.1
-      '@img/sharp-libvips-linuxmusl-arm64': 1.0.1
-      '@img/sharp-libvips-linuxmusl-x64': 1.0.1
-      '@img/sharp-linux-arm': 0.33.2
-      '@img/sharp-linux-arm64': 0.33.2
-      '@img/sharp-linux-s390x': 0.33.2
-      '@img/sharp-linux-x64': 0.33.2
-      '@img/sharp-linuxmusl-arm64': 0.33.2
-      '@img/sharp-linuxmusl-x64': 0.33.2
-      '@img/sharp-wasm32': 0.33.2
-      '@img/sharp-win32-ia32': 0.33.2
-      '@img/sharp-win32-x64': 0.33.2
-    dev: false
+      '@img/sharp-darwin-arm64': 0.33.3
+      '@img/sharp-darwin-x64': 0.33.3
+      '@img/sharp-libvips-darwin-arm64': 1.0.2
+      '@img/sharp-libvips-darwin-x64': 1.0.2
+      '@img/sharp-libvips-linux-arm': 1.0.2
+      '@img/sharp-libvips-linux-arm64': 1.0.2
+      '@img/sharp-libvips-linux-s390x': 1.0.2
+      '@img/sharp-libvips-linux-x64': 1.0.2
+      '@img/sharp-libvips-linuxmusl-arm64': 1.0.2
+      '@img/sharp-libvips-linuxmusl-x64': 1.0.2
+      '@img/sharp-linux-arm': 0.33.3
+      '@img/sharp-linux-arm64': 0.33.3
+      '@img/sharp-linux-s390x': 0.33.3
+      '@img/sharp-linux-x64': 0.33.3
+      '@img/sharp-linuxmusl-arm64': 0.33.3
+      '@img/sharp-linuxmusl-x64': 0.33.3
+      '@img/sharp-wasm32': 0.33.3
+      '@img/sharp-win32-ia32': 0.33.3
+      '@img/sharp-win32-x64': 0.33.3
 
-  /shebang-command@1.2.0:
-    resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
-    engines: {node: '>=0.10.0'}
+  shebang-command@1.2.0:
     dependencies:
       shebang-regex: 1.0.0
-    dev: false
 
-  /shebang-command@2.0.0:
-    resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
-    engines: {node: '>=8'}
+  shebang-command@2.0.0:
     dependencies:
       shebang-regex: 3.0.0
 
-  /shebang-regex@1.0.0:
-    resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==}
-    engines: {node: '>=0.10.0'}
-    dev: false
+  shebang-regex@1.0.0: {}
 
-  /shebang-regex@3.0.0:
-    resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
-    engines: {node: '>=8'}
+  shebang-regex@3.0.0: {}
 
-  /shiki@1.2.0:
-    resolution: {integrity: sha512-xLhiTMOIUXCv5DqJ4I70GgQCtdlzsTqFLZWcMHHG3TAieBUbvEGthdrlPDlX4mL/Wszx9C6rEcxU6kMlg4YlxA==}
+  shiki@1.4.0:
     dependencies:
-      '@shikijs/core': 1.2.0
-    dev: false
+      '@shikijs/core': 1.4.0
 
-  /side-channel@1.0.4:
-    resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
+  side-channel@1.0.4:
     dependencies:
       call-bind: 1.0.2
       get-intrinsic: 1.2.1
       object-inspect: 1.12.3
 
-  /siginfo@2.0.0:
-    resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
-    dev: true
+  siginfo@2.0.0: {}
 
-  /signal-exit@3.0.7:
-    resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+  signal-exit@3.0.7: {}
 
-  /signal-exit@4.1.0:
-    resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
-    engines: {node: '>=14'}
+  signal-exit@4.1.0: {}
 
-  /simple-oauth2@5.0.0:
-    resolution: {integrity: sha512-8291lo/z5ZdpmiOFzOs1kF3cxn22bMj5FFH+DNUppLJrpoIlM1QnFiE7KpshHu3J3i21TVcx4yW+gXYjdCKDLQ==}
+  simple-oauth2@5.0.0:
     dependencies:
       '@hapi/hoek': 10.0.1
       '@hapi/wreck': 18.0.1
@@ -17771,23 +22200,16 @@ packages:
       joi: 17.11.0
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /simple-swizzle@0.2.2:
-    resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
+  simple-swizzle@0.2.2:
     dependencies:
       is-arrayish: 0.3.2
-    dev: false
 
-  /simple-update-notifier@2.0.0:
-    resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
-    engines: {node: '>=10'}
+  simple-update-notifier@2.0.0:
     dependencies:
       semver: 7.5.4
-    dev: true
 
-  /sinon@16.1.3:
-    resolution: {integrity: sha512-mjnWWeyxcAf9nC0bXcPmiDut+oE8HYridTNzBbF98AYVLmWwGRp2ISEpyhYflG1ifILT+eNn3BmKUJPxjXUPlA==}
+  sinon@16.1.3:
     dependencies:
       '@sinonjs/commons': 3.0.0
       '@sinonjs/fake-timers': 10.3.0
@@ -17795,131 +22217,49 @@ packages:
       diff: 5.1.0
       nise: 5.1.4
       supports-color: 7.2.0
-    dev: true
 
-  /sisteransi@1.0.5:
-    resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
-    dev: true
+  sisteransi@1.0.5: {}
 
-  /slacc-android-arm-eabi@0.0.10:
-    resolution: {integrity: sha512-U3dVBuM1m8rT1D/w6S4knJ/uscNwsCR+MKxSQFbgDJEh8Atv+ovuC+FMGuaBT4iOQjpMj5dWSsN3ZPjVeo3hgA==}
-    engines: {node: '>= 10'}
-    cpu: [arm]
-    os: [android]
-    requiresBuild: true
-    dev: false
+  slacc-android-arm-eabi@0.0.10:
     optional: true
 
-  /slacc-android-arm64@0.0.10:
-    resolution: {integrity: sha512-guVp88sW+4j1clTSXMzyDJHG8ondVnd8/FMKXIOfzKCEwSwX3uBxsuyHqtGvXkEwyZAGsBUy13Ei/PZAwElwYA==}
-    engines: {node: '>= 10'}
-    cpu: [arm64]
-    os: [android]
-    requiresBuild: true
-    dev: false
+  slacc-android-arm64@0.0.10:
     optional: true
 
-  /slacc-darwin-arm64@0.0.10:
-    resolution: {integrity: sha512-633qnOMTP7egvd5IeljAOku0tnxlBXSoCRu7HiT0yeXxN9y5Tbg2X2/FaRzstI36lClfIJ0Lavne4mOw/90z9A==}
-    engines: {node: '>= 10'}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
-    dev: false
+  slacc-darwin-arm64@0.0.10:
     optional: true
 
-  /slacc-darwin-universal@0.0.10:
-    resolution: {integrity: sha512-x5kEqRMTEQTi3NCufPEukWvaWqcOL+7EkP18ZCCiajcWH83jWnT8DOSGOmmLYdrXd0B7ZZcbd8GyLp3i5zu8PA==}
-    engines: {node: '>= 10'}
-    os: [darwin]
-    requiresBuild: true
-    dev: false
+  slacc-darwin-universal@0.0.10:
     optional: true
 
-  /slacc-darwin-x64@0.0.10:
-    resolution: {integrity: sha512-5gQYboy/4T6Bj3sVXiCpM3EvF1sK/Zx1Nq5YBMUuYb2GzrIwywghHbCD6bK4JYGvNsLN7r4PC45ZUB4gVkU8yA==}
-    engines: {node: '>= 10'}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
-    dev: false
+  slacc-darwin-x64@0.0.10:
     optional: true
 
-  /slacc-freebsd-x64@0.0.10:
-    resolution: {integrity: sha512-Jmi5YszELef/aCzYto+LwiNGhCk5mrlJfTJU/pOI91HBbrZlV+aRyIsPCcxAMg5yPsPQuyRljrDouVYrPzNmjw==}
-    engines: {node: '>= 10'}
-    cpu: [x64]
-    os: [freebsd]
-    requiresBuild: true
-    dev: false
+  slacc-freebsd-x64@0.0.10:
     optional: true
 
-  /slacc-linux-arm-gnueabihf@0.0.10:
-    resolution: {integrity: sha512-9lTM3DGtISQlZYSKrMuQyKCiUnHYRcy04mY6HF1ywYcQ2sqfv3bKEnrypVewepIFUtytlIGzkgpiUAk/ghYGoA==}
-    engines: {node: '>= 10'}
-    cpu: [arm]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  slacc-linux-arm-gnueabihf@0.0.10:
     optional: true
 
-  /slacc-linux-arm64-gnu@0.0.10:
-    resolution: {integrity: sha512-qXrNWSINXOjHRO3c9idGm8DeOAjAjG1xHY8WiplCoHWgsZf3E7V+sPhWqRUaGQEvftsJg40+cFYREBaLQhpAVQ==}
-    engines: {node: '>= 10'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  slacc-linux-arm64-gnu@0.0.10:
     optional: true
 
-  /slacc-linux-arm64-musl@0.0.10:
-    resolution: {integrity: sha512-3lUX7752f6Okn54aONioaA+9M5TvifqXBAart+u2lNXEdWmmh003cVSU2Vcwg7nJ9lLHtju2DkDmKKfJjFuShA==}
-    engines: {node: '>= 10'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  slacc-linux-arm64-musl@0.0.10:
     optional: true
 
-  /slacc-linux-x64-gnu@0.0.10:
-    resolution: {integrity: sha512-BxxvylF9zlOLRLCpiyMvKTIUpdLlpetNBJ+DSMDh5+Ggq+AmQz2NUGawmcBJw58F8nMCj9TpWLlGNWc2AuY+JQ==}
-    engines: {node: '>= 10'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  slacc-linux-x64-gnu@0.0.10:
     optional: true
 
-  /slacc-linux-x64-musl@0.0.10:
-    resolution: {integrity: sha512-TYJi8LOtJiTFcZvka4du7bMjF9Bz1RHRwyLnScr5E5yjjgoLRrsvgSu7bxp87xH+rgJ3CdEwE3w3Ux8EiewHpA==}
-    engines: {node: '>= 10'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
+  slacc-linux-x64-musl@0.0.10:
     optional: true
 
-  /slacc-win32-arm64-msvc@0.0.10:
-    resolution: {integrity: sha512-1CHPLiDB4exzFyT5ndtJDsRRhBxNg8mGz6I6eJEMjelGkJR2KZPT9LZuby/1bS/bcVOr7zuJvGNfbEGBeHRwPQ==}
-    engines: {node: '>= 10'}
-    cpu: [arm64]
-    os: [win32]
-    requiresBuild: true
-    dev: false
+  slacc-win32-arm64-msvc@0.0.10:
     optional: true
 
-  /slacc-win32-x64-msvc@0.0.10:
-    resolution: {integrity: sha512-wAXBy5yKCAzfYWjVlyPpu6PscD+j4QhCQEy0wZaVuzNyx60HpXWcTZxxVnMR730Y7tfc7cBxSI8NtRb8RguSgg==}
-    engines: {node: '>= 10'}
-    cpu: [x64]
-    os: [win32]
-    requiresBuild: true
-    dev: false
+  slacc-win32-x64-msvc@0.0.10:
     optional: true
 
-  /slacc@0.0.10:
-    resolution: {integrity: sha512-2jgms2/4mLr1AMq4oloAwPdKQK9RQvgmoEpMIxvC+HeHMwCR0XxB7gr/rKo4iLOKJ6gx02mnBU0JHWcTIonpmA==}
-    engines: {node: '>= 10'}
+  slacc@0.0.10:
     optionalDependencies:
       slacc-android-arm-eabi: 0.0.10
       slacc-android-arm64: 0.0.10
@@ -17934,153 +22274,95 @@ packages:
       slacc-linux-x64-musl: 0.0.10
       slacc-win32-arm64-msvc: 0.0.10
       slacc-win32-x64-msvc: 0.0.10
-    dev: false
 
-  /slash@3.0.0:
-    resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
-    engines: {node: '>=8'}
+  slash@3.0.0: {}
 
-  /slice-ansi@3.0.0:
-    resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==}
-    engines: {node: '>=8'}
+  slice-ansi@3.0.0:
     dependencies:
       ansi-styles: 4.3.0
       astral-regex: 2.0.0
       is-fullwidth-code-point: 3.0.0
-    dev: true
 
-  /slice-ansi@4.0.0:
-    resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
-    engines: {node: '>=10'}
+  slice-ansi@4.0.0:
     dependencies:
       ansi-styles: 4.3.0
       astral-regex: 2.0.0
       is-fullwidth-code-point: 3.0.0
-    dev: true
 
-  /smart-buffer@4.2.0:
-    resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
-    engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
-    dev: false
+  smart-buffer@4.2.0: {}
 
-  /socks-proxy-agent@8.0.2:
-    resolution: {integrity: sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==}
-    engines: {node: '>= 14'}
+  socks-proxy-agent@8.0.2:
     dependencies:
       agent-base: 7.1.0
       debug: 4.3.4(supports-color@8.1.1)
       socks: 2.7.1
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /socks@2.7.1:
-    resolution: {integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==}
-    engines: {node: '>= 10.13.0', npm: '>= 3.0.0'}
+  socks@2.7.1:
     dependencies:
-      ip: 2.0.0
+      ip: 2.0.1
       smart-buffer: 4.2.0
-    dev: false
 
-  /sonic-boom@3.7.0:
-    resolution: {integrity: sha512-IudtNvSqA/ObjN97tfgNmOKyDOs4dNcg4cUUsHDebqsgb8wGBBwb31LIgShNO8fye0dFI52X1+tFoKKI6Rq1Gg==}
+  sonic-boom@3.7.0:
     dependencies:
       atomic-sleep: 1.0.0
-    dev: false
 
-  /sort-keys-length@1.0.1:
-    resolution: {integrity: sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==}
-    engines: {node: '>=0.10.0'}
+  sort-keys-length@1.0.1:
     dependencies:
       sort-keys: 1.1.2
-    dev: false
 
-  /sort-keys@1.1.2:
-    resolution: {integrity: sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==}
-    engines: {node: '>=0.10.0'}
+  sort-keys@1.1.2:
     dependencies:
       is-plain-obj: 1.1.0
-    dev: false
 
-  /sortablejs@1.14.0:
-    resolution: {integrity: sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==}
-    dev: false
+  sortablejs@1.14.0: {}
 
-  /source-map-js@1.0.2:
-    resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
-    engines: {node: '>=0.10.0'}
+  source-map-js@1.0.2: {}
 
-  /source-map-support@0.5.13:
-    resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==}
-    dependencies:
-      buffer-from: 1.1.2
-      source-map: 0.6.1
-    dev: true
+  source-map-js@1.2.0: {}
 
-  /source-map-support@0.5.21:
-    resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
+  source-map-support@0.5.13:
     dependencies:
       buffer-from: 1.1.2
       source-map: 0.6.1
 
-  /source-map@0.6.1:
-    resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
-    engines: {node: '>=0.10.0'}
+  source-map-support@0.5.21:
+    dependencies:
+      buffer-from: 1.1.2
+      source-map: 0.6.1
 
-  /source-map@0.7.4:
-    resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
-    engines: {node: '>= 8'}
-    dev: false
+  source-map@0.6.1: {}
 
-  /space-separated-tokens@2.0.2:
-    resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
-    dev: true
+  source-map@0.7.4: {}
 
-  /spdx-correct@3.1.1:
-    resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==}
+  space-separated-tokens@2.0.2: {}
+
+  spdx-correct@3.1.1:
     dependencies:
       spdx-expression-parse: 3.0.1
       spdx-license-ids: 3.0.12
-    dev: true
 
-  /spdx-exceptions@2.3.0:
-    resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==}
-    dev: true
+  spdx-exceptions@2.3.0: {}
 
-  /spdx-expression-parse@3.0.1:
-    resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==}
+  spdx-expression-parse@3.0.1:
     dependencies:
       spdx-exceptions: 2.3.0
       spdx-license-ids: 3.0.12
-    dev: true
 
-  /spdx-license-ids@3.0.12:
-    resolution: {integrity: sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==}
-    dev: true
+  spdx-license-ids@3.0.12: {}
 
-  /split2@4.1.0:
-    resolution: {integrity: sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==}
-    engines: {node: '>= 10.x'}
-    dev: false
+  split2@4.1.0: {}
 
-  /split@0.3.3:
-    resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==}
+  split@0.3.3:
     dependencies:
       through: 2.3.8
-    dev: true
 
-  /sprintf-js@1.0.3:
-    resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
-    requiresBuild: true
+  sprintf-js@1.0.3: {}
 
-  /sprintf-js@1.1.2:
-    resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==}
-    dev: false
+  sprintf-js@1.1.2: {}
 
-  /sshpk@1.17.0:
-    resolution: {integrity: sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==}
-    engines: {node: '>=0.10.0'}
-    hasBin: true
+  sshpk@1.17.0:
     dependencies:
       asn1: 0.2.6
       assert-plus: 1.0.0
@@ -18092,32 +22374,19 @@ packages:
       safer-buffer: 2.1.2
       tweetnacl: 0.14.5
 
-  /ssri@10.0.4:
-    resolution: {integrity: sha512-12+IR2CB2C28MMAw0Ncqwj5QbTcs0nGIhgJzYWzDkb21vWmfNI83KS4f3Ci6GI98WreIfG7o9UXp3C0qbpA8nQ==}
-    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+  ssri@10.0.4:
     dependencies:
       minipass: 5.0.0
-    dev: false
 
-  /stack-utils@2.0.6:
-    resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
-    engines: {node: '>=10'}
+  stack-utils@2.0.6:
     dependencies:
       escape-string-regexp: 2.0.0
-    dev: true
 
-  /stackback@0.0.2:
-    resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
-    dev: true
+  stackback@0.0.2: {}
 
-  /standard-as-callback@2.1.0:
-    resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==}
-    dev: false
+  standard-as-callback@2.1.0: {}
 
-  /start-server-and-test@2.0.3:
-    resolution: {integrity: sha512-QsVObjfjFZKJE6CS6bSKNwWZCKBG6975/jKRPPGFfFh+yOQglSeGXiNWjzgQNXdphcBI9nXbyso9tPfX4YAUhg==}
-    engines: {node: '>=16'}
-    hasBin: true
+  start-server-and-test@2.0.3:
     dependencies:
       arg: 5.0.2
       bluebird: 3.7.2
@@ -18129,32 +22398,33 @@ packages:
       wait-on: 7.2.0(debug@4.3.4)
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /statuses@2.0.1:
-    resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
-    engines: {node: '>= 0.8'}
+  statuses@2.0.1: {}
 
-  /std-env@3.7.0:
-    resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==}
-    dev: true
+  std-env@3.7.0: {}
 
-  /stop-iteration-iterator@1.0.0:
-    resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==}
-    engines: {node: '>= 0.4'}
+  stop-iteration-iterator@1.0.0:
     dependencies:
       internal-slot: 1.0.5
-    dev: true
 
-  /store2@2.14.2:
-    resolution: {integrity: sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==}
-    dev: true
+  store2@2.14.2: {}
 
-  /storybook@8.0.9(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-/Mvij0Br5bUwJpCvqAUZMEDIWmdRxEyllvVj8Ukw5lIWJePxfpSsz4px5jg9+R6B9tO8sQSqjg4HJvQ/pZk8Tg==}
-    hasBin: true
+  storybook-addon-misskey-theme@https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/components@8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/core-events@8.0.9)(@storybook/manager-api@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/preview-api@8.0.9)(@storybook/theming@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/types@8.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
     dependencies:
-      '@storybook/cli': 8.0.9(react-dom@18.2.0)(react@18.2.0)
+      '@storybook/blocks': 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+      '@storybook/components': 8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+      '@storybook/core-events': 8.0.9
+      '@storybook/manager-api': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+      '@storybook/preview-api': 8.0.9
+      '@storybook/theming': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+      '@storybook/types': 8.0.9
+    optionalDependencies:
+      react: 18.3.1
+      react-dom: 18.3.1(react@18.3.1)
+
+  storybook@8.0.9(@babel/preset-env@7.23.5(@babel/core@7.24.0))(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3):
+    dependencies:
+      '@storybook/cli': 8.0.9(@babel/preset-env@7.23.5(@babel/core@7.24.0))(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)
     transitivePeerDependencies:
       - '@babel/preset-env'
       - bufferutil
@@ -18163,258 +22433,157 @@ packages:
       - react-dom
       - supports-color
       - utf-8-validate
-    dev: true
 
-  /stream-browserify@3.0.0:
-    resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==}
+  stream-browserify@3.0.0:
     dependencies:
       inherits: 2.0.4
       readable-stream: 3.6.0
-    dev: false
 
-  /stream-combiner@0.0.4:
-    resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==}
+  stream-combiner@0.0.4:
     dependencies:
       duplexer: 0.1.2
-    dev: true
 
-  /stream-parser@0.3.1:
-    resolution: {integrity: sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==}
+  stream-parser@0.3.1:
     dependencies:
       debug: 2.6.9
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /stream-shift@1.0.1:
-    resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==}
-    dev: true
+  stream-shift@1.0.1: {}
 
-  /stream-wormhole@1.1.0:
-    resolution: {integrity: sha512-gHFfL3px0Kctd6Po0M8TzEvt3De/xu6cnRrjlfYNhwbhLPLwigI2t1nc6jrzNuaYg5C4YF78PPFuQPzRiqn9ew==}
-    engines: {node: '>=4.0.0'}
-    dev: false
+  stream-wormhole@1.1.0: {}
 
-  /streamsearch@1.1.0:
-    resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
-    engines: {node: '>=10.0.0'}
+  streamsearch@1.1.0: {}
 
-  /streamx@2.15.0:
-    resolution: {integrity: sha512-HcxY6ncGjjklGs1xsP1aR71INYcsXFJet5CU1CHqihQ2J5nOsbd4OjgjHO42w/4QNv9gZb3BueV+Vxok5pLEXg==}
+  streamx@2.15.0:
     dependencies:
       fast-fifo: 1.3.0
       queue-tick: 1.0.1
-    dev: false
 
-  /strict-event-emitter-types@2.0.0:
-    resolution: {integrity: sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA==}
-    dev: false
+  strict-event-emitter-types@2.0.0: {}
 
-  /strict-event-emitter@0.5.1:
-    resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==}
-    dev: true
+  strict-event-emitter@0.5.1: {}
 
-  /string-argv@0.3.1:
-    resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==}
-    engines: {node: '>=0.6.19'}
-    dev: true
+  string-argv@0.3.1: {}
 
-  /string-length@4.0.2:
-    resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
-    engines: {node: '>=10'}
+  string-length@4.0.2:
     dependencies:
       char-regex: 1.0.2
       strip-ansi: 6.0.1
-    dev: true
 
-  /string-width@4.2.3:
-    resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
-    engines: {node: '>=8'}
+  string-width@4.2.3:
     dependencies:
       emoji-regex: 8.0.0
       is-fullwidth-code-point: 3.0.0
       strip-ansi: 6.0.1
 
-  /string-width@5.1.2:
-    resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
-    engines: {node: '>=12'}
+  string-width@5.1.2:
     dependencies:
       eastasianwidth: 0.2.0
       emoji-regex: 9.2.2
       strip-ansi: 7.1.0
 
-  /string.prototype.trim@1.2.7:
-    resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==}
-    engines: {node: '>= 0.4'}
+  string.prototype.trim@1.2.7:
     dependencies:
       call-bind: 1.0.2
       define-properties: 1.2.0
       es-abstract: 1.22.1
-    dev: true
 
-  /string.prototype.trimend@1.0.6:
-    resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==}
+  string.prototype.trimend@1.0.6:
     dependencies:
       call-bind: 1.0.2
       define-properties: 1.2.0
       es-abstract: 1.22.1
-    dev: true
 
-  /string.prototype.trimstart@1.0.6:
-    resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==}
+  string.prototype.trimstart@1.0.6:
     dependencies:
       call-bind: 1.0.2
       define-properties: 1.2.0
       es-abstract: 1.22.1
-    dev: true
 
-  /string_decoder@0.10.31:
-    resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==}
-    dev: false
+  string_decoder@0.10.31: {}
 
-  /string_decoder@1.1.1:
-    resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
+  string_decoder@1.1.1:
     dependencies:
       safe-buffer: 5.1.2
 
-  /string_decoder@1.3.0:
-    resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+  string_decoder@1.3.0:
     dependencies:
       safe-buffer: 5.2.1
 
-  /stringz@2.1.0:
-    resolution: {integrity: sha512-KlywLT+MZ+v0IRepfMxRtnSvDCMc3nR1qqCs3m/qIbSOWkNZYT8XHQA31rS3TnKp0c5xjZu3M4GY/2aRKSi/6A==}
+  stringz@2.1.0:
     dependencies:
       char-regex: 1.0.2
-    dev: false
 
-  /strip-ansi@6.0.1:
-    resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
-    engines: {node: '>=8'}
+  strip-ansi@6.0.1:
     dependencies:
       ansi-regex: 5.0.1
 
-  /strip-ansi@7.1.0:
-    resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
-    engines: {node: '>=12'}
+  strip-ansi@7.1.0:
     dependencies:
       ansi-regex: 6.0.1
 
-  /strip-bom@3.0.0:
-    resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
-    engines: {node: '>=4'}
+  strip-bom@3.0.0: {}
 
-  /strip-bom@4.0.0:
-    resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==}
-    engines: {node: '>=8'}
-    dev: true
+  strip-bom@4.0.0: {}
 
-  /strip-eof@1.0.0:
-    resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==}
-    engines: {node: '>=0.10.0'}
-    dev: false
+  strip-eof@1.0.0: {}
 
-  /strip-final-newline@2.0.0:
-    resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
-    engines: {node: '>=6'}
+  strip-final-newline@2.0.0: {}
 
-  /strip-final-newline@3.0.0:
-    resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
-    engines: {node: '>=12'}
+  strip-final-newline@3.0.0: {}
 
-  /strip-indent@3.0.0:
-    resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
-    engines: {node: '>=8'}
+  strip-indent@3.0.0:
     dependencies:
       min-indent: 1.0.1
-    dev: true
 
-  /strip-indent@4.0.0:
-    resolution: {integrity: sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==}
-    engines: {node: '>=12'}
+  strip-indent@4.0.0:
     dependencies:
       min-indent: 1.0.1
-    dev: true
 
-  /strip-json-comments@3.1.1:
-    resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
-    engines: {node: '>=8'}
-    dev: true
+  strip-json-comments@3.1.1: {}
 
-  /strip-literal@1.3.0:
-    resolution: {integrity: sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==}
+  strip-literal@1.3.0:
     dependencies:
       acorn: 8.11.3
-    dev: true
 
-  /strip-outer@2.0.0:
-    resolution: {integrity: sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
-    dev: false
+  strip-outer@2.0.0: {}
 
-  /strnum@1.0.5:
-    resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==}
-    dev: false
+  strnum@1.0.5: {}
 
-  /strtok3@7.0.0:
-    resolution: {integrity: sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==}
-    engines: {node: '>=14.16'}
+  strtok3@7.0.0:
     dependencies:
       '@tokenizer/token': 0.3.0
       peek-readable: 5.0.0
-    dev: false
 
-  /stylehacks@6.0.3(postcss@8.4.35):
-    resolution: {integrity: sha512-KzBqjnqktc8/I0ERCb+lGq06giF/JxDbw2r9kEVhen9noHeIDRtMWUp9r62sOk+/2bbX6sFG1GhsS7ToXG0PEg==}
-    engines: {node: ^14 || ^16 || >=18.0}
-    peerDependencies:
-      postcss: ^8.4.31
+  stylehacks@6.1.1(postcss@8.4.38):
     dependencies:
       browserslist: 4.23.0
-      postcss: 8.4.35
-      postcss-selector-parser: 6.0.15
-    dev: false
+      postcss: 8.4.38
+      postcss-selector-parser: 6.0.16
 
-  /supports-color@5.5.0:
-    resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
-    engines: {node: '>=4'}
+  supports-color@5.5.0:
     dependencies:
       has-flag: 3.0.0
-    dev: true
 
-  /supports-color@7.2.0:
-    resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
-    engines: {node: '>=8'}
+  supports-color@7.2.0:
     dependencies:
       has-flag: 4.0.0
 
-  /supports-color@8.1.1:
-    resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
-    engines: {node: '>=10'}
+  supports-color@8.1.1:
     dependencies:
       has-flag: 4.0.0
 
-  /supports-color@9.4.0:
-    resolution: {integrity: sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==}
-    engines: {node: '>=12'}
-    dev: true
+  supports-color@9.4.0: {}
 
-  /supports-hyperlinks@2.3.0:
-    resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==}
-    engines: {node: '>=8'}
+  supports-hyperlinks@2.3.0:
     dependencies:
       has-flag: 4.0.0
       supports-color: 7.2.0
-    dev: true
 
-  /supports-preserve-symlinks-flag@1.0.0:
-    resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
-    engines: {node: '>= 0.4'}
+  supports-preserve-symlinks-flag@1.0.0: {}
 
-  /svgo@3.2.0:
-    resolution: {integrity: sha512-4PP6CMW/V7l/GmKRKzsLR8xxjdHTV4IMvhTnpuHwwBazSIlw5W/5SmPjN8Dwyt7lKbSJrRDgp4t9ph0HgChFBQ==}
-    engines: {node: '>=14.0.0'}
-    hasBin: true
+  svgo@3.2.0:
     dependencies:
       '@trysound/sax': 0.2.0
       commander: 7.2.0
@@ -18423,51 +22592,33 @@ packages:
       css-what: 6.1.0
       csso: 5.0.5
       picocolors: 1.0.0
-    dev: false
 
-  /symbol-tree@3.2.4:
-    resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
-    dev: false
+  symbol-tree@3.2.4: {}
 
-  /systeminformation@5.22.0:
-    resolution: {integrity: sha512-oAP80ymt8ssrAzjX8k3frbL7ys6AotqC35oikG6/SG15wBw+tG9nCk4oPaXIhEaAOAZ8XngxUv3ORq2IuR3r4Q==}
-    engines: {node: '>=8.0.0'}
-    os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android]
-    hasBin: true
-    dev: false
+  systeminformation@5.22.7: {}
 
-  /tar-fs@2.1.1:
-    resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
+  tar-fs@2.1.1:
     dependencies:
       chownr: 1.1.4
       mkdirp-classic: 0.5.3
       pump: 3.0.0
       tar-stream: 2.2.0
-    dev: true
 
-  /tar-stream@2.2.0:
-    resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
-    engines: {node: '>=6'}
+  tar-stream@2.2.0:
     dependencies:
       bl: 4.1.0
       end-of-stream: 1.4.4
       fs-constants: 1.0.0
       inherits: 2.0.4
       readable-stream: 3.6.0
-    dev: true
 
-  /tar-stream@3.1.6:
-    resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==}
+  tar-stream@3.1.6:
     dependencies:
       b4a: 1.6.4
       fast-fifo: 1.3.0
       streamx: 2.15.0
-    dev: false
 
-  /tar@4.4.19:
-    resolution: {integrity: sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==}
-    engines: {node: '>=4.5'}
-    requiresBuild: true
+  tar@4.4.19:
     dependencies:
       chownr: 1.1.4
       fs-minipass: 1.2.7
@@ -18476,12 +22627,9 @@ packages:
       mkdirp: 0.5.6
       safe-buffer: 5.2.1
       yallist: 3.1.1
-    dev: false
     optional: true
 
-  /tar@6.2.0:
-    resolution: {integrity: sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==}
-    engines: {node: '>=10'}
+  tar@6.2.1:
     dependencies:
       chownr: 2.0.0
       fs-minipass: 2.1.0
@@ -18490,285 +22638,160 @@ packages:
       mkdirp: 1.0.4
       yallist: 4.0.0
 
-  /taskkill@5.0.0:
-    resolution: {integrity: sha512-+HRtZ40Vc+6YfCDWCeAsixwxJgMbPY4HHuTgzPYH3JXvqHWUlsCfy+ylXlAKhFNcuLp4xVeWeFBUhDk+7KYUvQ==}
-    engines: {node: '>=14.16'}
+  taskkill@5.0.0:
     dependencies:
       execa: 6.1.0
-    dev: true
 
-  /telejson@7.2.0:
-    resolution: {integrity: sha512-1QTEcJkJEhc8OnStBx/ILRu5J2p0GjvWsBx56bmZRqnrkdBMUe+nX92jxV+p3dB4CP6PZCdJMQJwCggkNBMzkQ==}
+  telejson@7.2.0:
     dependencies:
       memoizerific: 1.11.3
-    dev: true
 
-  /temp-dir@2.0.0:
-    resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==}
-    engines: {node: '>=8'}
-    dev: true
+  temp-dir@2.0.0: {}
 
-  /temp@0.8.4:
-    resolution: {integrity: sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==}
-    engines: {node: '>=6.0.0'}
+  temp@0.8.4:
     dependencies:
       rimraf: 2.6.3
-    dev: true
 
-  /tempy@1.0.1:
-    resolution: {integrity: sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==}
-    engines: {node: '>=10'}
+  tempy@1.0.1:
     dependencies:
       del: 6.1.1
       is-stream: 2.0.1
       temp-dir: 2.0.0
       type-fest: 0.16.0
       unique-string: 2.0.0
-    dev: true
 
-  /terser@5.28.1:
-    resolution: {integrity: sha512-wM+bZp54v/E9eRRGXb5ZFDvinrJIOaTapx3WUokyVGZu5ucVCK55zEgGd5Dl2fSr3jUo5sDiERErUWLY6QPFyA==}
-    engines: {node: '>=10'}
-    hasBin: true
+  terser@5.30.3:
     dependencies:
       '@jridgewell/source-map': 0.3.5
       acorn: 8.11.3
       commander: 2.20.3
       source-map-support: 0.5.21
 
-  /test-exclude@6.0.0:
-    resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
-    engines: {node: '>=8'}
+  test-exclude@6.0.0:
     dependencies:
       '@istanbuljs/schema': 0.1.3
       glob: 7.2.3
       minimatch: 3.1.2
-    dev: true
 
-  /text-decoding@1.0.0:
-    resolution: {integrity: sha512-/0TJD42KDnVwKmDK6jj3xP7E2MG7SHAOG4tyTgyUCRPdHwvkquYNLEQltmdMa3owq3TkddCVcTsoctJI8VQNKA==}
-    dev: false
+  text-table@0.2.0: {}
 
-  /text-table@0.2.0:
-    resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
-    dev: true
+  textarea-caret@3.1.0: {}
 
-  /textarea-caret@3.1.0:
-    resolution: {integrity: sha512-cXAvzO9pP5CGa6NKx0WYHl+8CHKZs8byMkt3PCJBCmq2a34YA9pO1NrQET5pzeqnBjBdToF5No4rrmkDUgQC2Q==}
-    dev: false
-
-  /thenify-all@1.6.0:
-    resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
-    engines: {node: '>=0.8'}
+  thenify-all@1.6.0:
     dependencies:
       thenify: 3.3.1
-    dev: false
 
-  /thenify@3.3.1:
-    resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
+  thenify@3.3.1:
     dependencies:
       any-promise: 1.3.0
-    dev: false
 
-  /thread-stream@2.3.0:
-    resolution: {integrity: sha512-kaDqm1DET9pp3NXwR8382WHbnpXnRkN9xGN9dQt3B2+dmXiW8X1SOwmFOxAErEQ47ObhZ96J6yhZNXuyCOL7KA==}
+  thread-stream@2.3.0:
     dependencies:
       real-require: 0.2.0
-    dev: false
 
-  /three@0.162.0:
-    resolution: {integrity: sha512-xfCYj4RnlozReCmUd+XQzj6/5OjDNHBy5nT6rVwrOKGENAvpXe2z1jL+DZYaMu4/9pNsjH/4Os/VvS9IrH7IOQ==}
-    dev: false
+  three@0.164.1: {}
 
-  /throttle-debounce@5.0.0:
-    resolution: {integrity: sha512-2iQTSgkkc1Zyk0MeVrt/3BvuOXYPl/R8Z0U2xxo9rjwNciaHDG3R+Lm6dh4EeUci49DanvBnuqI6jshoQQRGEg==}
-    engines: {node: '>=12.22'}
-    dev: false
+  throttle-debounce@5.0.0: {}
 
-  /throttleit@1.0.0:
-    resolution: {integrity: sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==}
-    dev: true
+  throttleit@1.0.0: {}
 
-  /through2@2.0.5:
-    resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==}
+  through2@2.0.5:
     dependencies:
       readable-stream: 2.3.7
       xtend: 4.0.2
-    dev: true
 
-  /through@2.3.4:
-    resolution: {integrity: sha512-DwbmSAcABsMazNkLOJJSLRC3gfh4cPxUxJCn9npmvbcI6undhgoJ2ShvEOgZrW8BH62Gyr9jKboGbfFcmY5VsQ==}
-    dev: false
+  through@2.3.4: {}
 
-  /through@2.3.8:
-    resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
+  through@2.3.8: {}
 
-  /tiny-invariant@1.3.1:
-    resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==}
-    dev: true
+  tiny-invariant@1.3.1: {}
 
-  /tiny-invariant@1.3.3:
-    resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
-    dev: true
+  tiny-invariant@1.3.3: {}
 
-  /tiny-lru@10.0.1:
-    resolution: {integrity: sha512-Vst+6kEsWvb17Zpz14sRJV/f8bUWKhqm6Dc+v08iShmIJ/WxqWytHzCTd6m88pS33rE2zpX34TRmOpAJPloNCA==}
-    engines: {node: '>=6'}
-    dev: false
+  tiny-lru@10.0.1: {}
 
-  /tinybench@2.6.0:
-    resolution: {integrity: sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==}
-    dev: true
+  tinybench@2.6.0: {}
 
-  /tinycolor2@1.6.0:
-    resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
-    dev: false
+  tinycolor2@1.6.0: {}
 
-  /tinypool@0.7.0:
-    resolution: {integrity: sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==}
-    engines: {node: '>=14.0.0'}
-    dev: true
+  tinypool@0.7.0: {}
 
-  /tinyspy@2.2.0:
-    resolution: {integrity: sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==}
-    engines: {node: '>=14.0.0'}
-    dev: true
+  tinyspy@2.2.0: {}
 
-  /tmp@0.0.33:
-    resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
-    engines: {node: '>=0.6.0'}
-    dependencies:
-      os-tmpdir: 1.0.2
-    dev: true
+  tmp@0.2.3: {}
 
-  /tmp@0.2.2:
-    resolution: {integrity: sha512-ETcvHhaIc9J2MDEAH6N67j9bvBvu/3Gb764qaGhwtFvjtvhegqoqSpofgeyq1Sc24mW5pdyUDs9HP5j3ehkxRw==}
-    engines: {node: '>=14'}
-    dependencies:
-      rimraf: 5.0.5
+  tmpl@1.0.5: {}
 
-  /tmpl@1.0.5:
-    resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
-    dev: true
+  to-data-view@1.1.0: {}
 
-  /to-data-view@1.1.0:
-    resolution: {integrity: sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ==}
-    dev: false
+  to-fast-properties@2.0.0: {}
 
-  /to-fast-properties@2.0.0:
-    resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
-    engines: {node: '>=4'}
-
-  /to-regex-range@5.0.1:
-    resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
-    engines: {node: '>=8.0'}
+  to-regex-range@5.0.1:
     dependencies:
       is-number: 7.0.0
 
-  /toad-cache@3.3.0:
-    resolution: {integrity: sha512-3oDzcogWGHZdkwrHyvJVpPjA7oNzY6ENOV3PsWJY9XYPZ6INo94Yd47s5may1U+nleBPwDhrRiTPMIvKaa3MQg==}
-    engines: {node: '>=12'}
-    dev: false
+  toad-cache@3.3.0: {}
 
-  /tocbot@4.21.1:
-    resolution: {integrity: sha512-IfajhBTeg0HlMXu1f+VMbPef05QpDTsZ9X2Yn1+8npdaXsXg/+wrm9Ze1WG5OS1UDC3qJ5EQN/XOZ3gfXjPFCw==}
-    dev: true
+  toad-cache@3.7.0: {}
 
-  /toidentifier@1.0.1:
-    resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
-    engines: {node: '>=0.6'}
+  tocbot@4.21.1: {}
 
-  /token-stream@1.0.0:
-    resolution: {integrity: sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==}
+  toidentifier@1.0.1: {}
 
-  /token-types@5.0.1:
-    resolution: {integrity: sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==}
-    engines: {node: '>=14.16'}
+  token-stream@1.0.0: {}
+
+  token-types@5.0.1:
     dependencies:
       '@tokenizer/token': 0.3.0
       ieee754: 1.2.1
-    dev: false
 
-  /touch@3.1.0:
-    resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==}
-    hasBin: true
+  touch@3.1.0:
     dependencies:
       nopt: 1.0.10
-    dev: true
 
-  /tough-cookie@2.5.0:
-    resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==}
-    engines: {node: '>=0.8'}
+  tough-cookie@2.5.0:
     dependencies:
       psl: 1.9.0
       punycode: 2.3.1
-    dev: false
 
-  /tough-cookie@4.1.3:
-    resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==}
-    engines: {node: '>=6'}
+  tough-cookie@4.1.3:
     dependencies:
       psl: 1.9.0
       punycode: 2.3.1
       universalify: 0.2.0
       url-parse: 1.5.10
 
-  /tr46@0.0.3:
-    resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
-    requiresBuild: true
+  tr46@0.0.3: {}
 
-  /tr46@5.0.0:
-    resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==}
-    engines: {node: '>=18'}
+  tr46@5.0.0:
     dependencies:
       punycode: 2.3.1
-    dev: false
 
-  /trace-redirect@1.0.6:
-    resolution: {integrity: sha512-UUfa1DjjU5flcjMdaFIiIEGDTyu2y/IiMjOX4uGXa7meKBS4vD4f2Uy/tken9Qkd4Jsm4sRsfZcIIPqrRVF3Mg==}
+  trace-redirect@1.0.6: {}
 
-  /trim-newlines@3.0.1:
-    resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==}
-    engines: {node: '>=8'}
-    dev: true
+  trim-newlines@3.0.1: {}
 
-  /trim-repeated@2.0.0:
-    resolution: {integrity: sha512-QUHBFTJGdOwmp0tbOG505xAgOp/YliZP/6UgafFXYZ26WT1bvQmSMJUvkeVSASuJJHbqsFbynTvkd5W8RBTipg==}
-    engines: {node: '>=12'}
+  trim-repeated@2.0.0:
     dependencies:
       escape-string-regexp: 5.0.0
-    dev: false
 
-  /trough@2.2.0:
-    resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==}
-    dev: true
+  trough@2.2.0: {}
 
-  /ts-api-utils@1.0.1(typescript@5.3.3):
-    resolution: {integrity: sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==}
-    engines: {node: '>=16.13.0'}
-    peerDependencies:
-      typescript: '>=4.2.0'
+  ts-api-utils@1.0.1(typescript@5.3.3):
     dependencies:
       typescript: 5.3.3
-    dev: true
 
-  /ts-case-convert@2.0.2:
-    resolution: {integrity: sha512-vdKfx1VAdpvEBOBv5OpVu5ZFqRg9HdTI4sYt6qqMeICBeNyXvitrarCnFWNDAki51IKwCyx+ZssY46Q9jH5otA==}
-    dev: true
-    bundledDependencies: []
+  ts-api-utils@1.3.0(typescript@5.4.5):
+    dependencies:
+      typescript: 5.4.5
 
-  /ts-dedent@2.2.0:
-    resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==}
-    engines: {node: '>=6.10'}
-    dev: true
+  ts-case-convert@2.0.2: {}
 
-  /ts-map@1.0.3:
-    resolution: {integrity: sha512-vDWbsl26LIcPGmDpoVzjEP6+hvHZkBkLW7JpvwbCv/5IYPJlsbzCVXY3wsCeAxAUeTclNOUZxnLdGh3VBD/J6w==}
-    dev: true
+  ts-dedent@2.2.0: {}
 
-  /tsc-alias@1.8.8:
-    resolution: {integrity: sha512-OYUOd2wl0H858NvABWr/BoSKNERw3N9GTi3rHPK8Iv4O1UyUXIrTTOAZNHsjlVpXFOhpJBVARI1s+rzwLivN3Q==}
-    hasBin: true
+  ts-map@1.0.3: {}
+
+  tsc-alias@1.8.8:
     dependencies:
       chokidar: 3.5.3
       commander: 9.5.0
@@ -18776,29 +22799,21 @@ packages:
       mylas: 2.1.13
       normalize-path: 3.0.0
       plimit-lit: 1.5.0
-    dev: false
 
-  /tsconfig-paths@3.15.0:
-    resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
+  tsconfig-paths@3.15.0:
     dependencies:
       '@types/json5': 0.0.29
       json5: 1.0.2
       minimist: 1.2.8
       strip-bom: 3.0.0
-    dev: true
 
-  /tsconfig-paths@4.2.0:
-    resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==}
-    engines: {node: '>=6'}
+  tsconfig-paths@4.2.0:
     dependencies:
       json5: 2.2.3
       minimist: 1.2.8
       strip-bom: 3.0.0
 
-  /tsd@0.30.7:
-    resolution: {integrity: sha512-oTiJ28D6B/KXoU3ww/Eji+xqHJojiuPVMwA12g4KYX1O72N93Nb6P3P3h2OAhhf92Xl8NIhb/xFmBZd5zw/xUw==}
-    engines: {node: '>=14.16'}
-    hasBin: true
+  tsd@0.30.7:
     dependencies:
       '@tsd/typescript': 5.3.3
       eslint-formatter-pretty: 4.1.0
@@ -18807,189 +22822,81 @@ packages:
       meow: 9.0.0
       path-exists: 4.0.0
       read-pkg-up: 7.0.1
-    dev: true
 
-  /tslib@1.14.1:
-    resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
+  tslib@1.14.1: {}
 
-  /tslib@2.6.2:
-    resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
+  tslib@2.6.2: {}
 
-  /tsx@4.4.0:
-    resolution: {integrity: sha512-4fwcEjRUxW20ciSaMB8zkpGwCPxuRGnadDuj/pBk5S9uT29zvWz15PK36GrKJo45mSJomDxVejZ73c6lr3811Q==}
-    engines: {node: '>=18.0.0'}
-    hasBin: true
+  tsx@4.4.0:
     dependencies:
       esbuild: 0.18.20
       get-tsconfig: 4.7.2
     optionalDependencies:
       fsevents: 2.3.3
-    dev: true
 
-  /tunnel-agent@0.6.0:
-    resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
+  tunnel-agent@0.6.0:
     dependencies:
       safe-buffer: 5.2.1
 
-  /tweetnacl@0.14.5:
-    resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==}
+  tweetnacl@0.14.5: {}
 
-  /type-check@0.4.0:
-    resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
-    engines: {node: '>= 0.8.0'}
+  type-check@0.4.0:
     dependencies:
       prelude-ls: 1.2.1
-    dev: true
 
-  /type-detect@4.0.8:
-    resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
-    engines: {node: '>=4'}
+  type-detect@4.0.8: {}
 
-  /type-fest@0.16.0:
-    resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==}
-    engines: {node: '>=10'}
-    dev: true
+  type-fest@0.16.0: {}
 
-  /type-fest@0.18.1:
-    resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==}
-    engines: {node: '>=10'}
-    dev: true
+  type-fest@0.18.1: {}
 
-  /type-fest@0.20.2:
-    resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
-    engines: {node: '>=10'}
-    dev: true
+  type-fest@0.20.2: {}
 
-  /type-fest@0.21.3:
-    resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
-    engines: {node: '>=10'}
-    dev: true
+  type-fest@0.21.3: {}
 
-  /type-fest@0.6.0:
-    resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==}
-    engines: {node: '>=8'}
-    dev: true
+  type-fest@0.6.0: {}
 
-  /type-fest@0.8.1:
-    resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==}
-    engines: {node: '>=8'}
-    dev: true
+  type-fest@0.8.1: {}
 
-  /type-fest@2.19.0:
-    resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
-    engines: {node: '>=12.20'}
-    dev: true
+  type-fest@2.19.0: {}
 
-  /type-fest@4.9.0:
-    resolution: {integrity: sha512-KS/6lh/ynPGiHD/LnAobrEFq3Ad4pBzOlJ1wAnJx9N4EYoqFhMfLIBjUT2UEx4wg5ZE+cC1ob6DCSpppVo+rtg==}
-    engines: {node: '>=16'}
-    dev: true
+  type-fest@4.9.0: {}
 
-  /type-is@1.6.18:
-    resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
-    engines: {node: '>= 0.6'}
+  type-is@1.6.18:
     dependencies:
       media-typer: 0.3.0
       mime-types: 2.1.35
 
-  /typed-array-buffer@1.0.0:
-    resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==}
-    engines: {node: '>= 0.4'}
+  typed-array-buffer@1.0.0:
     dependencies:
       call-bind: 1.0.2
       get-intrinsic: 1.2.1
       is-typed-array: 1.1.10
-    dev: true
 
-  /typed-array-byte-length@1.0.0:
-    resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==}
-    engines: {node: '>= 0.4'}
+  typed-array-byte-length@1.0.0:
     dependencies:
       call-bind: 1.0.2
       for-each: 0.3.3
       has-proto: 1.0.1
       is-typed-array: 1.1.10
-    dev: true
 
-  /typed-array-byte-offset@1.0.0:
-    resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==}
-    engines: {node: '>= 0.4'}
+  typed-array-byte-offset@1.0.0:
     dependencies:
       available-typed-arrays: 1.0.5
       call-bind: 1.0.2
       for-each: 0.3.3
       has-proto: 1.0.1
       is-typed-array: 1.1.10
-    dev: true
 
-  /typed-array-length@1.0.4:
-    resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==}
+  typed-array-length@1.0.4:
     dependencies:
       call-bind: 1.0.2
       for-each: 0.3.3
       is-typed-array: 1.1.10
-    dev: true
 
-  /typedarray@0.0.6:
-    resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
+  typedarray@0.0.6: {}
 
-  /typeorm@0.3.20(ioredis@5.3.2)(pg@8.11.3):
-    resolution: {integrity: sha512-sJ0T08dV5eoZroaq9uPKBoNcGslHBR4E4y+EBHs//SiGbblGe7IeduP/IH4ddCcj0qp3PHwDwGnuvqEAnKlq/Q==}
-    engines: {node: '>=16.13.0'}
-    hasBin: true
-    peerDependencies:
-      '@google-cloud/spanner': ^5.18.0
-      '@sap/hana-client': ^2.12.25
-      better-sqlite3: ^7.1.2 || ^8.0.0 || ^9.0.0
-      hdb-pool: ^0.1.6
-      ioredis: ^5.0.4
-      mongodb: ^5.8.0
-      mssql: ^9.1.1 || ^10.0.1
-      mysql2: ^2.2.5 || ^3.0.1
-      oracledb: ^6.3.0
-      pg: ^8.5.1
-      pg-native: ^3.0.0
-      pg-query-stream: ^4.0.0
-      redis: ^3.1.1 || ^4.0.0
-      sql.js: ^1.4.0
-      sqlite3: ^5.0.3
-      ts-node: ^10.7.0
-      typeorm-aurora-data-api-driver: ^2.0.0
-    peerDependenciesMeta:
-      '@google-cloud/spanner':
-        optional: true
-      '@sap/hana-client':
-        optional: true
-      better-sqlite3:
-        optional: true
-      hdb-pool:
-        optional: true
-      ioredis:
-        optional: true
-      mongodb:
-        optional: true
-      mssql:
-        optional: true
-      mysql2:
-        optional: true
-      oracledb:
-        optional: true
-      pg:
-        optional: true
-      pg-native:
-        optional: true
-      pg-query-stream:
-        optional: true
-      redis:
-        optional: true
-      sql.js:
-        optional: true
-      sqlite3:
-        optional: true
-      ts-node:
-        optional: true
-      typeorm-aurora-data-api-driver:
-        optional: true
+  typeorm@0.3.20(ioredis@5.4.1)(pg@8.11.5):
     dependencies:
       '@sqltools/formatter': 1.2.5
       app-root-path: 3.1.0
@@ -19000,97 +22907,64 @@ packages:
       debug: 4.3.4(supports-color@8.1.1)
       dotenv: 16.0.3
       glob: 10.3.10
-      ioredis: 5.3.2
       mkdirp: 2.1.6
-      pg: 8.11.3
-      reflect-metadata: 0.2.1
+      reflect-metadata: 0.2.2
       sha.js: 2.4.11
       tslib: 2.6.2
       uuid: 9.0.1
       yargs: 17.7.2
+    optionalDependencies:
+      ioredis: 5.4.1
+      pg: 8.11.5
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /typescript@5.3.3:
-    resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==}
-    engines: {node: '>=14.17'}
-    hasBin: true
+  typescript@5.3.3: {}
 
-  /ufo@1.3.2:
-    resolution: {integrity: sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==}
-    dev: true
+  typescript@5.4.2: {}
 
-  /uglify-js@3.17.4:
-    resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==}
-    engines: {node: '>=0.8.0'}
-    hasBin: true
-    requiresBuild: true
-    dev: true
+  typescript@5.4.5: {}
+
+  ufo@1.3.2: {}
+
+  uglify-js@3.17.4:
     optional: true
 
-  /uid2@0.0.4:
-    resolution: {integrity: sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==}
-    dev: false
+  uid2@0.0.4: {}
 
-  /uid@2.0.2:
-    resolution: {integrity: sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==}
-    engines: {node: '>=8'}
+  uid@2.0.2:
     dependencies:
       '@lukeed/csprng': 1.0.1
 
-  /ulid@2.3.0:
-    resolution: {integrity: sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==}
-    hasBin: true
-    dev: false
+  ulid@2.3.0: {}
 
-  /unbox-primitive@1.0.2:
-    resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
+  unbox-primitive@1.0.2:
     dependencies:
       call-bind: 1.0.2
       has-bigints: 1.0.2
       has-symbols: 1.0.3
       which-boxed-primitive: 1.0.2
-    dev: true
 
-  /undefsafe@2.0.5:
-    resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==}
-    dev: true
+  undefsafe@2.0.5: {}
 
-  /undici-types@5.26.5:
-    resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
+  undici-types@5.26.5: {}
 
-  /undici@5.28.2:
-    resolution: {integrity: sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==}
-    engines: {node: '>=14.0'}
+  undici@5.28.2:
     dependencies:
       '@fastify/busboy': 2.1.0
 
-  /unicode-canonical-property-names-ecmascript@2.0.0:
-    resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==}
-    engines: {node: '>=4'}
-    dev: true
+  unicode-canonical-property-names-ecmascript@2.0.0: {}
 
-  /unicode-match-property-ecmascript@2.0.0:
-    resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==}
-    engines: {node: '>=4'}
+  unicode-match-property-ecmascript@2.0.0:
     dependencies:
       unicode-canonical-property-names-ecmascript: 2.0.0
       unicode-property-aliases-ecmascript: 2.1.0
-    dev: true
 
-  /unicode-match-property-value-ecmascript@2.1.0:
-    resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==}
-    engines: {node: '>=4'}
-    dev: true
+  unicode-match-property-value-ecmascript@2.1.0: {}
 
-  /unicode-property-aliases-ecmascript@2.1.0:
-    resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==}
-    engines: {node: '>=4'}
-    dev: true
+  unicode-property-aliases-ecmascript@2.1.0: {}
 
-  /unified@11.0.4:
-    resolution: {integrity: sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==}
+  unified@11.0.4:
     dependencies:
       '@types/unist': 3.0.2
       bail: 2.0.2
@@ -19099,241 +22973,152 @@ packages:
       is-plain-obj: 4.1.0
       trough: 2.2.0
       vfile: 6.0.1
-    dev: true
 
-  /uniq@1.0.1:
-    resolution: {integrity: sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==}
-    dev: false
+  uniq@1.0.1: {}
 
-  /unique-filename@3.0.0:
-    resolution: {integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==}
-    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+  unique-filename@3.0.0:
     dependencies:
       unique-slug: 4.0.0
-    dev: false
 
-  /unique-slug@4.0.0:
-    resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==}
-    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+  unique-slug@4.0.0:
     dependencies:
       imurmurhash: 0.1.4
-    dev: false
 
-  /unique-string@2.0.0:
-    resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==}
-    engines: {node: '>=8'}
+  unique-string@2.0.0:
     dependencies:
       crypto-random-string: 2.0.0
-    dev: true
 
-  /unist-util-is@6.0.0:
-    resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
+  unist-util-is@6.0.0:
     dependencies:
       '@types/unist': 3.0.2
-    dev: true
 
-  /unist-util-stringify-position@4.0.0:
-    resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
+  unist-util-stringify-position@4.0.0:
     dependencies:
       '@types/unist': 3.0.2
-    dev: true
 
-  /unist-util-visit-parents@6.0.1:
-    resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==}
+  unist-util-visit-parents@6.0.1:
     dependencies:
       '@types/unist': 3.0.2
       unist-util-is: 6.0.0
-    dev: true
 
-  /unist-util-visit@5.0.0:
-    resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
+  unist-util-visit@5.0.0:
     dependencies:
       '@types/unist': 3.0.2
       unist-util-is: 6.0.0
       unist-util-visit-parents: 6.0.1
-    dev: true
 
-  /universalify@0.1.2:
-    resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
-    engines: {node: '>= 4.0.0'}
+  universalify@0.1.2: {}
 
-  /universalify@0.2.0:
-    resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
-    engines: {node: '>= 4.0.0'}
+  universalify@0.2.0: {}
 
-  /universalify@2.0.0:
-    resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==}
-    engines: {node: '>= 10.0.0'}
-    dev: true
+  universalify@2.0.0: {}
 
-  /unload@2.4.1:
-    resolution: {integrity: sha512-IViSAm8Z3sRBYA+9wc0fLQmU9Nrxb16rcDmIiR6Y9LJSZzI7QY5QsDhqPpKOjAn0O9/kfK1TfNEMMAGPTIraPw==}
-    dev: false
+  unload@2.4.1: {}
 
-  /unpipe@1.0.0:
-    resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
-    engines: {node: '>= 0.8'}
+  unpipe@1.0.0: {}
 
-  /unplugin@1.4.0:
-    resolution: {integrity: sha512-5x4eIEL6WgbzqGtF9UV8VEC/ehKptPXDS6L2b0mv4FRMkJxRtjaJfOWDd6a8+kYbqsjklix7yWP0N3SUepjXcg==}
+  unplugin@1.4.0:
     dependencies:
       acorn: 8.11.3
       chokidar: 3.5.3
       webpack-sources: 3.2.3
       webpack-virtual-modules: 0.5.0
-    dev: true
 
-  /untildify@4.0.0:
-    resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==}
-    engines: {node: '>=8'}
-    dev: true
+  untildify@4.0.0: {}
 
-  /update-browserslist-db@1.0.13(browserslist@4.22.2):
-    resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
-    hasBin: true
-    peerDependencies:
-      browserslist: '>= 4.21.0'
+  update-browserslist-db@1.0.13(browserslist@4.22.2):
     dependencies:
       browserslist: 4.22.2
       escalade: 3.1.1
       picocolors: 1.0.0
-    dev: true
 
-  /update-browserslist-db@1.0.13(browserslist@4.23.0):
-    resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
-    hasBin: true
-    peerDependencies:
-      browserslist: '>= 4.21.0'
+  update-browserslist-db@1.0.13(browserslist@4.23.0):
     dependencies:
       browserslist: 4.23.0
       escalade: 3.1.1
       picocolors: 1.0.0
 
-  /uri-js@4.4.1:
-    resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+  uri-js@4.4.1:
     dependencies:
       punycode: 2.3.1
 
-  /url-parse@1.5.10:
-    resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
+  url-parse@1.5.10:
     dependencies:
       querystringify: 2.2.0
       requires-port: 1.0.0
 
-  /utf-8-validate@6.0.3:
-    resolution: {integrity: sha512-uIuGf9TWQ/y+0Lp+KGZCMuJWc3N9BHA+l/UmHd/oUHwJJDeysyTRxNQVkbzsIWfGFbRe3OcgML/i0mvVRPOyDA==}
-    engines: {node: '>=6.14.2'}
-    requiresBuild: true
+  utf-8-validate@6.0.3:
     dependencies:
       node-gyp-build: 4.6.0
+    optional: true
 
-  /util-deprecate@1.0.2:
-    resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+  util-deprecate@1.0.2: {}
 
-  /util@0.12.5:
-    resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==}
+  util@0.12.5:
     dependencies:
       inherits: 2.0.4
       is-arguments: 1.1.1
       is-generator-function: 1.0.10
       is-typed-array: 1.1.10
       which-typed-array: 1.1.11
-    dev: true
 
-  /utils-merge@1.0.1:
-    resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
-    engines: {node: '>= 0.4.0'}
+  utils-merge@1.0.1: {}
 
-  /uuid@3.4.0:
-    resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==}
-    deprecated: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
-    hasBin: true
-    dev: false
+  uuid@3.4.0: {}
 
-  /uuid@8.3.2:
-    resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
-    hasBin: true
+  uuid@8.3.2: {}
 
-  /uuid@9.0.1:
-    resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
-    hasBin: true
+  uuid@9.0.1: {}
 
-  /v-code-diff@1.9.0(vue@3.4.21):
-    resolution: {integrity: sha512-alg6krCxFvwTob/rJq+3LzjdIbLb/ni8tS8YmBbI0wckOkbJuN1cShFJ6XEkm82tMgpv5NYEeWLEWhggeV7BDg==}
-    requiresBuild: true
-    peerDependencies:
-      '@vue/composition-api': ^1.4.9
-      vue: ^2.6.0 || >=3.0.0
-    peerDependenciesMeta:
-      '@vue/composition-api':
-        optional: true
+  v-code-diff@1.11.0(vue@3.4.26(typescript@5.4.5)):
     dependencies:
       diff: 5.1.0
       diff-match-patch: 1.0.5
       highlight.js: 11.9.0
-      vue: 3.4.21(typescript@5.3.3)
-      vue-demi: 0.14.7(vue@3.4.21)
-    dev: false
+      vue: 3.4.26(typescript@5.4.5)
+      vue-demi: 0.14.7(vue@3.4.26(typescript@5.4.5))
+      vue-i18n: 9.13.1(vue@3.4.26(typescript@5.4.5))
 
-  /v8-to-istanbul@9.2.0:
-    resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==}
-    engines: {node: '>=10.12.0'}
+  v8-to-istanbul@9.2.0:
     dependencies:
       '@jridgewell/trace-mapping': 0.3.18
       '@types/istanbul-lib-coverage': 2.0.4
       convert-source-map: 2.0.0
-    dev: true
 
-  /validate-npm-package-license@3.0.4:
-    resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
+  validate-npm-package-license@3.0.4:
     dependencies:
       spdx-correct: 3.1.1
       spdx-expression-parse: 3.0.1
-    dev: true
 
-  /validator@13.9.0:
-    resolution: {integrity: sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==}
-    engines: {node: '>= 0.10'}
-    dev: true
+  validator@13.9.0: {}
 
-  /vary@1.1.2:
-    resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
-    engines: {node: '>= 0.8'}
+  vary@1.1.2: {}
 
-  /verror@1.10.0:
-    resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==}
-    engines: {'0': node >=0.6.0}
+  verror@1.10.0:
     dependencies:
       assert-plus: 1.0.0
       core-util-is: 1.0.2
       extsprintf: 1.3.0
 
-  /vfile-message@4.0.2:
-    resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==}
+  vfile-message@4.0.2:
     dependencies:
       '@types/unist': 3.0.2
       unist-util-stringify-position: 4.0.0
-    dev: true
 
-  /vfile@6.0.1:
-    resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==}
+  vfile@6.0.1:
     dependencies:
       '@types/unist': 3.0.2
       unist-util-stringify-position: 4.0.0
       vfile-message: 4.0.2
-    dev: true
 
-  /vite-node@0.34.6(@types/node@20.11.22)(sass@1.71.1)(terser@5.28.1):
-    resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==}
-    engines: {node: '>=v14.18.0'}
-    hasBin: true
+  vite-node@0.34.6(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3):
     dependencies:
       cac: 6.7.14
       debug: 4.3.4(supports-color@8.1.1)
       mlly: 1.5.0
       pathe: 1.1.2
       picocolors: 1.0.0
-      vite: 5.1.4(@types/node@20.11.22)(sass@1.71.1)(terser@5.28.1)
+      vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
     transitivePeerDependencies:
       - '@types/node'
       - less
@@ -19343,95 +23128,32 @@ packages:
       - sugarss
       - supports-color
       - terser
-    dev: true
 
-  /vite-plugin-turbosnap@1.0.3:
-    resolution: {integrity: sha512-p4D8CFVhZS412SyQX125qxyzOgIFouwOcvjZWk6bQbNPR1wtaEzFT6jZxAjf1dejlGqa6fqHcuCvQea6EWUkUA==}
-    dev: true
+  vite-plugin-turbosnap@1.0.3: {}
 
-  /vite@5.1.4(@types/node@20.11.22)(sass@1.71.1)(terser@5.28.1):
-    resolution: {integrity: sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg==}
-    engines: {node: ^18.0.0 || >=20.0.0}
-    hasBin: true
-    peerDependencies:
-      '@types/node': ^18.0.0 || >=20.0.0
-      less: '*'
-      lightningcss: ^1.21.0
-      sass: '*'
-      stylus: '*'
-      sugarss: '*'
-      terser: ^5.4.0
-    peerDependenciesMeta:
-      '@types/node':
-        optional: true
-      less:
-        optional: true
-      lightningcss:
-        optional: true
-      sass:
-        optional: true
-      stylus:
-        optional: true
-      sugarss:
-        optional: true
-      terser:
-        optional: true
+  vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3):
     dependencies:
-      '@types/node': 20.11.22
-      esbuild: 0.19.11
-      postcss: 8.4.35
-      rollup: 4.12.0
-      sass: 1.71.1
-      terser: 5.28.1
+      esbuild: 0.20.2
+      postcss: 8.4.38
+      rollup: 4.17.2
     optionalDependencies:
+      '@types/node': 20.12.7
       fsevents: 2.3.3
+      sass: 1.76.0
+      terser: 5.30.3
 
-  /vitest-fetch-mock@0.2.2(vitest@0.34.6):
-    resolution: {integrity: sha512-XmH6QgTSjCWrqXoPREIdbj40T7i1xnGmAsTAgfckoO75W1IEHKR8hcPCQ7SO16RsdW1t85oUm6pcQRLeBgjVYQ==}
-    engines: {node: '>=14.14.0'}
-    peerDependencies:
-      vitest: '>=0.16.0'
+  vitest-fetch-mock@0.2.2(encoding@0.1.13)(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)):
     dependencies:
-      cross-fetch: 3.1.6
-      vitest: 0.34.6(happy-dom@13.6.2)(sass@1.71.1)(terser@5.28.1)
+      cross-fetch: 3.1.6(encoding@0.1.13)
+      vitest: 0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)
     transitivePeerDependencies:
       - encoding
-    dev: true
 
-  /vitest@0.34.6(happy-dom@13.6.2)(sass@1.71.1)(terser@5.28.1):
-    resolution: {integrity: sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==}
-    engines: {node: '>=v14.18.0'}
-    hasBin: true
-    peerDependencies:
-      '@edge-runtime/vm': '*'
-      '@vitest/browser': '*'
-      '@vitest/ui': '*'
-      happy-dom: '*'
-      jsdom: '*'
-      playwright: '*'
-      safaridriver: '*'
-      webdriverio: '*'
-    peerDependenciesMeta:
-      '@edge-runtime/vm':
-        optional: true
-      '@vitest/browser':
-        optional: true
-      '@vitest/ui':
-        optional: true
-      happy-dom:
-        optional: true
-      jsdom:
-        optional: true
-      playwright:
-        optional: true
-      safaridriver:
-        optional: true
-      webdriverio:
-        optional: true
+  vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3):
     dependencies:
       '@types/chai': 4.3.11
       '@types/chai-subset': 1.3.5
-      '@types/node': 20.11.22
+      '@types/node': 20.12.7
       '@vitest/expect': 0.34.6
       '@vitest/runner': 0.34.6
       '@vitest/snapshot': 0.34.6
@@ -19442,7 +23164,6 @@ packages:
       cac: 6.7.14
       chai: 4.3.10
       debug: 4.3.4(supports-color@8.1.1)
-      happy-dom: 13.6.2
       local-pkg: 0.4.3
       magic-string: 0.30.7
       pathe: 1.1.2
@@ -19451,9 +23172,12 @@ packages:
       strip-literal: 1.3.0
       tinybench: 2.6.0
       tinypool: 0.7.0
-      vite: 5.1.4(@types/node@20.11.22)(sass@1.71.1)(terser@5.28.1)
-      vite-node: 0.34.6(@types/node@20.11.22)(sass@1.71.1)(terser@5.28.1)
+      vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
+      vite-node: 0.34.6(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
       why-is-node-running: 2.2.2
+    optionalDependencies:
+      happy-dom: 14.7.1
+      jsdom: 24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
     transitivePeerDependencies:
       - less
       - lightningcss
@@ -19462,114 +23186,63 @@ packages:
       - sugarss
       - supports-color
       - terser
-    dev: true
 
-  /void-elements@3.1.0:
-    resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
-    engines: {node: '>=0.10.0'}
+  void-elements@3.1.0: {}
 
-  /vscode-jsonrpc@8.2.0:
-    resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==}
-    engines: {node: '>=14.0.0'}
-    dev: false
+  vscode-jsonrpc@8.2.0: {}
 
-  /vscode-languageclient@9.0.1:
-    resolution: {integrity: sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==}
-    engines: {vscode: ^1.82.0}
+  vscode-languageclient@9.0.1:
     dependencies:
       minimatch: 5.1.2
       semver: 7.6.0
       vscode-languageserver-protocol: 3.17.5
-    dev: false
 
-  /vscode-languageserver-protocol@3.17.5:
-    resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==}
+  vscode-languageserver-protocol@3.17.5:
     dependencies:
       vscode-jsonrpc: 8.2.0
       vscode-languageserver-types: 3.17.5
-    dev: false
 
-  /vscode-languageserver-textdocument@1.0.11:
-    resolution: {integrity: sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==}
-    dev: false
+  vscode-languageserver-textdocument@1.0.11: {}
 
-  /vscode-languageserver-types@3.17.5:
-    resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==}
-    dev: false
+  vscode-languageserver-types@3.17.5: {}
 
-  /vscode-languageserver@9.0.1:
-    resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==}
-    hasBin: true
+  vscode-languageserver@9.0.1:
     dependencies:
       vscode-languageserver-protocol: 3.17.5
-    dev: false
 
-  /vue-component-meta@2.0.16(typescript@5.3.3):
-    resolution: {integrity: sha512-IyIMClUMYcKxAL34GqdPbR4V45MUeHXqQiZlHxeYMV5Qcqp4M+CEmtGpF//XBSS138heDkYkceHAtJQjLUB1Lw==}
-    peerDependencies:
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
+  vue-component-meta@2.0.16(typescript@5.4.5):
     dependencies:
       '@volar/typescript': 2.2.0
-      '@vue/language-core': 2.0.16(typescript@5.3.3)
+      '@vue/language-core': 2.0.16(typescript@5.4.5)
       path-browserify: 1.0.1
-      typescript: 5.3.3
       vue-component-type-helpers: 2.0.16
-    dev: true
+    optionalDependencies:
+      typescript: 5.4.5
 
-  /vue-component-type-helpers@1.8.27:
-    resolution: {integrity: sha512-0vOfAtI67UjeO1G6UiX5Kd76CqaQ67wrRZiOe7UAb9Jm6GzlUr/fC7CV90XfwapJRjpCMaZFhv1V0ajWRmE9Dg==}
-    dev: true
+  vue-component-type-helpers@1.8.4: {}
 
-  /vue-component-type-helpers@1.8.4:
-    resolution: {integrity: sha512-6bnLkn8O0JJyiFSIF0EfCogzeqNXpnjJ0vW/SZzNHfe6sPx30lTtTXlE5TFs2qhJlAtDFybStVNpL73cPe3OMQ==}
-    dev: true
+  vue-component-type-helpers@2.0.16: {}
 
-  /vue-component-type-helpers@2.0.16:
-    resolution: {integrity: sha512-qisL/iAfdO++7w+SsfYQJVPj6QKvxp4i1MMxvsNO41z/8zu3KuAw9LkhKUfP/kcOWGDxESp+pQObWppXusejCA==}
-    dev: true
-
-  /vue-demi@0.14.7(vue@3.4.21):
-    resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
-    engines: {node: '>=12'}
-    hasBin: true
-    requiresBuild: true
-    peerDependencies:
-      '@vue/composition-api': ^1.0.0-rc.1
-      vue: ^3.0.0-0 || ^2.6.0
-    peerDependenciesMeta:
-      '@vue/composition-api':
-        optional: true
+  vue-demi@0.14.7(vue@3.4.26(typescript@5.4.5)):
     dependencies:
-      vue: 3.4.21(typescript@5.3.3)
-    dev: false
+      vue: 3.4.26(typescript@5.4.5)
 
-  /vue-docgen-api@4.75.1(vue@3.4.21):
-    resolution: {integrity: sha512-MECZ3uExz+ssmhD/2XrFoQQs93y17IVO1KDYTp8nr6i9GNrk67AAto6QAtilW1H/pTDPMkQxJ7w/25ZIqVtfAA==}
-    peerDependencies:
-      vue: '>=2'
+  vue-docgen-api@4.75.1(vue@3.4.26(typescript@5.4.5)):
     dependencies:
       '@babel/parser': 7.24.0
       '@babel/types': 7.24.0
       '@vue/compiler-dom': 3.4.21
-      '@vue/compiler-sfc': 3.4.21
+      '@vue/compiler-sfc': 3.4.26
       ast-types: 0.16.1
       hash-sum: 2.0.0
       lru-cache: 8.0.4
       pug: 3.0.2
       recast: 0.23.4
       ts-map: 1.0.3
-      vue: 3.4.21(typescript@5.3.3)
-      vue-inbrowser-compiler-independent-utils: 4.71.1(vue@3.4.21)
-    dev: true
+      vue: 3.4.26(typescript@5.4.5)
+      vue-inbrowser-compiler-independent-utils: 4.71.1(vue@3.4.26(typescript@5.4.5))
 
-  /vue-eslint-parser@9.4.2(eslint@8.57.0):
-    resolution: {integrity: sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ==}
-    engines: {node: ^14.17.0 || >=16.0.0}
-    peerDependencies:
-      eslint: '>=6.0.0'
+  vue-eslint-parser@9.4.2(eslint@8.57.0):
     dependencies:
       debug: 4.3.4(supports-color@8.1.1)
       eslint: 8.57.0
@@ -19581,70 +23254,50 @@ packages:
       semver: 7.5.4
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /vue-inbrowser-compiler-independent-utils@4.71.1(vue@3.4.21):
-    resolution: {integrity: sha512-K3wt3iVmNGaFEOUR4JIThQRWfqokxLfnPslD41FDZB2ajXp789+wCqJyGYlIFsvEQ2P61PInw6/ph5iiqg51gg==}
-    peerDependencies:
-      vue: '>=2'
+  vue-i18n@9.13.1(vue@3.4.26(typescript@5.4.5)):
     dependencies:
-      vue: 3.4.21(typescript@5.3.3)
-    dev: true
+      '@intlify/core-base': 9.13.1
+      '@intlify/shared': 9.13.1
+      '@vue/devtools-api': 6.6.1
+      vue: 3.4.26(typescript@5.4.5)
 
-  /vue-template-compiler@2.7.14:
-    resolution: {integrity: sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==}
+  vue-inbrowser-compiler-independent-utils@4.71.1(vue@3.4.26(typescript@5.4.5)):
+    dependencies:
+      vue: 3.4.26(typescript@5.4.5)
+
+  vue-template-compiler@2.7.14:
     dependencies:
       de-indent: 1.0.2
       he: 1.2.0
-    dev: true
 
-  /vue-tsc@1.8.27(typescript@5.3.3):
-    resolution: {integrity: sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==}
-    hasBin: true
-    peerDependencies:
-      typescript: '*'
+  vue-tsc@2.0.16(typescript@5.4.5):
     dependencies:
-      '@volar/typescript': 1.11.1
-      '@vue/language-core': 1.8.27(typescript@5.3.3)
-      semver: 7.5.4
-      typescript: 5.3.3
-    dev: true
+      '@volar/typescript': 2.2.0
+      '@vue/language-core': 2.0.16(typescript@5.4.5)
+      semver: 7.6.0
+      typescript: 5.4.5
 
-  /vue@3.4.21(typescript@5.3.3):
-    resolution: {integrity: sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==}
-    peerDependencies:
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
+  vue@3.4.26(typescript@5.4.5):
     dependencies:
-      '@vue/compiler-dom': 3.4.21
-      '@vue/compiler-sfc': 3.4.21
-      '@vue/runtime-dom': 3.4.21
-      '@vue/server-renderer': 3.4.21(vue@3.4.21)
-      '@vue/shared': 3.4.21
-      typescript: 5.3.3
+      '@vue/compiler-dom': 3.4.26
+      '@vue/compiler-sfc': 3.4.26
+      '@vue/runtime-dom': 3.4.26
+      '@vue/server-renderer': 3.4.26(vue@3.4.26(typescript@5.4.5))
+      '@vue/shared': 3.4.26
+    optionalDependencies:
+      typescript: 5.4.5
 
-  /vuedraggable@4.1.0(vue@3.4.21):
-    resolution: {integrity: sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==}
-    peerDependencies:
-      vue: ^3.0.1
+  vuedraggable@4.1.0(vue@3.4.26(typescript@5.4.5)):
     dependencies:
       sortablejs: 1.14.0
-      vue: 3.4.21(typescript@5.3.3)
-    dev: false
+      vue: 3.4.26(typescript@5.4.5)
 
-  /w3c-xmlserializer@5.0.0:
-    resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
-    engines: {node: '>=18'}
+  w3c-xmlserializer@5.0.0:
     dependencies:
       xml-name-validator: 5.0.0
-    dev: false
 
-  /wait-on@7.2.0(debug@4.3.4):
-    resolution: {integrity: sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==}
-    engines: {node: '>=12.0.0'}
-    hasBin: true
+  wait-on@7.2.0(debug@4.3.4):
     dependencies:
       axios: 1.6.2(debug@4.3.4)
       joi: 17.11.0
@@ -19653,32 +23306,21 @@ packages:
       rxjs: 7.8.1
     transitivePeerDependencies:
       - debug
-    dev: true
 
-  /walker@1.0.8:
-    resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
+  walker@1.0.8:
     dependencies:
       makeerror: 1.0.12
-    dev: true
 
-  /watchpack@2.4.0:
-    resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==}
-    engines: {node: '>=10.13.0'}
+  watchpack@2.4.0:
     dependencies:
       glob-to-regexp: 0.4.1
       graceful-fs: 4.2.11
-    dev: true
 
-  /wcwidth@1.0.1:
-    resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
+  wcwidth@1.0.1:
     dependencies:
       defaults: 1.0.4
-    dev: true
 
-  /web-push@3.6.7:
-    resolution: {integrity: sha512-OpiIUe8cuGjrj3mMBFWY+e4MMIkW3SVT+7vEIjvD9kejGUypv8GPDf84JdPWskK8zMRIJ6xYGm+Kxr8YkPyA0A==}
-    engines: {node: '>= 16'}
-    hasBin: true
+  web-push@3.6.7:
     dependencies:
       asn1.js: 5.4.1
       http_ece: 1.2.0
@@ -19687,289 +23329,168 @@ packages:
       minimist: 1.2.8
     transitivePeerDependencies:
       - supports-color
-    dev: false
 
-  /web-streams-polyfill@3.2.1:
-    resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==}
-    engines: {node: '>= 8'}
+  web-streams-polyfill@3.2.1: {}
 
-  /webidl-conversions@3.0.1:
-    resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
-    requiresBuild: true
+  webidl-conversions@3.0.1: {}
 
-  /webidl-conversions@7.0.0:
-    resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
-    engines: {node: '>=12'}
+  webidl-conversions@7.0.0: {}
 
-  /webpack-sources@3.2.3:
-    resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==}
-    engines: {node: '>=10.13.0'}
-    dev: true
+  webpack-sources@3.2.3: {}
 
-  /webpack-virtual-modules@0.5.0:
-    resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==}
-    dev: true
+  webpack-virtual-modules@0.5.0: {}
 
-  /whatwg-encoding@2.0.0:
-    resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==}
-    engines: {node: '>=12'}
+  whatwg-encoding@3.1.1:
     dependencies:
       iconv-lite: 0.6.3
-    dev: false
 
-  /whatwg-encoding@3.1.1:
-    resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
-    engines: {node: '>=18'}
-    dependencies:
-      iconv-lite: 0.6.3
-    dev: false
+  whatwg-mimetype@3.0.0: {}
 
-  /whatwg-mimetype@3.0.0:
-    resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
-    engines: {node: '>=12'}
+  whatwg-mimetype@4.0.0: {}
 
-  /whatwg-mimetype@4.0.0:
-    resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
-    engines: {node: '>=18'}
-    dev: false
-
-  /whatwg-url@14.0.0:
-    resolution: {integrity: sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==}
-    engines: {node: '>=18'}
+  whatwg-url@14.0.0:
     dependencies:
       tr46: 5.0.0
       webidl-conversions: 7.0.0
-    dev: false
 
-  /whatwg-url@5.0.0:
-    resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
+  whatwg-url@5.0.0:
     dependencies:
       tr46: 0.0.3
       webidl-conversions: 3.0.1
 
-  /which-boxed-primitive@1.0.2:
-    resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
+  which-boxed-primitive@1.0.2:
     dependencies:
       is-bigint: 1.0.4
       is-boolean-object: 1.1.2
       is-number-object: 1.0.7
       is-string: 1.0.7
       is-symbol: 1.0.4
-    dev: true
 
-  /which-collection@1.0.1:
-    resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==}
+  which-collection@1.0.1:
     dependencies:
       is-map: 2.0.2
       is-set: 2.0.2
       is-weakmap: 2.0.1
       is-weakset: 2.0.2
-    dev: true
 
-  /which-module@2.0.0:
-    resolution: {integrity: sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==}
-    dev: false
+  which-module@2.0.0: {}
 
-  /which-typed-array@1.1.11:
-    resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==}
-    engines: {node: '>= 0.4'}
+  which-typed-array@1.1.11:
     dependencies:
       available-typed-arrays: 1.0.5
       call-bind: 1.0.2
       for-each: 0.3.3
       gopd: 1.0.1
       has-tostringtag: 1.0.0
-    dev: true
 
-  /which@1.3.1:
-    resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
-    hasBin: true
-    dependencies:
-      isexe: 2.0.0
-    dev: false
-
-  /which@2.0.2:
-    resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
-    engines: {node: '>= 8'}
-    hasBin: true
+  which@1.3.1:
     dependencies:
       isexe: 2.0.0
 
-  /which@4.0.0:
-    resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==}
-    engines: {node: ^16.13.0 || >=18.0.0}
-    hasBin: true
+  which@2.0.2:
+    dependencies:
+      isexe: 2.0.0
+
+  which@4.0.0:
     dependencies:
       isexe: 3.1.1
-    dev: false
 
-  /why-is-node-running@2.2.2:
-    resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==}
-    engines: {node: '>=8'}
-    hasBin: true
+  why-is-node-running@2.2.2:
     dependencies:
       siginfo: 2.0.0
       stackback: 0.0.2
-    dev: true
 
-  /wide-align@1.1.5:
-    resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
-    requiresBuild: true
+  wide-align@1.1.5:
     dependencies:
       string-width: 4.2.3
-    dev: false
     optional: true
 
-  /with@7.0.2:
-    resolution: {integrity: sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==}
-    engines: {node: '>= 10.0.0'}
+  with@7.0.2:
     dependencies:
       '@babel/parser': 7.23.9
       '@babel/types': 7.23.5
       assert-never: 1.2.1
       babel-walk: 3.0.0-canary-5
 
-  /wordwrap@1.0.0:
-    resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
-    dev: true
+  wordwrap@1.0.0: {}
 
-  /wrap-ansi@6.2.0:
-    resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
-    engines: {node: '>=8'}
+  wrap-ansi@6.2.0:
     dependencies:
       ansi-styles: 4.3.0
       string-width: 4.2.3
       strip-ansi: 6.0.1
 
-  /wrap-ansi@7.0.0:
-    resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
-    engines: {node: '>=10'}
+  wrap-ansi@7.0.0:
     dependencies:
       ansi-styles: 4.3.0
       string-width: 4.2.3
       strip-ansi: 6.0.1
 
-  /wrap-ansi@8.1.0:
-    resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
-    engines: {node: '>=12'}
+  wrap-ansi@8.1.0:
     dependencies:
       ansi-styles: 6.2.1
       string-width: 5.1.2
       strip-ansi: 7.1.0
 
-  /wrappy@1.0.2:
-    resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+  wrappy@1.0.2: {}
 
-  /write-file-atomic@2.4.3:
-    resolution: {integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==}
+  write-file-atomic@2.4.3:
     dependencies:
       graceful-fs: 4.2.11
       imurmurhash: 0.1.4
       signal-exit: 3.0.7
-    dev: true
 
-  /write-file-atomic@4.0.2:
-    resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==}
-    engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+  write-file-atomic@4.0.2:
     dependencies:
       imurmurhash: 0.1.4
       signal-exit: 3.0.7
-    dev: true
 
-  /ws@8.16.0(bufferutil@4.0.7)(utf-8-validate@6.0.3):
-    resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==}
-    engines: {node: '>=10.0.0'}
-    peerDependencies:
-      bufferutil: ^4.0.1
-      utf-8-validate: '>=5.0.2'
-    peerDependenciesMeta:
-      bufferutil:
-        optional: true
-      utf-8-validate:
-        optional: true
-    dependencies:
+  ws@8.17.0(bufferutil@4.0.7)(utf-8-validate@6.0.3):
+    optionalDependencies:
       bufferutil: 4.0.7
       utf-8-validate: 6.0.3
 
-  /xev@3.0.2:
-    resolution: {integrity: sha512-8kxuH95iMXzHZj+fwqfA4UrPcYOy6bGIgfWzo9Ji23JoEc30ge/Z++Ubkiuy8c0+M64nXmmxrmJ7C8wnuBhluw==}
-    dev: false
+  xev@3.0.2: {}
 
-  /xml-js@1.6.11:
-    resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==}
-    hasBin: true
+  xml-js@1.6.11:
     dependencies:
       sax: 1.2.4
-    dev: false
 
-  /xml-name-validator@4.0.0:
-    resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
-    engines: {node: '>=12'}
-    dev: true
+  xml-name-validator@4.0.0: {}
 
-  /xml-name-validator@5.0.0:
-    resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
-    engines: {node: '>=18'}
-    dev: false
+  xml-name-validator@5.0.0: {}
 
-  /xml2js@0.5.0:
-    resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==}
-    engines: {node: '>=4.0.0'}
+  xml2js@0.5.0:
     dependencies:
       sax: 1.2.4
       xmlbuilder: 11.0.1
-    dev: false
 
-  /xmlbuilder@11.0.1:
-    resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==}
-    engines: {node: '>=4.0'}
-    dev: false
+  xmlbuilder@11.0.1: {}
 
-  /xmlchars@2.2.0:
-    resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
-    dev: false
+  xmlchars@2.2.0: {}
 
-  /xtend@4.0.2:
-    resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
-    engines: {node: '>=0.4'}
+  xtend@4.0.2: {}
 
-  /y18n@4.0.3:
-    resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
-    dev: false
+  y18n@4.0.3: {}
 
-  /y18n@5.0.8:
-    resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
-    engines: {node: '>=10'}
+  y18n@5.0.8: {}
 
-  /yallist@2.1.2:
-    resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
-    dev: false
+  yallist@2.1.2: {}
 
-  /yallist@3.1.1:
-    resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+  yallist@3.1.1: {}
 
-  /yallist@4.0.0:
-    resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+  yallist@4.0.0: {}
 
-  /yargs-parser@18.1.3:
-    resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
-    engines: {node: '>=6'}
+  yargs-parser@18.1.3:
     dependencies:
       camelcase: 5.3.1
       decamelize: 1.2.0
-    dev: false
 
-  /yargs-parser@20.2.9:
-    resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
-    engines: {node: '>=10'}
+  yargs-parser@20.2.9: {}
 
-  /yargs-parser@21.1.1:
-    resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
-    engines: {node: '>=12'}
+  yargs-parser@21.1.1: {}
 
-  /yargs@15.4.1:
-    resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
-    engines: {node: '>=8'}
+  yargs@15.4.1:
     dependencies:
       cliui: 6.0.0
       decamelize: 1.2.0
@@ -19982,11 +23503,8 @@ packages:
       which-module: 2.0.0
       y18n: 4.0.3
       yargs-parser: 18.1.3
-    dev: false
 
-  /yargs@16.2.0:
-    resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}
-    engines: {node: '>=10'}
+  yargs@16.2.0:
     dependencies:
       cliui: 7.0.4
       escalade: 3.1.1
@@ -19995,11 +23513,8 @@ packages:
       string-width: 4.2.3
       y18n: 5.0.8
       yargs-parser: 20.2.9
-    dev: false
 
-  /yargs@17.7.2:
-    resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
-    engines: {node: '>=12'}
+  yargs@17.7.2:
     dependencies:
       cliui: 8.0.1
       escalade: 3.1.1
@@ -20009,98 +23524,27 @@ packages:
       y18n: 5.0.8
       yargs-parser: 21.1.1
 
-  /yauzl@2.10.0:
-    resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==}
+  yauzl@2.10.0:
     dependencies:
       buffer-crc32: 0.2.13
       fd-slicer: 1.1.0
-    dev: true
 
-  /yocto-queue@0.1.0:
-    resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
-    engines: {node: '>=10'}
+  yocto-queue@0.1.0: {}
 
-  /yocto-queue@1.0.0:
-    resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}
-    engines: {node: '>=12.20'}
-    dev: true
+  yocto-queue@1.0.0: {}
 
-  /z-schema@5.0.5:
-    resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==}
-    engines: {node: '>=8.0.0'}
-    hasBin: true
+  z-schema@5.0.5:
     dependencies:
       lodash.get: 4.4.2
       lodash.isequal: 4.5.0
       validator: 13.9.0
     optionalDependencies:
       commander: 9.5.0
-    dev: true
 
-  /zip-stream@5.0.1:
-    resolution: {integrity: sha512-UfZ0oa0C8LI58wJ+moL46BDIMgCQbnsb+2PoiJYtonhBsMh2bq1eRBVkvjfVsqbEHd9/EgKPUuL9saSSsec8OA==}
-    engines: {node: '>= 12.0.0'}
+  zip-stream@6.0.1:
     dependencies:
-      archiver-utils: 4.0.1
-      compress-commons: 5.0.1
-      readable-stream: 3.6.0
-    dev: false
+      archiver-utils: 5.0.2
+      compress-commons: 6.0.2
+      readable-stream: 4.3.0
 
-  /zwitch@2.0.4:
-    resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
-    dev: true
-
-  '@github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz':
-    resolution: {tarball: https://github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz}
-    name: '@aiscript-dev/aiscript-languageserver'
-    version: 0.1.6
-    hasBin: true
-    dependencies:
-      seedrandom: 3.0.5
-      stringz: 2.1.0
-      uuid: 9.0.1
-      vscode-languageserver: 9.0.1
-      vscode-languageserver-textdocument: 1.0.11
-    dev: false
-
-  github.com/aiscript-dev/aiscript-vscode/3f79d6f0550369267220aa67702287948d885424:
-    resolution: {tarball: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/3f79d6f0550369267220aa67702287948d885424}
-    name: aiscript-vscode
-    version: 0.1.4
-    engines: {vscode: ^1.83.0}
-    dependencies:
-      '@aiscript-dev/aiscript-languageserver': '@github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz'
-      vscode-languageclient: 9.0.1
-    dev: false
-
-  github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.0.9)(@storybook/components@8.0.9)(@storybook/core-events@8.0.9)(@storybook/manager-api@8.0.9)(@storybook/preview-api@8.0.9)(@storybook/theming@8.0.9)(@storybook/types@8.0.9)(react-dom@18.2.0)(react@18.2.0):
-    resolution: {tarball: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640}
-    id: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640
-    name: storybook-addon-misskey-theme
-    version: 0.0.0
-    peerDependencies:
-      '@storybook/blocks': ^7.0.0-rc.4
-      '@storybook/components': ^7.0.0-rc.4
-      '@storybook/core-events': ^7.0.0-rc.4
-      '@storybook/manager-api': ^7.0.0-rc.4
-      '@storybook/preview-api': ^7.0.0-rc.4
-      '@storybook/theming': ^7.0.0-rc.4
-      '@storybook/types': ^7.0.0-rc.4
-      react: ^16.8.0 || ^17.0.0 || ^18.0.0
-      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
-    peerDependenciesMeta:
-      react:
-        optional: true
-      react-dom:
-        optional: true
-    dependencies:
-      '@storybook/blocks': 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/components': 8.0.9(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/core-events': 8.0.9
-      '@storybook/manager-api': 8.0.9(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/preview-api': 8.0.9
-      '@storybook/theming': 8.0.9(react-dom@18.2.0)(react@18.2.0)
-      '@storybook/types': 8.0.9
-      react: 18.2.0
-      react-dom: 18.2.0(react@18.2.0)
-    dev: true
+  zwitch@2.0.4: {}
diff --git a/scripts/build-assets.mjs b/scripts/build-assets.mjs
index e7684d7cc9..b5aa5eb4ab 100644
--- a/scripts/build-assets.mjs
+++ b/scripts/build-assets.mjs
@@ -34,7 +34,7 @@ async function copyFrontendFonts() {
 }
 
 async function copyFrontendTablerIcons() {
-  await fs.cp('./packages/frontend/node_modules/@tabler/icons-webfont', './built/_frontend_dist_/tabler-icons', { dereference: true, recursive: true });
+  await fs.cp('./packages/frontend/node_modules/@tabler/icons-webfont/dist', './built/_frontend_dist_/tabler-icons', { dereference: true, recursive: true });
 }
 
 async function copyFrontendLocales() {

From fc77ad9355f74ec4b4b155a9d5624850b3dff351 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Mon, 6 May 2024 20:37:04 +0900
Subject: [PATCH 112/191] refactor(frontend): provide linkNavigationBehavior

---
 packages/frontend/src/components/MkAbuseReport.vue   |  2 +-
 packages/frontend/src/components/MkLink.vue          |  4 ++--
 packages/frontend/src/components/MkMention.vue       |  4 ++--
 packages/frontend/src/components/global/MkA.vue      | 12 +++++-------
 .../components/global/MkMisskeyFlavoredMarkdown.ts   | 10 ++++------
 packages/frontend/src/components/global/MkUrl.vue    |  4 ++--
 6 files changed, 16 insertions(+), 20 deletions(-)

diff --git a/packages/frontend/src/components/MkAbuseReport.vue b/packages/frontend/src/components/MkAbuseReport.vue
index ab65ea7ec7..a28e7c2559 100644
--- a/packages/frontend/src/components/MkAbuseReport.vue
+++ b/packages/frontend/src/components/MkAbuseReport.vue
@@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 	</div>
 	<div class="detail">
 		<div>
-			<Mfm :text="report.comment" :linkBehavior="'window'"/>
+			<Mfm :text="report.comment" :linkNavigationBehavior="'window'"/>
 		</div>
 		<hr/>
 		<div>{{ i18n.ts.reporter }}: <MkA :to="`/admin/user/${report.reporter.id}`" class="_link" :behavior="'window'">@{{ report.reporter.username }}</MkA></div>
diff --git a/packages/frontend/src/components/MkLink.vue b/packages/frontend/src/components/MkLink.vue
index bd1bd0e24a..5d54a58e97 100644
--- a/packages/frontend/src/components/MkLink.vue
+++ b/packages/frontend/src/components/MkLink.vue
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 <template>
 <component
 	:is="self ? 'MkA' : 'a'" ref="el" style="word-break: break-all;" class="_link" :[attr]="self ? url.substring(local.length) : url" :rel="rel ?? 'nofollow noopener'" :target="target"
-	:behavior="props.behavior"
+	:behavior="props.navigationBehavior"
 	:title="url"
 >
 	<slot></slot>
@@ -25,7 +25,7 @@ import { MkABehavior } from '@/components/global/MkA.vue';
 const props = withDefaults(defineProps<{
 	url: string;
 	rel?: null | string;
-	behavior?: MkABehavior;
+	navigationBehavior?: MkABehavior;
 }>(), {
 });
 
diff --git a/packages/frontend/src/components/MkMention.vue b/packages/frontend/src/components/MkMention.vue
index cbefecf03a..bfb49a416e 100644
--- a/packages/frontend/src/components/MkMention.vue
+++ b/packages/frontend/src/components/MkMention.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-<MkA v-user-preview="canonical" :class="[$style.root, { [$style.isMe]: isMe }]" :to="url" :style="{ background: bgCss }" :behavior="behavior">
+<MkA v-user-preview="canonical" :class="[$style.root, { [$style.isMe]: isMe }]" :to="url" :style="{ background: bgCss }" :behavior="navigationBehavior">
 	<img :class="$style.icon" :src="avatarUrl" alt="">
 	<span>
 		<span>@{{ username }}</span>
@@ -26,7 +26,7 @@ import { MkABehavior } from '@/components/global/MkA.vue';
 const props = defineProps<{
 	username: string;
 	host: string;
-	behavior?: MkABehavior;
+	navigationBehavior?: MkABehavior;
 }>();
 
 const canonical = props.host === localHost ? `@${props.username}` : `@${props.username}@${toUnicode(props.host)}`;
diff --git a/packages/frontend/src/components/global/MkA.vue b/packages/frontend/src/components/global/MkA.vue
index b64acacc32..d1e9113c48 100644
--- a/packages/frontend/src/components/global/MkA.vue
+++ b/packages/frontend/src/components/global/MkA.vue
@@ -14,7 +14,7 @@ export type MkABehavior = 'window' | 'browser' | null;
 </script>
 
 <script lang="ts" setup>
-import { computed, shallowRef } from 'vue';
+import { computed, inject, shallowRef } from 'vue';
 import * as os from '@/os.js';
 import copyToClipboard from '@/scripts/copy-to-clipboard.js';
 import { url } from '@/config.js';
@@ -30,7 +30,7 @@ const props = withDefaults(defineProps<{
 	behavior: null,
 });
 
-const linkBehaviour = props.behavior;
+const behavior = props.behavior ?? inject<MkABehavior>('linkNavigationBehavior', null);
 
 const el = shallowRef<HTMLElement>();
 
@@ -86,15 +86,13 @@ function openWindow() {
 }
 
 function nav(ev: MouseEvent) {
-	if (props.behavior === 'browser') {
+	if (behavior === 'browser') {
 		location.href = props.to;
 		return;
 	}
 
-	if (props.behavior) {
-		if (props.behavior === 'window') {
-			return openWindow();
-		}
+	if (behavior === 'window') {
+		return openWindow();
 	}
 
 	if (ev.shiftKey) {
diff --git a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
index 6e880fc322..cab8d9c704 100644
--- a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
+++ b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { VNode, h, SetupContext } from 'vue';
+import { VNode, h, SetupContext, provide } from 'vue';
 import * as mfm from 'mfm-js';
 import * as Misskey from 'misskey-js';
 import MkUrl from '@/components/global/MkUrl.vue';
@@ -43,7 +43,7 @@ type MfmProps = {
 	parsedNodes?: mfm.MfmNode[] | null;
 	enableEmojiMenu?: boolean;
 	enableEmojiMenuReaction?: boolean;
-	linkBehavior?: MkABehavior;
+	linkNavigationBehavior?: MkABehavior;
 };
 
 type MfmEvents = {
@@ -52,6 +52,8 @@ type MfmEvents = {
 
 // eslint-disable-next-line import/no-default-export
 export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEvents>['emit'] }) {
+	provide('linkNavigationBehavior', props.linkNavigationBehavior);
+
 	const isNote = props.isNote ?? true;
 	const shouldNyaize = props.nyaize ? props.nyaize === 'respect' ? props.author?.isCat : false : false;
 
@@ -343,7 +345,6 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
 					key: Math.random(),
 					url: token.props.url,
 					rel: 'nofollow noopener',
-					behavior: props.linkBehavior,
 				})];
 			}
 
@@ -352,7 +353,6 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
 					key: Math.random(),
 					url: token.props.url,
 					rel: 'nofollow noopener',
-					behavior: props.linkBehavior,
 				}, genEl(token.children, scale, true))];
 			}
 
@@ -361,7 +361,6 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
 					key: Math.random(),
 					host: (token.props.host == null && props.author && props.author.host != null ? props.author.host : token.props.host) ?? host,
 					username: token.props.username,
-					behavior: props.linkBehavior,
 				})];
 			}
 
@@ -370,7 +369,6 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
 					key: Math.random(),
 					to: isNote ? `/tags/${encodeURIComponent(token.props.hashtag)}` : `/user-tags/${encodeURIComponent(token.props.hashtag)}`,
 					style: 'color:var(--hashtag);',
-					behavior: props.linkBehavior,
 				}, `#${token.props.hashtag}`)];
 			}
 
diff --git a/packages/frontend/src/components/global/MkUrl.vue b/packages/frontend/src/components/global/MkUrl.vue
index 1c2f3ccedb..9d4cd559d9 100644
--- a/packages/frontend/src/components/global/MkUrl.vue
+++ b/packages/frontend/src/components/global/MkUrl.vue
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 <template>
 <component
 	:is="self ? 'MkA' : 'a'" ref="el" :class="$style.root" class="_link" :[attr]="self ? props.url.substring(local.length) : props.url" :rel="rel ?? 'nofollow noopener'" :target="target"
-	:behavior = "props.behavior"
+	:behavior="props.navigationBehavior"
 	@contextmenu.stop="() => {}"
 >
 	<template v-if="!self">
@@ -38,7 +38,7 @@ const props = withDefaults(defineProps<{
 	url: string;
 	rel?: string;
 	showUrlPreview?: boolean;
-	behavior?: MkABehavior;
+	navigationBehavior?: MkABehavior;
 }>(), {
 	showUrlPreview: true,
 });

From c639f30d39d3c4d08405df8a3eab541486efda9a Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Mon, 6 May 2024 20:41:39 +0900
Subject: [PATCH 113/191] Update CHANGELOG.md

---
 CHANGELOG.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index c54fa6ed78..d95ea3fc38 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -39,7 +39,7 @@
 - Enhance: Playを手動でリロードできるように
 - Enhance: 通報のコメント内のリンクをクリックした際、ウィンドウで開くように
 - Enhance: `Ui:C:postForm` および `Ui:C:postFormButton` に `localOnly` と `visibility` を設定できるように
-- Chore: AiScriptを0.18.0にバージョンアップ
+- Enhance: AiScriptを0.18.0にバージョンアップ
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
 - Fix: ローカルURLのプレビューポップアップが左上に表示される
@@ -63,6 +63,8 @@
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
 - Enhance: misskey-dev/summaly@5.1.0の取り込み(プレビュー生成処理の効率化)
+- Enhance: ドライブのファイルがNSFWかどうか個別に連合されるように (#13756)
+  - 可能な場合、ノートの添付ファイルのセンシティブ判定がファイル単位になります
 - Fix: リモートから配送されたアクティビティにJSON-LD compactionをかける
 - Fix: フォローリクエストを作成する際に既存のものは削除するように  
   (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/440)
@@ -78,8 +80,6 @@
 - Fix: グローバルタイムラインで返信が表示されないことがある問題を修正
 - Fix: リノートをミュートしたユーザの投稿のリノートがミュートされる問題を修正
 - Fix: AP Link等は添付ファイル扱いしないようになど (#13754)
-- Enhance: ドライブのファイルがNSFWかどうか個別に連合されるように (#13756)
-  - 可能な場合、ノートの添付ファイルのセンシティブ判定がファイル単位になります
 
 ## 2024.3.1
 

From 73a5b6cec904f251bcd043018e00480b84887f19 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Mon, 6 May 2024 11:50:00 +0000
Subject: [PATCH 114/191] Bump version to 2024.5.0-beta.0

---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d95ea3fc38..bc00d5975c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,4 @@
-## Unreleased
+## 2024.5.0
 
 ### Note
 - コントロールパネル内にあるサマリープロキシの設定個所がセキュリティから全般へ変更となります。

From 455543b36e1bf7b4cda56b96a7ef20b2473aa654 Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Mon, 6 May 2024 21:36:05 +0900
Subject: [PATCH 115/191] change package.json

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 23e0ea0ee5..6a377d899b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2024.3.1",
+	"version": "2024.5.0-beta.0",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index 6badc7f3ee..294c23086b 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2024.3.1",
+	"version": "2024.5.0-beta.0",
 	"description": "Misskey SDK for JavaScript",
 	"main": "./built/index.js",
 	"types": "./built/index.d.ts",

From 313515c6817479c2d781c808e96acad7c41e61d3 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Tue, 7 May 2024 01:45:00 +0000
Subject: [PATCH 116/191] Bump version to 2024.5.0-beta.1

---
 package.json                     | 148 +++++++++++++++----------------
 packages/misskey-js/package.json | 122 ++++++++++++-------------
 2 files changed, 135 insertions(+), 135 deletions(-)

diff --git a/package.json b/package.json
index 6a377d899b..bc5d396d6c 100644
--- a/package.json
+++ b/package.json
@@ -1,76 +1,76 @@
 {
-	"name": "misskey",
-	"version": "2024.5.0-beta.0",
-	"codename": "nasubi",
-	"repository": {
-		"type": "git",
-		"url": "https://github.com/misskey-dev/misskey.git"
-	},
-	"packageManager": "pnpm@9.0.6",
-	"workspaces": [
-		"packages/frontend",
-		"packages/backend",
-		"packages/sw",
-		"packages/misskey-js",
-		"packages/misskey-reversi",
-		"packages/misskey-bubble-game"
-	],
-	"private": true,
-	"scripts": {
-		"build-pre": "node ./scripts/build-pre.js",
-		"build-assets": "node ./scripts/build-assets.mjs",
-		"build": "pnpm build-pre && pnpm -r build && pnpm build-assets",
-		"build-storybook": "pnpm --filter frontend build-storybook",
-		"build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api",
-		"start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js",
-		"start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js",
-		"init": "pnpm migrate",
-		"migrate": "cd packages/backend && pnpm migrate",
-		"revert": "cd packages/backend && pnpm revert",
-		"check:connect": "cd packages/backend && pnpm check:connect",
-		"migrateandstart": "pnpm migrate && pnpm start",
-		"watch": "pnpm dev",
-		"dev": "node scripts/dev.mjs",
-		"lint": "pnpm -r lint",
-		"cy:open": "pnpm cypress open --browser --e2e --config-file=cypress.config.ts",
-		"cy:run": "pnpm cypress run",
-		"e2e": "pnpm start-server-and-test start:test http://localhost:61812 cy:run",
-		"jest": "cd packages/backend && pnpm jest",
-		"jest-and-coverage": "cd packages/backend && pnpm jest-and-coverage",
-		"test": "pnpm -r test",
-		"test-and-coverage": "pnpm -r test-and-coverage",
-		"clean": "node ./scripts/clean.js",
-		"clean-all": "node ./scripts/clean-all.js",
-		"cleanall": "pnpm clean-all"
-	},
-	"resolutions": {
-		"chokidar": "3.5.3",
-		"lodash": "4.17.21"
-	},
-	"dependencies": {
-		"cssnano": "6.1.2",
-		"execa": "8.0.1",
-		"fast-glob": "3.3.2",
-		"ignore-walk": "6.0.4",
-		"js-yaml": "4.1.0",
-		"postcss": "8.4.38",
-		"tar": "6.2.1",
-		"terser": "5.30.3",
-		"typescript": "5.4.5",
-		"esbuild": "0.20.2",
-		"glob": "10.3.12"
-	},
-	"devDependencies": {
-		"@types/node": "20.12.7",
-		"@typescript-eslint/eslint-plugin": "7.7.1",
-		"@typescript-eslint/parser": "7.7.1",
-		"cross-env": "7.0.3",
-		"cypress": "13.7.3",
-		"eslint": "8.57.0",
-		"ncp": "2.0.0",
-		"start-server-and-test": "2.0.3"
-	},
-	"optionalDependencies": {
-		"@tensorflow/tfjs-core": "4.4.0"
-	}
+  "name": "misskey",
+  "version": "2024.5.0-beta.1",
+  "codename": "nasubi",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/misskey-dev/misskey.git"
+  },
+  "packageManager": "pnpm@9.0.6",
+  "workspaces": [
+    "packages/frontend",
+    "packages/backend",
+    "packages/sw",
+    "packages/misskey-js",
+    "packages/misskey-reversi",
+    "packages/misskey-bubble-game"
+  ],
+  "private": true,
+  "scripts": {
+    "build-pre": "node ./scripts/build-pre.js",
+    "build-assets": "node ./scripts/build-assets.mjs",
+    "build": "pnpm build-pre && pnpm -r build && pnpm build-assets",
+    "build-storybook": "pnpm --filter frontend build-storybook",
+    "build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api",
+    "start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js",
+    "start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js",
+    "init": "pnpm migrate",
+    "migrate": "cd packages/backend && pnpm migrate",
+    "revert": "cd packages/backend && pnpm revert",
+    "check:connect": "cd packages/backend && pnpm check:connect",
+    "migrateandstart": "pnpm migrate && pnpm start",
+    "watch": "pnpm dev",
+    "dev": "node scripts/dev.mjs",
+    "lint": "pnpm -r lint",
+    "cy:open": "pnpm cypress open --browser --e2e --config-file=cypress.config.ts",
+    "cy:run": "pnpm cypress run",
+    "e2e": "pnpm start-server-and-test start:test http://localhost:61812 cy:run",
+    "jest": "cd packages/backend && pnpm jest",
+    "jest-and-coverage": "cd packages/backend && pnpm jest-and-coverage",
+    "test": "pnpm -r test",
+    "test-and-coverage": "pnpm -r test-and-coverage",
+    "clean": "node ./scripts/clean.js",
+    "clean-all": "node ./scripts/clean-all.js",
+    "cleanall": "pnpm clean-all"
+  },
+  "resolutions": {
+    "chokidar": "3.5.3",
+    "lodash": "4.17.21"
+  },
+  "dependencies": {
+    "cssnano": "6.1.2",
+    "execa": "8.0.1",
+    "fast-glob": "3.3.2",
+    "ignore-walk": "6.0.4",
+    "js-yaml": "4.1.0",
+    "postcss": "8.4.38",
+    "tar": "6.2.1",
+    "terser": "5.30.3",
+    "typescript": "5.4.5",
+    "esbuild": "0.20.2",
+    "glob": "10.3.12"
+  },
+  "devDependencies": {
+    "@types/node": "20.12.7",
+    "@typescript-eslint/eslint-plugin": "7.7.1",
+    "@typescript-eslint/parser": "7.7.1",
+    "cross-env": "7.0.3",
+    "cypress": "13.7.3",
+    "eslint": "8.57.0",
+    "ncp": "2.0.0",
+    "start-server-and-test": "2.0.3"
+  },
+  "optionalDependencies": {
+    "@tensorflow/tfjs-core": "4.4.0"
+  }
 }
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index 294c23086b..e7766cda12 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,63 +1,63 @@
 {
-	"type": "module",
-	"name": "misskey-js",
-	"version": "2024.5.0-beta.0",
-	"description": "Misskey SDK for JavaScript",
-	"main": "./built/index.js",
-	"types": "./built/index.d.ts",
-	"exports": {
-		".": {
-			"import": "./built/index.js",
-			"types": "./built/index.d.ts"
-		},
-		"./*": {
-			"import": "./built/*",
-			"types": "./built/*"
-		}
-	},
-	"scripts": {
-		"build": "node ./build.js",
-		"watch": "nodemon -w package.json -e json --exec \"node ./build.js --watch\"",
-		"tsd": "tsd",
-		"api": "pnpm api-extractor run --local --verbose",
-		"api-prod": "pnpm api-extractor run --verbose",
-		"eslint": "eslint . --ext .js,.jsx,.ts,.tsx",
-		"typecheck": "tsc --noEmit",
-		"lint": "pnpm typecheck && pnpm eslint",
-		"jest": "jest --coverage --detectOpenHandles",
-		"test": "pnpm jest && pnpm tsd",
-		"update-autogen-code": "pnpm --filter misskey-js-type-generator generate && ncp generator/built/autogen src/autogen"
-	},
-	"repository": {
-		"type": "git",
-		"url": "git+https://github.com/misskey-dev/misskey.js.git"
-	},
-	"devDependencies": {
-		"@microsoft/api-extractor": "7.43.1",
-		"@misskey-dev/eslint-plugin": "1.0.0",
-		"@swc/jest": "0.2.36",
-		"@types/jest": "29.5.12",
-		"@types/node": "20.12.7",
-		"@typescript-eslint/eslint-plugin": "7.7.1",
-		"@typescript-eslint/parser": "7.7.1",
-		"eslint": "8.57.0",
-		"jest": "29.7.0",
-		"jest-fetch-mock": "3.0.3",
-		"jest-websocket-mock": "2.5.0",
-		"mock-socket": "9.3.1",
-		"ncp": "2.0.0",
-		"nodemon": "3.1.0",
-		"execa": "8.0.1",
-		"tsd": "0.30.7",
-		"typescript": "5.4.5",
-		"esbuild": "0.19.11",
-		"glob": "10.3.12"
-	},
-	"files": [
-		"built"
-	],
-	"dependencies": {
-		"eventemitter3": "5.0.1",
-		"reconnecting-websocket": "4.4.0"
-	}
+  "type": "module",
+  "name": "misskey-js",
+  "version": "2024.5.0-beta.1",
+  "description": "Misskey SDK for JavaScript",
+  "main": "./built/index.js",
+  "types": "./built/index.d.ts",
+  "exports": {
+    ".": {
+      "import": "./built/index.js",
+      "types": "./built/index.d.ts"
+    },
+    "./*": {
+      "import": "./built/*",
+      "types": "./built/*"
+    }
+  },
+  "scripts": {
+    "build": "node ./build.js",
+    "watch": "nodemon -w package.json -e json --exec \"node ./build.js --watch\"",
+    "tsd": "tsd",
+    "api": "pnpm api-extractor run --local --verbose",
+    "api-prod": "pnpm api-extractor run --verbose",
+    "eslint": "eslint . --ext .js,.jsx,.ts,.tsx",
+    "typecheck": "tsc --noEmit",
+    "lint": "pnpm typecheck && pnpm eslint",
+    "jest": "jest --coverage --detectOpenHandles",
+    "test": "pnpm jest && pnpm tsd",
+    "update-autogen-code": "pnpm --filter misskey-js-type-generator generate && ncp generator/built/autogen src/autogen"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/misskey-dev/misskey.js.git"
+  },
+  "devDependencies": {
+    "@microsoft/api-extractor": "7.43.1",
+    "@misskey-dev/eslint-plugin": "1.0.0",
+    "@swc/jest": "0.2.36",
+    "@types/jest": "29.5.12",
+    "@types/node": "20.12.7",
+    "@typescript-eslint/eslint-plugin": "7.7.1",
+    "@typescript-eslint/parser": "7.7.1",
+    "eslint": "8.57.0",
+    "jest": "29.7.0",
+    "jest-fetch-mock": "3.0.3",
+    "jest-websocket-mock": "2.5.0",
+    "mock-socket": "9.3.1",
+    "ncp": "2.0.0",
+    "nodemon": "3.1.0",
+    "execa": "8.0.1",
+    "tsd": "0.30.7",
+    "typescript": "5.4.5",
+    "esbuild": "0.19.11",
+    "glob": "10.3.12"
+  },
+  "files": [
+    "built"
+  ],
+  "dependencies": {
+    "eventemitter3": "5.0.1",
+    "reconnecting-websocket": "4.4.0"
+  }
 }

From 0fd06e3f0d8589176d33acf2b15decd0643eac29 Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Tue, 7 May 2024 11:07:16 +0900
Subject: [PATCH 117/191] fix

---
 package.json                     | 148 +++++++++++++++----------------
 packages/misskey-js/package.json | 122 ++++++++++++-------------
 2 files changed, 135 insertions(+), 135 deletions(-)

diff --git a/package.json b/package.json
index bc5d396d6c..e05fbdcca7 100644
--- a/package.json
+++ b/package.json
@@ -1,76 +1,76 @@
 {
-  "name": "misskey",
-  "version": "2024.5.0-beta.1",
-  "codename": "nasubi",
-  "repository": {
-    "type": "git",
-    "url": "https://github.com/misskey-dev/misskey.git"
-  },
-  "packageManager": "pnpm@9.0.6",
-  "workspaces": [
-    "packages/frontend",
-    "packages/backend",
-    "packages/sw",
-    "packages/misskey-js",
-    "packages/misskey-reversi",
-    "packages/misskey-bubble-game"
-  ],
-  "private": true,
-  "scripts": {
-    "build-pre": "node ./scripts/build-pre.js",
-    "build-assets": "node ./scripts/build-assets.mjs",
-    "build": "pnpm build-pre && pnpm -r build && pnpm build-assets",
-    "build-storybook": "pnpm --filter frontend build-storybook",
-    "build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api",
-    "start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js",
-    "start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js",
-    "init": "pnpm migrate",
-    "migrate": "cd packages/backend && pnpm migrate",
-    "revert": "cd packages/backend && pnpm revert",
-    "check:connect": "cd packages/backend && pnpm check:connect",
-    "migrateandstart": "pnpm migrate && pnpm start",
-    "watch": "pnpm dev",
-    "dev": "node scripts/dev.mjs",
-    "lint": "pnpm -r lint",
-    "cy:open": "pnpm cypress open --browser --e2e --config-file=cypress.config.ts",
-    "cy:run": "pnpm cypress run",
-    "e2e": "pnpm start-server-and-test start:test http://localhost:61812 cy:run",
-    "jest": "cd packages/backend && pnpm jest",
-    "jest-and-coverage": "cd packages/backend && pnpm jest-and-coverage",
-    "test": "pnpm -r test",
-    "test-and-coverage": "pnpm -r test-and-coverage",
-    "clean": "node ./scripts/clean.js",
-    "clean-all": "node ./scripts/clean-all.js",
-    "cleanall": "pnpm clean-all"
-  },
-  "resolutions": {
-    "chokidar": "3.5.3",
-    "lodash": "4.17.21"
-  },
-  "dependencies": {
-    "cssnano": "6.1.2",
-    "execa": "8.0.1",
-    "fast-glob": "3.3.2",
-    "ignore-walk": "6.0.4",
-    "js-yaml": "4.1.0",
-    "postcss": "8.4.38",
-    "tar": "6.2.1",
-    "terser": "5.30.3",
-    "typescript": "5.4.5",
-    "esbuild": "0.20.2",
-    "glob": "10.3.12"
-  },
-  "devDependencies": {
-    "@types/node": "20.12.7",
-    "@typescript-eslint/eslint-plugin": "7.7.1",
-    "@typescript-eslint/parser": "7.7.1",
-    "cross-env": "7.0.3",
-    "cypress": "13.7.3",
-    "eslint": "8.57.0",
-    "ncp": "2.0.0",
-    "start-server-and-test": "2.0.3"
-  },
-  "optionalDependencies": {
-    "@tensorflow/tfjs-core": "4.4.0"
-  }
+	"name": "misskey",
+	"version": "2024.5.0-beta.1",
+	"codename": "nasubi",
+	"repository": {
+		"type": "git",
+		"url": "https://github.com/misskey-dev/misskey.git"
+	},
+	"packageManager": "pnpm@9.0.6",
+	"workspaces": [
+		"packages/frontend",
+		"packages/backend",
+		"packages/sw",
+		"packages/misskey-js",
+		"packages/misskey-reversi",
+		"packages/misskey-bubble-game"
+	],
+	"private": true,
+	"scripts": {
+		"build-pre": "node ./scripts/build-pre.js",
+		"build-assets": "node ./scripts/build-assets.mjs",
+		"build": "pnpm build-pre && pnpm -r build && pnpm build-assets",
+		"build-storybook": "pnpm --filter frontend build-storybook",
+		"build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api",
+		"start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js",
+		"start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js",
+		"init": "pnpm migrate",
+		"migrate": "cd packages/backend && pnpm migrate",
+		"revert": "cd packages/backend && pnpm revert",
+		"check:connect": "cd packages/backend && pnpm check:connect",
+		"migrateandstart": "pnpm migrate && pnpm start",
+		"watch": "pnpm dev",
+		"dev": "node scripts/dev.mjs",
+		"lint": "pnpm -r lint",
+		"cy:open": "pnpm cypress open --browser --e2e --config-file=cypress.config.ts",
+		"cy:run": "pnpm cypress run",
+		"e2e": "pnpm start-server-and-test start:test http://localhost:61812 cy:run",
+		"jest": "cd packages/backend && pnpm jest",
+		"jest-and-coverage": "cd packages/backend && pnpm jest-and-coverage",
+		"test": "pnpm -r test",
+		"test-and-coverage": "pnpm -r test-and-coverage",
+		"clean": "node ./scripts/clean.js",
+		"clean-all": "node ./scripts/clean-all.js",
+		"cleanall": "pnpm clean-all"
+	},
+	"resolutions": {
+		"chokidar": "3.5.3",
+		"lodash": "4.17.21"
+	},
+	"dependencies": {
+		"cssnano": "6.1.2",
+		"execa": "8.0.1",
+		"fast-glob": "3.3.2",
+		"ignore-walk": "6.0.4",
+		"js-yaml": "4.1.0",
+		"postcss": "8.4.38",
+		"tar": "6.2.1",
+		"terser": "5.30.3",
+		"typescript": "5.4.5",
+		"esbuild": "0.20.2",
+		"glob": "10.3.12"
+	},
+	"devDependencies": {
+		"@types/node": "20.12.7",
+		"@typescript-eslint/eslint-plugin": "7.7.1",
+		"@typescript-eslint/parser": "7.7.1",
+		"cross-env": "7.0.3",
+		"cypress": "13.7.3",
+		"eslint": "8.57.0",
+		"ncp": "2.0.0",
+		"start-server-and-test": "2.0.3"
+	},
+	"optionalDependencies": {
+		"@tensorflow/tfjs-core": "4.4.0"
+	}
 }
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index e7766cda12..cc5d5bdbf4 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,63 +1,63 @@
 {
-  "type": "module",
-  "name": "misskey-js",
-  "version": "2024.5.0-beta.1",
-  "description": "Misskey SDK for JavaScript",
-  "main": "./built/index.js",
-  "types": "./built/index.d.ts",
-  "exports": {
-    ".": {
-      "import": "./built/index.js",
-      "types": "./built/index.d.ts"
-    },
-    "./*": {
-      "import": "./built/*",
-      "types": "./built/*"
-    }
-  },
-  "scripts": {
-    "build": "node ./build.js",
-    "watch": "nodemon -w package.json -e json --exec \"node ./build.js --watch\"",
-    "tsd": "tsd",
-    "api": "pnpm api-extractor run --local --verbose",
-    "api-prod": "pnpm api-extractor run --verbose",
-    "eslint": "eslint . --ext .js,.jsx,.ts,.tsx",
-    "typecheck": "tsc --noEmit",
-    "lint": "pnpm typecheck && pnpm eslint",
-    "jest": "jest --coverage --detectOpenHandles",
-    "test": "pnpm jest && pnpm tsd",
-    "update-autogen-code": "pnpm --filter misskey-js-type-generator generate && ncp generator/built/autogen src/autogen"
-  },
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/misskey-dev/misskey.js.git"
-  },
-  "devDependencies": {
-    "@microsoft/api-extractor": "7.43.1",
-    "@misskey-dev/eslint-plugin": "1.0.0",
-    "@swc/jest": "0.2.36",
-    "@types/jest": "29.5.12",
-    "@types/node": "20.12.7",
-    "@typescript-eslint/eslint-plugin": "7.7.1",
-    "@typescript-eslint/parser": "7.7.1",
-    "eslint": "8.57.0",
-    "jest": "29.7.0",
-    "jest-fetch-mock": "3.0.3",
-    "jest-websocket-mock": "2.5.0",
-    "mock-socket": "9.3.1",
-    "ncp": "2.0.0",
-    "nodemon": "3.1.0",
-    "execa": "8.0.1",
-    "tsd": "0.30.7",
-    "typescript": "5.4.5",
-    "esbuild": "0.19.11",
-    "glob": "10.3.12"
-  },
-  "files": [
-    "built"
-  ],
-  "dependencies": {
-    "eventemitter3": "5.0.1",
-    "reconnecting-websocket": "4.4.0"
-  }
+	"type": "module",
+	"name": "misskey-js",
+	"version": "2024.5.0-beta.1",
+	"description": "Misskey SDK for JavaScript",
+	"main": "./built/index.js",
+	"types": "./built/index.d.ts",
+	"exports": {
+		".": {
+			"import": "./built/index.js",
+			"types": "./built/index.d.ts"
+		},
+		"./*": {
+			"import": "./built/*",
+			"types": "./built/*"
+		}
+	},
+	"scripts": {
+		"build": "node ./build.js",
+		"watch": "nodemon -w package.json -e json --exec \"node ./build.js --watch\"",
+		"tsd": "tsd",
+		"api": "pnpm api-extractor run --local --verbose",
+		"api-prod": "pnpm api-extractor run --verbose",
+		"eslint": "eslint . --ext .js,.jsx,.ts,.tsx",
+		"typecheck": "tsc --noEmit",
+		"lint": "pnpm typecheck && pnpm eslint",
+		"jest": "jest --coverage --detectOpenHandles",
+		"test": "pnpm jest && pnpm tsd",
+		"update-autogen-code": "pnpm --filter misskey-js-type-generator generate && ncp generator/built/autogen src/autogen"
+	},
+	"repository": {
+		"type": "git",
+		"url": "git+https://github.com/misskey-dev/misskey.js.git"
+	},
+	"devDependencies": {
+		"@microsoft/api-extractor": "7.43.1",
+		"@misskey-dev/eslint-plugin": "1.0.0",
+		"@swc/jest": "0.2.36",
+		"@types/jest": "29.5.12",
+		"@types/node": "20.12.7",
+		"@typescript-eslint/eslint-plugin": "7.7.1",
+		"@typescript-eslint/parser": "7.7.1",
+		"eslint": "8.57.0",
+		"jest": "29.7.0",
+		"jest-fetch-mock": "3.0.3",
+		"jest-websocket-mock": "2.5.0",
+		"mock-socket": "9.3.1",
+		"ncp": "2.0.0",
+		"nodemon": "3.1.0",
+		"execa": "8.0.1",
+		"tsd": "0.30.7",
+		"typescript": "5.4.5",
+		"esbuild": "0.19.11",
+		"glob": "10.3.12"
+	},
+	"files": [
+		"built"
+	],
+	"dependencies": {
+		"eventemitter3": "5.0.1",
+		"reconnecting-websocket": "4.4.0"
+	}
 }

From f5d57c02c7edbf71c4f2eaff789dfd093513027d Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Tue, 7 May 2024 14:38:43 +0900
Subject: [PATCH 118/191] dev: modify release manager to set indent type

---
 .github/workflows/release-with-dispatch.yml | 3 +++
 .github/workflows/release-with-ready.yml    | 1 +
 2 files changed, 4 insertions(+)

diff --git a/.github/workflows/release-with-dispatch.yml b/.github/workflows/release-with-dispatch.yml
index 1a954739d9..bc6448cb37 100644
--- a/.github/workflows/release-with-dispatch.yml
+++ b/.github/workflows/release-with-dispatch.yml
@@ -61,6 +61,7 @@ jobs:
         -
 
       use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
+      indent: ${{ vars.INDENT }}
     secrets:
       RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
       RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
@@ -75,6 +76,7 @@ jobs:
       pr_number: ${{ needs.get-pr.outputs.pr_number }}
       package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
       use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
+      indent: ${{ vars.INDENT }}
     secrets:
       RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
       RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
@@ -115,6 +117,7 @@ jobs:
       #  }
       package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
       use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
+      indent: ${{ vars.INDENT }}
     secrets:
       RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
       RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
diff --git a/.github/workflows/release-with-ready.yml b/.github/workflows/release-with-ready.yml
index b64ed20791..139503e563 100644
--- a/.github/workflows/release-with-ready.yml
+++ b/.github/workflows/release-with-ready.yml
@@ -33,6 +33,7 @@ jobs:
       pr_number: ${{ github.event.pull_request.number }}
       package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
       use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
+      indent: ${{ vars.INDENT }}
     secrets:
       RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
       RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}

From b298897bdedc988800f72798cdbf2dbcd2e994ae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?=
 <46447427+samunohito@users.noreply.github.com>
Date: Fri, 10 May 2024 15:32:23 +0900
Subject: [PATCH 119/191] =?UTF-8?q?fix(backend):=20=E4=B8=8D=E8=A6=81?=
 =?UTF-8?q?=E3=81=AAUserProfile=E3=81=AE=E5=8F=96=E5=BE=97=E3=82=92?=
 =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20(#13812)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(backend): 不要なuserProfileの取得を修正

* fix: pnpm@9.0.6 to pnpm@9.1.0

* Revert "fix: pnpm@9.0.6 to pnpm@9.1.0"

This reverts commit eaf265ec2cf255cadeaa516d5b668134bc397211.
---
 packages/backend/src/core/entities/UserEntityService.ts | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts
index df2b27d709..d85f31a989 100644
--- a/packages/backend/src/core/entities/UserEntityService.ts
+++ b/packages/backend/src/core/entities/UserEntityService.ts
@@ -637,18 +637,17 @@ export class UserEntityService implements OnModuleInit {
 		}
 		const _userIds = _users.map(u => u.id);
 
-		// -- 特に前提条件のない値群を取得
-
-		const profilesMap = await this.userProfilesRepository.findBy({ userId: In(_userIds) })
-			.then(profiles => new Map(profiles.map(p => [p.userId, p])));
-
 		// -- 実行者の有無や指定スキーマの種別によって要否が異なる値群を取得
 
+		let profilesMap: Map<MiUser['id'], MiUserProfile> = new Map();
 		let userRelations: Map<MiUser['id'], UserRelation> = new Map();
 		let userMemos: Map<MiUser['id'], string | null> = new Map();
 		let pinNotes: Map<MiUser['id'], MiUserNotePining[]> = new Map();
 
 		if (options?.schema !== 'UserLite') {
+			profilesMap = await this.userProfilesRepository.findBy({ userId: In(_userIds) })
+				.then(profiles => new Map(profiles.map(p => [p.userId, p])));
+
 			const meId = me ? me.id : null;
 			if (meId) {
 				userMemos = await this.userMemosRepository.findBy({ userId: meId })

From f6af6d9679305b36dc993a310462a6065248ae1a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?=
 <46447427+samunohito@users.noreply.github.com>
Date: Fri, 10 May 2024 15:33:25 +0900
Subject: [PATCH 120/191] =?UTF-8?q?fix(backend):=20UserEntityService.getRe?=
 =?UTF-8?q?lations=E3=81=AE=E5=8F=96=E5=BE=97=E5=87=A6=E7=90=86=E3=82=92?=
 =?UTF-8?q?=E8=BB=BD=E9=87=8F=E5=8C=96=20(#13811)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(backend): UserEntityService.getRelationsの取得処理を軽量化

* rollback
---
 .../src/core/entities/UserEntityService.ts    | 49 +++++++++++++------
 1 file changed, 35 insertions(+), 14 deletions(-)

diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts
index d85f31a989..b80a1ec206 100644
--- a/packages/backend/src/core/entities/UserEntityService.ts
+++ b/packages/backend/src/core/entities/UserEntityService.ts
@@ -249,20 +249,41 @@ export class UserEntityService implements OnModuleInit {
 		] = await Promise.all([
 			this.followingsRepository.findBy({ followerId: me })
 				.then(f => new Map(f.map(it => [it.followeeId, it]))),
-			this.followingsRepository.findBy({ followeeId: me })
-				.then(it => it.map(it => it.followerId)),
-			this.followRequestsRepository.findBy({ followerId: me })
-				.then(it => it.map(it => it.followeeId)),
-			this.followRequestsRepository.findBy({ followeeId: me })
-				.then(it => it.map(it => it.followerId)),
-			this.blockingsRepository.findBy({ blockerId: me })
-				.then(it => it.map(it => it.blockeeId)),
-			this.blockingsRepository.findBy({ blockeeId: me })
-				.then(it => it.map(it => it.blockerId)),
-			this.mutingsRepository.findBy({ muterId: me })
-				.then(it => it.map(it => it.muteeId)),
-			this.renoteMutingsRepository.findBy({ muterId: me })
-				.then(it => it.map(it => it.muteeId)),
+			this.followingsRepository.createQueryBuilder('f')
+				.select('f.followerId')
+				.where('f.followeeId = :me', { me })
+				.getRawMany<{ f_followerId: string }>()
+				.then(it => it.map(it => it.f_followerId)),
+			this.followRequestsRepository.createQueryBuilder('f')
+				.select('f.followeeId')
+				.where('f.followerId = :me', { me })
+				.getRawMany<{ f_followeeId: string }>()
+				.then(it => it.map(it => it.f_followeeId)),
+			this.followRequestsRepository.createQueryBuilder('f')
+				.select('f.followerId')
+				.where('f.followeeId = :me', { me })
+				.getRawMany<{ f_followerId: string }>()
+				.then(it => it.map(it => it.f_followerId)),
+			this.blockingsRepository.createQueryBuilder('b')
+				.select('b.blockeeId')
+				.where('b.blockerId = :me', { me })
+				.getRawMany<{ b_blockeeId: string }>()
+				.then(it => it.map(it => it.b_blockeeId)),
+			this.blockingsRepository.createQueryBuilder('b')
+				.select('b.blockerId')
+				.where('b.blockeeId = :me', { me })
+				.getRawMany<{ b_blockerId: string }>()
+				.then(it => it.map(it => it.b_blockerId)),
+			this.mutingsRepository.createQueryBuilder('m')
+				.select('m.muteeId')
+				.where('m.muterId = :me', { me })
+				.getRawMany<{ m_muteeId: string }>()
+				.then(it => it.map(it => it.m_muteeId)),
+			this.renoteMutingsRepository.createQueryBuilder('m')
+				.select('m.muteeId')
+				.where('m.muterId = :me', { me })
+				.getRawMany<{ m_muteeId: string }>()
+				.then(it => it.map(it => it.m_muteeId)),
 		]);
 
 		return new Map(

From 12ae9a2b23436732ef453c6bca5f22bbca229d2e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=B5=E3=82=8B=E3=81=B5=E3=82=8B?= <git@fluoride.dev>
Date: Mon, 13 May 2024 11:19:19 +0900
Subject: [PATCH 121/191] =?UTF-8?q?feat:=20DevContainer=E3=81=ABpnpm?=
 =?UTF-8?q?=E3=82=92=E3=82=A4=E3=83=B3=E3=82=B9=E3=83=88=E3=83=BC=E3=83=AB?=
 =?UTF-8?q?=E3=81=99=E3=82=8B=E9=9A=9B=E3=80=81corepack=E3=82=92=E4=BD=BF?=
 =?UTF-8?q?=E3=81=86=E3=82=88=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B=20(#1382?=
 =?UTF-8?q?1)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .devcontainer/devcontainer.json | 6 ++----
 .devcontainer/init.sh           | 2 ++
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 182ee2fbb2..31b6212cb5 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -4,12 +4,10 @@
 	"service": "app",
 	"workspaceFolder": "/workspace",
 	"features": {
-		"ghcr.io/devcontainers-contrib/features/pnpm:2": {
-			"version": "8.9.2"
-		},
 		"ghcr.io/devcontainers/features/node:1": {
 			"version": "20.12.2"
-		}
+		},
+		"ghcr.io/devcontainers-contrib/features/corepack:1": {}
 	},
 	"forwardPorts": [3000],
 	"postCreateCommand": "sudo chmod 755 .devcontainer/init.sh && .devcontainer/init.sh",
diff --git a/.devcontainer/init.sh b/.devcontainer/init.sh
index bcad3e6d85..729e1a9d2d 100755
--- a/.devcontainer/init.sh
+++ b/.devcontainer/init.sh
@@ -4,6 +4,8 @@ set -xe
 
 sudo chown -R node /workspace
 git submodule update --init
+corepack install
+corepack enable
 pnpm config set store-dir /home/node/.local/share/pnpm/store
 pnpm install --frozen-lockfile
 cp .devcontainer/devcontainer.yml .config/default.yml

From 9b0fc317514a9c6ec8f400a317e67fdeba160e7a Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Tue, 14 May 2024 19:18:30 +0900
Subject: [PATCH 122/191] Update FUNDING.yml

---
 .github/FUNDING.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index c6b2a1611c..d42b58abc0 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1,3 +1,4 @@
 # These are supported funding model platforms
 
+github: [misskey-dev]
 patreon: syuilo

From def7b8c55e342aea855e56da634994c02f56f600 Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Sat, 18 May 2024 12:42:26 +0900
Subject: [PATCH 123/191] fix(frontend): fix Chromatic test fails (#13826)

* fix: attempt to fix Chromatic test fails

* chore: add comment
---
 packages/frontend/src/components/MkModal.vue              | 5 ++++-
 .../frontend/src/components/global/MkAd.stories.impl.ts   | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/packages/frontend/src/components/MkModal.vue b/packages/frontend/src/components/MkModal.vue
index eb240da759..9e69ab2207 100644
--- a/packages/frontend/src/components/MkModal.vue
+++ b/packages/frontend/src/components/MkModal.vue
@@ -276,8 +276,11 @@ const align = () => {
 const onOpened = () => {
 	emit('opened');
 
+	// NOTE: Chromatic テストの際に undefined になる場合がある
+	if (content.value == null) return;
+
 	// モーダルコンテンツにマウスボタンが押され、コンテンツ外でマウスボタンが離されたときにモーダルバックグラウンドクリックと判定させないためにマウスイベントを監視しフラグ管理する
-	const el = content.value!.children[0];
+	const el = content.value.children[0];
 	el.addEventListener('mousedown', ev => {
 		contentClicking = true;
 		window.addEventListener('mouseup', ev => {
diff --git a/packages/frontend/src/components/global/MkAd.stories.impl.ts b/packages/frontend/src/components/global/MkAd.stories.impl.ts
index a1d274382f..aef26ab92d 100644
--- a/packages/frontend/src/components/global/MkAd.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkAd.stories.impl.ts
@@ -11,6 +11,10 @@ import { i18n } from '@/i18n.js';
 
 let lock: Promise<undefined> | undefined;
 
+function sleep(ms: number) {
+	return new Promise(resolve => setTimeout(resolve, ms));
+}
+
 const common = {
 	render(args) {
 		return {
@@ -43,6 +47,8 @@ const common = {
 		lock = new Promise(r => resolve = r);
 
 		try {
+			// NOTE: sleep しないと何故か落ちる
+			await sleep(100);
 			const canvas = within(canvasElement);
 			const a = canvas.getByRole<HTMLAnchorElement>('link');
 			// await expect(a.href).toMatch(/^https?:\/\/.*#test$/);
@@ -53,7 +59,7 @@ const common = {
 			const i = buttons[0];
 			await expect(i).toBeInTheDocument();
 			await userEvent.click(i);
-			// await expect(canvasElement).toHaveTextContent(i18n.ts._ad.back);
+			await expect(canvasElement).toHaveTextContent(i18n.ts._ad.back);
 			await expect(a).not.toBeInTheDocument();
 			await expect(i).not.toBeInTheDocument();
 			buttons = canvas.getAllByRole<HTMLButtonElement>('button');

From ba62b7378bb13b384bd9db27acb0013fb90b53b3 Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Sat, 18 May 2024 18:52:17 +0900
Subject: [PATCH 124/191] fix(storybook): fix wrong `tabler-icons` CSS path
 (#13828)

---
 packages/frontend/.storybook/preview-head.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/frontend/.storybook/preview-head.html b/packages/frontend/.storybook/preview-head.html
index 4722fe7f5f..ae42fd49bc 100644
--- a/packages/frontend/.storybook/preview-head.html
+++ b/packages/frontend/.storybook/preview-head.html
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <link rel="preload" href="https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/about-icon.png?raw=true" as="image" type="image/png" crossorigin="anonymous">
 <link rel="preload" href="https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true" as="image" type="image/jpeg" crossorigin="anonymous">
-<link rel="stylesheet" href="https://unpkg.com/@tabler/icons-webfont@3.3.0/tabler-icons.min.css">
+<link rel="stylesheet" href="https://unpkg.com/@tabler/icons-webfont@3.3.0/dist/tabler-icons.min.css">
 <link rel="stylesheet" href="https://unpkg.com/@fontsource/m-plus-rounded-1c/index.css">
 <style>
 	html {

From acf84a2516c08b7d3a26a2521a9bef5543303ed2 Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Mon, 20 May 2024 08:28:28 +0900
Subject: [PATCH 125/191] =?UTF-8?q?FTT=E3=81=8C=E6=9C=89=E5=8A=B9=E3=81=8B?=
 =?UTF-8?q?=E3=81=A4sinceId=E3=81=AE=E3=81=BF=E3=82=92=E6=8C=87=E5=AE=9A?=
 =?UTF-8?q?=E3=81=97=E3=81=9F=E5=A0=B4=E5=90=88=E3=81=AB=E5=B8=B0=E3=81=A3?=
 =?UTF-8?q?=E3=81=A6=E6=9D=A5=E3=82=8B=E3=83=AC=E3=82=B9=E3=83=9D=E3=83=B3?=
 =?UTF-8?q?=E3=82=B9=E3=81=8C=E9=80=86=E9=A0=86=E3=81=A7=E3=81=82=E3=82=8B?=
 =?UTF-8?q?=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3=20(#13837)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix: FTTが有効かつsinceIdのみを指定した場合に帰って来るレスポンスが逆順である問題

* docs(changelog): FTTが有効かつsinceIdのみを指定した場合に帰って来るレスポンスが逆順である問題を修正
---
 CHANGELOG.md                                        |  1 +
 .../src/core/FanoutTimelineEndpointService.ts       | 13 +++++--------
 2 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d95ea3fc38..280c63b2a7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -80,6 +80,7 @@
 - Fix: グローバルタイムラインで返信が表示されないことがある問題を修正
 - Fix: リノートをミュートしたユーザの投稿のリノートがミュートされる問題を修正
 - Fix: AP Link等は添付ファイル扱いしないようになど (#13754)
+- Fix: FTTが有効かつsinceIdのみを指定した場合に帰って来るレスポンスが逆順である問題を修正
 
 ## 2024.3.1
 
diff --git a/packages/backend/src/core/FanoutTimelineEndpointService.ts b/packages/backend/src/core/FanoutTimelineEndpointService.ts
index 884723ff81..d5058f37c2 100644
--- a/packages/backend/src/core/FanoutTimelineEndpointService.ts
+++ b/packages/backend/src/core/FanoutTimelineEndpointService.ts
@@ -61,8 +61,8 @@ export class FanoutTimelineEndpointService {
 		// 呼び出し元と以下の処理をシンプルにするためにdbFallbackを置き換える
 		if (!ps.useDbFallback) ps.dbFallback = () => Promise.resolve([]);
 
-		const shouldPrepend = ps.sinceId && !ps.untilId;
-		const idCompare: (a: string, b: string) => number = shouldPrepend ? (a, b) => a < b ? -1 : 1 : (a, b) => a > b ? -1 : 1;
+		const ascending = ps.sinceId && !ps.untilId;
+		const idCompare: (a: string, b: string) => number = ascending ? (a, b) => a < b ? -1 : 1 : (a, b) => a > b ? -1 : 1;
 
 		const redisResult = await this.fanoutTimelineService.getMulti(ps.redisTimelines, ps.untilId, ps.sinceId);
 
@@ -142,9 +142,7 @@ export class FanoutTimelineEndpointService {
 
 				if (ps.allowPartial ? redisTimeline.length !== 0 : redisTimeline.length >= ps.limit) {
 					// 十分Redisからとれた
-					const result = redisTimeline.slice(0, ps.limit);
-					if (shouldPrepend) result.reverse();
-					return result;
+					return redisTimeline.slice(0, ps.limit);
 				}
 			}
 
@@ -152,8 +150,7 @@ export class FanoutTimelineEndpointService {
 			const remainingToRead = ps.limit - redisTimeline.length;
 			let dbUntil: string | null;
 			let dbSince: string | null;
-			if (shouldPrepend) {
-				redisTimeline.reverse();
+			if (ascending) {
 				dbUntil = ps.untilId;
 				dbSince = noteIds[noteIds.length - 1];
 			} else {
@@ -161,7 +158,7 @@ export class FanoutTimelineEndpointService {
 				dbSince = ps.sinceId;
 			}
 			const gotFromDb = await ps.dbFallback(dbUntil, dbSince, remainingToRead);
-			return shouldPrepend ? [...gotFromDb, ...redisTimeline] : [...redisTimeline, ...gotFromDb];
+			return [...redisTimeline, ...gotFromDb];
 		}
 
 		return await ps.dbFallback(ps.untilId, ps.sinceId, ps.limit);

From 4d0db37d2e5baddea3995e222bddca7032052ef1 Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Mon, 20 May 2024 18:05:46 +0900
Subject: [PATCH 126/191] fix notification limit with exclude/include types
 (#13836)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix: /i/notificationsがsinceIdのみのときに正しく動かない問題

Fix #10902 again

* chore: use exclusive range to fetch data

* fix: フィルタによって通知が0件だった場合でもリトライするように

* docs(changelog): `/i/notifications`に includeTypes`か`excludeTypes`を指定しているとき、通知が存在するのに空配列を返すことがある問題を修正
---
 CHANGELOG.md                                  |  1 +
 .../server/api/endpoints/i/notifications.ts   | 60 +++++++++++++------
 2 files changed, 43 insertions(+), 18 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 280c63b2a7..0a19f32db6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -81,6 +81,7 @@
 - Fix: リノートをミュートしたユーザの投稿のリノートがミュートされる問題を修正
 - Fix: AP Link等は添付ファイル扱いしないようになど (#13754)
 - Fix: FTTが有効かつsinceIdのみを指定した場合に帰って来るレスポンスが逆順である問題を修正
+- Fix: `/i/notifications`に `includeTypes`か`excludeTypes`を指定しているとき、通知が存在するのに空配列を返すことがある問題を修正
 
 ## 2024.3.1
 
diff --git a/packages/backend/src/server/api/endpoints/i/notifications.ts b/packages/backend/src/server/api/endpoints/i/notifications.ts
index 320d9fdb00..2f619380e9 100644
--- a/packages/backend/src/server/api/endpoints/i/notifications.ts
+++ b/packages/backend/src/server/api/endpoints/i/notifications.ts
@@ -7,7 +7,7 @@ import { In } from 'typeorm';
 import * as Redis from 'ioredis';
 import { Inject, Injectable } from '@nestjs/common';
 import type { NotesRepository } from '@/models/_.js';
-import { obsoleteNotificationTypes, notificationTypes, FilterUnionByProperty } from '@/types.js';
+import { FilterUnionByProperty, notificationTypes, obsoleteNotificationTypes } from '@/types.js';
 import { Endpoint } from '@/server/api/endpoint-base.js';
 import { NoteReadService } from '@/core/NoteReadService.js';
 import { NotificationEntityService } from '@/core/entities/NotificationEntityService.js';
@@ -84,27 +84,51 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 			const includeTypes = ps.includeTypes && ps.includeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof notificationTypes[number][];
 			const excludeTypes = ps.excludeTypes && ps.excludeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof notificationTypes[number][];
 
-			const limit = ps.limit + (ps.untilId ? 1 : 0) + (ps.sinceId ? 1 : 0); // untilIdに指定したものも含まれるため+1
-			const notificationsRes = await this.redisClient.xrevrange(
-				`notificationTimeline:${me.id}`,
-				ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : '+',
-				ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : '-',
-				'COUNT', limit);
+			let sinceTime = ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime().toString() : null;
+			let untilTime = ps.untilId ? this.idService.parse(ps.untilId).date.getTime().toString() : null;
 
-			if (notificationsRes.length === 0) {
-				return [];
-			}
+			let notifications: MiNotification[];
+			for (;;) {
+				let notificationsRes: [id: string, fields: string[]][];
 
-			let notifications = notificationsRes.map(x => JSON.parse(x[1][1])).filter(x => x.id !== ps.untilId && x !== ps.sinceId) as MiNotification[];
+				// sinceidのみの場合は古い順、そうでない場合は新しい順。 QueryService.makePaginationQueryも参照
+				if (sinceTime && !untilTime) {
+					notificationsRes = await this.redisClient.xrange(
+						`notificationTimeline:${me.id}`,
+						'(' + sinceTime,
+						'+',
+						'COUNT', ps.limit);
+				} else {
+					notificationsRes = await this.redisClient.xrevrange(
+						`notificationTimeline:${me.id}`,
+						untilTime ? '(' + untilTime : '+',
+						sinceTime ? '(' + sinceTime : '-',
+						'COUNT', ps.limit);
+				}
 
-			if (includeTypes && includeTypes.length > 0) {
-				notifications = notifications.filter(notification => includeTypes.includes(notification.type));
-			} else if (excludeTypes && excludeTypes.length > 0) {
-				notifications = notifications.filter(notification => !excludeTypes.includes(notification.type));
-			}
+				if (notificationsRes.length === 0) {
+					return [];
+				}
 
-			if (notifications.length === 0) {
-				return [];
+				notifications = notificationsRes.map(x => JSON.parse(x[1][1])) as MiNotification[];
+
+				if (includeTypes && includeTypes.length > 0) {
+					notifications = notifications.filter(notification => includeTypes.includes(notification.type));
+				} else if (excludeTypes && excludeTypes.length > 0) {
+					notifications = notifications.filter(notification => !excludeTypes.includes(notification.type));
+				}
+
+				if (notifications.length !== 0) {
+					// 通知が1件以上ある場合は返す
+					break;
+				}
+
+				// フィルタしたことで通知が0件になった場合、次のページを取得する
+				if (ps.sinceId && !ps.untilId) {
+					sinceTime = notificationsRes[notificationsRes.length - 1][0];
+				} else {
+					untilTime = notificationsRes[notificationsRes.length - 1][0];
+				}
 			}
 
 			// Mark all as read

From f6df94070b0fc1ca862d560b17488bd718c2ec85 Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Mon, 20 May 2024 18:08:20 +0900
Subject: [PATCH 127/191] Exclude channel notes from featured polls (#13838)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* feat(backend): add `channelId` to `MiPoll` as a Denormalized field

* feat(backend): option to exclude polls in channels

* chore: exclude channel notes from featured polls

* docs(changelog): みつけるのアンケート欄にてチャンネルのアンケートが含まれてしまう問題を修正

* fix: missing license header
---
 CHANGELOG.md                                  |  1 +
 ...29964060-ChannelIdDenormalizedForMiPoll.js | 21 +++++++++++++++++++
 .../backend/src/core/NoteCreateService.ts     |  1 +
 packages/backend/src/models/Poll.ts           |  9 ++++++++
 .../endpoints/notes/polls/recommendation.ts   |  7 +++++++
 .../frontend/src/pages/explore.featured.vue   |  3 +++
 packages/misskey-js/src/autogen/types.ts      |  2 ++
 7 files changed, 44 insertions(+)
 create mode 100644 packages/backend/migration/1716129964060-ChannelIdDenormalizedForMiPoll.js

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0a19f32db6..d0b98db96a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,7 @@
   - 「アカウントを見つけやすくする」が有効なユーザーか
 - Fix: Play作成時に設定した公開範囲が機能していない問題を修正
 - Fix: 正規化されていない状態のhashtagが連合されてきたhtmlに含まれているとhashtagが正しくhashtagに復元されない問題を修正
+- Fix: みつけるのアンケート欄にてチャンネルのアンケートが含まれてしまう問題を修正
 
 ### Client
 - Feat: アップロードするファイルの名前をランダム文字列にできるように
diff --git a/packages/backend/migration/1716129964060-ChannelIdDenormalizedForMiPoll.js b/packages/backend/migration/1716129964060-ChannelIdDenormalizedForMiPoll.js
new file mode 100644
index 0000000000..f736378c04
--- /dev/null
+++ b/packages/backend/migration/1716129964060-ChannelIdDenormalizedForMiPoll.js
@@ -0,0 +1,21 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class ChannelIdDenormalizedForMiPoll1716129964060 {
+    name = 'ChannelIdDenormalizedForMiPoll1716129964060'
+
+    async up(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "poll" ADD "channelId" character varying(32)`);
+        await queryRunner.query(`COMMENT ON COLUMN "poll"."channelId" IS '[Denormalized]'`);
+        await queryRunner.query(`CREATE INDEX "IDX_c1240fcc9675946ea5d6c2860e" ON "poll" ("channelId") `);
+        await queryRunner.query(`UPDATE "poll" SET "channelId" = "note"."channelId" FROM "note" WHERE "poll"."noteId" = "note"."id"`);
+    }
+
+    async down(queryRunner) {
+        await queryRunner.query(`DROP INDEX "public"."IDX_c1240fcc9675946ea5d6c2860e"`);
+        await queryRunner.query(`COMMENT ON COLUMN "poll"."channelId" IS '[Denormalized]'`);
+        await queryRunner.query(`ALTER TABLE "poll" DROP COLUMN "channelId"`);
+    }
+}
diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts
index 32104fea90..e5580f36d1 100644
--- a/packages/backend/src/core/NoteCreateService.ts
+++ b/packages/backend/src/core/NoteCreateService.ts
@@ -473,6 +473,7 @@ export class NoteCreateService implements OnApplicationShutdown {
 						noteVisibility: insert.visibility,
 						userId: user.id,
 						userHost: user.host,
+						channelId: insert.channelId,
 					});
 
 					await transactionalEntityManager.insert(MiPoll, poll);
diff --git a/packages/backend/src/models/Poll.ts b/packages/backend/src/models/Poll.ts
index c2693dbb19..ca985c8b24 100644
--- a/packages/backend/src/models/Poll.ts
+++ b/packages/backend/src/models/Poll.ts
@@ -8,6 +8,7 @@ import { noteVisibilities } from '@/types.js';
 import { id } from './util/id.js';
 import { MiNote } from './Note.js';
 import type { MiUser } from './User.js';
+import type { MiChannel } from "@/models/Channel.js";
 
 @Entity('poll')
 export class MiPoll {
@@ -58,6 +59,14 @@ export class MiPoll {
 		comment: '[Denormalized]',
 	})
 	public userHost: string | null;
+
+	@Index()
+	@Column({
+		...id(),
+		nullable: true,
+		comment: '[Denormalized]',
+	})
+	public channelId: MiChannel['id'] | null;
 	//#endregion
 
 	constructor(data: Partial<MiPoll>) {
diff --git a/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts b/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts
index ba38573065..4fd6f8682d 100644
--- a/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts
+++ b/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts
@@ -32,6 +32,7 @@ export const paramDef = {
 	properties: {
 		limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
 		offset: { type: 'integer', default: 0 },
+		excludeChannels: { type: 'boolean', default: false },
 	},
 	required: [],
 } as const;
@@ -86,6 +87,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 			query.setParameters(mutingQuery.getParameters());
 			//#endregion
 
+			//#region exclude channels
+			if (ps.excludeChannels) {
+				query.andWhere('poll.channelId IS NULL');
+			}
+			//#endregion
+
 			const polls = await query
 				.orderBy('poll.noteId', 'DESC')
 				.limit(ps.limit)
diff --git a/packages/frontend/src/pages/explore.featured.vue b/packages/frontend/src/pages/explore.featured.vue
index b5c8e70166..cfdb235d3a 100644
--- a/packages/frontend/src/pages/explore.featured.vue
+++ b/packages/frontend/src/pages/explore.featured.vue
@@ -29,6 +29,9 @@ const paginationForPolls = {
 	endpoint: 'notes/polls/recommendation' as const,
 	limit: 10,
 	offsetMode: true,
+	params: {
+		excludeChannels: true,
+	},
 };
 
 const tab = ref('notes');
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 1b9f1304d5..302587ccfa 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -21019,6 +21019,8 @@ export type operations = {
           limit?: number;
           /** @default 0 */
           offset?: number;
+          /** @default false */
+          excludeChannels?: boolean;
         };
       };
     };

From ed74f7b4a88223fe11b63d424bb0f90768a88926 Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Mon, 20 May 2024 18:55:42 +0900
Subject: [PATCH 128/191] ci: use pnpm version from packageManager field in the
 package.json. (#13825)

---
 .github/workflows/check-misskey-js-autogen.yml |  4 +---
 .github/workflows/get-api-diff.yml             |  5 +----
 .github/workflows/lint.yml                     | 15 +++------------
 .github/workflows/on-release-created.yml       |  5 +----
 .github/workflows/storybook.yml                |  5 +----
 .github/workflows/test-backend.yml             | 10 ++--------
 .github/workflows/test-frontend.yml            | 10 ++--------
 .github/workflows/test-production.yml          |  5 +----
 .github/workflows/validate-api-json.yml        |  5 +----
 9 files changed, 13 insertions(+), 51 deletions(-)

diff --git a/.github/workflows/check-misskey-js-autogen.yml b/.github/workflows/check-misskey-js-autogen.yml
index 9052b2e372..39acad8bc3 100644
--- a/.github/workflows/check-misskey-js-autogen.yml
+++ b/.github/workflows/check-misskey-js-autogen.yml
@@ -24,9 +24,7 @@ jobs:
           ref: refs/pull/${{ github.event.pull_request.number }}/merge
 
       - name: setup pnpm
-        uses: pnpm/action-setup@v3
-        with:
-          version: 9
+        uses: pnpm/action-setup@v4
 
       - name: setup node
         id: setup-node
diff --git a/.github/workflows/get-api-diff.yml b/.github/workflows/get-api-diff.yml
index 146e0686e5..9b9c8f11c4 100644
--- a/.github/workflows/get-api-diff.yml
+++ b/.github/workflows/get-api-diff.yml
@@ -32,10 +32,7 @@ jobs:
         ref: ${{ matrix.ref }}
         submodules: true
     - name: Install pnpm
-      uses: pnpm/action-setup@v3
-      with:
-        version: 9
-        run_install: false
+      uses: pnpm/action-setup@v4
     - name: Use Node.js ${{ matrix.node-version }}
       uses: actions/setup-node@v4.0.2
       with:
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 9a269014ab..76616ec5a7 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -27,10 +27,7 @@ jobs:
       with:
         fetch-depth: 0
         submodules: true
-    - uses: pnpm/action-setup@v3
-      with:
-        version: 9
-        run_install: false
+    - uses: pnpm/action-setup@v4
     - uses: actions/setup-node@v4.0.2
       with:
         node-version-file: '.node-version'
@@ -54,10 +51,7 @@ jobs:
       with:
         fetch-depth: 0
         submodules: true
-    - uses: pnpm/action-setup@v3
-      with:
-        version: 9
-        run_install: false
+    - uses: pnpm/action-setup@v4
     - uses: actions/setup-node@v4.0.2
       with:
         node-version-file: '.node-version'
@@ -80,10 +74,7 @@ jobs:
       with:
         fetch-depth: 0
         submodules: true
-    - uses: pnpm/action-setup@v3
-      with:
-        version: 9
-        run_install: false
+    - uses: pnpm/action-setup@v4
     - uses: actions/setup-node@v4.0.2
       with:
         node-version-file: '.node-version'
diff --git a/.github/workflows/on-release-created.yml b/.github/workflows/on-release-created.yml
index 52463d7542..edfdab99e9 100644
--- a/.github/workflows/on-release-created.yml
+++ b/.github/workflows/on-release-created.yml
@@ -24,10 +24,7 @@ jobs:
         with:
           submodules: true
       - name: Install pnpm
-        uses: pnpm/action-setup@v3
-        with:
-          version: 9
-          run_install: false
+        uses: pnpm/action-setup@v4
       - name: Use Node.js ${{ matrix.node-version }}
         uses: actions/setup-node@v4.0.2
         with:
diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml
index 3bc354b331..c52883ffdd 100644
--- a/.github/workflows/storybook.yml
+++ b/.github/workflows/storybook.yml
@@ -34,10 +34,7 @@ jobs:
         echo "base=$(git rev-list --parents -n1 HEAD | cut -d" " -f2)" >> $GITHUB_OUTPUT
         git checkout $(git rev-list --parents -n1 HEAD | cut -d" " -f3)
     - name: Install pnpm
-      uses: pnpm/action-setup@v3
-      with:
-        version: 9
-        run_install: false
+      uses: pnpm/action-setup@v4
     - name: Use Node.js 20.x
       uses: actions/setup-node@v4.0.2
       with:
diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml
index 525cd0916b..b1c54bb3e7 100644
--- a/.github/workflows/test-backend.yml
+++ b/.github/workflows/test-backend.yml
@@ -41,10 +41,7 @@ jobs:
       with:
         submodules: true
     - name: Install pnpm
-      uses: pnpm/action-setup@v3
-      with:
-        version: 9
-        run_install: false
+      uses: pnpm/action-setup@v4
     - name: Install FFmpeg
       uses: FedericoCarboni/setup-ffmpeg@v3
     - name: Use Node.js ${{ matrix.node-version }}
@@ -93,10 +90,7 @@ jobs:
         with:
           submodules: true
       - name: Install pnpm
-        uses: pnpm/action-setup@v3
-        with:
-          version: 9
-          run_install: false
+        uses: pnpm/action-setup@v4
       - name: Use Node.js ${{ matrix.node-version }}
         uses: actions/setup-node@v4.0.2
         with:
diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml
index 9df3c98393..9d5053b82a 100644
--- a/.github/workflows/test-frontend.yml
+++ b/.github/workflows/test-frontend.yml
@@ -33,10 +33,7 @@ jobs:
       with:
         submodules: true
     - name: Install pnpm
-      uses: pnpm/action-setup@v3
-      with:
-        version: 9
-        run_install: false
+      uses: pnpm/action-setup@v4
     - name: Use Node.js ${{ matrix.node-version }}
       uses: actions/setup-node@v4.0.2
       with:
@@ -91,10 +88,7 @@ jobs:
     #- uses: browser-actions/setup-firefox@latest
     #  if: ${{ matrix.browser == 'firefox' }}
     - name: Install pnpm
-      uses: pnpm/action-setup@v3
-      with:
-        version: 9
-        run_install: false
+      uses: pnpm/action-setup@v4
     - name: Use Node.js ${{ matrix.node-version }}
       uses: actions/setup-node@v4.0.2
       with:
diff --git a/.github/workflows/test-production.yml b/.github/workflows/test-production.yml
index 24a530e073..7f8db65293 100644
--- a/.github/workflows/test-production.yml
+++ b/.github/workflows/test-production.yml
@@ -23,10 +23,7 @@ jobs:
       with:
         submodules: true
     - name: Install pnpm
-      uses: pnpm/action-setup@v3
-      with:
-        version: 9
-        run_install: false
+      uses: pnpm/action-setup@v4
     - name: Use Node.js ${{ matrix.node-version }}
       uses: actions/setup-node@v4.0.2
       with:
diff --git a/.github/workflows/validate-api-json.yml b/.github/workflows/validate-api-json.yml
index 229c447893..24340e7d81 100644
--- a/.github/workflows/validate-api-json.yml
+++ b/.github/workflows/validate-api-json.yml
@@ -24,10 +24,7 @@ jobs:
       with:
         submodules: true
     - name: Install pnpm
-      uses: pnpm/action-setup@v3
-      with:
-        version: 9
-        run_install: false
+      uses: pnpm/action-setup@v4
     - name: Use Node.js ${{ matrix.node-version }}
       uses: actions/setup-node@v4.0.2
       with:

From 5836bd85df4fe511f0ab766349eb4c9d1e1e5fdf Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Mon, 20 May 2024 19:25:50 +0900
Subject: [PATCH 129/191] =?UTF-8?q?fix:=20=E8=A4=87=E6=95=B0id=E3=82=92?=
 =?UTF-8?q?=E6=8C=87=E5=AE=9A=E3=81=99=E3=82=8B`users/show`=E3=81=8C?=
 =?UTF-8?q?=E9=96=A2=E4=BF=82=E3=81=AA=E3=81=84=E3=83=A6=E3=83=BC=E3=82=B6?=
 =?UTF-8?q?=E3=82=92=E8=BF=94=E3=81=99=E3=81=93=E3=81=A8=E3=81=8C=E3=81=82?=
 =?UTF-8?q?=E3=82=8B=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3=20(#1376?=
 =?UTF-8?q?5)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix: 複数idを指定する`users/show`が関係ないユーザを返すことがある問題を修正

* test: fix misskey js test

* chore: user/showがnullを返さないように

* chore: pass lambda instead of pushVisibleUser
---
 CHANGELOG.md                                           |  1 +
 packages/backend/src/misc/json-schema.ts               |  2 +-
 .../backend/src/server/api/endpoints/users/show.ts     |  4 +++-
 packages/frontend/src/components/MkPostForm.vue        | 10 +++-------
 4 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d0b98db96a..a9944d4b5e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -83,6 +83,7 @@
 - Fix: AP Link等は添付ファイル扱いしないようになど (#13754)
 - Fix: FTTが有効かつsinceIdのみを指定した場合に帰って来るレスポンスが逆順である問題を修正
 - Fix: `/i/notifications`に `includeTypes`か`excludeTypes`を指定しているとき、通知が存在するのに空配列を返すことがある問題を修正
+- Fix: 複数idを指定する`users/show`が関係ないユーザを返すことがある問題を修正
 
 ## 2024.3.1
 
diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts
index a620d7c94b..41e5bfe9e4 100644
--- a/packages/backend/src/misc/json-schema.ts
+++ b/packages/backend/src/misc/json-schema.ts
@@ -228,7 +228,7 @@ export type SchemaTypeDef<p extends Schema> =
 			p['items']['allOf'] extends ReadonlyArray<Schema> ? UnionToIntersection<UnionSchemaType<NonNullable<p['items']['allOf']>>>[] :
 			never
 		) :
-		p['items'] extends NonNullable<Schema> ? SchemaTypeDef<p['items']>[] :
+		p['items'] extends NonNullable<Schema> ? SchemaType<p['items']>[] :
 		any[]
 	) :
 	p['anyOf'] extends ReadonlyArray<Schema> ? UnionSchemaType<p['anyOf']> & PartialIntersection<UnionSchemaType<p['anyOf']>> :
diff --git a/packages/backend/src/server/api/endpoints/users/show.ts b/packages/backend/src/server/api/endpoints/users/show.ts
index bd81989cb9..26cfa921c5 100644
--- a/packages/backend/src/server/api/endpoints/users/show.ts
+++ b/packages/backend/src/server/api/endpoints/users/show.ts
@@ -110,9 +110,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				});
 
 				// リクエストされた通りに並べ替え
+				// 順番は保持されるけど数は減ってる可能性がある
 				const _users: MiUser[] = [];
 				for (const id of ps.userIds) {
-					_users.push(users.find(x => x.id === id)!);
+					const user = users.find(x => x.id === id);
+					if (user != null) _users.push(user);
 				}
 
 				return await Promise.all(_users.map(u => this.userEntityService.pack(u, me, {
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index 7dbc127298..41d603e40f 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -190,7 +190,7 @@ const localOnly = ref(props.initialLocalOnly ?? (defaultStore.state.rememberNote
 const visibility = ref(props.initialVisibility ?? (defaultStore.state.rememberNoteVisibility ? defaultStore.state.visibility : defaultStore.state.defaultNoteVisibility));
 const visibleUsers = ref<Misskey.entities.UserDetailed[]>([]);
 if (props.initialVisibleUsers) {
-	props.initialVisibleUsers.forEach(pushVisibleUser);
+	props.initialVisibleUsers.forEach(u => pushVisibleUser(u));
 }
 const reactionAcceptance = ref(defaultStore.state.reactionAcceptance);
 const autocomplete = ref(null);
@@ -336,7 +336,7 @@ if (props.reply && ['home', 'followers', 'specified'].includes(props.reply.visib
 			misskeyApi('users/show', {
 				userIds: props.reply.visibleUserIds.filter(uid => uid !== $i.id && uid !== props.reply?.userId),
 			}).then(users => {
-				users.forEach(pushVisibleUser);
+				users.forEach(u => pushVisibleUser(u));
 			});
 		}
 
@@ -967,11 +967,7 @@ onMounted(() => {
 				}
 				if (draft.data.visibleUserIds) {
 					misskeyApi('users/show', { userIds: draft.data.visibleUserIds }).then(users => {
-						for (let i = 0; i < users.length; i++) {
-							if (users[i].id === draft.data.visibleUserIds[i]) {
-								pushVisibleUser(users[i]);
-							}
-						}
+						users.forEach(u => pushVisibleUser(u));
 					});
 				}
 			}

From 367bf0c8fcd96ff56ce1016e52fcb4751331440a Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Mon, 20 May 2024 23:21:11 +0900
Subject: [PATCH 130/191] fix: `/share` with unicode characters in the URL
 (#13846)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix: `/share` with unicode characters in the URL

* docs(changelog): `/share` で日本語等を含むurlがurlエンコードされない問題を修正
---
 CHANGELOG.md                          |  1 +
 packages/frontend/src/pages/share.vue | 29 ++++++++++++++++++++++++++-
 2 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index a9944d4b5e..8d1b0a010a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -60,6 +60,7 @@
 - Fix: リバーシの対局を正しく共有できないことがある問題を修正
 - Fix: 通知をグループ化している際に、人数が正常に表示されないことがある問題を修正
 - Fix: 連合なしの状態の読み書きができない問題を修正
+- Fix: `/share` で日本語等を含むurlがurlエンコードされない問題を修正
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
diff --git a/packages/frontend/src/pages/share.vue b/packages/frontend/src/pages/share.vue
index 680934e7ce..37f6558d64 100644
--- a/packages/frontend/src/pages/share.vue
+++ b/packages/frontend/src/pages/share.vue
@@ -64,7 +64,34 @@ async function init() {
 	// Googleニュース対策
 	if (text?.startsWith(`${title.value}.\n`)) noteText += text.replace(`${title.value}.\n`, '');
 	else if (text && title.value !== text) noteText += `${text}\n`;
-	if (url) noteText += `${url}`;
+	if (url) {
+		try {
+			// Normalize the URL to URL-encoded and puny-coded from with the URL constructor.
+			//
+			// It's common to use unicode characters in the URL for better visibility of URL
+			//     like: https://ja.wikipedia.org/wiki/ミスキー
+			//  or like: https://藍.moe/
+			// However, in the MFM, the unicode characters must be URL-encoded to be parsed as `url` node
+			//     like: https://ja.wikipedia.org/wiki/%E3%83%9F%E3%82%B9%E3%82%AD%E3%83%BC
+			//  or like: https://xn--931a.moe/
+			// Therefore, we need to normalize the URL to URL-encoded form.
+			//
+			// The URL constructor will parse the URL and normalize unicode characters
+			//   in the host to punycode and in the path component to URL-encoded form.
+			//   (see url.spec.whatwg.org)
+			//
+			// In addition, the current MFM renderer decodes the URL-encoded path and / punycode encoded host name so
+			//   this normalization doesn't make the visible URL ugly.
+			//   (see MkUrl.vue)
+
+			noteText += new URL(url).href;
+		} catch {
+			// fallback to original URL if the URL is invalid.
+			// note that this is extremely rare since the `url` parameter is designed to share a URL and
+			// the URL constructor will throw TypeError only if failure, which means the URL is not valid.
+			noteText += url;
+		}
+	}
 	initialText.value = noteText.trim();
 
 	if (visibility.value === 'specified') {

From 1d4e6393f34179c40a91ad3f674c94a5d3942264 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?=
 <root@acid-chicken.com>
Date: Tue, 21 May 2024 10:10:59 +0900
Subject: [PATCH 131/191] ci: verify locale data (#13849)

* ci: verify locale data

* ci: separate workflows

* ci: missing installation
---
 .github/workflows/locale.yml | 27 ++++++++++++++++++
 locales/verify.js            | 53 ++++++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+)
 create mode 100644 .github/workflows/locale.yml
 create mode 100644 locales/verify.js

diff --git a/.github/workflows/locale.yml b/.github/workflows/locale.yml
new file mode 100644
index 0000000000..de2247e772
--- /dev/null
+++ b/.github/workflows/locale.yml
@@ -0,0 +1,27 @@
+name: Lint
+
+on:
+  push:
+    paths:
+      - locales/**
+  pull_request:
+    paths:
+      - locales/**
+
+jobs:
+  locale_verify:
+    runs-on: ubuntu-latest
+    continue-on-error: true
+    steps:
+    - uses: actions/checkout@v4.1.1
+      with:
+        fetch-depth: 0
+        submodules: true
+    - uses: pnpm/action-setup@v4
+    - uses: actions/setup-node@v4.0.2
+      with:
+        node-version-file: '.node-version'
+        cache: 'pnpm'
+    - run: corepack enable
+    - run: pnpm i --frozen-lockfile
+    - run: cd locales && node verify.js
diff --git a/locales/verify.js b/locales/verify.js
new file mode 100644
index 0000000000..a8e9875d6e
--- /dev/null
+++ b/locales/verify.js
@@ -0,0 +1,53 @@
+import locales from './index.js';
+
+let valid = true;
+
+function writeError(type, lang, tree, data) {
+	process.stderr.write(JSON.stringify({ type, lang, tree, data }));
+	process.stderr.write('\n');
+	valid = false;
+}
+
+function verify(expected, actual, lang, trace) {
+	for (let key in expected) {
+		if (!Object.prototype.hasOwnProperty.call(actual, key)) {
+			continue;
+		}
+		if (typeof expected[key] === 'object') {
+			if (typeof actual[key] !== 'object') {
+				writeError('mismatched_type', lang, trace ? `${trace}.${key}` : key, { expected: 'object', actual: typeof actual[key] });
+				continue;
+			}
+			verify(expected[key], actual[key], lang, trace ? `${trace}.${key}` : key);
+		} else if (typeof expected[key] === 'string') {
+			switch (typeof actual[key]) {
+				case 'object':
+					writeError('mismatched_type', lang, trace ? `${trace}.${key}` : key, { expected: 'string', actual: 'object' });
+					break;
+				case 'undefined':
+					continue;
+				case 'string':
+					const expectedParameters = new Set(expected[key].match(/\{[^}]+\}/g)?.map((s) => s.slice(1, -1)));
+					const actualParameters = new Set(actual[key].match(/\{[^}]+\}/g)?.map((s) => s.slice(1, -1)));
+					for (let parameter of expectedParameters) {
+						if (!actualParameters.has(parameter)) {
+							writeError('missing_parameter', lang, trace ? `${trace}.${key}` : key, { parameter });
+						}
+					}
+			}
+		}
+	}
+}
+
+const { ['ja-JP']: original, ...verifiees } = locales;
+
+for (let lang in verifiees) {
+	if (!Object.prototype.hasOwnProperty.call(locales, lang)) {
+		continue;
+	}
+	verify(original, verifiees[lang], lang);
+}
+
+if (!valid) {
+	process.exit(1);
+}

From 3fba7686f8413442ff8b6e1149de36f81e75dfe1 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Tue, 21 May 2024 10:14:58 +0900
Subject: [PATCH 132/191] New Crowdin updates (#13500)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Japanese, Kansai)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Polish)

* New translations ja-jp.yml (Polish)

* New translations ja-jp.yml (Polish)

* New translations ja-jp.yml (Polish)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Russian)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Korean (Gyeongsang))

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Arabic)

* New translations ja-jp.yml (Czech)

* New translations ja-jp.yml (Danish)

* New translations ja-jp.yml (Greek)

* New translations ja-jp.yml (Hungarian)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Dutch)

* New translations ja-jp.yml (Norwegian)

* New translations ja-jp.yml (Polish)

* New translations ja-jp.yml (Portuguese)

* New translations ja-jp.yml (Russian)

* New translations ja-jp.yml (Slovak)

* New translations ja-jp.yml (Swedish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Ukrainian)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Indonesian)

* New translations ja-jp.yml (Bengali)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Croatian)

* New translations ja-jp.yml (Uyghur)

* New translations ja-jp.yml (Lojban)

* New translations ja-jp.yml (Sinhala)

* New translations ja-jp.yml (Uzbek)

* New translations ja-jp.yml (Kannada)

* New translations ja-jp.yml (Lao)

* New translations ja-jp.yml (Haitian Creole)

* New translations ja-jp.yml (Kabyle)

* New translations ja-jp.yml (Japanese, Kansai)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Korean (Gyeongsang))

* New translations ja-jp.yml (Korean (Gyeongsang))

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Sinhala)

* New translations ja-jp.yml (Sinhala)

* New translations ja-jp.yml (Korean (Gyeongsang))

* New translations ja-jp.yml (Korean (Gyeongsang))

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Indonesian)

* New translations ja-jp.yml (Indonesian)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Czech)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Russian)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Indonesian)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Japanese, Kansai)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Japanese, Kansai)

* New translations ja-jp.yml (Japanese, Kansai)

* New translations ja-jp.yml (Japanese, Kansai)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Korean (Gyeongsang))

* New translations ja-jp.yml (Korean (Gyeongsang))

* New translations ja-jp.yml (Korean (Gyeongsang))

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Japanese, Kansai)

* New translations ja-jp.yml (Arabic)

* New translations ja-jp.yml (Arabic)

* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Japanese, Kansai)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Russian)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Japanese, Kansai)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Indonesian)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (Czech)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Polish)

* New translations ja-jp.yml (Portuguese)

* New translations ja-jp.yml (Vietnamese)
---
 locales/ar-SA.yml   |  16 +++-
 locales/bn-BD.yml   |   1 -
 locales/ca-ES.yml   |  25 +++--
 locales/cs-CZ.yml   |   6 +-
 locales/da-DK.yml   |   1 -
 locales/de-DE.yml   |   2 -
 locales/el-GR.yml   |   1 -
 locales/en-US.yml   |  45 ++++++++-
 locales/es-ES.yml   |  63 +++++++++++-
 locales/fr-FR.yml   |  43 +++++++--
 locales/hr-HR.yml   |   1 -
 locales/ht-HT.yml   |   1 -
 locales/hu-HU.yml   |   1 -
 locales/id-ID.yml   | 139 ++++++++++++++++++++++++++-
 locales/it-IT.yml   | 140 ++++++++++++++++++---------
 locales/ja-KS.yml   |  77 ++++++++++++++-
 locales/jbo-EN.yml  |   1 -
 locales/kab-KAB.yml |   1 -
 locales/kn-IN.yml   |   1 -
 locales/ko-GS.yml   |  87 ++++++++++-------
 locales/ko-KR.yml   | 227 ++++++++++++++++++++++++++------------------
 locales/lo-LA.yml   |   1 -
 locales/nl-NL.yml   |   1 -
 locales/no-NO.yml   |   1 -
 locales/pl-PL.yml   | 160 ++++++++++++++++++++++++++++++-
 locales/pt-PT.yml   |  15 ++-
 locales/ro-RO.yml   |   1 -
 locales/ru-RU.yml   |  17 +++-
 locales/si-LK.yml   |  19 +++-
 locales/sk-SK.yml   |   1 -
 locales/sv-SE.yml   |   1 -
 locales/th-TH.yml   |  49 +++++++++-
 locales/tr-TR.yml   |   1 -
 locales/ug-CN.yml   |   1 -
 locales/uk-UA.yml   |   1 -
 locales/uz-UZ.yml   |   1 -
 locales/vi-VN.yml   |  77 ++++++++++++++-
 locales/zh-CN.yml   |  53 +++++++++--
 locales/zh-TW.yml   |  55 +++++++++--
 39 files changed, 1073 insertions(+), 261 deletions(-)

diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml
index 17c8f24fa5..88707fe111 100644
--- a/locales/ar-SA.yml
+++ b/locales/ar-SA.yml
@@ -123,6 +123,7 @@ reactions: "التفاعلات"
 reactionSettingDescription2: "اسحب لترتيب ، انقر للحذف ، استخدم \"+\" للإضافة."
 rememberNoteVisibility: "تذكر إعدادت مدى رؤية الملاحظات"
 attachCancel: "أزل المرفق"
+deleteFile: "حُذف الملف"
 markAsSensitive: "علّمه كمحتوى حساس"
 unmarkAsSensitive: "ألغ تعيينه كمحتوى حساس"
 enterFileName: "ادخل اسم الملف"
@@ -1565,8 +1566,21 @@ _webhookSettings:
     reaction: "عند التفاعل"
 _moderationLogTypes:
   suspend: "علِق"
+  deleteDriveFile: "حُذف الملف"
+  deleteNote: "حُذفت الملاحظة"
+  createGlobalAnnouncement: "أُنشئ إعلان عام"
+  createUserAnnouncement: "أُنشئ إعلان مستخدم"
+  updateGlobalAnnouncement: "حُدث إعلان عام"
+  updateUserAnnouncement: "حُدث إعلان مستخدم"
   resetPassword: "أعد تعيين كلمتك السرية"
   createInvitation: "ولِّد دعوة"
 _reversi:
   total: "المجموع"
-
+  lookingForPlayer: "يبحث عن خصم..."
+  gameCanceled: "أُلغيت اللعبة."
+  opponentHasSettingsChanged: "غيَر الخصم إعدادته."
+  showBoardLabels: "اعرض ترقيم الصفوف والأعمدة على اللوح"
+  useAvatarAsStone: "حوَل الحجارة إلى صور مستخدمين"
+_offlineScreen:
+  title: "غير متصل - يتعذر الاتصال بالخادم"
+  header: "يتعذر الاتصال بالخادم"
diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml
index 2a23cda06b..dc5d315aed 100644
--- a/locales/bn-BD.yml
+++ b/locales/bn-BD.yml
@@ -1347,4 +1347,3 @@ _moderationLogTypes:
   resetPassword: "পাসওয়ার্ড রিসেট করুন"
 _reversi:
   total: "মোট"
-
diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml
index 2ea6bd9309..d035555c73 100644
--- a/locales/ca-ES.yml
+++ b/locales/ca-ES.yml
@@ -400,6 +400,7 @@ name: "Nom"
 antennaSource: "Font de l'antena"
 antennaKeywords: "Paraules clau a seguir"
 antennaExcludeKeywords: "Paraules clau a excloure"
+antennaExcludeBots: "Exclou els bots"
 antennaKeywordsDescription: "Separar amb espais per la condició AND o amb salts de línia per la condició OR."
 notifyAntenna: "Notifica'm les publicacions noves"
 withFileAntenna: "Només les publicacions amb fitxers"
@@ -494,6 +495,7 @@ emojiStyle: "Estil d'emoji"
 native: "Nadiu"
 disableDrawer: "No mostrar els menús en calaixos"
 showNoteActionsOnlyHover: "Només mostra accions de la nota en passar amb el cursor"
+showReactionsCount: "Mostra el nombre de reaccions a les publicacions"
 noHistory: "No hi ha un registre previ"
 signinHistory: "Historial d'autenticacions"
 enableAdvancedMfm: "Habilitar l'MFM avançat"
@@ -543,7 +545,7 @@ objectStorageUseProxyDesc: "Desactiva'l si no faràs servir un Proxy per les con
 objectStorageSetPublicRead: "Configurar les pujades com públiques "
 s3ForcePathStyleDesc: "Si s3ForcePathStyle es troba activat el nom del dipòsit s'ha d'incloure a l'adreça URL en comtes del nom del host. Potser que necessitis activar-ho quan facis servir, per exemple, Minio a un servidor propi."
 serverLogs: "Registres del servidor"
-deleteAll: "Esborrar tot"
+deleteAll: "Elimina-ho tot"
 showFixedPostForm: "Mostrar el formulari per escriure a l'inici de la línia de temps"
 showFixedPostFormInChannel: "Mostrar el formulari d'escriptura al principi de la línia de temps (Canals)"
 withRepliesByDefaultForNewlyFollowed: "Inclou les respostes d'usuaris nous seguits a la línia de temps per defecte."
@@ -691,9 +693,9 @@ reporter: "Denunciant "
 reporteeOrigin: "Origen de la denúncia "
 reporterOrigin: "Origen del denunciant"
 forwardReport: "Transferir la denúncia a una instància remota"
-forwardReportIsAnonymous: "En comptes del teu compte, es farà servir un compte anònim com a denunciat a la instància remota."
-send: "Enviar"
-abuseMarkAsResolved: "Marcar la denúncia com a resolta"
+forwardReportIsAnonymous: "En lloc del teu compte, es farà servir un compte anònim com a denunciant al servidor remot."
+send: "Envia"
+abuseMarkAsResolved: "Marca la denúncia com a resolta"
 openInNewTab: "Obre a una pestanya nova"
 openInSideView: "Obre a una vista lateral"
 defaultNavigationBehaviour: "Navegació per defecte"
@@ -853,7 +855,7 @@ customCss: "CSS personalitzat"
 customCssWarn: "Aquesta configuració només hauries de configurar-la si saps que fas. Si poses valors inadequats pots fer que el client deixi de funcionar correctament."
 global: "Global"
 squareAvatars: "Mostrar avatars quadrats"
-sent: "Enviar"
+sent: "Envia"
 received: "Rebut"
 searchResult: "Resultats de la cerca"
 hashtags: "Etiquetes"
@@ -991,6 +993,7 @@ neverShow: "No mostrar més "
 remindMeLater: "Recorda-m'ho més tard"
 didYouLikeMisskey: "T'està agradant Misskey?"
 pleaseDonate: "A {host} fem servir el software lliure Misskey. Considera fer un donatiu a Misskey perquè pugui continuar el seu desenvolupament!"
+correspondingSourceIsAvailable: "El codi font corresponent està disponible a {anchor}."
 roles: "Rols"
 role: "Rols"
 noRole: "No s'han trobat rols"
@@ -1159,6 +1162,7 @@ showRenotes: "Mostrar impulsos"
 edited: "Editat"
 notificationRecieveConfig: "Paràmetres de notificacions"
 mutualFollow: "Seguidor mutu"
+followingOrFollower: "Seguit o seguidor"
 fileAttachedOnly: "Només notes amb adjunts"
 showRepliesToOthersInTimeline: "Mostrar les respostes a altres a la línia de temps"
 hideRepliesToOthersInTimeline: "Amagar les respostes a altres a la línia de temps"
@@ -1168,6 +1172,9 @@ confirmShowRepliesAll: "Aquesta opció no té marxa enrere. Vols mostrar les tev
 confirmHideRepliesAll: "Aquesta opció no té marxa enrere. Vols ocultar les teves respostes a tots els usuaris que segueixes a la línia de temps?"
 externalServices: "Serveis externs"
 sourceCode: "Codi font"
+repositoryUrl: "URL del repositori"
+feedback: "Opinió"
+feedbackUrl: "URL per a opinar"
 impressum: "Impressum"
 impressumUrl: "Adreça URL impressum"
 impressumDescription: "A països, com Alemanya, la inclusió de la informació de contacte de l'operador (un Impressum) és requereix de manera legal per llocs comercials."
@@ -1203,6 +1210,7 @@ soundWillBePlayed: "Es reproduiran efectes de so"
 showReplay: "Veure reproducció"
 replay: "Reproduir"
 replaying: "Reproduint"
+endReplay: "Tanca la redifusió"
 ranking: "Classificació"
 lastNDays: "Últims {n} dies"
 backToTitle: "Torna al títol"
@@ -1210,7 +1218,12 @@ hemisphere: "Geolocalització"
 withSensitive: "Incloure notes amb fitxers sensibles"
 userSaysSomethingSensitive: "La publicació de {name} conte material sensible"
 enableHorizontalSwipe: "Lliscar per canviar de pestanya"
+loading: "S’està carregant"
 surrender: "Cancel·lar "
+gameRetry: "Torna a provar"
+notUsePleaseLeaveBlank: "Si no voleu usar-ho, deixeu-ho en blanc"
+useTotp: "Usa una contrasenya d'un sol ús"
+useBackupCode: "Usa un codi de recuperació"
 _bubbleGame:
   howToPlay: "Com es juga"
   _howToPlay:
@@ -1915,7 +1928,6 @@ _2fa:
   registerTOTP: "Registrar una aplicació autenticadora"
   step1: "Primer instal·la una aplicació autenticadora (com {a} o {b}) al teu dispositiu."
   step2: "Després escaneja el codi QR que es mostra en aquesta pantalla."
-  step2Click: "Fent clic en aquest codi QR et permetrà registrar l'autenticació de doble factor a la teva clau de seguretat o en l'aplicació d'autenticació del teu dispositiu."
   step2Uri: "Escriu la següent URI si estàs fent servir una aplicació d'escriptori "
   step3Title: "Escriu un codi d'autenticació"
   step3: "Escriu el codi d'autenticació (token) que es mostra a la teva aplicació per finalitzar la configuració."
@@ -2255,4 +2267,3 @@ _externalResourceInstaller:
       title: "Paràmetres no vàlids "
 _reversi:
   total: "Total"
-
diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml
index cbf5c33c18..cff533976e 100644
--- a/locales/cs-CZ.yml
+++ b/locales/cs-CZ.yml
@@ -1664,7 +1664,6 @@ _2fa:
   registerTOTP: "Registrovat aplikaci autentizátoru"
   step1: "Nejprve si do zařízení nainstalujte aplikaci pro ověřování (například {a} nebo {b})."
   step2: "Poté naskenujte QR kód zobrazený na této obrazovce."
-  step2Click: "Kliknutím na tento QR kód můžete zaregistrovat 2FA do bezpečnostního klíče nebo aplikace autentizace telefonu."
   step3Title: "Zadejte ověřovací kód"
   step3: "Pro dokončení nastavení zadejte token poskytnutý vaší aplikací."
   step4: "Od této chvíle budou všechny budoucí pokusy o přihlášení vyžadovat tento přihlašovací token."
@@ -1718,7 +1717,7 @@ _auth:
   shareAccessTitle: "Udělovat oprávnění k aplikacím"
   shareAccess: "Chcete autorizovat \"{name}\" pro přístup k tomuto účtu?"
   shareAccessAsk: "Opravdu chcete této aplikaci povolit přístup k vašemu účtu?"
-  permission: "{jméno} požaduje tato oprávnění"
+  permission: "{name} požaduje tato oprávnění"
   permissionAsk: "Tato aplikace požaduje následující oprávnění"
   pleaseGoBack: "Vraťte se prosím zpět do aplikace"
   callback: "Návrat k aplikaci"
@@ -1942,7 +1941,7 @@ _notification:
   youGotMention: "{name} vás zmínil"
   youGotReply: "{name} vám odpověděl"
   youGotQuote: "{name} vás citoval"
-  youRenoted: "Poznámka od {jméno}"
+  youRenoted: "Poznámka od {name}"
   youWereFollowed: "Máte nového následovníka"
   youReceivedFollowRequest: "Obdrželi jste žádost o sledování"
   yourFollowRequestAccepted: "Vaše žádost o sledování byla přijata"
@@ -2025,4 +2024,3 @@ _moderationLogTypes:
   createInvitation: "Vygenerovat pozvánku"
 _reversi:
   total: "Celkem"
-
diff --git a/locales/da-DK.yml b/locales/da-DK.yml
index d1fbec9f67..08c15ed092 100644
--- a/locales/da-DK.yml
+++ b/locales/da-DK.yml
@@ -1,3 +1,2 @@
 ---
 _lang_: "Dansk"
-
diff --git a/locales/de-DE.yml b/locales/de-DE.yml
index 9a22a7b445..3b39938255 100644
--- a/locales/de-DE.yml
+++ b/locales/de-DE.yml
@@ -1819,7 +1819,6 @@ _2fa:
   registerTOTP: "Authentifizierungs-App registrieren"
   step1: "Installiere zuerst eine Authentifizierungsapp (z.B. {a} oder {b}) auf deinem Gerät."
   step2: "Dann, scanne den angezeigten QR-Code mit deinem Gerät."
-  step2Click: "Durch Klicken dieses QR-Codes kannst du Verifikation mit deinem Security-Token oder einer App registrieren."
   step2Uri: "Nutzt du ein Desktopprogramm, gib folgende URI eingeben"
   step3Title: "Authentifizierungsscode eingeben"
   step3: "Gib zum Abschluss den Code (Token) ein, der von deiner App angezeigt wird."
@@ -2289,4 +2288,3 @@ _reversi:
   black: "Schwarz"
   white: "Weiß"
   total: "Gesamt"
-
diff --git a/locales/el-GR.yml b/locales/el-GR.yml
index bb5639a741..2098c7ef50 100644
--- a/locales/el-GR.yml
+++ b/locales/el-GR.yml
@@ -398,4 +398,3 @@ _moderationLogTypes:
   suspend: "Αποβολή"
 _reversi:
   total: "Σύνολο"
-
diff --git a/locales/en-US.yml b/locales/en-US.yml
index d00f23632c..10e9fd778e 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -130,7 +130,7 @@ overwriteFromPinnedEmojis: "Override from general settings"
 reactionSettingDescription2: "Drag to reorder, click to delete, press \"+\" to add."
 rememberNoteVisibility: "Remember note visibility settings"
 attachCancel: "Remove attachment"
-deleteFile: "File deleted"
+deleteFile: "Delete file"
 markAsSensitive: "Mark as sensitive"
 unmarkAsSensitive: "Unmark as sensitive"
 enterFileName: "Enter filename"
@@ -400,6 +400,7 @@ name: "Name"
 antennaSource: "Antenna source"
 antennaKeywords: "Keywords to listen to"
 antennaExcludeKeywords: "Keywords to exclude"
+antennaExcludeBots: "Exclude bot accounts"
 antennaKeywordsDescription: "Separate with spaces for an AND condition or with line breaks for an OR condition."
 notifyAntenna: "Notify about new notes"
 withFileAntenna: "Only notes with files"
@@ -494,6 +495,7 @@ emojiStyle: "Emoji style"
 native: "Native"
 disableDrawer: "Don't use drawer-style menus"
 showNoteActionsOnlyHover: "Only show note actions on hover"
+showReactionsCount: "See the number of reactions in notes"
 noHistory: "No history available"
 signinHistory: "Login history"
 enableAdvancedMfm: "Enable advanced MFM"
@@ -1223,6 +1225,16 @@ enableHorizontalSwipe: "Swipe to switch tabs"
 loading: "Loading"
 surrender: "Cancel"
 gameRetry: "Retry"
+notUsePleaseLeaveBlank: "Leave blank if not used"
+useTotp: "Enter the One-Time Password"
+useBackupCode: "Use the backup codes"
+launchApp: "Launch the app"
+useNativeUIForVideoAudioPlayer: "Use UI of browser when play video and audio"
+keepOriginalFilename: "Keep original file name"
+keepOriginalFilenameDescription: "If you turn off this setting, files names will be replaced with random string automatically when you upload files."
+noDescription: "There is not the explanation"
+alwaysConfirmFollow: "Always confirm when following"
+inquiry: "Contact"
 _bubbleGame:
   howToPlay: "How to play"
   hold: "Hold"
@@ -1682,6 +1694,11 @@ _role:
     roleAssignedTo: "Assigned to manual roles"
     isLocal: "Local user"
     isRemote: "Remote user"
+    isCat: "Cat Users"
+    isBot: "Bot Users"
+    isSuspended: "Suspended user"
+    isLocked: "Private accounts"
+    isExplorable: "Effective user of \"make an account discoverable\""
     createdLessThan: "Less than X has passed since account creation"
     createdMoreThan: "More than X has passed since account creation"
     followersLessThanOrEq: "Has X or fewer followers"
@@ -1751,6 +1768,7 @@ _plugin:
   installWarn: "Please do not install untrustworthy plugins."
   manage: "Manage plugins"
   viewSource: "View source"
+  viewLog: "Show log"
 _preferencesBackups:
   list: "Created backups"
   saveNew: "Save new backup"
@@ -1940,7 +1958,6 @@ _2fa:
   registerTOTP: "Register authenticator app"
   step1: "First, install an authentication app (such as {a} or {b}) on your device."
   step2: "Then, scan the QR code displayed on this screen."
-  step2Click: "Clicking on this QR code will allow you to register 2FA to your security key or phone authenticator app."
   step2Uri: "Enter the following URI if you are using a desktop program"
   step3Title: "Enter an authentication code"
   step3: "Enter the authentication code (token) provided by your app to finish setup."
@@ -1964,6 +1981,7 @@ _2fa:
   backupCodesDescription: "You can use these codes to gain access to your account in case of becoming unable to use your two-factor authentificator app. Each can only be used once. Please keep them in a safe place."
   backupCodeUsedWarning: "A backup code has been used. Please reconfigure two-factor authentification as soon as possible if you are no longer able to use it."
   backupCodesExhaustedWarning: "All backup codes have been used. Should you lose access to your two-factor authentification app, you will be unable to access this account. Please reconfigure two-factor authentification."
+  moreDetailedGuideHere: "Here is detailed guide"
 _permissions:
   "read:account": "View your account information"
   "write:account": "Edit your account information"
@@ -2225,6 +2243,7 @@ _play:
   title: "Title"
   script: "Script"
   summary: "Description"
+  visibilityDescription: "Putting it private means it won't be visible on your profile, but anyone that has the URL can still access it."
 _pages:
   newPage: "Create a new Page"
   editPage: "Edit this Page"
@@ -2269,6 +2288,8 @@ _pages:
     section: "Section"
     image: "Images"
     button: "Button"
+    dynamic: "Dynamic Blocks"
+    dynamicDescription: "This block has been abolished. Please use {play} from now on."
     note: "Embedded note"
     _note:
       id: "Note ID"
@@ -2298,6 +2319,7 @@ _notification:
   sendTestNotification: "Send test notification"
   notificationWillBeDisplayedLikeThis: "Notifications look like this"
   reactedBySomeUsers: "{n} users reacted"
+  likedBySomeUsers: "{n} users liked your note"
   renotedBySomeUsers: "Renote from {n} users"
   followedBySomeUsers: "Followed by {n} users"
   flushNotification: "Clear notifications"
@@ -2524,4 +2546,21 @@ _reversi:
 _offlineScreen:
   title: "Offline - cannot connect to the server"
   header: "Unable to connect to the server"
-
+_urlPreviewSetting:
+  title: "URL preview settings"
+  enable: "Enable URL preview"
+  timeout: "Time out when getting preview (ms)"
+  timeoutDescription: "If it takes longer than this value to get the preview, the preview won’t be generated."
+  maximumContentLength: "Maximum Content-Length (bytes)"
+  maximumContentLengthDescription: "If Content-Length is higher than this value, the preview won't be generated."
+  requireContentLength: "Generate the preview only if you could get Content-Length"
+  requireContentLengthDescription: "If other server doesn't return Content-Length, the preview won't be generated."
+  userAgent: "User-Agent"
+  userAgentDescription: "Sets the User-Agent to be used when retrieving previews. If left blank, the default User-Agent will be used."
+  summaryProxy: "Proxy endpoints that generate previews"
+  summaryProxyDescription: "Not Misskey itself, but generate previews using Summaly Proxy."
+  summaryProxyDescription2: "The following parameters are linked to the proxy as a query string. If the proxy does not support them, the values are ignored."
+_mediaControls:
+  pip: "Picture in Picture"
+  playbackRate: "Playback Speed"
+  loop: "Loop playback"
diff --git a/locales/es-ES.yml b/locales/es-ES.yml
index 246ec23604..2e05364c31 100644
--- a/locales/es-ES.yml
+++ b/locales/es-ES.yml
@@ -235,7 +235,7 @@ done: "Terminado"
 processing: "Procesando"
 preview: "Vista previa"
 default: "Predeterminado"
-defaultValueIs: "Predeterminado"
+defaultValueIs: "Por defecto: {value}"
 noCustomEmojis: "No hay emojis personalizados"
 noJobs: "No hay trabajos"
 federating: "Federando"
@@ -400,6 +400,7 @@ name: "Nombre"
 antennaSource: "Origen de la antena"
 antennaKeywords: "Palabras clave para recibir"
 antennaExcludeKeywords: "Palabras clave para excluir"
+antennaExcludeBots: "Excluir bots"
 antennaKeywordsDescription: "Separar con espacios es una declaración AND, separar con una linea nueva es una declaración OR"
 notifyAntenna: "Notificar nueva nota"
 withFileAntenna: "Sólo notas con archivos adjuntados"
@@ -494,6 +495,7 @@ emojiStyle: "Estilo de emoji"
 native: "Nativo"
 disableDrawer: "No mostrar los menús en cajones"
 showNoteActionsOnlyHover: "Mostrar acciones de la nota sólo al pasar el cursor"
+showReactionsCount: "Mostrar el número de reacciones en las notas"
 noHistory: "No hay datos en el historial"
 signinHistory: "Historial de ingresos"
 enableAdvancedMfm: "Habilitar MFM avanzado"
@@ -991,6 +993,7 @@ neverShow: "No mostrar de nuevo"
 remindMeLater: "Recordar después"
 didYouLikeMisskey: "¿Te gusta Misskey?"
 pleaseDonate: "{host} usa el software gratuito Misskey. Por favor ¡Considera donar al proyecto principal para que podamos continuar!"
+correspondingSourceIsAvailable: "El código fuente correspondiente se encuentra disponible en {anchor}"
 roles: "Roles"
 role: "Rol"
 noRole: "Rol no encontrado"
@@ -1042,6 +1045,7 @@ sensitiveWords: "Palabras sensibles"
 sensitiveWordsDescription: "La visibilidad de todas las notas que contienen cualquiera de las palabras configuradas serán puestas en \"Inicio\" automáticamente. Puedes enumerás varias separándolas con saltos de línea"
 sensitiveWordsDescription2: "Si se usan espacios se crearán expresiones AND y las palabras subsecuentes con barras inclinadas se convertirán en expresiones regulares."
 prohibitedWords: "Palabras explícitas"
+prohibitedWordsDescription: "Activa un error cuando se intenta publicar una nota que contiene una o varias palabras prohibidas. Se pueden establecer varias palabras, una por línea."
 prohibitedWordsDescription2: "Si se usan espacios se crearán expresiones AND y las palabras subsecuentes con barras inclinadas se convertirán en expresiones regulares."
 hiddenTags: "Hashtags ocultos"
 hiddenTagsDescription: "Selecciona las etiquetas que no se mostrarán en tendencias. Una etiqueta por línea."
@@ -1158,6 +1162,7 @@ showRenotes: "Mostrar renotas"
 edited: "Editado"
 notificationRecieveConfig: "Ajustes de Notificaciones"
 mutualFollow: "Os seguís mutuamente"
+followingOrFollower: "Siguiendo o seguidor"
 fileAttachedOnly: "Solo notas con archivos"
 showRepliesToOthersInTimeline: "Mostrar respuestas a otros en la línea de tiempo"
 hideRepliesToOthersInTimeline: "Ocultar respuestas a otros en la línea de tiempo"
@@ -1167,6 +1172,12 @@ confirmShowRepliesAll: "Esta operación es irreversible. ¿Confirmas que quieres
 confirmHideRepliesAll: "Esta operación es irreversible. ¿Confirmas que quieres ocultar tus respuestas a otros usuarios que sigues en tu línea de tiempo?"
 externalServices: "Servicios Externos"
 sourceCode: "Código fuente"
+sourceCodeIsNotYetProvided: "El código fuente aún no está disponible. Contacta con el administrador para solucionarlo."
+repositoryUrl: "URL del repositorio"
+repositoryUrlDescription: "Si estás usando Misskey tal cual (sin cambios en el código fuente), entra en https://github.com/misskey-dev/misskey"
+repositoryUrlOrTarballRequired: "Si no has publicado un repositorio aún, deberás publicar un tarball en su lugar. Mira el archivo .config/example.yml para más información."
+feedback: "Comentarios"
+feedbackUrl: "URL de comentarios"
 impressum: "Impressum"
 impressumUrl: "Impressum URL"
 impressumDescription: "En algunos países, como Alemania, la inclusión del operador de datos (el Impressum) es requerido legalmente para sitios web comerciales."
@@ -1202,6 +1213,8 @@ soundWillBePlayed: "Se reproducirán efectos sonoros"
 showReplay: "Ver reproducción"
 replay: "Reproducir"
 replaying: "Reproduciendo"
+endReplay: "Terminar reproducción"
+copyReplayData: "Copiar datos de reproducción"
 ranking: "Clasificación"
 lastNDays: "Últimos {n} días"
 backToTitle: "Regresar al inicio"
@@ -1209,9 +1222,28 @@ hemisphere: "Región"
 withSensitive: "Mostrar notas que contengan material sensible"
 userSaysSomethingSensitive: "La publicación de {name} contiene material sensible"
 enableHorizontalSwipe: "Deslice para cambiar de pestaña"
+loading: "Cargando"
 surrender: "detener"
+gameRetry: "Reintentar"
+notUsePleaseLeaveBlank: "Dejar en blanco si no se usa"
+useTotp: "Introduce la contraseña de un solo uso"
+useBackupCode: "Usar códigos de respaldo"
+launchApp: "Ejecutar la app"
+useNativeUIForVideoAudioPlayer: "Usar la interfaz del navegador cuando se reproduce audio y vídeo"
+keepOriginalFilename: "Mantener el nombre original del archivo"
+noDescription: "No hay descripción"
+alwaysConfirmFollow: "Confirmar siempre cuando se sigue a alguien"
 _bubbleGame:
   howToPlay: "Cómo jugar"
+  hold: "Mantener"
+  _score:
+    score: "Puntos"
+    scoreYen: "Cantidad de dinero ganada"
+    highScore: "Puntuación más alta"
+    maxChain: "Número máximo de cadenas"
+    yen: "{yen} Yenes"
+    estimatedQty: "{qty} Piezas"
+    scoreSweets: "{onigiriQtyWithUnit} Onigiris"
   _howToPlay:
     section1: "Ajuste la posición y deje caer el objeto en la caja"
     section2: "Cuando dos objetos del mismo tipo se tocan, cambian a otro tipo y consigues puntos"
@@ -1329,7 +1361,7 @@ _serverSettings:
 _accountMigration:
   moveFrom: "Trasladar de otra cuenta a ésta"
   moveFromSub: "Crear un alias para otra cuenta."
-  moveFromLabel: "Cuenta desde la que se realiza el traslado:"
+  moveFromLabel: "Cuenta desde la que se realiza el traslado #{n}"
   moveFromDescription: "Si quieres transferir seguidores de otra cuenta a esta cuenta y trasladarlos, tendrás que crear un alias aquí. Asegúrate de crearlo antes de realizar el traslado. Introduce la cuenta desde la que estás moviendo los seguidores así: @person@instance.com"
   moveTo: "Mover esta cuenta a una nueva"
   moveToLabel: "Cuenta destino:"
@@ -1588,8 +1620,11 @@ _achievements:
       description: "Tutorial completado"
     _bubbleGameExplodingHead:
       title: "🤯"
+      description: "El objeto más grande en el juego de burbujas"
     _bubbleGameDoubleExplodingHead:
       title: "Doble 🤯"
+      description: "Dos de los objetos más grandes en el juego de burbujas al mismo tiempo"
+      flavor: "Puedes llenar el bento un poco de esta forma 🤯 🤯."
 _role:
   new: "Crear rol"
   edit: "Editar rol"
@@ -1630,6 +1665,7 @@ _role:
     gtlAvailable: "Explorar la línea de tiempo global"
     ltlAvailable: "Explorar la línea de tiempo local"
     canPublicNote: "Permitir la publicación"
+    mentionMax: "Número máximo de menciones en una nota"
     canInvite: "Puede crear códigos de invitación"
     inviteLimit: "Límite de invitaciones"
     inviteLimitCycle: "Enfriamiento del límite de invitaciones"
@@ -1653,8 +1689,13 @@ _role:
     canUseTranslator: "Uso de traductor"
     avatarDecorationLimit: "Número máximo de decoraciones de avatar"
   _condition:
+    roleAssignedTo: "Asignado a roles manuales"
     isLocal: "Usuario local"
     isRemote: "Usuario remoto"
+    isCat: "Usuarios Gato"
+    isBot: "Usuarios Bot"
+    isSuspended: "Usuario suspendido"
+    isLocked: "Cuentas privadas"
     createdLessThan: "Menos de X han pasado desde la creación de la cuenta"
     createdMoreThan: "Más de X han pasado desde la creación de la cuenta"
     followersLessThanOrEq: "Tiene X o menos seguidores"
@@ -1724,6 +1765,7 @@ _plugin:
   installWarn: "Por favor no instale plugins que no son de confianza"
   manage: "Gestionar plugins"
   viewSource: "Ver la fuente"
+  viewLog: "Ver log"
 _preferencesBackups:
   list: "Respaldos creados"
   saveNew: "Guardar nuevo respaldo"
@@ -1753,6 +1795,8 @@ _aboutMisskey:
   contributors: "Principales colaboradores"
   allContributors: "Todos los colaboradores"
   source: "Código fuente"
+  original: "Original"
+  thisIsModifiedVersion: "{name} usa una versión modificada de Misskey."
   translation: "Traducir Misskey"
   donate: "Donar a Misskey"
   morePatrons: "Muchas más personas nos apoyan. Muchas gracias🥰"
@@ -1911,7 +1955,6 @@ _2fa:
   registerTOTP: "Registrar aplicación autenticadora"
   step1: "Primero, instale en su dispositivo la aplicación de autenticación {a} o {b} u otra."
   step2: "Luego, escanee con la aplicación el código QR mostrado en pantalla."
-  step2Click: "Clicking on this QR code will allow you to register 2FA to your security key or phone authenticator app.\nTocar este código QR te permitirá registrar la autenticación 2FA a tu llave de seguridad o aplicación autenticadora."
   step2Uri: "Si usas una aplicación de escritorio, introduce en ella la siguiente URL."
   step3Title: "Ingresa un código de autenticación"
   step3: "Para terminar, ingrese el token mostrado en la aplicación."
@@ -1935,6 +1978,7 @@ _2fa:
   backupCodesDescription: "En caso de que no puedas usar tu aplicación de autenticación, podrás usar los códigos de respaldo que figuran abajo para acceder a tu cuenta. Asegúrate de guardar en lugar seguro los códigos de respaldo. Cada uno de los códigos de respaldo es de un solo uso."
   backupCodeUsedWarning: "Has usado todos los códigos de respaldo. Si dejas de tener acceso a tu aplicación de autenticación, no podrás volver a iniciar sesión en tu cuenta. Por favor, reconfigura tu aplicación de autenticación lo antes posible."
   backupCodesExhaustedWarning: "Has usado todos los códigos de respaldo. Si dejas de tener acceso a tu aplicación de autenticación, no podrás volver a iniciar sesión en la cuenta que figura arriba. Por favor, reconfigura tu aplicación de autenticación lo antes posible."
+  moreDetailedGuideHere: "Guía detallada"
 _permissions:
   "read:account": "Ver información de la cuenta"
   "write:account": "Editar información de la cuenta"
@@ -1976,6 +2020,7 @@ _permissions:
   "write:admin:delete-account": "Eliminar cuentas de usuario"
   "write:admin:delete-all-files-of-a-user": "Eliminar todos los archivos de un usuario"
   "read:admin:index-stats": "Ver datos indexados"
+  "read:admin:table-stats": "Ver estadísticas de las tablas de la base de datos"
   "read:admin:user-ips": "Ver dirección IP de usuario"
   "read:admin:meta": "Ver metadatos de la instancia"
   "write:admin:reset-password": "Restablecer contraseñas de usuario"
@@ -2195,6 +2240,7 @@ _play:
   title: "Título"
   script: "Script"
   summary: "Descripción"
+  visibilityDescription: "Poniéndola como privada significa que no será visible en tu perfil, pero cualquiera que tenga la URL aún podrá acceder a ella."
 _pages:
   newPage: "Crear página"
   editPage: "Editar página"
@@ -2239,6 +2285,8 @@ _pages:
     section: "Sección"
     image: "Imagen"
     button: "Botón"
+    dynamic: "Bloques Dinámicos"
+    dynamicDescription: "Los bloques dinámicos están obsoletos. A partir de ahora, utiliza {play} por favor."
     note: "Nota embebida"
     _note:
       id: "Id de la nota"
@@ -2448,4 +2496,11 @@ _reversi:
   reversi: "Reversi"
   won: "{name} ha ganado"
   total: "Total"
-
+_urlPreviewSetting:
+  timeout: "Timeout de la carga de vista previa de las URLs (ms)"
+  maximumContentLength: "Content-Length Máximo (bytes)"
+  userAgent: "User-Agent"
+_mediaControls:
+  pip: "Picture in Picture"
+  playbackRate: "Velocidad de reproducción"
+  loop: "Reproducción en bucle"
diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml
index 9629726f54..58a11a5cc4 100644
--- a/locales/fr-FR.yml
+++ b/locales/fr-FR.yml
@@ -129,7 +129,7 @@ overwriteFromPinnedEmojisForReaction: "Remplacer par les émojis épinglés pour
 overwriteFromPinnedEmojis: "Remplacer par les émojis épinglés globalement"
 reactionSettingDescription2: "Déplacer pour réorganiser, cliquer pour effacer, utiliser « + » pour ajouter."
 rememberNoteVisibility: "Se souvenir de la visibilité des notes"
-attachCancel: "Supprimer le fichier attaché"
+attachCancel: "Supprimer le fichier joint"
 deleteFile: "Fichier supprimé"
 markAsSensitive: "Marquer comme sensible"
 unmarkAsSensitive: "Supprimer le marquage comme sensible"
@@ -400,6 +400,7 @@ name: "Nom"
 antennaSource: "Source de l’antenne"
 antennaKeywords: "Mots clés à recevoir"
 antennaExcludeKeywords: "Mots clés à exclure"
+antennaExcludeBots: "Exclure les comptes robot"
 antennaKeywordsDescription: "Séparer avec des espaces pour la condition AND. Séparer avec un saut de ligne pour une condition OR."
 notifyAntenna: "Me notifier pour les nouvelles notes"
 withFileAntenna: "Notes ayant des fichiers joints uniquement"
@@ -494,6 +495,7 @@ emojiStyle: "Style des émojis"
 native: "Natif"
 disableDrawer: "Les menus ne s'affichent pas dans le tiroir"
 showNoteActionsOnlyHover: "Afficher les actions de note uniquement au survol"
+showReactionsCount: "Afficher le nombre de réactions des notes"
 noHistory: "Pas d'historique"
 signinHistory: "Historique de connexion"
 enableAdvancedMfm: "Activer la MFM avancée"
@@ -541,6 +543,7 @@ objectStorageUseSSLDesc: "Désactivez cette option si vous n'utilisez pas HTTPS
 objectStorageUseProxy: "Se connecter via proxy"
 objectStorageUseProxyDesc: "Désactivez cette option si vous n'utilisez pas de proxy pour la connexion API"
 objectStorageSetPublicRead: "Régler sur « public » lors de l'envoi"
+s3ForcePathStyleDesc: "Si s3ForcePathStyle est activé, le nom du compartiment doit être spécifié comme une partie du chemin de l'URL plutôt que le nom d'hôte. Il faudra peut-être l'activer lors de l'utilisation d'une instance de Minio autohébergée, etc."
 serverLogs: "Journal du serveur"
 deleteAll: "Supprimer tout"
 showFixedPostForm: "Afficher le formulaire de publication en haut du fil d'actualité"
@@ -655,7 +658,7 @@ testEmail: "Tester la distribution de courriel"
 wordMute: "Filtre de mots"
 hardWordMute: "Filtre de mots dur"
 regexpError: "Erreur d’expression régulière"
-regexpErrorDescription: "Une erreur s'est produite dans l'expression régulière sur la ligne {ligne} de votre mot muet {tab} :"
+regexpErrorDescription: "Une erreur s'est produite dans l'expression régulière sur la ligne {line} de votre mot muet {tab} :"
 instanceMute: "Instance en sourdine"
 userSaysSomething: "{name} a dit quelque chose"
 makeActive: "Activer"
@@ -675,6 +678,7 @@ useGlobalSettingDesc: "S'il est activé, les paramètres de notification de votr
 other: "Autre"
 regenerateLoginToken: "Régénérer le jeton de connexion"
 regenerateLoginTokenDescription: "Générer un nouveau jeton d'authentification. Cette opération ne devrait pas être nécessaire ; lors de la génération d'un nouveau jeton, tous les appareils seront déconnectés. "
+theKeywordWhenSearchingForCustomEmoji: "Ce mot-clé est utilisé lors de la recherche des émojis personnalisés."
 setMultipleBySeparatingWithSpace: "Vous pouvez en définir plusieurs, en les séparant par des espaces."
 fileIdOrUrl: "ID du fichier ou URL"
 behavior: "Comportement"
@@ -989,6 +993,7 @@ neverShow: "Ne plus afficher"
 remindMeLater: "Peut-être plus tard"
 didYouLikeMisskey: "Avez-vous aimé Misskey ?"
 pleaseDonate: "Misskey est le logiciel libre utilisé par {host}. Merci de faire un don pour que nous puissions continuer à le développer !"
+correspondingSourceIsAvailable: "Le code source correspondant est disponible à {anchor}"
 roles: "Rôles"
 role: "Rôles"
 noRole: "Aucun rôle"
@@ -1003,6 +1008,7 @@ youCannotCreateAnymore: "Vous avez atteint la limite de création."
 cannotPerformTemporary: "Temporairement indisponible"
 cannotPerformTemporaryDescription: "Temporairement indisponible puisque le nombre d'opérations dépasse la limite. Veuillez patienter un peu, puis réessayer."
 invalidParamError: "Paramètres invalides"
+invalidParamErrorDescription: "Les paramètres de la requête sont invalides. Il s'agit généralement d'un bogue, mais cela peut aussi être causé par un excès de caractères ou quelque chose de similaire."
 permissionDeniedError: "Opération refusée"
 permissionDeniedErrorDescription: "Ce compte n'a pas la permission d'effectuer cette opération."
 preset: "Préréglage"
@@ -1016,6 +1022,7 @@ thisPostMayBeAnnoyingCancel: "Annuler"
 thisPostMayBeAnnoyingIgnore: "Publier quand-même"
 collapseRenotes: "Réduire les renotes déjà vues"
 internalServerError: "Erreur interne du serveur"
+internalServerErrorDescription: "Une erreur inattendue s'est produite sur le serveur."
 copyErrorInfo: "Copier les détails de l’erreur"
 joinThisServer: "S'inscrire à cette instance"
 exploreOtherServers: "Trouver une autre instance"
@@ -1035,8 +1042,10 @@ nonSensitiveOnlyForLocalLikeOnlyForRemote: "Non sensibles seulement (mentions j'
 rolesAssignedToMe: "Rôles attribués à moi"
 resetPasswordConfirm: "Souhaitez-vous réinitialiser votre mot de passe ?"
 sensitiveWords: "Mots sensibles"
+sensitiveWordsDescription: "Définir la visibilité des notes contenant un mot défini ici au fil principal automatiquement. Vous pouvez définir plusieurs valeurs en les séparant par des sauts de ligne."
 sensitiveWordsDescription2: "Séparer par une espace pour créer une expression AND ; entourer de barres obliques pour créer une expression régulière."
 prohibitedWords: "Mots interdits"
+prohibitedWordsDescription: "Publier une note contenant un mot défini ici produira une erreur. Vous pouvez définir plusieurs valeurs en les séparant par des sauts de ligne."
 prohibitedWordsDescription2: "Séparer par une espace pour créer une expression AND ; entourer de barres obliques pour créer une expression régulière."
 hiddenTags: "Hashtags cachés"
 hiddenTagsDescription: "Les hashtags définis ne s'afficheront pas dans les tendances. Vous pouvez définir plusieurs hashtags en faisant un saut de ligne."
@@ -1082,9 +1091,11 @@ pleaseConfirmBelowBeforeSignup: "Pour vous inscrire sur cette instance, vous dev
 pleaseAgreeAllToContinue: "Pour continuer, veuillez accepter tous les champs ci-dessus."
 continue: "Continuer"
 preservedUsernames: "Noms d'utilisateur·rice réservés"
+preservedUsernamesDescription: "Énumérez les noms d'utilisateur à réserver, séparés par des nouvelles lignes. Les noms d'utilisateur spécifiés ici ne seront plus utilisables lors de la création d'un compte, sauf la création manuelle par un administrateur. De plus, les comptes existants ne seront pas affectés."
 createNoteFromTheFile: "Rédiger une note de ce fichier"
 archive: "Archive"
 channelArchiveConfirmTitle: "Voulez-vous vraiment archiver {name} ?"
+channelArchiveConfirmDescription: "Une fois archivé, le canal n'apparaîtra plus dans la liste des canaux ni dans les résultats de recherche, et la publication des nouvelles notes sera impossible."
 thisChannelArchived: "Ce canal a été archivé."
 displayOfNote: "Affichage de la note"
 initialAccountSetting: "Configuration initiale du profil"
@@ -1113,6 +1124,8 @@ createWithOptions: "Options"
 createCount: "Quantité à créer"
 inviteCodeCreated: "Code d'invitation créé"
 inviteLimitExceeded: "Vous avez atteint la limite de codes d'invitation que vous pouvez générer."
+createLimitRemaining: "Codes d'invitation pouvant être créés : {limit} restants"
+inviteLimitResetCycle: "Vous pouvez créer jusqu'à {limit} codes d'invitation en {time}."
 expirationDate: "Date d’expiration"
 noExpirationDate: "Ne pas expirer"
 inviteCodeUsedAt: "Code d'invitation utilisé à"
@@ -1132,11 +1145,14 @@ forYou: "Pour vous"
 currentAnnouncements: "Annonces actuelles"
 pastAnnouncements: "Annonces passées"
 youHaveUnreadAnnouncements: "Il y a des annonces non lues."
+useSecurityKey: "Suivez les instructions de votre navigateur ou de votre appareil pour utiliser une clé de sécurité ou une clé d'accès."
 replies: "Réponses"
 renotes: "Renotes"
 loadReplies: "Inclure les réponses"
 loadConversation: "Afficher la conversation"
 pinnedList: "Liste épinglée"
+keepScreenOn: "Garder l'écran toujours allumé"
+verifiedLink: "Votre propriété de ce lien a été vérifiée"
 notifyNotes: "Notifier à propos des nouvelles notes"
 unnotifyNotes: "Ne pas notifier pour la publication des notes"
 authentication: "Authentification"
@@ -1146,6 +1162,7 @@ showRenotes: "Afficher les renotes"
 edited: "Modifié"
 notificationRecieveConfig: "Paramètres des notifications"
 mutualFollow: "Abonnement mutuel"
+followingOrFollower: "Abonnement ou abonné"
 fileAttachedOnly: "Avec fichiers joints seulement"
 showRepliesToOthersInTimeline: "Afficher les réponses aux autres dans le fil"
 hideRepliesToOthersInTimeline: "Masquer les réponses aux autres dans le fil"
@@ -1201,6 +1218,8 @@ ranking: "Classement"
 lastNDays: "Derniers {n} jours"
 backToTitle: "Retourner au titre"
 hemisphere: "Votre région"
+withSensitive: "Afficher les notes contenant des fichiers joints sensibles"
+userSaysSomethingSensitive: "Note de {name} contenant des fichiers joints sensibles"
 enableHorizontalSwipe: "Glisser pour changer d'onglet"
 loading: "Chargement en cours"
 surrender: "Annuler"
@@ -1212,15 +1231,25 @@ _bubbleGame:
     score: "Score"
     scoreYen: "Montant gagné"
     highScore: "Meilleur score"
+    maxChain: "Nombre maximum de chaînes"
     yen: "{yen} yens"
+    estimatedQty: "{qty} pièces"
 _announcement:
   forExistingUsers: "Pour les utilisateurs existants seulement"
+  needConfirmationToRead: "Exiger la confirmation de la lecture"
+  needConfirmationToReadDescription: "Si activé, afficher un dialogue de confirmation quand l'annonce est marquée comme lue. Aussi, elle sera exclue de « marquer tout comme lu » ."
+  end: "Archiver l'annonce"
+  tooManyActiveAnnouncementDescription: "Un grand nombre d'annonces actives peut baisser l'expérience utilisateur. Considérez d'archiver les annonces obsolètes."
   readConfirmTitle: "Marquer comme lu ?"
+  readConfirmText: "Cela marquera le contenu de  « {title} » comme lu."
   shouldNotBeUsedToPresentPermanentInfo: "Puisque cela pourrait nuire considérablement à l'expérience utilisateur pour les nouveaux utilisateurs, il est recommandé d'utiliser les annonces pour afficher des informations temporaires plutôt que des informations persistantes."
   dialogAnnouncementUxWarn: "Avoir deux ou plus annonces de style dialogue en même temps pourrait nuire considérablement à l'expérience utilisateur. Veuillez les utiliser avec caution."
   silence: "Ne pas me notifier"
   silenceDescription: "Si activée, vous ne recevrez pas de notifications sur les annonces et n'aurez pas besoin de les marquer comme lues."
 _initialAccountSetting:
+  accountCreated: "Votre compte a été créé avec succès !"
+  letsStartAccountSetup: "Procédons au réglage initial du compte."
+  letsFillYourProfile: "Commençons par configurer votre profil !"
   profileSetting: "Paramètres du profil"
   privacySetting: "Paramètres de confidentialité"
   initialAccountSettingCompleted: "Configuration du profil terminée avec succès !"
@@ -1288,7 +1317,7 @@ _initialTutorial:
     doItToContinue: "Marquez le fichier joint comme sensible pour procéder."
   _done:
     title: "Le tutoriel est terminé ! 🎉"
-    description: "Les fonctionnalités introduites ici ne sont que quelques-unes. Pour savoir plus sur l'utilisation de Misskey, veuillez consulter {lien}."
+    description: "Les fonctionnalités introduites ici ne sont que quelques-unes. Pour savoir plus sur l'utilisation de Misskey, veuillez consulter {link}."
 _timelineDescription:
   home: "Sur le fil principal, vous pouvez voir les notes des utilisateurs auxquels vous êtes abonné·e."
   local: "Sur le fil local, vous pouvez voir les notes de tous les utilisateurs sur cette instance."
@@ -1449,7 +1478,7 @@ _role:
   edit: "Modifier le rôle"
   name: "Nom du rôle"
   description: "Description du rôle"
-  permission: "Rôle et autorisations"
+  permission: "Autorisations du rôle"
   assignTarget: "Attribuer"
   manual: "Manuel"
   manualRoles: "Rôles manuels"
@@ -1984,7 +2013,7 @@ _notification:
   unreadAntennaNote: "Antenne {name}"
   roleAssigned: "Rôle attribué"
   emptyPushNotificationMessage: "Les notifications push ont été mises à jour"
-  achievementEarned: "Accomplissement"
+  achievementEarned: "Accomplissement déverrouillé"
   testNotification: "Tester la notification"
   reactedBySomeUsers: "{n} utilisateur·rice·s ont réagi"
   renotedBySomeUsers: "{n} utilisateur·rice·s ont renoté"
@@ -2001,7 +2030,7 @@ _notification:
     receiveFollowRequest: "Demande d'abonnement reçue"
     followRequestAccepted: "Demande d'abonnement acceptée"
     roleAssigned: "Rôle reçu"
-    achievementEarned: "Accomplissement"
+    achievementEarned: "Déverrouillage d'accomplissement"
     app: "Notifications provenant des apps"
   _actions:
     followBack: "Suivre"
@@ -2139,5 +2168,5 @@ _dataSaver:
     title: "Mise en évidence du code"
     description: "Si la notation de mise en évidence du code est utilisée, par exemple dans la MFM, elle ne sera pas chargée tant qu'elle n'aura pas été tapée. La mise en évidence du code nécessite le chargement du fichier de définition de chaque langue à mettre en évidence, mais comme ces fichiers ne sont plus chargés automatiquement, on peut s'attendre à une réduction du trafic de données."
 _reversi:
+  waitingBoth: "Préparez-vous"
   total: "Total"
-
diff --git a/locales/hr-HR.yml b/locales/hr-HR.yml
index 881aa8464e..9cfebdd01a 100644
--- a/locales/hr-HR.yml
+++ b/locales/hr-HR.yml
@@ -3,4 +3,3 @@ _lang_: "japanski"
 ok: "OK"
 gotIt: "Razumijem"
 cancel: "otkazati"
-
diff --git a/locales/ht-HT.yml b/locales/ht-HT.yml
index 1698c9f280..e3595c79b6 100644
--- a/locales/ht-HT.yml
+++ b/locales/ht-HT.yml
@@ -16,4 +16,3 @@ _2fa:
   renewTOTPCancel: "Sispann"
 _widgets:
   profile: "pwofil"
-
diff --git a/locales/hu-HU.yml b/locales/hu-HU.yml
index 2f7006484a..023a91494d 100644
--- a/locales/hu-HU.yml
+++ b/locales/hu-HU.yml
@@ -102,4 +102,3 @@ _deck:
   _columns:
     notifications: "Értesítések"
     tl: "Idővonal"
-
diff --git a/locales/id-ID.yml b/locales/id-ID.yml
index 514a2866ca..f8e645d63b 100644
--- a/locales/id-ID.yml
+++ b/locales/id-ID.yml
@@ -400,6 +400,7 @@ name: "Nama"
 antennaSource: "Sumber Antenna"
 antennaKeywords: "Kata kunci yang diterima"
 antennaExcludeKeywords: "Kata kunci yang dikecualikan"
+antennaExcludeBots: "Kecualikan akun bot"
 antennaKeywordsDescription: "Pisahkan dengan spasi untuk kondisi AND. Pisahkan dengan baris baru untuk kondisi OR."
 notifyAntenna: "Beritahu untuk catatan baru"
 withFileAntenna: "Hanya tampilkan catatan dengan berkas yang dilampirkan"
@@ -494,6 +495,7 @@ emojiStyle: "Gaya emoji"
 native: "Native"
 disableDrawer: "Jangan gunakan menu bergaya laci"
 showNoteActionsOnlyHover: "Hanya tampilkan aksi catatan saat ditunjuk"
+showReactionsCount: "Lihat jumlah reaksi dalam catatan"
 noHistory: "Tidak ada riwayat"
 signinHistory: "Riwayat masuk"
 enableAdvancedMfm: "Nyalakan MFM tingkat lanjut"
@@ -991,6 +993,7 @@ neverShow: "Jangan tampilkan lagi"
 remindMeLater: "Mungkin nanti"
 didYouLikeMisskey: "Apakah kamu mulai menyukai Misskey?"
 pleaseDonate: "{host} menggunakan perangkat lunak bebas yaitu Misskey. Kami sangat mengapresiasi sekali donasi dari kamu agar pengembangan Misskey tetap dapat berlanjut!"
+correspondingSourceIsAvailable: "Sumber kode terkait tersedia di {anchor}"
 roles: "Peran"
 role: "Peran"
 noRole: "Peran tidak temukan"
@@ -1042,6 +1045,7 @@ sensitiveWords: "Kata sensitif"
 sensitiveWordsDescription: "Visibilitas dari semua catatan mengandung kata yang telah diatur akan dijadikan \"Beranda\" secara otomatis. Kamu dapat mendaftarkan kata tersebut lebih dari satu dengan menuliskannya di baris baru."
 sensitiveWordsDescription2: "Menggunakan spasi akan membuat ekspresi AND dan kata kunci disekitarnya dengan garis miring akan mengubahnya menjadi ekspresi reguler."
 prohibitedWords: "Kata yang dilarang"
+prohibitedWordsDescription: "Menyalakan kesalahan ketika mencoba untuk memposting catatan dengan set kata-kata yang termasuk. Beberapa kata dapat diatur dan dipisahkan dengan baris baru."
 prohibitedWordsDescription2: "Menggunakan spasi akan membuat ekspresi AND dan kata kunci disekitarnya dengan garis miring akan mengubahnya menjadi ekspresi reguler."
 hiddenTags: "Tagar tersembunyi"
 hiddenTagsDescription: "Pilih tanda yang mana akan tidak diperlihatkan dalam daftar tren.\nTanda lebih dari satu dapat didaftarkan dengan tiap baris."
@@ -1158,6 +1162,7 @@ showRenotes: "Tampilkan renote"
 edited: "Telah disunting"
 notificationRecieveConfig: "Pengaturan notifikasi"
 mutualFollow: "Saling mengikuti"
+followingOrFollower: "Mengikuti atau pengikut"
 fileAttachedOnly: "Hanya catatan dengan berkas"
 showRepliesToOthersInTimeline: "Tampilkan balasan ke pengguna lain dalam lini masa"
 hideRepliesToOthersInTimeline: "Sembunyikan balasan ke orang lain dari lini masa"
@@ -1167,6 +1172,12 @@ confirmShowRepliesAll: "Operasi ini tidak dapat diubah. Apakah kamu yakin untuk
 confirmHideRepliesAll: "Operasi ini tidak dapat diubah. Apakah kamu yakin untuk menyembunyikan balasan ke lainnya dari semua orang yang kamu ikuti di lini masa?"
 externalServices: "Layanan eksternal"
 sourceCode: "Sumber kode"
+sourceCodeIsNotYetProvided: "Sumber kode belum tersedia. Hubungi admin untuk memperbaiki masalah ini."
+repositoryUrl: "URL Repositori"
+repositoryUrlDescription: "Jika kamu menggunakan Misskey begitu saja (tanpa ada perubahan dalam kode sumber), masukkan https://github.com/misskey-dev/misskey"
+repositoryUrlOrTarballRequired: "Apabila kamu masih mempublikasikan repositori, kamu setidaknya harus menyediakan berkas tarball. Lihat .config/example.yml untuk informasi lebih lanjut."
+feedback: "Umpan balik"
+feedbackUrl: "URL Umpan balik"
 impressum: "Impressum"
 impressumUrl: "Tautan Impressum"
 impressumDescription: "Pada beberapa negara seperti Jerman, inklusi dari informasi kontak operator (sebuah Impressum) diperlukan secara legal untuk situs web komersil."
@@ -1202,6 +1213,8 @@ soundWillBePlayed: "Suara yang akan dimainkan"
 showReplay: "Lihat tayangan ulang"
 replay: "Tayangan ulang"
 replaying: "Menayangkan Ulang"
+endReplay: "Keluat dari tayangan ulang"
+copyReplayData: "Salin data tayangan ulang"
 ranking: "Peringkat"
 lastNDays: "{n} hari terakhir"
 backToTitle: "Ke Judul"
@@ -1209,11 +1222,34 @@ hemisphere: "Letak kamu tinggal"
 withSensitive: "Lampirkan catatan dengan berkas sensitif"
 userSaysSomethingSensitive: "Postingan oleh {name} mengandung konten sensitif"
 enableHorizontalSwipe: "Geser untuk mengganti tab"
+loading: "Memuat..."
 surrender: "Batalkan"
+gameRetry: "Coba lagi"
+notUsePleaseLeaveBlank: "Kosongi bila tidak digunakan"
+useTotp: "Gunakan TOTP"
+useBackupCode: "Gunakan kode cadangan"
+launchApp: "Luncurkan Aplikasi"
+useNativeUIForVideoAudioPlayer: "Gunakan antarmuka peramban ketika memainkan video dan audio"
+keepOriginalFilename: "Simpan nama berkas asli"
+keepOriginalFilenameDescription: "Apabila pengaturan ini dimatikan, nama berkas akan diganti dengan string acak secara otomatis ketika kamu mengunggah berkas."
+noDescription: "Tidak ada deskripsi"
+alwaysConfirmFollow: "Selalu konfirmasi ketika mengikuti"
+inquiry: "Hubungi kami"
 _bubbleGame:
   howToPlay: "Cara bermain"
+  hold: "Tahan"
+  _score:
+    score: "Skor"
+    scoreYen: "Jumlah uang didapat"
+    highScore: "Skor tertinggi"
+    maxChain: "Jumlah skor berantai"
+    yen: "{yen} Yen"
+    estimatedQty: "{qty} buah"
+    scoreSweets: "{onigiriQtyWithUnit} onigiri"
   _howToPlay:
     section1: "Atur posisi dan jatuhkan obyek ke dalam kotak."
+    section2: "Ketika dua obyek menyentuh tipe yang sama satu sama lain, obyek tersebut akan berganti dan kamu mendapatkan poin skor."
+    section3: "Permainan berakhir jika obyek memenuhi kotak. Capai skor tertinggi dengan menggabungkan obyek bersama sambil menghindari obyek tersebut memenuhi kotak permainan!"
 _announcement:
   forExistingUsers: "Hanya pengguna yang telah ada"
   forExistingUsersDescription: "Pengumuman ini akan dimunculkan ke pengguna yang sudah ada dari titik waktu publikasi jika dinyalakan. Apabila dimatikan, mereka yang baru mendaftar setelah publikasi ini akan juga melihatnya."
@@ -1257,26 +1293,59 @@ _initialTutorial:
     reply: "Klik pada tombol ini untuk membalas ke sebuah pesan. Bisa juga untuk membalas ke sebuah balasan dan melanjutkannya seperti percakapan selayaknya utas."
     renote: "Kamu dapat membagikan catatan ke lini masa milikmu. Kamu juga dapat mengutipnya dengan komentarmu."
     reaction: "Kamu dapat menambahkan reaksi ke Catatan. Detil lebih lanjut akan dijelaskan di halaman berikutnya."
+    menu: "Kamu dapat melihat detil catatan, menyalin tautan, dan melakukan aksi lainnya."
   _reaction:
     title: "Apa itu Reaksi?"
+    description: "Catatan dapat direaksi dengan berbagai emoji. Reaksi memperbolehkan kamu untuk mengekspresikan nuansa yang tidak dapat disampaikan hanya dengan sebuah \"suka\"."
+    letsTryReacting: "Reaksi dapat ditambahkan dengan mengklik tombol '+' pada catatan. Coba lakukan mereaksi contoh catatan ini!"
+    reactToContinue: "Tambahkan reaksi untuk melanjutkan."
+    reactNotification: "Kamu akan menerima notifikasi real0time ketika seseorang mereaksi catatan kamu."
+    reactDone: "Kamu dapat mengurungkan reaksi dengan menekan tombol '-'."
   _timeline:
     title: "Konsep Lini Masa"
+    description1: "Misskey menyediakan berbagai lini masa sesuai dengan penggunaan (beberapa mungkin tidak tersedia karena bergantung dengan kebijakan peladen)."
+    home: "Kamu dapat melihat catatan dari akun yang kamu ikuti."
+    local: "Kamu dapat melihat catatan dari semua pengguna yang ada pada peladen ini."
+    social: "Catatan dari linimasa Beranda dan Lokal akan ditampilkan."
+    global: "Kamu dapat melihat catatan dari semua peladen yang terhubung."
+    description2: "Kamu dapat mengganti linimasa di bagian atas layar kamu kapan saja."
+    description3: "Sebagai tambahan, terdapat juga linimasa daftar dan linimasa kanal. Untuk detil lebih lanjut, silahkan melihat ke tautan berikut: {link}."
   _postNote:
     title: "Pengaturan posting Catatan"
+    description1: "Ketika memposting catatan ke Misskey, terdapat beberapa opsi yang tersedia. Form posting terlihat seperti ini."
     _visibility:
+      description: "Kamu dapat membatasi siapa yang dapat melihat catatan kamu."
       public: "Perlihatkan catatan ke semua pengguna."
       home: "Hanya publik ke lini masa Beranda. Pengguna yang mengunjungi profilmu melalui pengikut dan renote dapat melihatnya."
       followers: "Perlihatkan ke pengikut saja. Hanya pengikut yang dapat melihat postinganmu dan tidak dapat direnote oleh siapapun."
       direct: "Hanya perlihatkan ke pengguna spesifik dan penerima akan diberi tahu. Dapat juga digunakan sebagai alternatif dari pesan langsung."
+      doNotSendConfidencialOnDirect1: "Hati-hati ketika mengirim informasi yang sensitif!"
+      doNotSendConfidencialOnDirect2: "Admin dari peladen dapat melihat apa yang kamu tulis. Hati-hati dengan informasi sensitif ketika mengirimkan catatan langsung kepada pengguna pada peladen yang tidak dipercaya."
+      localOnly: "Memposting dengan opsi ini tidak akan memfederasi catatan ke peladen lain. Pengguna pada peladen lain tidak akan dapat melihat catatan ini secara langsung, meskipun dengan pengaturan visibilitas yang sudah diatur di atas."
     _cw:
       title: "Peringatan Konten (CW)"
+      description: "Alih-alih isinya, konten yang ditulis dalam kolom 'komentar' akan ditampilkan. Menekan 'Selebihnya' akan menampilkan isi konten."
       _exampleNote:
         cw: "Peringatan: Bikin Lapar!"
         note: "Baru aja makan donat berlapis coklat 🍩😋"
+      useCases: "Fungsi ini digunakan ketika mengikutik panduan peladen untuk catatan yang dibutuhkan atau untuk membatasi diri dari teks sensitif atau spoiler."
   _howToMakeAttachmentsSensitive:
     title: "Bagaimana menandai lampiran sebagai sensitif?"
+    description: "Fungsi ini digunakan untuk lampiran yang dibutuhkan oleh panduan peladen atau sesuatu yang seharusnya tidak boleh dibiarkan begitu saja dengan cara menambahkan penanda \"sensitif\"."
+    tryThisFile: "Coba tandai gambar yang dilampirkan pada form ini sebagai sensitif!"
+    _exampleNote:
+      note: "Ups, kesalahan banget buka penutup wadah natto..."
+    method: "Untuk menandai lampiran sebagai sensitif, klik gambar pada berkas, buka menu, lalu klik \"Tandai sebagai sensitif\"."
+    sensitiveSucceeded: "Ketika melampirkan berkas, mohon atur sensitifitas sesuai dengan panduan peladen."
+    doItToContinue: "Tandai berkas terlampir sebagai sensitif untuk melanjutkan."
   _done:
     title: "Kamu telah menyelesaikan tutorial! 🎉"
+    description: "Fungsi yang diperkenalkan di sini merupakan sebagian kecil dari fitur yang ada. Untuk pemahaman lebih detil dalam menggunakan Misskey, kamu dapat merujuk ke {link}."
+_timelineDescription:
+  home: "Pada linimasa Beranda, kamu dapat melihat catatan dari akun yang kamu ikuti."
+  local: "Pada linimasa Lokal, kamu dapat melihat catatan dari semua pengguna yang ada pada peladen ini."
+  social: "Linimasa sosial menampilkan catatan dari kedua linimasa Beranda dan Lokal."
+  global: "Pada linimasa Global, kamu dapat melihat catatan dari semua peladen yang terhubung."
 _serverRules:
   description: "Daftar peraturan akan ditampilkan sebelum pendaftaran. Mengatur ringkasan dari Syarat dan Ketentuan sangat direkomendasikan."
 _serverSettings:
@@ -1288,6 +1357,9 @@ _serverSettings:
   manifestJsonOverride: "Ambil alih manifest.json"
   shortName: "Nama pendek"
   shortNameDescription: "Inisial untuk nama instansi yang dapat ditampilkan apabila nama lengkap resmi terlalu panjang."
+  fanoutTimelineDescription: "Dapat meningkatkan performa dalam pengambilan data linimasa dan mengurangi beban pada database ketika dinyalakan. Sebagai gantinya, penggunaan memory pada Redis akan meningkan. Pertimbangkan untuk menonaktifkan fitur ini jika mengalami kekurangan memori pada server atau menyebabkan server tidak stabil."
+  fanoutTimelineDbFallback: "Fallback ke database"
+  fanoutTimelineDbFallbackDescription: "Ketika diaktifkan, lini masa akan fallback ke database untuk melakukan kueri tambahan apabila linimasa tidak disimpan dalam cache. Menonaktifkan ini dapat mengurangi beban server dengan mengeliminasi proses fallback, namun dapat berakibat membatasi jarak data dari lini masa yang dapat diambil."
 _accountMigration:
   moveFrom: "Pindahkan akun lain ke akun ini"
   moveFromSub: "Buat alias ke akun lain"
@@ -1545,6 +1617,16 @@ _achievements:
     _smashTestNotificationButton:
       title: "Tes overflow"
       description: "Picu tes notifikasi secara berulang dalam waktu yang sangat pendek"
+    _tutorialCompleted:
+      title: "Ijazah Sekolah Dasar Misskey"
+      description: "Tutorial selesai"
+    _bubbleGameExplodingHead:
+      title: "🤯"
+      description: "Obyek paling terbesar di permainan gelembung"
+    _bubbleGameDoubleExplodingHead:
+      title: "Ganda 🤯"
+      description: "Dua dari obyek paling terbesar pada permainan gelembung di waktu yang sama"
+      flavor: "Kamu dapat mengisi kotak makan siang seperti ini 🤯 🤯."
 _role:
   new: "Buat peran"
   edit: "Sunting peran"
@@ -1555,7 +1637,9 @@ _role:
   assignTarget: "Tipe tugas"
   descriptionOfAssignTarget: "<b>Manual</b> untuk mengganti secara manual siapa yang mendapatkan peran ini dan siapa yang tidak.\n<b>Kondisional</b> untuk pengguna secara otomatis dimasukkan atau dihapus dari peran berdasarkan kondisi yang ditentukan."
   manual: "Manual"
+  manualRoles: "Peran manual"
   conditional: "Kondisional"
+  conditionalRoles: "Peran kondisional"
   condition: "Kondisi"
   isConditionalRole: "Ini adalah peran kondisional"
   isPublic: "Publikkan Peran"
@@ -1583,6 +1667,7 @@ _role:
     gtlAvailable: "Dapat melihat lini masa global"
     ltlAvailable: "Dapat melihat lini masa lokal"
     canPublicNote: "Dapat mengirim catatan publik"
+    mentionMax: "Jumlah maksimum sebutan dalam sebuah catatan"
     canInvite: "Dapat membuat kode undangan instansi"
     inviteLimit: "Batas jumlah undangan"
     inviteLimitCycle: "Interval Penerbitan Kode Undangan"
@@ -1604,9 +1689,16 @@ _role:
     canHideAds: "Dapat menyembunyikan iklan"
     canSearchNotes: "Penggunaan pencarian catatan"
     canUseTranslator: "Penggunaan penerjemah"
+    avatarDecorationLimit: "Jumlah maksimum dekorasi avatar yang dapat diterapkan"
   _condition:
+    roleAssignedTo: "Ditugaskan ke peran manual"
     isLocal: "Pengguna lokal"
     isRemote: "Pengguna remote"
+    isCat: "Pengguna Kucing"
+    isBot: "Pengguna Bot"
+    isSuspended: "Pengguna yang ditangguhkan"
+    isLocked: "Akun privat"
+    isExplorable: "Pengguna efektif yang akunnya dapat dicari"
     createdLessThan: "Telah berlalu kurang dari X sejak pembuatan akun"
     createdMoreThan: "Telah berlalu lebih dari X sejak pembuatan akun"
     followersLessThanOrEq: "Memiliki pengikut X atau kurang dari tersebut"
@@ -1632,6 +1724,7 @@ _emailUnavailable:
   disposable: "Alamat surel temporer tidak dapat digunakan"
   mx: "Peladen alamat surel ini tidak valid"
   smtp: "Peladen alamat surel ini tidak merespon"
+  banned: "Kamu tidak dapat mendaftar dengan alamat surel ini"
 _ffVisibility:
   public: "Terbitkan"
   followers: "Tampil untuk pengikut saja"
@@ -1675,6 +1768,7 @@ _plugin:
   installWarn: "Mohon jangan memasang plugin yang tidak dapat dipercayai."
   manage: "Manajemen plugin"
   viewSource: "Lihat sumber"
+  viewLog: "Tampilkan log"
 _preferencesBackups:
   list: "Cadangan yang dibuat"
   saveNew: "Simpan cadangan baru"
@@ -1704,10 +1798,13 @@ _aboutMisskey:
   contributors: "Kontributor utama"
   allContributors: "Seluruh kontributor"
   source: "Sumber kode"
+  original: "Asli"
+  thisIsModifiedVersion: "{name} menggunakan versi modifikasi dari Misskey yang asli."
   translation: "Terjemahkan Misskey"
   donate: "Donasi ke Misskey"
   morePatrons: "Kami sangat mengapresiasi dukungan dari banyak penolong lain yang tidak tercantum disini. Terima kasih! 🥰"
   patrons: "Pendukung"
+  projectMembers: "Anggota proyek"
 _displayOfSensitiveMedia:
   respect: "Sembunyikan media yang ditandai sensitif"
   ignore: "Tampilkan media yang ditandai sensitif"
@@ -1732,6 +1829,7 @@ _channel:
   notesCount: "terdapat {n} catatan"
   nameAndDescription: "Nama dan deskripsi"
   nameOnly: "Hanya nama"
+  allowRenoteToExternal: "Perbolehkan catat ulang dan kutipan di luar dari kanal"
 _menuDisplay:
   sideFull: "Horisontal"
   sideIcon: "Horisontal (Ikon)"
@@ -1860,7 +1958,6 @@ _2fa:
   registerTOTP: "Daftarkan aplikasi autentikator"
   step1: "Pertama, pasang aplikasi autentikasi (seperti {a} atau {b}) di perangkat kamu."
   step2: "Lalu, pindai kode QR yang ada di layar."
-  step2Click: "Mengeklik kode QR ini akan membolehkanmu untuk mendaftarkan 2FA ke security-key atau aplikasi autentikator ponsel."
   step2Uri: "Masukkan URI berikut jika kamu menggunakan program desktop"
   step3Title: "Masukkan kode autentikasi"
   step3: "Masukkan token yang telah disediakan oleh aplikasimu untuk menyelesaikan pemasangan."
@@ -1884,6 +1981,7 @@ _2fa:
   backupCodesDescription: "Kamu dapat menggunakan kode ini untuk mendapatkan akses ke akun kamu apabila berada dalam situasi tidak dapat menggunakan aplikasi autentikasi 2-faktor yang kamu miliki. Setiap kode hanya dapat digunakan satu kali. Mohon simpan kode ini di tempat yang aman."
   backupCodeUsedWarning: "Kode cadangan telah digunakan. Mohon mengatur ulang autentikasi 2-faktor secepatnya apabila kamu sudah tidak dapat menggunakannya lagi."
   backupCodesExhaustedWarning: "Semua kode cadangan telah digunakan. Apabila kamu kehilangan akses pada aplikasi autentikasi 2-faktor milikmu, kamu tidak dapat mengakses akun ini lagi. Mohon atur ulang autentikasi 2-faktor kamu."
+  moreDetailedGuideHere: "Berikut panduan detilnya"
 _permissions:
   "read:account": "Lihat informasi akun"
   "write:account": "Sunting informasi akun"
@@ -2145,6 +2243,7 @@ _play:
   title: "Judul"
   script: "Script"
   summary: "Deskripsi"
+  visibilityDescription: "Membuat catatan ini privat berarti tidak akan terlihat pada profil kamu, namun siapapun yang memiliki URL dari catatan ini akan dapat mengaksesnya."
 _pages:
   newPage: "Buat halaman baru"
   editPage: "Sunting halaman"
@@ -2189,6 +2288,8 @@ _pages:
     section: "Bagian"
     image: "Gambar"
     button: "Tombol"
+    dynamic: "Blok Dinamis"
+    dynamicDescription: "Blok ini telah dihapus. Mohon gunakan {play} dari sekarang."
     note: "Catatan yang ditanam"
     _note:
       id: "ID Catatan"
@@ -2218,8 +2319,10 @@ _notification:
   sendTestNotification: "Kirim tes notifikasi"
   notificationWillBeDisplayedLikeThis: "Notifikasi akan terlihat seperti ini"
   reactedBySomeUsers: "{n} orang memberikan reaksi"
+  likedBySomeUsers: "{n} pengguna menyukai catatan kamu"
   renotedBySomeUsers: "{n} orang telah merenote"
   followedBySomeUsers: "{n} orang telah mengikuti"
+  flushNotification: "Bersihkan notifikasi"
   _types:
     all: "Semua"
     note: "Catatan baru"
@@ -2317,6 +2420,7 @@ _moderationLogTypes:
   resetPassword: "Atur ulang kata sandi"
   suspendRemoteInstance: "Instansi luar telah ditangguhkan"
   unsuspendRemoteInstance: "Instansi luar batal ditangguhkan"
+  updateRemoteInstanceNote: "Catatan moderasi telah diperbaharui untuk peladen luar."
   markSensitiveDriveFile: "Berkas ditandai sensitif"
   unmarkSensitiveDriveFile: "Berkas batal ditandai sensitif"
   resolveAbuseReport: "Laporan terselesaikan"
@@ -2428,4 +2532,35 @@ _reversi:
   isLlotheo: "Pemain dengan batu yang sedikit menang (Llotheo)"
   loopedMap: "Peta melingkar"
   canPutEverywhere: "Keping dapat ditaruh dimana saja"
-
+  timeLimitForEachTurn: "Batas waktu untuk gantian"
+  freeMatch: "Pertandingan bebas"
+  lookingForPlayer: "Mencari lawan..."
+  gameCanceled: "Permainan ini telah dibatalkan."
+  shareToTlTheGameWhenStart: "Bagikan permainan ke lini masa ketika dimulai"
+  iStartedAGame: "Permainan telah dimulai! #MisskeyReversi"
+  opponentHasSettingsChanged: "Lawan telah mengganti pengaturan mereka."
+  allowIrregularRules: "Aturan non-reguler (bebas sepenuhnya)"
+  disallowIrregularRules: "Tanpa aturan non-reguler"
+  showBoardLabels: "Tampilkan penomoran baris dan kolom pada papan"
+  useAvatarAsStone: "Ubah batu menjadi avatar pengguna"
+_offlineScreen:
+  title: "Luring - tidak dapat terhubung ke peladen"
+  header: "Tidak dapat tersambung ke server"
+_urlPreviewSetting:
+  title: "Pengaturan pratinjau URL"
+  enable: "Aktifkan pratinjau URL"
+  timeout: "Waktu timeout pratinjau URL (ms)"
+  timeoutDescription: "Apabila ini memakan waktu lama dari nilai yang ditentukan untuk mendapatkan pratinjau, pratinjau tidak akan dibuat."
+  maximumContentLength: "Content-Length Maksimum (bytes)"
+  maximumContentLengthDescription: "Apabila Content-Length lebih besar dari nilai ini, pratinjau tidak akan dibuat."
+  requireContentLength: "Buat pratinjau hanya ketika Content-Length dapat didapatkan"
+  requireContentLengthDescription: "Apabila peladen lain tidak memberika Content-Length, pratinjau tidak akan dibuat."
+  userAgent: "User-Agent"
+  userAgentDescription: "Atur User-Agent yang digunakan untuk mengambil pratinjau. Apabila dibiarkan kosong, User-Agent bawaan akan digunakan."
+  summaryProxy: "Titik akhir proksi yang membuat pratinjau"
+  summaryProxyDescription: "Bukan untuk Misskey, namun untuk menghasilkan pratinjau menggunakan Summaly Proxy."
+  summaryProxyDescription2: "Parameter berikut tertautkan dengan proksi sebagai string kueri. Apabila proksi tidak mendukung tersebut, nilai di dalamnya diabaikan."
+_mediaControls:
+  pip: "Gambar dalam Gambar"
+  playbackRate: "Kecepatan Pemutaran"
+  loop: "Ulangi Pemutaran"
diff --git a/locales/it-IT.yml b/locales/it-IT.yml
index 480d11b6ba..0a250a2e28 100644
--- a/locales/it-IT.yml
+++ b/locales/it-IT.yml
@@ -85,7 +85,7 @@ note: "Nota"
 notes: "Note"
 following: "Follow"
 followers: "Follower"
-followsYou: "Segue"
+followsYou: "Follower"
 createList: "Aggiungi una nuova lista"
 manageLists: "Gestisci liste"
 error: "Errore"
@@ -134,12 +134,12 @@ deleteFile: "File da Drive eliminato"
 markAsSensitive: "Segna come esplicito"
 unmarkAsSensitive: "Non segnare come esplicito "
 enterFileName: "Nome del file"
-mute: "Silenzia"
+mute: "Silenziare"
 unmute: "Riattiva l'audio"
-renoteMute: "Silenzia le Rinota"
+renoteMute: "Silenziare le Rinota"
 renoteUnmute: "Non silenziare le Rinota"
-block: "Blocca"
-unblock: "Sblocca"
+block: "Bloccare"
+unblock: "Sbloccare"
 suspend: "Sospensione"
 unsuspend: "Revoca la sospensione"
 blockConfirm: "Vuoi davvero bloccare il profilo?"
@@ -200,8 +200,8 @@ charts: "Grafici"
 perHour: "orario"
 perDay: "giornaliero"
 stopActivityDelivery: "Interrompi la distribuzione di attività"
-blockThisInstance: "Blocca questa istanza"
-silenceThisInstance: "Silenzia l'istanza"
+blockThisInstance: "Bloccare l'istanza"
+silenceThisInstance: "Silenziare l'istanza"
 operations: "Operazioni"
 software: "Software"
 version: "Versione"
@@ -223,7 +223,7 @@ blockedInstances: "Istanze bloccate"
 blockedInstancesDescription: "Elenca le istanze che vuoi bloccare, una per riga. Esse non potranno più interagire con la tua istanza."
 silencedInstances: "Istanze silenziate"
 silencedInstancesDescription: "Elenca i nomi host delle istanze che vuoi silenziare. Tutti i profili nelle istanze silenziate vengono trattati come tali. Possono solo inviare richieste di follow e menzionare soltanto i profili locali che seguono. Le istanze bloccate non sono interessate."
-muteAndBlock: "Silenziati / Bloccati"
+muteAndBlock: "Silenziare e bloccare"
 mutedUsers: "Profili silenziati"
 blockedUsers: "Profili bloccati"
 noUsers: "Non ci sono profili"
@@ -400,6 +400,7 @@ name: "Nome"
 antennaSource: "Fonte dell'antenna"
 antennaKeywords: "Parole chiavi da ricevere"
 antennaExcludeKeywords: "Parole chiavi da escludere"
+antennaExcludeBots: "Escludere i Bot"
 antennaKeywordsDescription: "Sparando con uno spazio indichi la condizione E (and). Separando con un a capo, indichi la condizione O (or)."
 notifyAntenna: "Invia notifiche delle nuove note"
 withFileAntenna: "Solo note con file in allegato"
@@ -410,7 +411,7 @@ withReplies: "Includere le risposte"
 connectedTo: "Connessione ai seguenti profili:"
 notesAndReplies: "Note e risposte"
 withFiles: "Con allegati"
-silence: "Silenzia"
+silence: "Silenziare"
 silenceConfirm: "Vuoi davvero silenziare questo profilo?"
 unsilence: "Riattiva"
 unsilenceConfirm: "Vuoi davvero riattivare questo profilo?"
@@ -450,7 +451,7 @@ share: "Condividi"
 notFound: "Non trovato"
 notFoundDescription: "Nessuna pagina corrisponde all'URL indicata."
 uploadFolder: "Destinazione caricamento predefinita"
-markAsReadAllNotifications: "Segna tutte le notifiche come lette"
+markAsReadAllNotifications: "Segnare tutte le notifiche come lette"
 markAsReadAllUnreadNotes: "Segna tutte le note come lette"
 markAsReadAllTalkMessages: "Segna tutte le chat come lette"
 help: "Guida"
@@ -494,6 +495,7 @@ emojiStyle: "Stile emoji"
 native: "Nativo"
 disableDrawer: "Non mostrare il menù sul drawer"
 showNoteActionsOnlyHover: "Mostra le azioni delle Note solo al passaggio del mouse"
+showReactionsCount: "Visualizza il numero di reazioni su una nota"
 noHistory: "Nessuna cronologia"
 signinHistory: "Storico degli accessi al profilo"
 enableAdvancedMfm: "Attiva MFM avanzati"
@@ -577,7 +579,7 @@ scratchpadDescription: "Lo Scratchpad offre un ambiente per esperimenti di AiScr
 output: "Uscita"
 script: "Script"
 disablePagesScript: "Disabilita AiScript nelle pagine"
-updateRemoteUser: "Aggiorna le informazioni dal profilo remoto"
+updateRemoteUser: "Aggiorna dati dal profilo remoto"
 unsetUserAvatar: "Rimozione foto profilo"
 unsetUserAvatarConfirm: "Vuoi davvero rimuovere la foto profilo?"
 unsetUserBanner: "Rimuovi intestazione profilo"
@@ -587,7 +589,7 @@ deleteAllFilesConfirm: "Vuoi davvero eliminare tutti i file?"
 removeAllFollowing: "Annulla tutti i follow"
 removeAllFollowingDescription: "Cancella tutti i follows del server {host}. Per favore, esegui se, ad esempio, l'istanza non esiste più."
 userSuspended: "L'utente è in sospensione"
-userSilenced: "Profilo silente."
+userSilenced: "Profilo silenziato"
 yourAccountSuspendedTitle: "Questo profilo è sospeso"
 yourAccountSuspendedDescription: "Questo profilo è stato sospeso a causa di una violazione del regolamento. Per informazioni, contattare l'amministrazione. Si prega di non creare un nuovo account."
 tokenRevoked: "Il token non è valido"
@@ -657,7 +659,7 @@ wordMute: "Filtri parole"
 hardWordMute: "Filtro parole forte"
 regexpError: "errore regex"
 regexpErrorDescription: "Si è verificato un errore nell'espressione regolare alla riga {line} della parola muta {tab}:"
-instanceMute: "Silenzia l'istanza"
+instanceMute: "Silenziare l'istanza"
 userSaysSomething: "{name} ha parlato"
 makeActive: "Attiva"
 display: "Visualizza"
@@ -682,14 +684,14 @@ fileIdOrUrl: "ID o URL del file"
 behavior: "Comportamento"
 sample: "Esempio"
 abuseReports: "Segnalazioni"
-reportAbuse: "Segnala"
-reportAbuseRenote: "Segnala la Rinota"
-reportAbuseOf: "Segnala {name}"
+reportAbuse: "Segnalare"
+reportAbuseRenote: "Segnalare la Rinota"
+reportAbuseOf: "Segnalare {name}"
 fillAbuseReportDescription: "Per favore, spiegaci il motivo della segnalazione. Se riguarda una Nota precisa, indica anche l'indirizzo URL."
 abuseReported: "La segnalazione è stata inviata. Grazie."
 reporter: "il corrispondente"
-reporteeOrigin: "Origine del segnalato"
-reporterOrigin: "Origine del segnalatore"
+reporteeOrigin: "Segnalazione a"
+reporterOrigin: "Segnalazione da"
 forwardReport: "Inoltro di un report a un'istanza remota."
 forwardReportIsAnonymous: "L'istanza remota non vedrà le tue informazioni, apparirai come profilo di sistema, anonimo."
 send: "Inviare"
@@ -861,7 +863,7 @@ troubleshooting: "Risoluzione problemi"
 useBlurEffect: "Utilizza effetto sfocatura"
 learnMore: "Più dettagli"
 misskeyUpdated: "Misskey è stato aggiornato!"
-whatIsNew: "Visualizza le informazioni sull'aggiornamento"
+whatIsNew: "Informazioni sull'aggiornamento"
 translate: "Traduci"
 translatedFrom: "Traduzione da {x}"
 accountDeletionInProgress: "È in corso l'eliminazione del profilo"
@@ -887,7 +889,7 @@ manageAccounts: "Gestisci i profili"
 makeReactionsPublic: "Pubblicare la lista delle reazioni."
 makeReactionsPublicDescription: "La lista delle reazioni che avete fatto è a disposizione di tutti."
 classic: "Classico"
-muteThread: "Silenzia conversazione"
+muteThread: "Silenziare conversazione"
 unmuteThread: "Riattiva la conversazione"
 followingVisibility: "Visibilità dei profili seguiti"
 followersVisibility: "Visibilità dei profili che ti seguono"
@@ -969,11 +971,11 @@ shuffle: "Casuale"
 account: "Account"
 move: "Sposta"
 pushNotification: "Notifiche Push"
-subscribePushNotification: "Attiva le notifiche push"
-unsubscribePushNotification: "Disattiva le notifiche push"
+subscribePushNotification: "Attivare le notifiche push"
+unsubscribePushNotification: "Disattivare le notifiche push"
 pushNotificationAlreadySubscribed: "Le notifiche push sono già attivate"
 pushNotificationNotSupported: "Il client o il server non supporta le notifiche push"
-sendPushNotificationReadMessage: "Elimina le notifiche push dopo la relativa lettura"
+sendPushNotificationReadMessage: "Eliminare le notifiche push dopo la relativa lettura"
 sendPushNotificationReadMessageCaption: "Se possibile, verrà mostrata brevemente una notifica con il testo \"{emptyPushNotificationMessage}\". Potrebbe influire negativamente sulla durata della batteria."
 windowMaximize: "Ingrandisci"
 windowMinimize: "Contrai finestra"
@@ -1160,6 +1162,7 @@ showRenotes: "Includi le Rinota"
 edited: "Modificato"
 notificationRecieveConfig: "Preferenze di notifica"
 mutualFollow: "Follow reciproco"
+followingOrFollower: "Following o Follower"
 fileAttachedOnly: "Solo con allegati"
 showRepliesToOthersInTimeline: "Risposte altrui nella TL"
 hideRepliesToOthersInTimeline: "Nascondi Riposte altrui nella TL"
@@ -1210,6 +1213,8 @@ soundWillBePlayed: "Con musica ed effetti sonori"
 showReplay: "Vedi i replay"
 replay: "Replay"
 replaying: "Replay in corso"
+endReplay: "Termina replay"
+copyReplayData: "Copia replay"
 ranking: "Classifica"
 lastNDays: "Ultimi {n} giorni"
 backToTitle: "Torna al titolo"
@@ -1217,9 +1222,28 @@ hemisphere: "Geolocalizzazione"
 withSensitive: "Mostra le Note con allegati espliciti"
 userSaysSomethingSensitive: "Note da {name} con allegati espliciti"
 enableHorizontalSwipe: "Trascina per invertire i tab"
+loading: "Caricamento"
 surrender: "Annulla"
+gameRetry: "Riprova"
+notUsePleaseLeaveBlank: "Lasciare vuoto, se non in uso"
+useTotp: "Usare il codice OTP"
+useBackupCode: "Usare il codice usa-e-getta"
+launchApp: "Esegui l'App"
+useNativeUIForVideoAudioPlayer: "Riprodurre audio/video usando le funzionalità del browser"
+keepOriginalFilename: "Mantieni il nome file originale"
+keepOriginalFilenameDescription: "Disattivandola, i file verranno caricati usando nomi casuali."
+noDescription: "Manca la descrizione"
 _bubbleGame:
   howToPlay: "Come giocare"
+  hold: "Tieni"
+  _score:
+    score: "Punteggio"
+    scoreYen: "Capitale"
+    highScore: "Punteggio migliore"
+    maxChain: "Miglior combo"
+    yen: "{yen}¥"
+    estimatedQty: "{qty} punti"
+    scoreSweets: "Onigiri {onigiriQtyWithUnit}"
   _howToPlay:
     section1: "Scegli la posizione e rilascia l'oggetto nel contenitore."
     section2: "Se due oggetti dello stesso tipo si toccano, si trasformano in un oggetto diverso, aumentando il punteggio."
@@ -1235,7 +1259,7 @@ _announcement:
   readConfirmText: "Hai già letto \"{title}˝?"
   shouldNotBeUsedToPresentPermanentInfo: "Ti consigliamo di utilizzare gli annunci per pubblicare informazioni tempestive e limitate nel tempo, anziché informazioni importanti a lungo andare nel tempo, poiché potrebbero risultare difficili da ritrovare e peggiorare la fruibilità del servizio, specialmente alle nuove persone iscritte."
   dialogAnnouncementUxWarn: "Ti consigliamo di usarli con cautela, poiché è molto probabile che avere più di un annuncio in stile \"finestra di dialogo\" peggiori sensibilmente la fruibilità del servizio, specialmente alle nuove persone iscritte."
-  silence: "Silenzia gli annunci"
+  silence: "Silenziare gli annunci"
   silenceDescription: "Se attivi questa opzione, non riceverai notifiche sugli annunci, evitando di contrassegnarle come già lette."
 _initialAccountSetting:
   accountCreated: "Il tuo profilo è stato creato!"
@@ -1274,14 +1298,14 @@ _initialTutorial:
     letsTryReacting: "Puoi aggiungere una Reazione cliccando il bottone \"+\" (più) della relativa Nota. Prova ad aggiungerne una a questa Nota di esempio!"
     reactToContinue: "Aggiungere la Reazione ti consentirà di procedere col tutorial."
     reactNotification: "Quando qualcuno reagisce alle tue Note, ricevi una notifica in tempo reale."
-    reactDone: "Puoi annullare la tua Reazione premendo il bottone \"ー\" (meno)"
+    reactDone: "Annulla la tua Reazione premendo il bottone \"ー\" (meno)"
   _timeline:
     title: "Come funziona la Timeline"
     description1: "Misskey fornisce alcune Timeline (sequenze cronologiche di Note). Una di queste potrebbe essere stata disattivata dagli amministratori."
-    home: "Puoi vedere le Note provenienti dai profili che segui (follow)."
-    local: "Puoi vedere tutte le Note pubblicate dai profili di questa istanza."
-    social: "Puoi vedere sia le Note della Timeline Home che quelle della Timeline Locale, insieme!"
-    global: "Puoi vedere le Note da pubblicate da tutte le altre istanze federate con la nostra."
+    home: "le Note provenienti dai profili che segui (follow)."
+    local: "tutte le Note pubblicate dai profili di questa istanza."
+    social: "sia le Note della Timeline Home che quelle della Timeline Locale, insieme!"
+    global: "le Note da pubblicate da tutte le altre istanze federate con la nostra."
     description2: "Nella parte superiore dello schermo, puoi scegliere una Timeline o l'altra in qualsiasi momento."
     description3: "Ci sono anche sequenze temporali di elenchi, sequenze temporali di canali, ecc. Per ulteriori dettagli, consultare il {link}.\nPuoi vedere anche Timeline delle liste di profili (se ne hai create), canali, ecc... Per i dettagli, visita {link}."
   _postNote:
@@ -1305,13 +1329,13 @@ _initialTutorial:
       useCases: "Utilizzalo per chiarire il contenuto della Nota, prima che sia letta. Come richiesto dal regolamento del server o per autoregolamentare spoiler e testi troppo espliciti."
   _howToMakeAttachmentsSensitive:
     title: "Come indicare che gli allegati sono espliciti?"
-    description: "Contrassegnare gli allegati come espliciti, va fatto quando è richiesto dal regolamento del server o quando gli allegati non devono essere immediatamente visibili."
+    description: "Si fa quando è richiesto dal regolamento del server o quando non devono essere visibili immediatamente."
     tryThisFile: "Prova a rendere esplicite le immagini allegate a questo modulo!"
     _exampleNote:
-      note: "Ho fatto un errore aprendo il coperchio del natto... (fagioli di soia fermentati, particolarmente appiccicosi)"
-    method: "Per indicare che un allegato è esplicito, tocca il file per aprirne il menu e scegliere la voce \"Segna come esplicito\"."
-    sensitiveSucceeded: "Quando alleghi file, assicurati di indicare se è materiale esplicito, in modo appropriato, in base al regolamento del tuo server."
-    doItToContinue: "Impostando l'immagine come esplicita, potrai procedere col tutorial."
+      note: "AAA! Ho rotto il coperchio del natto... (fagioli di soia fermentati)"
+    method: "Tocca il file, si aprirà il menu, scegli la voce \"Segna come esplicito\""
+    sensitiveSucceeded: "Quando alleghi file, assicurati di indicare se è materiale esplicito in modo appropriato, decidi in base al regolamento dell'istanza."
+    doItToContinue: "Imposta l'immagine come esplicita per procedere col tutorial."
   _done:
     title: "Il tutorial è finito! 🎉"
     description: "Queste sono solamente alcune delle funzionalità principali di Misskey. Per ulteriori informazioni, {link}."
@@ -1337,7 +1361,7 @@ _serverSettings:
 _accountMigration:
   moveFrom: "Migra un altro profilo dentro a questo"
   moveFromSub: "Crea un alias verso un altro profilo remoto"
-  moveFromLabel: "Profilo da cui migrare:"
+  moveFromLabel: "Profilo da cui migrare #{n}"
   moveFromDescription: "Se desideri spostare i profili follower da un altro profilo a questo, devi prima creare un alias qui. Assicurati averlo creato PRIMA di eseguire l'attività! Inserisci l'indirizzo del profilo mittente in questo modo: @persona@istanza.it"
   moveTo: "Migrare questo profilo verso un un altro"
   moveToLabel: "Profilo verso cui migrare"
@@ -1641,6 +1665,7 @@ _role:
     gtlAvailable: "Disponibilità della Timeline Federata"
     ltlAvailable: "Disponibilità della Timeline Locale"
     canPublicNote: "Scrivere Note con Visibilità Pubblica"
+    mentionMax: "Numero massimo di menzioni in una nota"
     canInvite: "Generare codici di invito all'istanza"
     inviteLimit: "Limite di codici invito"
     inviteLimitCycle: "Intervallo di emissione del codice di invito"
@@ -1664,6 +1689,7 @@ _role:
     canUseTranslator: "Tradurre le Note"
     avatarDecorationLimit: "Numero massimo di decorazioni foto profilo installabili"
   _condition:
+    roleAssignedTo: "Assegnato a ruoli manualmente"
     isLocal: "Profilo locale"
     isRemote: "Profilo remoto"
     createdLessThan: "Profilo creato da meno di N"
@@ -1735,6 +1761,7 @@ _plugin:
   installWarn: "Si prega di installare soltanto estensioni che provengono da fonti affidabili."
   manage: "Gestisci estensioni"
   viewSource: "Visualizza sorgente"
+  viewLog: "Mostra log"
 _preferencesBackups:
   list: "Elenco di impostazioni salvate in precedenza"
   saveNew: "Nuovo salvataggio"
@@ -1809,7 +1836,7 @@ _instanceMute:
   instanceMuteDescription: "Disattiva tutte le note, le note di rinvio (condivisione) dell'istanza configurata, comprese le risposte agli utenti dell'istanza."
   instanceMuteDescription2: "Impostazione separata da una nuova riga"
   title: "Nasconde le note dell'istanza configurata."
-  heading: "Istanze da silenziare."
+  heading: "Istanze da silenziare"
 _theme:
   explore: "Esplora temi"
   install: "Installa un tema"
@@ -1924,7 +1951,6 @@ _2fa:
   registerTOTP: "Registra una App di autenticazione a due fattori (2FA/MFA)"
   step1: "Innanzitutto, installa sul dispositivo un'App di autenticazione come {a} o {b}."
   step2: "Quindi, tramite la App installata, scansiona questo codice QR."
-  step2Click: "Cliccando sul codice QR, puoi registrarlo con l'app di autenticazione o il portachiavi installato sul tuo dispositivo."
   step2Uri: "Inserisci il seguente URL se desideri utilizzare una App per PC"
   step3Title: "Inserisci il codice di verifica"
   step3: "Inserite il token visualizzato nell'app e il gioco è fatto."
@@ -1948,6 +1974,7 @@ _2fa:
   backupCodesDescription: "Puoi usare questi codici usa-e-getta per ottenere l'accesso al tuo profilo in caso sia impossibile usare l'App col codice OTP. Salvali in un posto sicuro."
   backupCodeUsedWarning: "È stato usato un codice usa-e-getta. Per favore, riconfigura l'autenticazione a due fattori il prima possibile, nel caso la configurazione precedente abbia smesso di funzionare."
   backupCodesExhaustedWarning: "Hai esaurito i codici usa-e-getta. Se l'App che genera il codice OTP non è più disponibile, non potrai più accedere al tuo profilo. Ripeti la configurazione per l'autenticazione a due fattori."
+  moreDetailedGuideHere: "Informazioni dettagliate sull'autenticazione multi fattore (2FA/MFA)"
 _permissions:
   "read:account": "Visualizza le informazioni sul profilo"
   "write:account": "Modifica le informazioni sul profilo"
@@ -1964,8 +1991,8 @@ _permissions:
   "read:mutes": "Vedi i profili silenziati"
   "write:mutes": "Gestisci i profili silenziati"
   "write:notes": "Creare / Eliminare note"
-  "read:notifications": "Visualizza notifiche"
-  "write:notifications": "Gerisci notifiche"
+  "read:notifications": "Visualizzare notifiche"
+  "write:notifications": "Gestire notifiche"
   "read:reactions": "Vedi reazioni"
   "write:reactions": "Gerisci reazioni"
   "write:votes": "Votare"
@@ -2209,6 +2236,7 @@ _play:
   title: "Titolo"
   script: "Script"
   summary: "Descrizione"
+  visibilityDescription: "Impostarlo su privato significa che non verrà visualizzato sul tuo profilo, ma chiunque ha l'URL potrà comunque accedervi."
 _pages:
   newPage: "Crea pagina"
   editPage: "Modifica pagina"
@@ -2253,6 +2281,8 @@ _pages:
     section: "Sezione"
     image: "Immagini"
     button: "Pulsante"
+    dynamic: "Riquadri dinamici"
+    dynamicDescription: "Questo riquadro è obsoleto. Utilizza {play} da ora in poi."
     note: "Nota integrata"
     _note:
       id: "ID nota"
@@ -2277,13 +2307,15 @@ _notification:
   roleAssigned: "Ruolo assegnato"
   emptyPushNotificationMessage: "Le notifiche push sono state aggiornate."
   achievementEarned: "Obiettivo raggiunto"
-  testNotification: "Prova la notifica"
-  checkNotificationBehavior: "Prova il comportamento della notifica"
+  testNotification: "Provare la notifica"
+  checkNotificationBehavior: "Provare il comportamento della notifica"
   sendTestNotification: "Spedisci una notifica di prova"
   notificationWillBeDisplayedLikeThis: "La notifica apparirà così"
   reactedBySomeUsers: "{n} reazioni"
+  likedBySomeUsers: "{n} apprezzamenti"
   renotedBySomeUsers: "{n} Rinota"
-  followedBySomeUsers: "{n} nuovi follower"
+  followedBySomeUsers: "{n} follower"
+  flushNotification: "Azzera le notifiche"
   _types:
     all: "Tutto"
     note: "Nuove Note"
@@ -2335,8 +2367,8 @@ _deck:
     direct: "Note Dirette"
     roleTimeline: "Timeline Ruolo"
 _dialog:
-  charactersExceeded: "Hai superato il limite di {max} caratteri! ({corrente})"
-  charactersBelow: "Sei al di sotto del minimo di {min} caratteri!  ({corrente})"
+  charactersExceeded: "Hai superato il limite di {max} caratteri! ({current})"
+  charactersBelow: "Sei al di sotto del minimo di {min} caratteri!  ({current})"
 _disabledTimeline:
   title: "Timeline disabilitata"
   description: "Il ruolo in cui sei non ti permette di leggere questa timeline"
@@ -2381,6 +2413,7 @@ _moderationLogTypes:
   resetPassword: "Password azzerata"
   suspendRemoteInstance: "Istanza remota sospesa"
   unsuspendRemoteInstance: "Istanza remota riattivata"
+  updateRemoteInstanceNote: "Aggiornamento del promemoria di moderazione per il server remoto"
   markSensitiveDriveFile: "File nel Drive segnato come esplicito"
   unmarkSensitiveDriveFile: "File nel Drive segnato come non esplicito"
   resolveAbuseReport: "Segnalazione risolta"
@@ -2501,7 +2534,24 @@ _reversi:
   opponentHasSettingsChanged: "L'avversario ha cambiato configurazione"
   allowIrregularRules: "Regole inconsuete (completamente libere)"
   disallowIrregularRules: "Impedire le regole inconsuete"
+  showBoardLabels: "Mostra le coordinate del gioco"
+  useAvatarAsStone: "Immagini profilo come pedine"
 _offlineScreen:
   title: "Scollegato. Impossibile connettersi al server"
   header: "Impossibile connettersi al server"
-
+_urlPreviewSetting:
+  title: "Impostazioni per l'anteprima delle URL"
+  enable: "Attiva l'anteprima delle URL"
+  timeout: "Timeout dell'anteprima in millisecondi"
+  timeoutDescription: "Impegna al massimo il tempo indicato, altrimenti ignora l'anteprima"
+  maximumContentLength: "Grandezza del contenuto (Content-Length in byte)"
+  maximumContentLengthDescription: "Se la grandezza supera il valore, l'anteprima verrà ignorata."
+  requireContentLength: "Genenerare l'anteprima solo quando è definito Content-Length"
+  requireContentLengthDescription: "In assenza di questo parametro dal server remoto, l'anteprima verrà ignorata."
+  userAgent: "User-Agent"
+  userAgentDescription: "Definire con quale User-Agent si intende identificarsi durante l'acquisizione di un'anteprima. Se è vuoto, useremo il valore predefinito."
+  summaryProxy: "Endpoint proxy che genera l'anteprima"
+_mediaControls:
+  pip: "Sovraimpressione"
+  playbackRate: "Velocità di riproduzione"
+  loop: "Ripetizione infinita"
diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml
index 7ff26c757d..e6a23a34d7 100644
--- a/locales/ja-KS.yml
+++ b/locales/ja-KS.yml
@@ -400,6 +400,7 @@ name: "名前"
 antennaSource: "受信ソース(このソースは食われへん)"
 antennaKeywords: "受信キーワード"
 antennaExcludeKeywords: "除外キーワード"
+antennaExcludeBots: "Botアカウントを除外"
 antennaKeywordsDescription: "スペースで区切ったるとAND指定で、改行で区切ったるとOR指定や"
 notifyAntenna: "新しいノートを通知すんで"
 withFileAntenna: "なんか添付されたノートだけ"
@@ -494,6 +495,7 @@ emojiStyle: "絵文字のスタイル"
 native: "ネイティブ"
 disableDrawer: "メニューをドロワーで表示せえへん"
 showNoteActionsOnlyHover: "ノートの操作部をホバー時のみ表示するで"
+showReactionsCount: "ノートのリアクション数を表示する"
 noHistory: "履歴はないわ。"
 signinHistory: "ログイン履歴"
 enableAdvancedMfm: "ややこしいMFMもありにする"
@@ -1042,6 +1044,8 @@ resetPasswordConfirm: "パスワード作り直すんでええな?"
 sensitiveWords: "けったいな単語"
 sensitiveWordsDescription: "設定した単語が入っとるノートの公開範囲をホームにしたるわ。改行で区切ったら複数設定できるで。"
 sensitiveWordsDescription2: "スペースで区切るとAND指定、キーワードをスラッシュで囲んだら正規表現や。"
+prohibitedWords: "禁止ワード"
+prohibitedWordsDescription: "設定した言葉が含まれるノートを投稿しようとしたら、エラーが出るようにするで。改行で区切って複数設定できるで。"
 prohibitedWordsDescription2: "スペースで区切るとAND指定、キーワードをスラッシュで囲んだら正規表現や。"
 hiddenTags: "見えてへんハッシュタグ"
 hiddenTagsDescription: "設定したタグを最近流行りのとこに見えんようにすんで。複数設定するときは改行で区切ってな。"
@@ -1158,6 +1162,7 @@ showRenotes: "リノート出す"
 edited: "いじったやつ"
 notificationRecieveConfig: "通知もらうかの設定"
 mutualFollow: "お互いフォローしてんで"
+followingOrFollower: "フォロー中またはフォロワー"
 fileAttachedOnly: "ファイルのっけてあるやつだけ"
 showRepliesToOthersInTimeline: "タイムラインに他の人への返信とかも入れるで"
 hideRepliesToOthersInTimeline: "タイムラインに他の人への返信とかは入れへん"
@@ -1167,6 +1172,12 @@ confirmShowRepliesAll: "これは元に戻せへんから慎重に決めてや
 confirmHideRepliesAll: "これは元に戻せへんから慎重に決めてや。本当にタイムラインに今フォローしとる全員の返信を入れへんのか?"
 externalServices: "他のサイトのサービス"
 sourceCode: "ソースコード"
+sourceCodeIsNotYetProvided: "ソースコードはまだ提供されてへんで。問題の修正について管理者に問い合わせてみ。"
+repositoryUrl: "リポジトリURL"
+repositoryUrlDescription: "ソースコードが公開されているリポジトリがある場合、そのURLを記入するで。Misskeyをそのまんま(ソースコードにいかなる変更も加えずに)使っとる場合は https://github.com/misskey-dev/misskey と記入するで。"
+repositoryUrlOrTarballRequired: "リポジトリを公開してへんなら、代わりにtarballを提供する必要があるで。詳細は.config/example.ymlを参照してな。"
+feedback: "フィードバック"
+feedbackUrl: "フィードバックURL"
 impressum: "運営者の情報"
 impressumUrl: "運営者の情報URL"
 impressumDescription: "ドイツとかの一部んところではな、表示が義務付けられてんねん(Impressum)。"
@@ -1202,6 +1213,8 @@ soundWillBePlayed: "サウンドが再生されるで"
 showReplay: "リプレイ見る"
 replay: "リプレイ"
 replaying: "リプレイ中"
+endReplay: "リプレイを終了"
+copyReplayData: "リプレイデータをコピー"
 ranking: "ランキング"
 lastNDays: "直近{n}日"
 backToTitle: "タイトルへ"
@@ -1209,9 +1222,30 @@ hemisphere: "住んでる地域"
 withSensitive: "センシティブなファイルを含むノートを表示"
 userSaysSomethingSensitive: "{name}のセンシティブなファイルを含む投稿"
 enableHorizontalSwipe: "スワイプしてタブを切り替える"
+loading: "読み込み中"
 surrender: "やめとく"
+gameRetry: "もういっちょ"
+notUsePleaseLeaveBlank: "使用せえへん場合は空欄にしてや"
+useTotp: "ワンタイムパスワードを使う"
+useBackupCode: "バックアップコードを使う"
+launchApp: "アプリを起動"
+useNativeUIForVideoAudioPlayer: "動画・音声の再生にブラウザのUIを使用する"
+keepOriginalFilename: "オリジナルのファイル名を保持"
+keepOriginalFilenameDescription: "この設定をオフにすると、アップロード時にファイル名が自動でランダム文字列に置き換えられるで。"
+noDescription: "説明文はあらへんで"
+alwaysConfirmFollow: "フォローの際常に確認する"
+inquiry: "問い合わせ"
 _bubbleGame:
   howToPlay: "遊び方"
+  hold: "ホールド"
+  _score:
+    score: "スコア"
+    scoreYen: "稼いだ金額"
+    highScore: "ハイスコア"
+    maxChain: "最大チェーン数"
+    yen: "{yen}円"
+    estimatedQty: "{qty}個分"
+    scoreSweets: "おにぎり {onigiriQtyWithUnit}"
   _howToPlay:
     section1: "位置を調整してハコにモノを落とすで。"
     section2: "同じもんがくっついたら別のやつになって、スコアがもらえるで。"
@@ -1633,6 +1667,7 @@ _role:
     gtlAvailable: "グローバルタイムライン見る"
     ltlAvailable: "ローカルタイムライン見る"
     canPublicNote: "パブリック投稿できるか"
+    mentionMax: "ノート内の最大メンション数"
     canInvite: "サーバー招待コード作る"
     inviteLimit: "招待コード作れる数"
     inviteLimitCycle: "招待コードの作れる間隔"
@@ -1656,8 +1691,14 @@ _role:
     canUseTranslator: "翻訳使えるかどうか"
     avatarDecorationLimit: "アイコンデコのいっちばんつけれる数"
   _condition:
+    roleAssignedTo: "マニュアルロールにアサイン済み"
     isLocal: "ローカルユーザー"
     isRemote: "リモートユーザー"
+    isCat: "猫ユーザー"
+    isBot: "botユーザー"
+    isSuspended: "サスペンド済みユーザー"
+    isLocked: "鍵アカウントユーザー"
+    isExplorable: "「アカウントを見つけやすくする」が有効なユーザー"
     createdLessThan: "アカウント作ってから~以内"
     createdMoreThan: "アカウント作ってから~経過"
     followersLessThanOrEq: "フォロワー数が~以下"
@@ -1727,6 +1768,7 @@ _plugin:
   installWarn: "信頼できへんプラグインはインストールせんとってな"
   manage: "プラグインの管理"
   viewSource: "ソース見る"
+  viewLog: "ログを表示"
 _preferencesBackups:
   list: "作ったバックアップ"
   saveNew: "新しく保存"
@@ -1741,8 +1783,8 @@ _preferencesBackups:
   deleteConfirm: "{name}を消すん?"
   renameConfirm: "「{old}」を「{new}」に変えるん?"
   noBackups: "バックアップはないで。「新しく保存」ってとこでこのクライアント設定を鯖に保存できるで。"
-  createdAt: "作った日時:{date}{time}"
-  updatedAt: "更新日時:{date}{time}"
+  createdAt: "作った日時: {date} {time}"
+  updatedAt: "更新日時: {date} {time}"
   cannotLoad: "読み込みできへん..."
   invalidFile: "ファイル形式が違うで?"
 _registry:
@@ -1756,6 +1798,8 @@ _aboutMisskey:
   contributors: "主な貢献者"
   allContributors: "全ての貢献者"
   source: "ソースコード"
+  original: "オリジナル"
+  thisIsModifiedVersion: "{name}はオリジナルのMisskeyをいじったバージョンをつこうてるで。"
   translation: "Misskeyを翻訳"
   donate: "Misskeyに寄付"
   morePatrons: "他にもぎょうさんの人からサポートしてもろてんねん。ほんまおおきに🥰"
@@ -1914,7 +1958,6 @@ _2fa:
   registerTOTP: "認証アプリの設定はじめる"
   step1: "ほんなら、{a}や{b}とかの認証アプリを使っとるデバイスにインストールしてな。"
   step2: "次に、ここにあるQRコードをアプリでスキャンしてな~。"
-  step2Click: "QRコード押したら、今使とる端末に入っとる認証アプリとかキーリングに登録できるで。"
   step2Uri: "デスクトップアプリを使う時は次のURIを入れるで"
   step3Title: "確認コードを入れてーや"
   step3: "アプリに映っとる確認コード(トークン)を入れて終わりや。"
@@ -1938,6 +1981,7 @@ _2fa:
   backupCodesDescription: "認証アプリが使用できんなった場合、以下のバックアップコードを使ってアカウントにアクセスできるで。これらのコードは必ず安全な場所に置いときや。各コードは一回だけ使用できるで。"
   backupCodeUsedWarning: "バックアップコードが使用されたで。認証アプリが使えなくなってるん場合、なるべく早く認証アプリを再設定しや。"
   backupCodesExhaustedWarning: "バックアップコードが全て使用されたで。認証アプリを利用できん場合、これ以上アカウントにアクセスできなくなるで。認証アプリを再登録しや。"
+  moreDetailedGuideHere: "詳細なガイドはこちら"
 _permissions:
   "read:account": "アカウントの情報を見るで"
   "write:account": "アカウントの情報を変更するで"
@@ -2199,6 +2243,7 @@ _play:
   title: "タイトル"
   script: "スクリプト"
   summary: "説明"
+  visibilityDescription: "非公開に設定するとプロフィールに表示されへんくなるけど、URLを知っとる人は引き続きアクセスできるで。"
 _pages:
   newPage: "ページを作る"
   editPage: "ページの編集"
@@ -2243,6 +2288,8 @@ _pages:
     section: "セクション"
     image: "画像"
     button: "ボタン"
+    dynamic: "動的ブロック"
+    dynamicDescription: "このブロックは廃止されとるで。今後は{play}を利用してや。"
     note: "ノート埋め込み"
     _note:
       id: "ノートID"
@@ -2272,8 +2319,10 @@ _notification:
   sendTestNotification: "テスト通知を送信するで"
   notificationWillBeDisplayedLikeThis: "通知はこのように表示されるで"
   reactedBySomeUsers: "{n}人がツッコんだで"
+  likedBySomeUsers: "{n}人がいいねしたで"
   renotedBySomeUsers: "{n}人がリノートしたで"
   followedBySomeUsers: "{n}人にフォローされたで"
+  flushNotification: "通知の履歴をリセットする"
   _types:
     all: "すべて"
     note: "あんたらの新規投稿"
@@ -2371,6 +2420,7 @@ _moderationLogTypes:
   resetPassword: "パスワードをリセット"
   suspendRemoteInstance: "リモートサーバーを止めんで"
   unsuspendRemoteInstance: "リモートサーバーを再開すんで"
+  updateRemoteInstanceNote: "リモートサーバーのモデレーションノート更新"
   markSensitiveDriveFile: "ファイルをセンシティブ付与"
   unmarkSensitiveDriveFile: "ファイルをセンシティブ解除"
   resolveAbuseReport: "苦情を解決"
@@ -2491,7 +2541,26 @@ _reversi:
   opponentHasSettingsChanged: "相手が設定変えたで"
   allowIrregularRules: "変則許可 (完全フリー)"
   disallowIrregularRules: "変則なし"
+  showBoardLabels: "盤面に行・列番号を表示"
+  useAvatarAsStone: "石をアイコンにする"
 _offlineScreen:
   title: "オフライン - サーバーに接続できひんで"
   header: "サーバーに接続できへんわ"
-
+_urlPreviewSetting:
+  title: "URLプレビューの設定"
+  enable: "URLプレビューを有効にする"
+  timeout: "プレビュー取得時のタイムアウト(ms)"
+  timeoutDescription: "プレビュー取得の所要時間がこの値を超えた場合、プレビューは生成されへんで。"
+  maximumContentLength: "Content-Lengthの最大値(byte)"
+  maximumContentLengthDescription: "Content-Lengthがこの値を超えた場合、プレビューは生成されへんで。"
+  requireContentLength: "Content-Lengthが取得できた場合のみプレビューを生成"
+  requireContentLengthDescription: "相手サーバがContent-Lengthを返さない場合、プレビューは生成されへんで。"
+  userAgent: "User-Agent"
+  userAgentDescription: "プレビュー取得時に使用されるUser-Agentを設定するで。空欄の場合、デフォルトのUser-Agentが使用されるで。"
+  summaryProxy: "プレビューを生成するプロキシのエンドポイント"
+  summaryProxyDescription: "Misskey本体やなく、サマリープロキシを使用してプレビューを生成するで。"
+  summaryProxyDescription2: "プロキシには下記パラメータがクエリ文字列として連携されるで。プロキシ側がこれらをサポートせえへんときは、設定値は無視されるで。"
+_mediaControls:
+  pip: "ピクチャインピクチャ"
+  playbackRate: "再生速度"
+  loop: "ループ再生"
diff --git a/locales/jbo-EN.yml b/locales/jbo-EN.yml
index 297ca53dd7..d4fea291d7 100644
--- a/locales/jbo-EN.yml
+++ b/locales/jbo-EN.yml
@@ -1,4 +1,3 @@
 ---
 _lang_: "la .lojban."
 headlineMisskey: "lo se tcana noi jorne fi loi notci"
-
diff --git a/locales/kab-KAB.yml b/locales/kab-KAB.yml
index b976f028f0..22e24d3baa 100644
--- a/locales/kab-KAB.yml
+++ b/locales/kab-KAB.yml
@@ -104,4 +104,3 @@ _deck:
   _columns:
     notifications: "Ilɣuyen"
     list: "Tibdarin"
-
diff --git a/locales/kn-IN.yml b/locales/kn-IN.yml
index bb6d1ee242..b3ad46f2b1 100644
--- a/locales/kn-IN.yml
+++ b/locales/kn-IN.yml
@@ -84,4 +84,3 @@ _deck:
     notifications: "ಅಧಿಸೂಚನೆಗಳು"
     tl: "ಸಮಯಸಾಲು"
     mentions: "ಹೆಸರಿಸಿದ"
-
diff --git a/locales/ko-GS.yml b/locales/ko-GS.yml
index 39492d902f..c80a4d3997 100644
--- a/locales/ko-GS.yml
+++ b/locales/ko-GS.yml
@@ -16,8 +16,8 @@ cancel: "아이예"
 noThankYou: "뎃어예"
 enterUsername: "사용자 이럼 서기"
 renotedBy: "{user}님이 리노트햇어예"
-noNotes: "노트가 없십니다"
-noNotifications: "알림이 없십니다"
+noNotes: "노트가 어ᇝ십니다"
+noNotifications: "알림이 어ᇝ십니다"
 instance: "서버"
 settings: "설정"
 notificationSettings: "알림 설정"
@@ -26,7 +26,7 @@ otherSettings: "다린 설정"
 openInWindow: "창서 옐기"
 profile: "프로필"
 timeline: "타임라인"
-noAccountDescription: "자기소개가 없십니다"
+noAccountDescription: "자기소개가 어ᇝ십니다"
 login: "로그인"
 loggingIn: "로그인하고 잇어예"
 logout: "로그아웃"
@@ -80,7 +80,7 @@ unfollowConfirm: "{name}님얼 고마 팔로잉합니꺼?"
 exportRequested: "내가기 요청얼 햇십니다. 시간이 쪼매 걸릴 깁니다. 요청이 껕나모 ‘드라이브’에 옇십니다."
 importRequested: "가오기 요청얼 햇십니다. 시간이 쪼매 걸릴 깁니다."
 lists: "리스트"
-noLists: "리스트가 없십니다"
+noLists: "리스트가 어ᇝ십니다"
 note: "노트"
 notes: "노트"
 following: "팔로잉"
@@ -161,7 +161,7 @@ youCanCleanRemoteFilesCache: "파일 간리으 🗑️ 모냥얼 누질리모 
 cacheRemoteSensitiveFiles: "웬겍으 수ᇚ힌 파일얼 캐시하기"
 cacheRemoteSensitiveFilesDescription: "요 설정얼 꺼모 웬겍 수ᇚ힌 파일이 캐시하지 아이하고 바리 링크합니다."
 flagAsBot: "자동 게정입니다"
-flagAsBotDescription: "요 게정얼 프로그램서 설라먼 키야 합니다. 키모 다런 개발자가 반엉얼 끋없이 데풀이하지 몬 하게 도아 줄 수 잇고 Misskey으 시스템서 자동 게정이 뎁니다."
+flagAsBotDescription: "요 게정얼 프로그램서 설라먼 키야 합니다. 키모 다런 개발자가 반엉얼 끋어ᇝ이 데풀이하지 몬 하게 도아 줄 수 잇고 Misskey으 시스템서 자동 게정이 뎁니다."
 flagAsCat: "애웅애웅애웅애웅!"
 flagAsCatDescription: "애옹?"
 flagShowTimelineReplies: "타임라인서 노트으 답하기 보기"
@@ -176,7 +176,7 @@ wallpaper: "벡지"
 setWallpaper: "벡지 설정"
 removeWallpaper: "벡지 뭉캐기"
 searchWith: "찾기: {q}"
-youHaveNoLists: "리스트가 없십니다"
+youHaveNoLists: "리스트가 어ᇝ십니다"
 followConfirm: "{name}님얼 팔로잉합니꺼?"
 proxyAccount: "프락시 게정"
 proxyAccountDescription: "프락시 게정언 턱벨한 조겐서 웬겍 팔로잉얼 하넌 게정입니다. 사용자가 웬겍 사용자럴 리스트에 옇얼 때 리스트에 옇언 사용자럴 누도 팔로잉 아이하모 할동이 서버로 아이 오니께 요 게정이 아인 프락시 게정얼 팔로잉하게 합니다."
@@ -210,17 +210,17 @@ instanceInfo: "서버 정보"
 statistics: "통게"
 clearQueue: "대기옐 비우기"
 clearQueueConfirmTitle: "대기옐얼 비웁니꺼?"
-clearQueueConfirmText: "대기옐에 잇넌 걸얼 아이 보냅니다. 흐이 요 동작언 할 필요가 없십니다."
+clearQueueConfirmText: "대기옐에 잇넌 걸얼 아이 보냅니다. 흐이 요 동작언 할 필요가 어ᇝ십니다."
 clearCachedFiles: "캐시 비우기"
 clearCachedFilesConfirm: "캐시한 웬겍 파일얼 말캉 뭉캡니꺼?"
 blockedInstances: "차단한 서버"
 blockedInstancesDescription: "차단할라넌 서버으 호스트럴 줄 바꿈해서로 비이 줍니다. 차단한 서버넌 요 서버하고 교류 몬 합니다."
 silencedInstances: "수ᇚ훈 서버"
-silencedInstancesDescription: "수ᇚ훌라넌 서버으 호스트럴 줄 바꿈해서로 비이 줍니다. 수ᇚ훈 서버으 게정언 말캉 ‘수ᇚ후기’가 데서 팔로잉 요청만 데고 팔로워가 아인 로컬 게정서 멘션얼 몬 합니다. 차단한 서버넌 상간 없십니다."
+silencedInstancesDescription: "수ᇚ훌라넌 서버으 호스트럴 줄 바꿈해서로 비이 줍니다. 수ᇚ훈 서버으 게정언 말캉 ‘수ᇚ후기’가 데서 팔로잉 요청만 데고 팔로워가 아인 로컬 게정서 멘션얼 몬 합니다. 차단한 서버넌 상간 어ᇝ십니다."
 muteAndBlock: "수ᇚ훔하고 차단"
 mutedUsers: "수ᇚ훈 사용자"
 blockedUsers: "차단한 사용자"
-noUsers: "사용자가 없십니다"
+noUsers: "사용자가 어ᇝ십니다"
 editProfile: "프로필 적기"
 noteDeleteConfirm: "요 노트럴 뭉캡니꺼?"
 pinLimitExceeded: "더 몬 붙입니다"
@@ -230,15 +230,15 @@ processing: "처리하고 잇어예"
 preview: "미리보기"
 default: "기본값"
 defaultValueIs: "기본값: {value}"
-noCustomEmojis: "이모지가 없십니다"
-noJobs: "작업이 없십니다"
+noCustomEmojis: "이모지가 어ᇝ십니다"
+noJobs: "작업이 어ᇝ십니다"
 federating: "옌합하고 잇어예"
 blocked: "차단햇어예"
 suspended: "고만 보내예"
 all: "말캉"
 subscribing: "구독하고 잇어예"
 publishing: "보내고 잇어예"
-notResponding: "답이 없어예"
+notResponding: "답이 어ᇝ어예"
 instanceFollowing: "서버으 팔로잉"
 instanceFollowers: "서버으 팔로워"
 instanceUsers: "서버으 사용자"
@@ -275,7 +275,7 @@ uploadFromUrlRequested: "올리기럴 요청햇십니다"
 uploadFromUrlMayTakeTime: "올리기가 껕날라먼 시간이 쪼매 걸릴 깁니다."
 explore: "살펴보기"
 messageRead: "이럿어예"
-noMoreHistory: "요카마 엣날 기록이 없십니다"
+noMoreHistory: "요카마 옛날 기록이 어ᇝ십니다"
 startMessaging: "대화하기"
 nUsersRead: "{n}멩이 이럿십니다"
 agreeTo: "{0}에 동이하기"
@@ -432,28 +432,28 @@ securityKey: "보안키"
 lastUsed: "마지막 쓰임"
 lastUsedAt: "마지막 쓰임: {t}"
 unregister: "맨걸기 무루기"
-passwordLessLogin: "비밀번호 없시 로그인"
-passwordLessLoginDescription: "비밀번호 말고 보안키나 패스키 같은 것만 써 가 로그인합니다."
+passwordLessLogin: "비밀번호 어ᇝ이 로그인"
+passwordLessLoginDescription: "비밀번호 어ᇝ이 보안 키나 패스 키만 서서 로그인합니다."
 resetPassword: "비밀번호 재설정"
-newPasswordIs: "새 비밀번호는 \"{password}\" 입니다"
+newPasswordIs: "새 비밀번호넌 ‘{password}’입니다"
 reduceUiAnimation: "화면 움직임 효과들을 수ᇚ후기"
 share: "노누기"
 notFound: "몬 찾앗십니다"
-notFoundDescription: "고런 주소로 들어가는 하멘은 없십니다."
-uploadFolder: "기본 업로드 위치"
-markAsReadAllNotifications: "모든 알림 이럿다고 표시"
-markAsReadAllUnreadNotes: "모든 글 이럿다고 표시"
-markAsReadAllTalkMessages: "모든 대화 이럿다고 표시"
+notFoundDescription: "선 주소에 맞넌 페이지가 어ᇝ십니다."
+uploadFolder: "기본 올리기 위치"
+markAsReadAllNotifications: "모던 알림얼 읽엄 포시"
+markAsReadAllUnreadNotes: "모던 걸얼 읽엄 포시"
+markAsReadAllTalkMessages: "모던 대화 읽엄 포시"
 help: "도움말"
-inputMessageHere: "여따가 메시지를 입력해주이소"
-close: "닫기"
+inputMessageHere: "옇다 메시지럴 서이소"
+close: "꺼기"
 invites: "초대하기"
-members: "멤버"
-transfer: "양도"
+members: "구성원"
+transfer: "넘구기"
 title: "제목"
-text: "글"
+text: "걸"
 enable: "키기"
-next: "다음"
+next: "다엄"
 retype: "다시 서기"
 noteOf: "{user}님으 노트"
 quoteAttached: "따옴"
@@ -468,6 +468,7 @@ tooShort: "억수로 짜립니다"
 tooLong: "억수로 집니다"
 passwordMatched: "맞십니다"
 passwordNotMatched: "안 맞십니다"
+signinWith: "{n}서 로그인"
 signinFailed: "로그인 몬 했십니다. 고 이름이랑 비밀번호 제대로 썼는가 확인해 주이소."
 or: "아니면"
 language: "언어"
@@ -512,13 +513,13 @@ useObjectStorage: "오브젝트 스토리지 키기"
 objectStorageBaseUrl: "Base URL"
 objectStorageBaseUrlDesc: "오브젝트 (미디어) 참조 링크 만들 때 쓰는 URL임다. CDN 내지 프락시를 쓴다 카멘은 그 URL을 갖다 늫고, 아이면 써먹을 서비스네 가이드를 봐봐가 공개적으로 접근할 수 있는 주소를 여 넣어 주이소. 그니께, 내가 AWS S3을 쓴다 카면은 'https://<bucket>.s3.amazonaws.com', GCS를 쓴다 카면 'https://storage.googleapis.com/<bucket>' 처럼 쓰믄 되입니더."
 objectStorageBucket: "Bucket"
-objectStorageBucketDesc: "써먹을 서비스의 바께쓰 이름을 여 써 주이소."
+objectStorageBucketDesc: "설 서비스으 버킷 이럼얼 서 주이소."
 objectStoragePrefix: "Prefix"
 objectStoragePrefixDesc: "요 Prefix 디렉토리 안에다가 파일이 들어감다."
 objectStorageEndpoint: "Endpoint"
-objectStorageEndpointDesc: "AWS S3을 쓸라멘 요는 비워두고, 아이멘은 그 서비스 가이드에 맞게 endpoint를 넣어 주이소. '<host>' 내지 '<host>:<port>'처럼 넣십니다."
+objectStorageEndpointDesc: "AWS S3넌 비아 두고 다런 것언 거 서비스으 엔드포인트럴 서 주이소. ‘<host>’나 ‘<host>:<port>’맨치로 섭니다."
 objectStorageRegion: "Region"
-objectStorageRegionDesc: "'xx-east-1' 같은 region 이름을 옇어 주이소. 만약에 내 서비스엔 region 같은 개념이 읎다, 카면은 대신에 'us-east-1'라고 해 두이소. AWS 설정 파일이나 환경 변수를 끌어다 쓰겠다믄 요는 비워 두이소."
+objectStorageRegionDesc: "‘xx-east-1’맨치로 리전 이럼얼 서 주이소. 설 서비스에 리전 개넴이 어ᇝ어먼 ‘us-east-1’라고 해 두이소. 에이더블유에스 설정 파일이나 환겡 벤수가 이ᇇ어면 비아 두이소."
 objectStorageUseSSL: "SSL 쓰기"
 objectStorageUseSSLDesc: "API 호출할 때 HTTPS 안 쓸거면은 꺼 두이소"
 objectStorageUseProxy: "연결에 프락시 사용"
@@ -534,7 +535,7 @@ newNoteRecived: "새 노트 있어예"
 sounds: "소리"
 sound: "소리"
 listen: "듣기"
-none: "없음"
+none: "어ᇝ엄"
 showInPage: "바닥서 보기"
 popout: "새 창 열기"
 volume: "음량"
@@ -542,13 +543,13 @@ masterVolume: "대빵 음량"
 notUseSound: "음소거하기"
 useSoundOnlyWhenActive: "Misskey가 활성화되어 있을 때만 소리 내기"
 details: "자세히"
-chooseEmoji: "이모지 선택"
+chooseEmoji: "이모지 개리기"
 unableToProcess: "작업 다 몬 했십니다"
 recentUsed: "최근 쓴 놈"
 install: "설치"
 uninstall: "삭제"
 installedApps: "설치된 애플리케이션"
-nothing: "뭣도 없어예"
+nothing: "어ᇝ어예"
 installedDate: "설치한 날"
 lastUsedDate: "마지막 사용"
 state: "상태"
@@ -579,6 +580,7 @@ enableInfiniteScroll: "알아서 더 보기"
 useCw: "내용 수ᇚ후기"
 description: "설멩"
 describeFile: "캡션 옇기"
+enterFileDescription: "캡션 서기"
 author: "맨던 사람"
 manage: "간리"
 emailServer: "전자우펜 서버"
@@ -598,6 +600,7 @@ reporter: "신고한 사람"
 reporteeOrigin: "신고덴 사람"
 reporterOrigin: "신고한 곳"
 forwardReport: "웬겍 서버에 신고 보내기"
+waitingFor: "{x}(얼)럴 지달리고 잇십니다"
 random: "무작이"
 system: "시스템"
 clip: "클립 맨걸기"
@@ -610,10 +613,13 @@ followersCount: "팔로워 수"
 noteFavoritesCount: "질겨찾기한 노트 수"
 clips: "클립 맨걸기"
 clearCache: "캐시 비우기"
+typingUsers: "{users} 님이 서고 잇어예"
 unlikeConfirm: "좋네예럴 무룹니꺼?"
 info: "정보"
+selectAccount: "계정 개리기"
 user: "사용자"
 administration: "간리"
+translatedFrom: "{x}서 번옉"
 on: "킴"
 off: "껌"
 hide: "수ᇚ후기"
@@ -625,6 +631,8 @@ oneDay: "하리"
 oneWeek: "한 주"
 oneMonth: "한 달"
 file: "파일"
+typeToConfirm: "게속할라먼 {x}럴 누질라 주이소"
+pleaseSelect: "개리 주이소"
 tools: "도구"
 like: "좋네예!"
 unlike: "좋네예 무루기"
@@ -632,7 +640,7 @@ numberOfLikes: "좋네예 수"
 show: "보기"
 roles: "옉할"
 role: "옉할"
-noRole: "옉할이 없십니다"
+noRole: "옉할이 어ᇝ십니다"
 thisPostMayBeAnnoyingCancel: "아이예"
 likeOnly: "좋네예마"
 myClips: "내 클립"
@@ -720,6 +728,7 @@ _theme:
 _sfx:
   note: "새 노트"
   notification: "알림"
+  reaction: "리액션 개리기"
 _2fa:
   step3Title: "학인 기호럴 서기"
   renewTOTPCancel: "뎃어예"
@@ -744,6 +753,9 @@ _cw:
 _visibility:
   home: "덜머리"
   followers: "팔로워"
+_postForm:
+  _placeholders:
+    e: "옇다 서 주이소"
 _profile:
   name: "이럼"
   username: "사용자 이럼"
@@ -796,5 +808,8 @@ _moderationLogTypes:
   resetPassword: "비밀번호 재설정"
   resolveAbuseReport: "신고 해겔하기"
 _reversi:
-  total: "합계"
-
+  reversi: "리버시"
+  chooseBoard: "보드 개리기"
+  black: "꺼멍"
+  white: "허영"
+  total: "합게"
diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml
index 877ae6b217..fc3a64acab 100644
--- a/locales/ko-KR.yml
+++ b/locales/ko-KR.yml
@@ -38,9 +38,9 @@ addUser: "유저 추가"
 favorite: "즐겨찾기"
 favorites: "즐겨찾기"
 unfavorite: "즐겨찾기에서 제거"
-favorited: "즐겨찾기에 등록했습니다"
-alreadyFavorited: "이미 즐겨찾기에 등록되어 있습니다"
-cantFavorite: "즐겨찾기에 등록하지 못했습니다"
+favorited: "즐겨찾기에 등록했습니다."
+alreadyFavorited: "이미 즐겨찾기에 등록했습니다."
+cantFavorite: "즐겨찾기에 등록하지 못했습니다."
 pin: "프로필에 고정"
 unpin: "프로필에서 고정 해제"
 copyContent: "내용 복사"
@@ -93,7 +93,7 @@ somethingHappened: "오류가 발생했습니다"
 retry: "다시 시도"
 pageLoadError: "페이지를 불러오지 못했습니다."
 pageLoadErrorDescription: "네트워크 연결 또는 브라우저 캐시로 인해 발생했을 가능성이 높습니다. 캐시를 삭제하거나, 잠시 후 다시 시도해 주세요."
-serverIsDead: "서버로부터 응답이 없습니다. 잠시 후 다시 시도해주세요."
+serverIsDead: "서버가 응답하지 않습니다. 잠시 후 다시 시도해 주세요."
 youShouldUpgradeClient: "이 페이지를 표시하려면 새로고침하여 새로운 버전의 클라이언트를 이용해 주십시오."
 enterListName: "리스트 이름을 입력"
 privacy: "프라이버시"
@@ -119,8 +119,8 @@ you: "나"
 clickToShow: "클릭하여 보기"
 sensitive: "열람 주의"
 add: "추가"
-reaction: "리액션"
-reactions: "리액션"
+reaction: "반응"
+reactions: "반응"
 emojiPicker: "이모지 선택기"
 pinnedEmojisForReactionSettingDescription: "리액션을 할 때 프로필에 고정하여 표시할 이모지를 설정할 수 있습니다"
 pinnedEmojisSettingDescription: "이모지를 입력할 때 프로필에 고정하여 표시할 이모지를 설정할 수 있습니다"
@@ -169,7 +169,7 @@ cacheRemoteSensitiveFilesDescription: "이 설정을 비활성화하면 리모
 flagAsBot: "나는 봇입니다"
 flagAsBotDescription: "이 계정을 자동화된 수단으로 운용할 경우에 활성화해 주세요. 이 플래그를 활성화하면, 다른 봇이 이를 참고하여 봇 끼리의 무한 연쇄 반응을 회피하거나, 이 계정의 시스템 상에서의 취급이 Bot 운영에 최적화되는 등의 변화가 생깁니다."
 flagAsCat: "미야아아아오오오오오오오오오옹!!!!!!!"
-flagAsCatDescription: "야옹?"
+flagAsCatDescription: "야옹?(이 계정이 고양이라면 눌러 주세요.)"
 flagShowTimelineReplies: "타임라인에 노트의 답글을 표시하기"
 flagShowTimelineRepliesDescription: "이 설정을 활성화하면 타임라인에 다른 유저 간의 답글을 표시합니다."
 autoAcceptFollowed: "팔로우 중인 유저로부터의 팔로우 요청을 자동 수락"
@@ -187,7 +187,7 @@ followConfirm: "{name}님을 팔로우 하시겠습니까?"
 proxyAccount: "프록시 계정"
 proxyAccountDescription: "프록시 계정은 특정 조건 하에서 유저의 리모트 팔로우를 대행하는 계정입니다. 예를 들면, 유저가 리모트 유저를 리스트에 넣었을 때, 리스트에 들어간 유저를 아무도 팔로우한 적이 없다면 액티비티가 서버로 배달되지 않기 때문에, 대신 프록시 계정이 해당 유저를 팔로우하도록 합니다."
 host: "호스트"
-selectUser: "유저 선택"
+selectUser: "사용자 선택"
 recipient: "수신인"
 annotation: "내용에 대한 주석"
 federation: "연합"
@@ -230,7 +230,7 @@ noUsers: "아무도 없습니다"
 editProfile: "프로필 수정"
 noteDeleteConfirm: "이 노트를 삭제하시겠습니까?"
 pinLimitExceeded: "더 이상 고정할 수 없습니다."
-intro: "Misskey의 설치가 완료되었습니다! 관리자 계정을 생성해주세요."
+intro: "Misskey의 설치를 완료했습니다! 관리자 계정을 만들어 주세요."
 done: "완료"
 processing: "처리중"
 preview: "미리보기"
@@ -296,7 +296,7 @@ activity: "활동"
 images: "이미지"
 image: "이미지"
 birthday: "생일"
-yearsOld: "{age}세"
+yearsOld: "만 {age} 세"
 registeredDate: "등록일"
 location: "장소"
 theme: "테마"
@@ -400,6 +400,7 @@ name: "이름"
 antennaSource: "받을 소스"
 antennaKeywords: "받을 검색어"
 antennaExcludeKeywords: "제외할 검색어"
+antennaExcludeBots: "봇 계정 제외"
 antennaKeywordsDescription: "공백으로 구분하는 경우 AND, 줄바꿈으로 구분하는 경우 OR로 지정됩니다"
 notifyAntenna: "새로운 노트를 알림"
 withFileAntenna: "파일이 첨부된 노트만"
@@ -414,11 +415,11 @@ silence: "사일런스"
 silenceConfirm: "이 계정을 사일런스로 설정하시겠습니까?"
 unsilence: "사일런스 해제"
 unsilenceConfirm: "이 계정의 사일런스를 해제하시겠습니까?"
-popularUsers: "인기 유저"
-recentlyUpdatedUsers: "최근 활동한 유저"
-recentlyRegisteredUsers: "최근 가입한 유저"
-recentlyDiscoveredUsers: "최근 발견한 유저"
-exploreUsersCount: "{count}명의 유저가 있습니다"
+popularUsers: "인기 사용자"
+recentlyUpdatedUsers: "최근에 활동한 사용자"
+recentlyRegisteredUsers: "최근에 가입한 사용자"
+recentlyDiscoveredUsers: "최근에 발견한 사용자"
+exploreUsersCount: "{count}명의 사용자가 있습니다"
 exploreFediverse: "연합우주를 탐색"
 popularTags: "인기 태그"
 userList: "리스트"
@@ -470,7 +471,7 @@ quoteQuestion: "인용해서 작성하시겠습니까?"
 noMessagesYet: "아직 대화가 없습니다"
 newMessageExists: "새 메시지가 있습니다"
 onlyOneFileCanBeAttached: "메시지에 첨부할 수 있는 파일은 하나까지입니다"
-signinRequired: "로그인 해주세요"
+signinRequired: "진행하기 전에 로그인을 해 주세요"
 invitations: "초대"
 invitationCode: "초대 코드"
 checking: "확인하는 중입니다"
@@ -494,6 +495,7 @@ emojiStyle: "이모지 스타일"
 native: "기본"
 disableDrawer: "드로어 메뉴를 사용하지 않기"
 showNoteActionsOnlyHover: "노트 액션 버튼을 마우스를 올렸을 때에만 표시"
+showReactionsCount: "노트의 반응 수를 표시하기"
 noHistory: "기록이 없습니다"
 signinHistory: "로그인 기록"
 enableAdvancedMfm: "고급 MFM을 활성화"
@@ -529,13 +531,13 @@ useObjectStorage: "오브젝트 스토리지를 사용"
 objectStorageBaseUrl: "Base URL"
 objectStorageBaseUrlDesc: "오브젝트 (미디어) 참조 URL 을 만들 때 사용되는 URL입니다. CDN 또는 프록시를 사용하는 경우 그 URL을 지정하고, 그 외의 경우 사용할 서비스의 가이드에 따라 공개적으로 액세스 할 수 있는 주소를 지정해 주세요. 예를 들어, AWS S3의 경우 'https://<bucket>.s3.amazonaws.com', GCS등의 경우 'https://storage.googleapis.com/<bucket>' 와 같이 지정합니다."
 objectStorageBucket: "Bucket"
-objectStorageBucketDesc: "사용 서비스의 bucket명을 지정해주세요."
+objectStorageBucketDesc: "사용하는 서비스의 bucket 이름을 지정해 주세요."
 objectStoragePrefix: "Prefix"
 objectStoragePrefixDesc: "이 Prefix 의 디렉토리 아래에 파일이 저장됩니다."
 objectStorageEndpoint: "Endpoint"
-objectStorageEndpointDesc: "AWS S3의 경우 공란, 다른 서비스의 경우 각 서비스의 가이드에 맞게 endpoint를 설정해주세요. '<host>' 혹은 '<host>:<port>' 와 같이 지정합니다."
+objectStorageEndpointDesc: "AWS S3는 비워 두고 다른 서비스는 각 서비스의 endpoint를 설정해 주세요. ‘<host>’ 혹은 ‘<host>:<port>’처럼 지정합니다."
 objectStorageRegion: "Region"
-objectStorageRegionDesc: "'xx-east-1'와 같이 region을 지정해 주세요. 사용하는 서비스에 region 개념이 없는 경우 'us-east-1'으로 설정해 주세요. AWS 설정 파일 또는 환경 변수를 참조할 경우에는 비워주세요."
+objectStorageRegionDesc: "‘xx-east-1’처럼 region을 지정해 주세요. 사용하는 서비스에 region 개념이 없으면 ‘us-east-1’처럼 설정해 주세요. AWS 설정 파일이나 환경 변수가 있으면 비워 주세요."
 objectStorageUseSSL: "SSL 사용"
 objectStorageUseSSLDesc: "API 호출시 HTTPS 를 사용하지 않는 경우 OFF 로 설정해 주세요"
 objectStorageUseProxy: "연결에 프록시를 사용"
@@ -577,7 +579,7 @@ scratchpadDescription: "스크래치 패드는 AiScript 의 테스트 환경을
 output: "출력"
 script: "스크립트"
 disablePagesScript: "Pages 에서 AiScript 를 사용하지 않음"
-updateRemoteUser: "리모트 유저 정보 갱신"
+updateRemoteUser: "원격 사용자 정보 갱신"
 unsetUserAvatar: "아바타 제거"
 unsetUserAvatarConfirm: "아바타를 제거할까요?"
 unsetUserBanner: "배너 제거"
@@ -660,7 +662,7 @@ regexpErrorDescription: "{tab}단어 뮤트 {line}행의 정규 표현식에 오
 instanceMute: "서버 뮤트"
 userSaysSomething: "{name}님이 무언가를 말했습니다"
 makeActive: "활성화"
-display: "표시"
+display: "보기"
 copy: "복사"
 metrics: "통계"
 overview: "요약"
@@ -684,7 +686,7 @@ sample: "예시"
 abuseReports: "신고"
 reportAbuse: "신고"
 reportAbuseRenote: "리노트 신고하기"
-reportAbuseOf: "{name}을 신고하기"
+reportAbuseOf: "{name} 신고하기"
 fillAbuseReportDescription: "신고하려는 이유를 자세히 알려주세요. 특정 게시물을 신고할 때에는 게시물의 URL도 포함해 주세요."
 abuseReported: "신고를 보냈습니다. 신고해 주셔서 감사합니다."
 reporter: "신고자"
@@ -709,7 +711,7 @@ createNew: "새로 만들기"
 optional: "옵션"
 createNewClip: "새 클립 만들기"
 unclip: "클립 해제"
-confirmToUnclipAlreadyClippedNote: "이 노트는 이미 \"{name}\" 클립에 포함되어 있습니다. 클립을 해제하시겠습니까?"
+confirmToUnclipAlreadyClippedNote: "이 노트는 ‘{name}’ 클립을 이미 포함합니다. 클립에서 제외하시겠습니까?"
 public: "공개"
 private: "비공개"
 i18nInfo: "Misskey는 자원봉사자들에 의해 다양한 언어로 번역되고 있습니다. {link}에서 번역에 참가할 수 있습니다."
@@ -722,13 +724,13 @@ repliedCount: "받은 답글 수"
 renotedCount: "받은 리노트 수"
 followingCount: "팔로우 수"
 followersCount: "팔로워 수"
-sentReactionsCount: "보낸 리액션 수"
-receivedReactionsCount: "받은 리액션 수"
-pollVotesCount: "투표한 횟수"
-pollVotedCount: "투표받은 횟수"
+sentReactionsCount: "반응 수"
+receivedReactionsCount: "받은 반응 수"
+pollVotesCount: "투표 수"
+pollVotedCount: "받은 투표 수"
 yes: "예"
 no: "아니오"
-driveFilesCount: "드라이브 파일 개수"
+driveFilesCount: "드라이브에 있는 파일 수"
 driveUsage: "드라이브 사용량"
 noCrawle: "검색엔진의 인덱싱 거부"
 noCrawleDescription: "검색엔진에 사용자 페이지, 노트, 페이지 등의 콘텐츠를 인덱싱되지 않게 합니다."
@@ -763,7 +765,7 @@ needReloadToApply: "변경 사항은 새로고침하면 적용됩니다."
 showTitlebar: "타이틀 바를 표시하기"
 clearCache: "캐시 비우기"
 onlineUsersCount: "{n}명이 접속 중"
-nUsers: "{n} 유저"
+nUsers: "{n} 사용자"
 nNotes: "{n} 노트"
 sendErrorReports: "오류 보고서 보내기"
 sendErrorReportsDescription: "이 설정을 활성화하면, 문제가 발생했을 때 오류에 대한 상세 정보를 Misskey에 보내어 더 나은 소프트웨어를 만드는 데에 도움을 줄 수 있습니다."
@@ -809,7 +811,7 @@ addDescription: "설명 추가"
 userPagePinTip: "각 노트의 메뉴에서 「프로필에 고정」을 선택하는 것으로, 여기에 노트를 표시해 둘 수 있어요."
 notSpecifiedMentionWarning: "수신자가 선택되지 않은 멘션이 있어요"
 info: "정보"
-userInfo: "유저 정보"
+userInfo: "사용자 정보"
 unknown: "알 수 없음"
 onlineStatus: "온라인 상태"
 hideOnlineStatus: "온라인 상태 숨기기"
@@ -897,7 +899,7 @@ incorrectPassword: "비밀번호가 올바르지 않습니다."
 voteConfirm: "\"{choice}\"에 투표하시겠습니까?"
 hide: "숨기기"
 useDrawerReactionPickerForMobile: "모바일에서 드로어 메뉴로 표시"
-welcomeBackWithName: "환영합니다, {name}님"
+welcomeBackWithName: "{name}님, 환영합니다."
 clickToFinishEmailVerification: "[{ok}]를 눌러 이메일 인증을 완료하세요."
 overridedDeviceKind: "장치 유형"
 smartphone: "스마트폰"
@@ -1092,9 +1094,9 @@ preservedUsernames: "예약된 사용자명"
 preservedUsernamesDescription: "예약할 사용자명을 한 줄에 하나씩 입력합니다. 여기에서 지정한 사용자명으로는 계정을 생성할 수 없게 됩니다. 단, 관리자 권한으로 계정을 생성할 때에는 해당되지 않으며, 이미 존재하는 계정도 영향을 받지 않습니다."
 createNoteFromTheFile: "이 파일로 노트를 작성"
 archive: "아카이브"
-channelArchiveConfirmTitle: "{name} 을(를) 아카이브하시겠습니까?"
-channelArchiveConfirmDescription: "아카이브한 채널은 채널 목록과 검색 결과에 표시되지 않으며, 채널에 새로운 노트를 작성할 수 없게 됩니다."
-thisChannelArchived: "이 채널은 아카이브되었습니다."
+channelArchiveConfirmTitle: "{name} 채널을 보존하시겠습니까?"
+channelArchiveConfirmDescription: "보존한 채널은 채널 목록과 검색 결과에 표시되지 않으며 새로운 노트도 작성할 수 없습니다."
+thisChannelArchived: "이 채널은 보존되었습니다."
 displayOfNote: "노트 표시"
 initialAccountSetting: "초기 설정"
 youFollowing: "팔로잉"
@@ -1156,10 +1158,11 @@ unnotifyNotes: "새 노트 알림 끄기"
 authentication: "인증"
 authenticationRequiredToContinue: "계속하려면 인증하십시오"
 dateAndTime: "일시"
-showRenotes: "리노트 표시"
+showRenotes: "리노트 보기"
 edited: "수정됨"
 notificationRecieveConfig: "알림 설정"
 mutualFollow: "맞팔로우"
+followingOrFollower: "팔로 중이거나 팔로워"
 fileAttachedOnly: "미디어를 포함한 노트만"
 showRepliesToOthersInTimeline: "타임라인에 다른 사람에게 보내는 답글을 포함"
 hideRepliesToOthersInTimeline: "타임라인에 다른 사람에게 보내는 답글을 포함하지 않음"
@@ -1210,16 +1213,34 @@ soundWillBePlayed: "소리가 재생됩니다"
 showReplay: "리플레이 보기"
 replay: "리플레이"
 replaying: "리플레이 중"
+endReplay: "리플레이 종료"
+copyReplayData: "리플레이 데이터를 복사"
 ranking: "랭킹"
 lastNDays: "최근 {n}일"
 backToTitle: "타이틀로 가기"
 hemisphere: "거주 지역"
 withSensitive: "민감한 파일이 포함된 노트 보기"
-userSaysSomethingSensitive: "{name}의 민감한 파일이 포함된 게시물"
+userSaysSomethingSensitive: "{name} 같은 민감한 파일이 포함된 글"
 enableHorizontalSwipe: "스와이프하여 탭 전환"
+loading: "불러오는 중"
 surrender: "그만두기"
+gameRetry: "다시 시도"
+notUsePleaseLeaveBlank: "사용하지 않는 경우 비워두세요."
+useTotp: "일회용 비밀번호 사용"
+useBackupCode: "백업 코드 사용"
+launchApp: "앱 실행"
+useNativeUIForVideoAudioPlayer: "브라우저 UI에서 미디어 재생"
 _bubbleGame:
   howToPlay: "설명"
+  hold: "홀드"
+  _score:
+    score: "점수"
+    scoreYen: "번 돈"
+    highScore: "최고 점수"
+    maxChain: "최대 콤보 수"
+    yen: "{yen}엔"
+    estimatedQty: "{qty}개"
+    scoreSweets: "오니기리 {onigiriQtyWithUnit}"
   _howToPlay:
     section1: "위치를 조정하여 상자에 물건을 떨어뜨립니다."
     section2: "같은 종류의 물건이 붙으면 다른 물건으로 바뀌면서 점수를 얻게 됩니다."
@@ -1232,7 +1253,7 @@ _announcement:
   end: "공지에서 내리기"
   tooManyActiveAnnouncementDescription: "공지사항이 너무 많을 경우, 사용자 경험에 영향을 끼칠 가능성이 있습니다. 오래된 공지사항은 아카이브하시는 것을 권장드립니다."
   readConfirmTitle: "읽음으로 표시합니까?"
-  readConfirmText: "\"{title}\"을(를) 읽음으로 표시합니다."
+  readConfirmText: "〈{title}〉의 내용을 읽음으로 표시합니다."
   shouldNotBeUsedToPresentPermanentInfo: "신규 유저의 이용 경험에 악영향을 끼칠 수 있으므로, 일시적인 알림 수단으로만 사용하고 고정된 정보에는 사용을 지양하는 것을 추천합니다."
   dialogAnnouncementUxWarn: "다이얼로그 형태의 알림이 동시에 2개 이상 존재하는 경우, 사용자 경험에 악영향을 끼칠 수 있으므로 신중히 결정하십시오."
   silence: "조용히 알림"
@@ -1513,7 +1534,7 @@ _achievements:
     _iLoveMisskey:
       title: "I Love Misskey"
       description: "\"I ❤ #Misskey\"를 포스트했습니다"
-      flavor: "Misskey를 이용해주셔서 감사합니다! - 개발팀 일동"
+      flavor: "Misskey를 이용해 주셔서 감사합니다! ― 개발 팀"
     _foundTreasure:
       title: "보물찾기"
       description: "숨겨진 보물을 발견했습니다"
@@ -1551,10 +1572,10 @@ _achievements:
       description: "3개 이상의 창을 열었습니다"
     _driveFolderCircularReference:
       title: "순환 참조"
-      description: "드라이브 폴더를 자신을 가리키도록 만드려 시도했습니다"
+      description: "드라이브 폴더에 스스로를 넣게 했습니다"
     _reactWithoutRead:
       title: "읽고 답하긴 하시는 건가요?"
-      description: "100자가 넘는 노트가 작성되고 3초 안에 반응했습니다"
+      description: "100자가 넘는 노트를 작성한 지 3초 안에 반응했어요"
     _clickedClickHere:
       title: "여기를 누르세요"
       description: "여기를 눌렀습니다"
@@ -1641,6 +1662,7 @@ _role:
     gtlAvailable: "글로벌 타임라인 보이기"
     ltlAvailable: "로컬 타임라인 보이기"
     canPublicNote: "공개 노트 허용"
+    mentionMax: "노트에 넣을 수 있는 멘션 수"
     canInvite: "서버 초대 코드 발행"
     inviteLimit: "초대 한도"
     inviteLimitCycle: "초대 발급 간격"
@@ -1650,13 +1672,13 @@ _role:
     driveCapacity: "드라이브 용량"
     alwaysMarkNsfw: "파일을 항상 NSFW로 지정"
     pinMax: "고정할 수 있는 노트 수"
-    antennaMax: "최대 안테나 생성 허용 수"
+    antennaMax: "만들 수 있는 안테나 수"
     wordMuteMax: "단어 뮤트할 수 있는 문자 수"
-    webhookMax: "생성할 수 있는 웹훅 수"
-    clipMax: "생성할 수 있는 클립 수"
-    noteEachClipsMax: "각 클립에 추가할 수 있는 노트 수"
-    userListMax: "생성할 수 있는 유저 리스트 수"
-    userEachUserListsMax: "유저 리스트당 최대 사용자 수"
+    webhookMax: "만들 수 있는 웹후크 수"
+    clipMax: "만들 수 있는 클립 수"
+    noteEachClipsMax: "클립에 넣을 수 있는 노트 수"
+    userListMax: "만들 수 있는 사용자 리스트 수"
+    userEachUserListsMax: "사용자 리스트에 넣을 수 있는 사용자 수"
     rateLimitFactor: "요청 빈도 제한"
     descriptionOfRateLimitFactor: "작을수록 제한이 완화되고, 클수록 제한이 강화됩니다."
     canHideAds: "광고 숨기기"
@@ -1664,16 +1686,17 @@ _role:
     canUseTranslator: "번역 기능의 사용"
     avatarDecorationLimit: "아바타 장식의 최대 붙임 개수"
   _condition:
+    roleAssignedTo: "수동 역할에 이미 할당됨"
     isLocal: "로컬 사용자"
     isRemote: "리모트 사용자"
     createdLessThan: "가입한 지 다음 일수 이내인 유저"
     createdMoreThan: "가입한 지 다음 일수 이상인 유저"
     followersLessThanOrEq: "팔로워 수가 다음 이하인 유저"
-    followersMoreThanOrEq: "팔로워 수가 다음 이상인 유저"
+    followersMoreThanOrEq: "팔로워 수가 다음보다 많은 사용자"
     followingLessThanOrEq: "팔로잉 수가 다음 이하인 유저"
-    followingMoreThanOrEq: "팔로잉 수가 다음 이상인 유저"
+    followingMoreThanOrEq: "팔로잉 수가 다음보다 많은 사용자"
     notesLessThanOrEq: "노트 수가 다음 이하인 유저"
-    notesMoreThanOrEq: "노트 수가 다음 이상인 유저"
+    notesMoreThanOrEq: "노트 수가 다음보다 많은 사용자"
     and: "다음을 모두 만족"
     or: "다음을 하나라도 만족"
     not: "다음을 만족하지 않음"
@@ -1735,6 +1758,7 @@ _plugin:
   installWarn: "신뢰할 수 없는 플러그인은 설치하지 않는 것이 좋습니다."
   manage: "플러그인 관리"
   viewSource: "소스 보기"
+  viewLog: "로그 보기"
 _preferencesBackups:
   list: "생성한 백업"
   saveNew: "새 백업 만들기"
@@ -1745,12 +1769,12 @@ _preferencesBackups:
   cannotSave: "저장하지 못했습니다"
   nameAlreadyExists: "\"{name}\" 백업이 이미 존재합니다. 다른 이름을 설정하여 주십시오."
   applyConfirm: "\"{name}\" 백업을 현재 기기에 적용하시겠습니까? 현재 설정은 덮어 씌워집니다."
-  saveConfirm: "{name} 을 덮어쓰시겠습니까?"
-  deleteConfirm: "{name} 을(를) 삭제하시겠습니까?"
-  renameConfirm: "\"{old}\" 백업을 \"{new}\"(으)로 바꾸시겠습니까?"
+  saveConfirm: "{name} 백업을 덮어쓰시겠습니까?"
+  deleteConfirm: "{name} 백업을 삭제하시겠습니까?"
+  renameConfirm: "‘{old}’ 백업을 ‘{new}’ 백업으로 바꾸시겠습니까?"
   noBackups: "저장된 백업이 없습니다. \"새 백업 만들기\"를 눌러 현재 클라이언트 설정을 서버에 백업할 수 있습니다."
-  createdAt: "생성 날짜: {date} {time}"
-  updatedAt: "갱신 날짜: {date} {time}"
+  createdAt: "만든 날짜: {date} {time}"
+  updatedAt: "고친 날짜: {date} {time}"
   cannotLoad: "가져오기에 실패했습니다"
   invalidFile: "파일 형식이 올바르지 않습니다."
 _registry:
@@ -1924,7 +1948,6 @@ _2fa:
   registerTOTP: "인증 앱 설정 시작"
   step1: "먼저, {a}나 {b}등의 인증 앱을 사용 중인 디바이스에 설치합니다."
   step2: "그 후, 표시되어 있는 QR코드를 앱으로 스캔합니다."
-  step2Click: "QR 코드를 클릭하면 기기에 설치된 인증 앱에 등록할 수 있습니다."
   step2Uri: "데스크톱 앱을 사용하려면 다음 URI를 입력하십시오"
   step3Title: "인증 코드 입력"
   step3: "앱에 표시된 토큰을 입력하시면 완료됩니다."
@@ -1937,7 +1960,7 @@ _2fa:
   securityKeyName: "키 이름 입력"
   tapSecurityKey: "브라우저의 지시에 따라 보안 키 또는 패스키를 등록하여 주십시오"
   removeKey: "보안 키를 삭제"
-  removeKeyConfirm: "{name} 을(를) 삭제하시겠습니까?"
+  removeKeyConfirm: "{name} 앱을 삭제하시겠습니까?"
   whyTOTPOnlyRenew: "보안 키가 등록되어 있는 경우 인증 앱을 해제할 수 없습니다."
   renewTOTP: "인증 앱 재설정"
   renewTOTPConfirm: "기존에 등록되어 있던 인증 키는 사용하지 못하게 됩니다."
@@ -2078,7 +2101,7 @@ _widgets:
   postForm: "글 입력란"
   slideshow: "슬라이드 쇼"
   button: "버튼"
-  onlineUsers: "온라인 유저"
+  onlineUsers: "온라인 사용자"
   jobQueue: "작업 대기열"
   serverMetric: "서버 통계"
   aiscript: "AiScript 콘솔"
@@ -2137,10 +2160,10 @@ _postForm:
     c: "무엇을 생각하고 있나요?"
     d: "말하고 싶은 게 있나요?"
     e: "여기에 적어 주세요"
-    f: "작성해주시길 기다리고 있어요..."
+    f: "글 쓰기를 기다려요…"
 _profile:
   name: "이름"
-  username: "유저명"
+  username: "사용자 이름"
   description: "자기소개"
   youCanIncludeHashtags: "해시 태그를 포함할 수 있습니다."
   metadata: "추가 정보"
@@ -2168,7 +2191,7 @@ _charts:
   apRequest: "요청"
   usersIncDec: "유저 수 증감"
   usersTotal: "유저 수 합계"
-  activeUsers: "활성 유저 수"
+  activeUsers: "활동 사용자 수"
   notesIncDec: "노트 수 증감"
   localNotesIncDec: "로컬 노트 수 증감"
   remoteNotesIncDec: "리모트 노트 수 증감"
@@ -2179,8 +2202,8 @@ _charts:
   storageUsageTotal: "스토리지 사용량 합계"
 _instanceCharts:
   requests: "요청"
-  users: "유저 수 증감"
-  usersTotal: "누적 유저 수"
+  users: "사용자 수 차이"
+  usersTotal: "누적 사용자 수"
   notes: "노트 수 증감"
   notesTotal: "누적 노트 수"
   ff: "팔로잉/팔로워 증감"
@@ -2209,6 +2232,7 @@ _play:
   title: "제목"
   script: "스크립트"
   summary: "설명"
+  visibilityDescription: "비공개로 설정하면 프로필에 표시하지 않지만 URL을 아는 사람은 계속해서 접속할 수 있습니다."
 _pages:
   newPage: "페이지 만들기"
   editPage: "페이지 수정"
@@ -2219,7 +2243,7 @@ _pages:
   pageSetting: "페이지 설정"
   nameAlreadyExists: "지정한 페이지 URL이 이미 존재합니다"
   invalidNameTitle: "유효하지 않은 페이지 URL입니다"
-  invalidNameText: "비어있지 않은지 확인해주세요"
+  invalidNameText: "비어있는지 확인해 주세요"
   editThisPage: "이 페이지를 편집"
   viewSource: "소스 보기"
   viewPage: "페이지 보기"
@@ -2253,6 +2277,8 @@ _pages:
     section: "섹션"
     image: "이미지"
     button: "버튼"
+    dynamic: "동적 블록"
+    dynamicDescription: "이 블록은 폐지되었습니다. 이제부터 {play}에서 이용해 주세요."
     note: "노트필기"
     _note:
       id: "노트 ID"
@@ -2282,17 +2308,19 @@ _notification:
   sendTestNotification: "테스트 알림 보내기"
   notificationWillBeDisplayedLikeThis: "알림이 이렇게 표시됩니다"
   reactedBySomeUsers: "{n}명이 반응했습니다"
+  likedBySomeUsers: "{n}명이 좋아요를 했습니다"
   renotedBySomeUsers: "{n}명이 리노트했습니다"
   followedBySomeUsers: "{n}명에게 팔로우됨"
+  flushNotification: "알림 이력을 초기화"
   _types:
     all: "전부"
-    note: "유저의 새 게시물"
+    note: "사용자의 새 글"
     follow: "팔로잉"
     mention: "멘션"
     reply: "답글"
     renote: "리노트"
     quote: "인용"
-    reaction: "리액션"
+    reaction: "반응"
     pollEnded: "투표가 종료됨"
     receiveFollowRequest: "팔로우 요청을 받았을 때"
     followRequestAccepted: "팔로우 요청이 승인되었을 때"
@@ -2335,7 +2363,7 @@ _deck:
     direct: "다이렉트"
     roleTimeline: "역할 타임라인"
 _dialog:
-  charactersExceeded: "최대 글자수를 초과하였습니다! 현재 {current} / 최대 {min}"
+  charactersExceeded: "최대 글자수를 초과하였습니다! 현재 {current} / 최대 {max}"
   charactersBelow: "최소 글자수 미만입니다! 현재 {current} / 최소 {min}"
 _disabledTimeline:
   title: "비활성화된 타임라인"
@@ -2459,7 +2487,7 @@ _dataSaver:
 _hemisphere:
   N: "북반구"
   S: "남반구"
-  caption: "일부 클라이언트 설정에서 계절을 판단하기 위해 사용합니다."
+  caption: "일부 클라이언트 설정에서 계절을 판단하려고 사용합니다."
 _reversi:
   reversi: "리버시"
   gameSettings: "대국 설정"
@@ -2467,42 +2495,61 @@ _reversi:
   blackOrWhite: "선공/후공"
   blackIs: "{name}님이 흑(선공)"
   rules: "규칙"
-  thisGameIsStartedSoon: "대국이 곧 시작됩니다"
-  waitingForOther: "상대방의 준비가 완료되기를 기다리고 있습니다."
-  waitingForMe: "당신의 준비가 완료되기를 기다리고 있습니다."
+  thisGameIsStartedSoon: "대국을 곧 시작합니다"
+  waitingForOther: "상대의 준비가 끝나기를 기다리고 있습니다."
+  waitingForMe: "나의 준비가 끝나기를 기다리고 있습니다."
   waitingBoth: "준비하세요"
   ready: "준비 완료"
-  cancelReady: "준비 다시 시작"
+  cancelReady: "준비되지 않음"
   opponentTurn: "상대의 차례입니다"
-  myTurn: "당신의 차례입니다"
-  turnOf: "{name}의 차례입니다"
-  pastTurnOf: "{name}의 차례"
+  myTurn: "나의 차례입니다"
+  turnOf: "{name}님의 차례입니다"
+  pastTurnOf: "{name}님의 차례"
   surrender: "기권"
-  surrendered: "기권에 의해"
+  surrendered: "상대의 기권"
   timeout: "시간 초과"
   drawn: "무승부"
-  won: "{name}의 승리"
+  won: "{name}님의 승리"
   black: "흑"
   white: "백"
   total: "합계"
-  turnCount: "{count}턴 째"
+  turnCount: "{count}번째 수"
   myGames: "내 대국"
-  allGames: "모두의 대국"
+  allGames: "모든 대국"
   ended: "종료"
   playing: "대국 중"
-  isLlotheo: "돌이 적은 사람이 승리 (로세오)"
-  loopedMap: "루프 지도"
-  canPutEverywhere: "어디에도 둘 수 있는 모드"
-  timeLimitForEachTurn: "1턴의 시간 제한"
-  freeMatch: "프리매치"
-  lookingForPlayer: "상대를 찾고 있습니다"
+  isLlotheo: "돌이 적은 쪽이 승리(로세오)"
+  loopedMap: "순환 지도"
+  canPutEverywhere: "어디든 둘 수 있는 모드"
+  timeLimitForEachTurn: "각 수의 시간 제한"
+  freeMatch: "자유 대국"
+  lookingForPlayer: "대국 상대를 찾고 있습니다"
   gameCanceled: "대국이 취소되었습니다"
-  shareToTlTheGameWhenStart: "대국 시작 시 타임라인에 대국을 게시"
-  iStartedAGame: "대국이 시작되었습니다! #MisskeyReversi"
-  opponentHasSettingsChanged: "상대방이 설정을 변경했습니다"
-  allowIrregularRules: "규칙변경 허가 (완전 자유)"
-  disallowIrregularRules: "규칙변경 없음"
+  shareToTlTheGameWhenStart: "대국이 시작할 때 타임라인에 공유"
+  iStartedAGame: "대국을 시작하였습니다! #MisskeyReversi"
+  opponentHasSettingsChanged: "상대가 설정을 변경했습니다"
+  allowIrregularRules: "규칙 변경 허용(완전 자유)"
+  disallowIrregularRules: "규칙 변경 없음"
+  showBoardLabels: "판에 행·열 번호 표시"
+  useAvatarAsStone: "돌을 아이콘으로 표시"
 _offlineScreen:
   title: "오프라인 - 서버에 접속할 수 없습니다"
   header: "서버에 접속할 수 없습니다"
-
+_urlPreviewSetting:
+  title: "URL 미리보기 설정"
+  enable: "URL 미리보기 활성화"
+  timeout: "미리보기를 불러올 때의 타임아웃 (ms)"
+  timeoutDescription: "미리보기를 로딩하는데 걸리는 시간이 정한 시간보다 오래 걸리는 경우, 미리보기를 생성하지 않습니다."
+  maximumContentLength: "Content-Length의 최대치 (byte)"
+  maximumContentLengthDescription: "Content-Length가 이 값을 넘어서면 미리보기를 생성하지 않습니다."
+  requireContentLength: "Content-Length를 얻었을 때만 미리보기 만들기"
+  requireContentLengthDescription: "상대 서버가 Content-Length를 되돌려주지 않는다면 미리보기를 만들지 않습니다."
+  userAgent: "User-Agent"
+  userAgentDescription: "미리보기를 얻을 때 사용한 User-Agent를 설정합니다. 비어 있다면 기본값의 User-Agent를 사용합니다."
+  summaryProxy: "미리보기를 만든 프록시의 엔드포인트"
+  summaryProxyDescription: "Misskey 본체를 사용하지 않고 서머리 프록시로 미리보기를 만듭니다."
+  summaryProxyDescription2: "프록시는 아래의 파라미터를 쿼리 문자열로 연동합니다. 프록시 측이 이를 지원하지 않으면 설정값을 무시합니다."
+_mediaControls:
+  pip: "화면 속 화면"
+  playbackRate: "재생 속도"
+  loop: "반복 재생"
diff --git a/locales/lo-LA.yml b/locales/lo-LA.yml
index 6f03c914fd..fa4b3b6f9a 100644
--- a/locales/lo-LA.yml
+++ b/locales/lo-LA.yml
@@ -466,4 +466,3 @@ _webhookSettings:
   name: "ຊື່"
 _moderationLogTypes:
   suspend: "ລະງັບ"
-
diff --git a/locales/nl-NL.yml b/locales/nl-NL.yml
index e3ff426177..e33b978bc8 100644
--- a/locales/nl-NL.yml
+++ b/locales/nl-NL.yml
@@ -497,4 +497,3 @@ _webhookSettings:
 _moderationLogTypes:
   suspend: "Opschorten"
   resetPassword: "Wachtwoord terugzetten"
-
diff --git a/locales/no-NO.yml b/locales/no-NO.yml
index 098faa8add..475f93267b 100644
--- a/locales/no-NO.yml
+++ b/locales/no-NO.yml
@@ -721,4 +721,3 @@ _webhookSettings:
   name: "Navn"
 _moderationLogTypes:
   suspend: "Suspender"
-
diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml
index 99eb1f3028..b7eb4683eb 100644
--- a/locales/pl-PL.yml
+++ b/locales/pl-PL.yml
@@ -20,6 +20,7 @@ noNotes: "Brak wpisów"
 noNotifications: "Brak powiadomień"
 instance: "Instancja"
 settings: "Ustawienia"
+notificationSettings: "Powiadomienia"
 basicSettings: "Podstawowe ustawienia"
 otherSettings: "Pozostałe ustawienia"
 openInWindow: "Otwórz w oknie"
@@ -44,13 +45,20 @@ pin: "Przypnij do profilu"
 unpin: "Odepnij z profilu"
 copyContent: "Skopiuj zawartość"
 copyLink: "Skopiuj odnośnik"
+copyLinkRenote: "Skopiuj link renote'a"
 delete: "Usuń"
 deleteAndEdit: "Usuń i edytuj"
 deleteAndEditConfirm: "Czy na pewno chcesz usunąć ten wpis i zedytować go? Utracisz wszystkie reakcje, udostępnienia i odpowiedzi do tego wpisu."
 addToList: "Dodaj do listy"
+addToAntenna: "Dodaj do anteny"
 sendMessage: "Wyślij wiadomość"
 copyRSS: "Kopiuj RSS"
 copyUsername: "Kopiuj nazwę użytkownika"
+copyUserId: "Kopiuj ID użytkownika"
+copyNoteId: "Kopiuj ID notatki"
+copyFileId: "Kopiuj ID pliku"
+copyFolderId: "Kopiuj ID folderu"
+copyProfileUrl: "Kopiuj URL profilu"
 searchUser: "Wyszukiwanie użytkowników"
 reply: "Odpowiedz"
 loadMore: "Załaduj więcej"
@@ -103,6 +111,8 @@ renoted: "Udostępniono."
 cantRenote: "Ten wpis nie może zostać udostępniony."
 cantReRenote: "Udostępnienie nie może zostać udostępnione."
 quote: "Cytuj"
+inChannelRenote: "Renote tylko na kanale"
+inChannelQuote: "Cytat tylko na kanale"
 pinnedNote: "Przypięty wpis"
 pinned: "Przypnij do profilu"
 you: "Ty"
@@ -111,14 +121,23 @@ sensitive: "NSFW"
 add: "Dodaj"
 reaction: "Reakcja"
 reactions: "Reakcja"
+emojiPicker: "Selektor Emoji"
+pinnedEmojisForReactionSettingDescription: "Ustaw emotikony które powinny być przypięte i od razu wyświetlone podczas reagowania."
+pinnedEmojisSettingDescription: "Ustaw emotikony które powinny być przypięte i wyświetlone podczas przeglądania selektora Emoji"
+emojiPickerDisplay: "Wyświetlanie selektora Emoji"
+overwriteFromPinnedEmojisForReaction: "Zastąp z ustawień reakcji"
+overwriteFromPinnedEmojis: "Zastąp z ogólnych ustawień"
 reactionSettingDescription2: "Przeciągnij aby zmienić kolejność, naciśnij aby usunąć, naciśnij „+” aby dodać"
 rememberNoteVisibility: "Zapamiętuj ustawienia widoczności wpisu"
 attachCancel: "Usuń załącznik"
+deleteFile: "Usuń plik"
 markAsSensitive: "Oznacz jako NSFW"
 unmarkAsSensitive: "Cofnij NSFW"
 enterFileName: "Wprowadź nazwę pliku"
 mute: "Wycisz"
 unmute: "Cofnij wyciszenie"
+renoteMute: "Wycisz renote'y"
+renoteUnmute: "Wyłącz wyciszenie renote'ów"
 block: "Zablokuj"
 unblock: "Odblokuj"
 suspend: "Zawieś"
@@ -128,8 +147,10 @@ unblockConfirm: "Czy na pewno chcesz odblokować to konto?"
 suspendConfirm: "Czy na pewno chcesz zawiesić to konto?"
 unsuspendConfirm: "Czy na pewno chcesz cofnąć zawieszenie tego konta?"
 selectList: "Wybierz listę"
+editList: "Edytuj listę"
 selectChannel: "Wybierz kanał"
 selectAntenna: "Wybierz Antennę"
+editAntenna: "Edytuj antenę"
 selectWidget: "Wybierz widżet"
 editWidgets: "Edytuj widżety"
 editWidgetsExit: "Gotowe"
@@ -142,11 +163,15 @@ addEmoji: "Dodaj emoji"
 settingGuide: "Proponowana konfiguracja"
 cacheRemoteFiles: "Przechowuj zdalne pliki w pamięci podręcznej"
 cacheRemoteFilesDescription: "Gdy ta opcja jest wyłączona, zdalne pliki są ładowane bezpośrednio ze zdalnych instancji. Wyłączenie the opcji zmniejszy użycie powierzchni dyskowej, ale zwiększy transfer, ponieważ miniaturki nie będą generowane."
+youCanCleanRemoteFilesCache: "Możesz wyczyścić cache poprzez kliknięcie przycisku 🗑️ w widoku menedżera plików."
+cacheRemoteSensitiveFiles: "Przechowuj wrażliwe zdalne pliki w pamięci podręcznej"
+cacheRemoteSensitiveFilesDescription: "Gdy ta opcja jest wyłączona, wrażliwe pliki zdalne są wczytywane bezpośrednio ze zdalnej instancji bez cacheowania."
 flagAsBot: "To konto jest botem"
 flagAsBotDescription: "Jeżeli ten kanał jest kontrolowany przez jakiś program, ustaw tę opcję. Jeżeli włączona, będzie działać jako flaga informująca innych programistów, aby zapobiegać nieskończonej interakcji z różnymi botami i dostosowywać wewnętrzne systemy Misskey, traktując konto jako bota."
 flagAsCat: "To konto jest kotem"
 flagAsCatDescription: "Przełącz tę opcję, aby konto było oznaczone jako kot."
 flagShowTimelineReplies: "Pokazuj odpowiedzi na osi czasu"
+flagShowTimelineRepliesDescription: "Gdy włączone, pokazuje odpowiedzi użytkowników na notatki innych użytkowników w osi czasu."
 autoAcceptFollowed: "Automatycznie przyjmuj prośby o możliwość obserwacji od użytkowników, których obserwujesz"
 addAccount: "Dodaj konto"
 reloadAccountsList: "Odśwież listę kont"
@@ -176,6 +201,7 @@ perHour: "co godzinę"
 perDay: "co dzień"
 stopActivityDelivery: "Przestań przesyłać aktywności"
 blockThisInstance: "Zablokuj tę instancję"
+silenceThisInstance: "Wycisz tę instancję"
 operations: "Działania"
 software: "Oprogramowanie"
 version: "Wersja"
@@ -195,6 +221,8 @@ clearCachedFiles: "Wyczyść pamięć podręczną"
 clearCachedFilesConfirm: "Czy na pewno chcesz usunąć wszystkie zdalne pliki z pamięci podręcznej?"
 blockedInstances: "Zablokowane instancje"
 blockedInstancesDescription: "Wypisz nazwy hostów instancji, które powinny zostać zablokowane. Wypisane instancje nie będą mogły dłużej komunikować się z tą instancją."
+silencedInstances: "Wyciszone instancje"
+silencedInstancesDescription: "Wypisz nazwy hostów instancji, które chcesz wyciszyć. Wszystkie konta wymienionych instancji będą traktowane jako wyciszone, będą mogły jedynie wysyłać prośby o obserwację i nie będą mogły wspominać kont lokalnych, jeśli nie będą obserwowane. Nie będzie to miało wpływu na zablokowane instancje."
 muteAndBlock: "Wycisz / Zablokuj"
 mutedUsers: "Wyciszeni użytkownicy"
 blockedUsers: "Zablokowani użytkownicy"
@@ -239,10 +267,12 @@ removed: "Pomyślnie usunięto"
 removeAreYouSure: "Czy na pewno chcesz usunąć „{x}”?"
 deleteAreYouSure: "Czy na pewno chcesz usunąć „{x}”?"
 resetAreYouSure: "Czy na pewno chcesz zresetować?"
+areYouSure: "Na pewno?"
 saved: "Zapisano"
 messaging: "Wiadomości"
 upload: "Wyślij"
 keepOriginalUploading: "Zachowaj oryginalny obraz"
+keepOriginalUploadingDescription: "Zapisuje oryginalnie przesłany obraz w niezmienionej postaci. Jeśli ta opcja jest wyłączona, po przesłaniu zostanie wygenerowana wersja do wyświetlenia w Internecie."
 fromDrive: "Z dysku"
 fromUrl: "Z adresu URL"
 uploadFromUrl: "Wyślij z adresu URL"
@@ -255,7 +285,10 @@ noMoreHistory: "Nie ma dalszej historii"
 startMessaging: "Rozpocznij czat"
 nUsersRead: "przeczytano przez {n}"
 agreeTo: "Wyrażam zgodę na {0}"
+agree: "Zatwierdź"
 agreeBelow: "Zaakceptuj poniżej"
+basicNotesBeforeCreateAccount: "Ważne notatki"
+termsOfService: "Warunki usługi"
 start: "Rozpocznij"
 home: "Strona główna"
 remoteUserCaution: "Te informacje mogą nie być aktualne, ponieważ użytkownik pochodzi ze zdalnej instancji."
@@ -285,6 +318,7 @@ folderName: "Nazwa katalogu"
 createFolder: "Utwórz katalog"
 renameFolder: "Zmień nazwę katalogu"
 deleteFolder: "Usuń ten katalog"
+folder: "Folder"
 addFile: "Dodaj plik"
 emptyDrive: "Dysk jest pusty"
 emptyFolder: "Ten katalog jest pusty"
@@ -298,6 +332,7 @@ copyUrl: "Skopiuj adres URL"
 rename: "Zmień nazwę"
 avatar: "Awatar"
 banner: "Baner"
+displayOfSensitiveMedia: "Wyświetlanie wrażliwej zawartości"
 whenServerDisconnected: "Po utracie połączenia z serwerem"
 disconnectedFromServer: "Utracono połączenie z serwerem."
 reload: "Odśwież"
@@ -345,8 +380,11 @@ hcaptcha: "hCaptcha"
 enableHcaptcha: "Włącz hCaptcha"
 hcaptchaSiteKey: "Klucz strony"
 hcaptchaSecretKey: "Tajny klucz"
+mcaptcha: "mCaptcha"
+enableMcaptcha: "Włącz mCaptcha"
 mcaptchaSiteKey: "Klucz strony"
 mcaptchaSecretKey: "Tajny klucz"
+mcaptchaInstanceUrl: "URL instancji mCaptcha"
 recaptcha: "reCAPTCHA"
 enableRecaptcha: "Włącz reCAPTCHA"
 recaptchaSiteKey: "Klucz strony"
@@ -389,15 +427,19 @@ aboutMisskey: "O Misskey"
 administrator: "Admin"
 token: "Token"
 2fa: "Klucz 2FA "
+setupOf2fa: "Skonfiguruj dwuetapową autentykację"
 totp: "Klucz aplikacji uwierzytelniającej (totp)"
 totpDescription: "Opis klucza czasowego"
 moderator: "Moderator"
 moderation: "Moderacja"
+moderationNote: "Notka moderacyjna"
+addModerationNote: "Dodaj notkę moderacyjną"
+moderationLogs: "Logi moderacyjne"
 nUsersMentioned: "{n} wspomnianych użytkowników"
 securityKeyAndPasskey: "Klucz bezpieczeństwa i klucze Passkey"
 securityKey: "Klucz bezpieczeństwa"
 lastUsed: "Ostatnio używane"
-lastUsedAt: "Ostatnio używane w"
+lastUsedAt: "Ostatnio używane: {t}"
 unregister: "Cofnij rejestrację"
 passwordLessLogin: "Skonfiguruj logowanie bez użycia hasła"
 passwordLessLoginDescription: "Opis logowania bez użycia hasła"
@@ -451,8 +493,12 @@ aboutX: "O {x}"
 emojiStyle: "Styl emoji"
 native: "Natywny"
 disableDrawer: "Nie używaj menu w stylu szuflady"
+showNoteActionsOnlyHover: "Pokazuj akcje notatek tylko po najechaniu myszką"
+showReactionsCount: "Wyświetl liczbę reakcji na notatkę"
 noHistory: "Brak historii"
 signinHistory: "Historia logowania"
+enableAdvancedMfm: "Włącz zaawansowane MFM"
+enableAnimatedMfm: "Włącz animowane MFM"
 doing: "Przetwarzanie..."
 category: "Kategoria"
 tags: "Tagi"
@@ -461,6 +507,8 @@ createAccount: "Utwórz konto"
 existingAccount: "Istniejące konto"
 regenerate: "Wygeneruj ponownie"
 fontSize: "Rozmiar czcionki"
+mediaListWithOneImageAppearance: "Wysokość list multimediów z tylko jednym obrazem"
+limitTo: "Limituj do {x}"
 noFollowRequests: "Nie masz żadnych oczekujących próśb o możliwość obserwacji"
 openImageInNewTab: "Otwórz obraz w nowej karcie"
 dashboard: "Kokpit"
@@ -480,6 +528,7 @@ showFeaturedNotesInTimeline: "Pokazuj wyróżnione wpisy w osi czasu"
 objectStorage: "Pamięć obiektowa"
 useObjectStorage: "Używaj pamięci obiektowej"
 objectStorageBaseUrl: "Podstawowy URL"
+objectStorageBaseUrlDesc: "Adres URL używany jako odniesienie. Podaj adres URL swojego CDN lub Proxy, gdy używasz któregokolwiek z nich.\nDla S3 użyj 'https://<bucket>.s3.amazonaws.com' a dla GCS lub równej usługi użyj 'https://storage.googleapis.com/<bucket>', itd."
 objectStorageBucket: "Bucket"
 objectStorageBucketDesc: "Podaj nazwę „wiadra” używaną przez konfigurowaną usługę."
 objectStoragePrefix: "Prefiks"
@@ -492,9 +541,13 @@ objectStorageUseSSL: "Użyj SSL"
 objectStorageUseSSLDesc: "Wyłącz, jeżeli nie zamierzasz używać HTTPS dla połączenia z API"
 objectStorageUseProxy: "Połącz przez proxy"
 objectStorageUseProxyDesc: "Wyłącz, jeżeli nie zamierzasz używać proxy dla połączenia z pamięcią blokową"
+objectStorageSetPublicRead: "Ustaw opcję \"public-read\" przy przesyłaniu"
+s3ForcePathStyleDesc: "Jeśli opcja s3ForcePathStyle jest włączona, nazwa Bucket'u musi być zawarta w ścieżce adresu URL, a nie w nazwie hosta adresu URL. Włączenie tego ustawienia może być konieczne w przypadku użycia usług takich jak self-hosted instancja Minio."
 serverLogs: "Dziennik zdarzeń"
 deleteAll: "Usuń wszystkie"
 showFixedPostForm: "Wyświetlaj formularz tworzenia wpisu w górnej części osi czasu"
+showFixedPostFormInChannel: "Wyświetl formularz postowania w górnej części osi czasu (Kanały)"
+withRepliesByDefaultForNewlyFollowed: "Domyślnie uwzględnij odpowiedzi nowo obserwowanych użytkowników w osi czasu"
 newNoteRecived: "Masz nowy wpis"
 sounds: "Dźwięk"
 sound: "Dźwięki"
@@ -504,6 +557,8 @@ showInPage: "Pokaż na stronie"
 popout: "Popout"
 volume: "Głośność"
 masterVolume: "Głośność główna"
+notUseSound: "Wyłącz dźwięk"
+useSoundOnlyWhenActive: "Puszczaj dźwięki tylko, gdy Misskey jest aktywne."
 details: "Szczegóły"
 chooseEmoji: "Wybierz emoji"
 unableToProcess: "Nie udało się dokończyć działania."
@@ -524,6 +579,10 @@ output: "Wyjście"
 script: "Skrypt"
 disablePagesScript: "Wyłącz AiScript na Stronach"
 updateRemoteUser: "Aktualizuj zdalne dane o użytkowniku"
+unsetUserAvatar: "Usuń awatar"
+unsetUserAvatarConfirm: "Czy na pewno chcesz usunąć awatar tego użytkownika?"
+unsetUserBanner: "Usuń baner"
+unsetUserBannerConfirm: "Czy na pewno chcesz usunąć baner?"
 deleteAllFiles: "Usuń wszystkie pliki"
 deleteAllFilesConfirm: "Czy na pewno chcesz usunąć wszystkie pliki?"
 removeAllFollowing: "Przestań obserwować"
@@ -539,6 +598,7 @@ accountDeletedDescription: "Opis konta usuniętego"
 menu: "Menu"
 divider: "Rozdzielacz"
 addItem: "Dodaj element"
+rearrange: "Posortuj"
 relays: "Przekaźniki"
 addRelay: "Dodaj przekaźnik"
 inboxUrl: "Adres URL skrzynki nadawczej"
@@ -573,6 +633,7 @@ medium: "Średnie"
 small: "Małe"
 generateAccessToken: "Generuj token dostępu"
 permission: "Uprawnienia"
+adminPermission: "Uprawnienia administracyjne"
 enableAll: "Włącz wszystko"
 disableAll: "Wyłącz wszystko"
 tokenRequested: "Przydziel dostęp do konta"
@@ -590,9 +651,12 @@ smtpPort: "Port"
 smtpUser: "Nazwa użytkownika"
 smtpPass: "Hasło"
 emptyToDisableSmtpAuth: "Pozostaw adres e-mail i hasło puste, aby wyłączyć weryfikację SMTP"
+smtpSecure: "Użyj niejawnego SSL/TLS dla połączeń SMTP"
 smtpSecureInfo: "Wyłącz, jeżeli używasz STARTTLS"
 testEmail: "Przetestuj dostarczanie wiadomości e-mail"
 wordMute: "Wyciszenie słowa"
+regexpError: "Błąd wyrażenia regularnego"
+regexpErrorDescription: "Wystąpił błąd w wyrażeniu regularnym w linii {line} twoich {tab} wyciszeń:"
 instanceMute: "Wyciszone instancje"
 userSaysSomething: "{name} powiedział(-a) coś"
 makeActive: "Aktywuj"
@@ -612,18 +676,22 @@ useGlobalSettingDesc: "Jeżeli włączone, zostaną wykorzystane ustawienia powi
 other: "Inne"
 regenerateLoginToken: "Generuj token logowania ponownie"
 regenerateLoginTokenDescription: "Regeneruje token używany wewnętrznie podczas logowania. Zazwyczaj nie jest to konieczne. Po regeneracji wszystkie urządzenia zostaną wylogowane."
+theKeywordWhenSearchingForCustomEmoji: "To jest słowo kluczowe używane podczas wyszukiwania customowych Emoji."
 setMultipleBySeparatingWithSpace: "Możesz ustawić wiele, oddzielając je spacjami."
 fileIdOrUrl: "ID pliku albo URL"
 behavior: "Zachowanie"
 sample: "Przykład"
 abuseReports: "Zgłoszenia"
 reportAbuse: "Zgłoś"
+reportAbuseRenote: "Zgłoś renote"
 reportAbuseOf: "Zgłoś {name}"
 fillAbuseReportDescription: "Wypełnij szczegóły zgłoszenia. Jeżeli dotyczy ono określonego wpisu, uwzględnij jego adres URL."
 abuseReported: "Twoje zgłoszenie zostało wysłane. Dziękujemy."
+reporter: "Zgłaszający"
 reporteeOrigin: "Pochodzenie zgłoszonego"
 reporterOrigin: "Pochodzenie zgłaszającego"
 forwardReport: "Przekaż zgłoszenie do innej instancji"
+forwardReportIsAnonymous: "Zamiast twojego konta, anonimowe konto systemowe będzie wyświetlone jako zgłaszający na instancji zdalnej."
 send: "Wyślij"
 abuseMarkAsResolved: "Oznacz zgłoszenie jako rozwiązane"
 openInNewTab: "Otwórz w nowej karcie"
@@ -668,6 +736,7 @@ lockedAccountInfo: "Dopóki nie ustawisz widoczności wpisu na \"Obserwujący\",
 alwaysMarkSensitive: "Oznacz domyślnie jako NSFW"
 loadRawImages: "Wyświetlaj zdjęcia w załącznikach w całości zamiast miniatur"
 disableShowingAnimatedImages: "Nie odtwarzaj animowanych obrazów"
+highlightSensitiveMedia: "Podkreśl wrażliwą zawartość"
 verificationEmailSent: "Wiadomość weryfikacyjna została wysłana. Odwiedź uwzględniony odnośnik, aby ukończyć weryfikację."
 notSet: "Nie ustawiono"
 emailVerified: "Adres e-mail został potwierdzony"
@@ -678,6 +747,8 @@ contact: "Kontakt"
 useSystemFont: "Używaj domyślnej czcionki systemu"
 clips: "Klipy"
 experimentalFeatures: "Eksperymentalne funkcje"
+experimental: "Eksperymentalne"
+thisIsExperimentalFeature: "Ta funkcja jest eksperymentalna. Jej funkcjonalność może ulec zmianie, i może ona nie funkcjonować tak, jak zamierzono."
 developer: "Programista"
 makeExplorable: "Pokazuj konto na stronie „Eksploruj”"
 makeExplorableDescription: "Jeżeli wyłączysz tę opcję, Twoje konto nie będzie wyświetlać się w sekcji „Eksploruj”."
@@ -695,12 +766,14 @@ onlineUsersCount: "{n} osób jest online"
 nUsers: "{n} użytkowników"
 nNotes: "{n} wpisów"
 sendErrorReports: "Wyślij raporty o błędach"
+sendErrorReportsDescription: "Gdy włączone, jeśli wystąpi problem, szczegółowe informacje o błędach będą udostępniane Misskey, pomagając ulepszyć jakość Misskey.\nBędzie to zawierało informacje takie jak wersja twojego systemu operacyjnego, jakiej przeglądarki używasz, twoja aktywność w Misskey, itd."
 myTheme: "Mój motyw"
 backgroundColor: "Tło"
 accentColor: "Akcent"
 textColor: "Tekst"
 saveAs: "Zapisz jako…"
 advanced: "Zaawansowane"
+advancedSettings: "Zaawansowane ustawienia"
 value: "Wartość"
 createdAt: "Utworzono"
 updatedAt: "Zaktualizowano"
@@ -760,12 +833,14 @@ noMaintainerInformationWarning: "Informacje o administratorze nie są skonfiguro
 noBotProtectionWarning: "Zabezpieczenie przed botami nie jest skonfigurowane."
 configure: "Skonfiguruj"
 postToGallery: "Opublikuj w galerii"
+postToHashtag: "Postuj do tego hashtagu"
 gallery: "Galeria"
 recentPosts: "Ostatnie wpisy"
 popularPosts: "Popularne wpisy"
 shareWithNote: "Udostępnij z wpisem"
 ads: "Reklamy"
 expiration: "Ankieta kończy się"
+startingperiod: "Początek"
 memo: "Notatki"
 priority: "Priorytet"
 high: "Wysoki"
@@ -792,13 +867,19 @@ translatedFrom: "Przetłumaczone z {x}"
 accountDeletionInProgress: "Trwa usuwanie konta"
 usernameInfo: "Nazwa, która identyfikuje Twoje konto spośród innych na tym serwerze.  Możesz użyć alfabetu (a~z, A~Z), cyfr (0~9) lub podkreślników (_). Nazwy użytkownika nie mogą być później zmieniane."
 aiChanMode: "Tryb Ai"
+devMode: "Tryb programisty"
 keepCw: "Zostaw ostrzeżenia o zawartości"
 pubSub: "Konta Pub/Sub"
+lastCommunication: "Ostatnia komunikacja"
 resolved: "Rozwiązane"
 unresolved: "Nierozwiązane"
 breakFollow: "Usuń obserwującego"
+breakFollowConfirm: "Czy na pewno usunąć tego obserwującego?"
 itsOn: "Włączone"
 itsOff: "Wyłączone"
+on: "Włączone"
+off: "Wyłączone"
+emailRequiredForSignup: "Wymagaj adresu e-mail do rejestracji"
 unread: "Nieodczytane"
 filter: "Filtr"
 controlPanel: "Panel sterowania"
@@ -808,6 +889,8 @@ makeReactionsPublicDescription: "To spowoduje, że lista wszystkich Twoich dotyc
 classic: "Klasyczny"
 muteThread: "Wycisz wątek"
 unmuteThread: "Wyłącz wyciszenie wątku"
+followingVisibility: "Widoczność obserwacji"
+followersVisibility: "Widoczność obserwujących"
 continueThread: "Pokaż kontynuację wątku"
 deleteAccountConfirm: "Spowoduje to nieodwracalne usunięcie Twojego konta. Kontynuować?"
 incorrectPassword: "Nieprawidłowe hasło."
@@ -820,9 +903,14 @@ overridedDeviceKind: "Typ urządzenia"
 smartphone: "Smartfon"
 tablet: "Tablet"
 auto: "Automatycznie"
+themeColor: "Motyw kolorystyczny"
 size: "Rozmiar"
 numberOfColumn: "Liczba kolumn"
 searchByGoogle: "Szukaj"
+instanceDefaultLightTheme: "Domyślny motyw dla trybu jasnego"
+instanceDefaultDarkTheme: "Domyślny motyw dla trybu ciemnego"
+instanceDefaultThemeDescription: "Opis domyślnego motywu instancji"
+mutePeriod: "Okres wyciszenia"
 period: "Ankieta kończy się"
 indefinitely: "Nigdy"
 tenMinutes: "10 minut"
@@ -831,29 +919,50 @@ oneDay: "1 dzień"
 oneWeek: "1 tydzień"
 oneMonth: "jeden miesiąc"
 failedToFetchAccountInformation: "Nie udało się uzyskać informacji o koncie"
+rateLimitExceeded: "Limit szybkości przekroczony"
+cropImage: "Przytnij obraz"
+cropImageAsk: "Czy chcesz przyciąć obrazek?"
+cropYes: "Tak, przytnij"
+cropNo: "Nie chce przycinać"
 file: "Pliki"
+recentNHours: "W ciągu ostatnich {n} godzin"
+recentNDays: "W ciągu ostatnich {n} dni"
+noEmailServerWarning: "Serwer Email nie jest skonfigurowany"
 recommended: "Zalecane"
 check: "Zweryfikuj"
+driveCapOverrideLabel: "Zmień limit pojemności dysku użytkownika"
+requireAdminForView: "Aby to zobaczyć, musisz być administratorem"
+isSystemAccount: "To jest konto stworzone i zarządzane przez system"
+typeToConfirm: "Wielki chuj "
 deleteAccount: "Usuń konto"
 document: "Dokumentacja"
 numberOfPageCache: "Ilość stron w cache"
+numberOfPageCacheDescription: "Zwiększenie tej liczby polepszy wygodę, ale spowoduje większe obciążenie jako użycie pamięci na urządzeniu użytkownika."
 logoutConfirm: "Czy na pewno chcesz się wylogować?"
 lastActiveDate: "Ostatnio użyte w"
 statusbar: "Pasek stanu"
 pleaseSelect: "Wybierz opcję"
 reverse: "Odwróć"
 colored: "Kolorowe"
+refreshInterval: "Okres aktualizacji"
 label: "Etykieta"
 type: "Typ"
 speed: "Prędkość"
+slow: "Wolny"
+fast: "Szybki"
+sensitiveMediaDetection: "Detekcja wrażliwej zawartości"
 localOnly: "Lokalne tylko"
+remoteOnly: "Tylko zdalne instancje"
 failedToUpload: "Przesyłanie nie powiodło się"
 cannotUploadBecauseInappropriate: "Nie można przesłać tego pliku, ponieważ jego części zostały wykryte jako potencjalnie nieodpowiednie."
 cannotUploadBecauseNoFreeSpace: "Przesyłanie nie powiodło się z powodu braku miejsca na dysku."
+cannotUploadBecauseExceedsFileSizeLimit: "Nie można przesłać pliku, ponieważ wykracza on poza limit wielkości pliku."
 beta: "Beta"
 enableAutoSensitive: "Automatyczne oznaczanie NSFW"
 enableAutoSensitiveDescription: "Umożliwia automatyczne wykrywanie i oznaczanie zawartości NSFW za pomocą uczenia maszynowego. Nawet jeśli ta opcja jest wyłączona, może być włączona w całej instancji."
+activeEmailValidationDescription: "Włącza bardziej restrykcyjną walidację adresów e-mail, co obejmuje sprawdzanie adresów jednorazowych i czy komunikacja z tym adresem jest możliwa. Gdy wyłączone, tylko format adresu e-mail jest sprawdzany."
 navbar: "Pasek nawigacyjny"
+shuffle: "Mieszaj"
 account: "Konta"
 move: "Przenieś"
 pushNotification: "Powiadomienia"
@@ -863,22 +972,70 @@ pushNotificationAlreadySubscribed: "Powiadomienia push są włączone"
 pushNotificationNotSupported: "Przeglądarka lub instancja nie obsługuje powiadomień push"
 sendPushNotificationReadMessage: "Usuń powiadomienia push po przeczytaniu powiadomień i wiadomości."
 sendPushNotificationReadMessageCaption: "Chwilowo pojawi się powiadomienie \"{emptyPushNotificationMessage}\". Może wzrosnąć zużycie baterii urządzenia."
+windowMaximize: "Maksymalizuj"
+windowMinimize: "Minimalizuj"
+windowRestore: "Przywróć"
+caption: "Legenda"
 loggedInAsBot: "Jesteś obecnie zalogowany/a jako bot"
+tools: "Narzędzia"
+cannotLoad: "Nie można wczytać"
+numberOfProfileView: "Wyświetlenia profilu"
 like: "Polub"
+unlike: "Usuń polubienie"
+numberOfLikes: "Liczba polubień"
 show: "Wyświetlanie"
+neverShow: "Nie pokazuj ponownie"
+remindMeLater: "Przypomnij później"
+didYouLikeMisskey: "Czy Misskey się tobie spodobało?"
+pleaseDonate: "{host} używa darmowego oprogramowania — Misskey. Bylibyśmy bardzo wdzięczni za datki, które pozwolą na kontynuację rozwoju Misskey!"
+correspondingSourceIsAvailable: "Odpowiedni kod źródłowy jest dostępny pod {anchor}."
+roles: "Role"
+role: "Rola"
+noRole: "Rola nie znaleziona"
+normalUser: "Normalny użytkownik"
+undefined: "Niezdefiniowane"
+assign: "Przydziel"
+unassign: "Cofnij przydzielenie"
 color: "Kolor"
+manageCustomEmojis: "Zarządzaj niestandardowymi Emoji"
+manageAvatarDecorations: "Zarządzaj dekoracjami awatara"
+invalidParamError: "Błąd parametrów"
+permissionDeniedError: "Odrzucono operacje"
+permissionDeniedErrorDescription: "Konto nie posiada uprawnień"
+preset: "Konfiguracja"
+selectFromPresets: "Wybierz konfiguracje"
+achievements: "Osiągnięcia"
+thisPostMayBeAnnoyingCancel: "Odrzuć"
+internalServerError: "Wewnętrzny błąd serwera"
+internalServerErrorDescription: "Niespodziewany błąd po stronie serwera"
+copyErrorInfo: "Kopiuj informacje o błędzie"
+joinThisServer: "Dołącz do chaty"
+disableFederationOk: "Wyłącz federacje"
+invitationRequiredToRegister: "Ten serwer wymaga zaproszenia. Tylko osoby z zaproszeniem mogą się zarejestrować"
+emailNotSupported: "Wysyłanie wiadomości E-mail nie jest obsługiwane na tym serwerze"
+postToTheChannel: "Publikuj na kanale"
 youFollowing: "Śledzeni"
 icon: "Awatar"
 replies: "Odpowiedz"
 renotes: "Udostępnij"
 sourceCode: "Kod źródłowy"
 flip: "Odwróć"
+lastNDays: "W ciągu ostatnich {n} dni"
+surrender: "Odrzuć"
+gameRetry: "Spróbuj ponownie"
+_bubbleGame:
+  _score:
+    score: "Wynik"
 _role:
+  assignTarget: "Przydziel"
   priority: "Priorytet"
   _priority:
     low: "Niski"
     middle: "Średnie"
     high: "Wysoki"
+  _options:
+    canManageCustomEmojis: "Zarządzaj niestandardowymi Emoji"
+    canManageAvatarDecorations: "Zarządzaj dekoracjami awatara"
 _sensitiveMediaDetection:
   description: "Zmniejsza wysiłek związany z moderacją serwera dzięki automatycznemu rozpoznawaniu zawartości NSFW za pomocą uczenia maszynowego. To nieznacznie zwiększy obciążenie serwera."
   setSensitiveFlagAutomatically: "Oznacz jako NSFW"
@@ -1400,4 +1557,3 @@ _moderationLogTypes:
   resetPassword: "Zresetuj hasło"
 _reversi:
   total: "Łącznie"
-
diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml
index f62557fb23..e00f5750dd 100644
--- a/locales/pt-PT.yml
+++ b/locales/pt-PT.yml
@@ -733,9 +733,9 @@ reloadToApplySetting: "As configurações serão refletidas após recarregar a p
 needReloadToApply: "É necessário recarregar a página para refletir as alterações."
 showTitlebar: "Exibir barra de título"
 clearCache: "Limpar o cache"
-onlineUsersCount: "Pessoas Online"
-nUsers: "Usuários"
-nNotes: "Notas"
+onlineUsersCount: "{n} Pessoas Online"
+nUsers: "{n} Usuários"
+nNotes: "{n} Notas"
 sendErrorReports: "Enviar relatórios de erro"
 sendErrorReportsDescription: "Ao ativar essa opção, informações detalhadas de erro serão compartilhadas com o Misskey em caso de problemas, o que pode ajudar a melhorar a qualidade do software. As informações de erro podem incluir a versão do sistema operacional, o tipo de navegador e o sua atividade no Misskey."
 myTheme: "Meu tema"
@@ -767,7 +767,7 @@ emailNotification: "Notificações por e-mail"
 publish: "Publicar"
 inChannelSearch: "Pesquisar no canal"
 useReactionPickerForContextMenu: "Clique com o botão direito do mouse para abrir o seletor de reações."
-typingUsers: "digitando"
+typingUsers: "{users} pessoas digitando"
 jumpToSpecifiedDate: "Pular para uma data específica"
 showingPastTimeline: "Visualizar linha de tempo anterior"
 clear: "Limpar"
@@ -834,7 +834,7 @@ learnMore: "Saiba mais"
 misskeyUpdated: "Misskey foi atualizado!"
 whatIsNew: "Ver atualizações"
 translate: "Traduzir"
-translatedFrom: "Traduzido de"
+translatedFrom: "Traduzido de {x}"
 accountDeletionInProgress: "Encerramento de conta em andamento"
 usernameInfo: "O nome para identificar exclusivamente a sua conta no servidor. Pode conter letras (az, AZ), números (0~9) e sublinhados (_). O nome de usuário não pode ser alterado posteriormente."
 aiChanMode: "Modo AI-chan"
@@ -1301,8 +1301,8 @@ _preferencesBackups:
 _channel:
   featured: "Destaques"
   following: "Seguindo"
-  usersCount: "usuários ativos"
-  notesCount: "notas"
+  usersCount: "{n} usuários ativos"
+  notesCount: "{n} notas"
   nameAndDescription: "Nome e descrição"
 _menuDisplay:
   sideFull: "Exibir painel lateral inteiro"
@@ -1501,4 +1501,3 @@ _moderationLogTypes:
   resetPassword: "Redefinir senha"
 _reversi:
   total: "Total"
-
diff --git a/locales/ro-RO.yml b/locales/ro-RO.yml
index c1158e47b7..695eb2501f 100644
--- a/locales/ro-RO.yml
+++ b/locales/ro-RO.yml
@@ -729,4 +729,3 @@ _moderationLogTypes:
   resetPassword: "Resetează parola"
 _reversi:
   total: "Total"
-
diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml
index d666b69490..66e032f16f 100644
--- a/locales/ru-RU.yml
+++ b/locales/ru-RU.yml
@@ -17,7 +17,7 @@ noThankYou: "Нет, спасибо"
 enterUsername: "Введите имя пользователя"
 renotedBy: "{user} делится"
 noNotes: "Нет ни одной заметки"
-noNotifications: "Нет ни одного уведомления"
+noNotifications: "Нет уведомлений"
 instance: "Инстанс"
 settings: "Настройки"
 notificationSettings: "Настройки уведомлений"
@@ -129,6 +129,7 @@ overwriteFromPinnedEmojis: "Заменить на эмодзи из общего
 reactionSettingDescription2: "Расставляйте перетаскиванием, удаляйте нажатием, добавляйте кнопкой «+»."
 rememberNoteVisibility: "Запоминать видимость заметок"
 attachCancel: "Удалить вложение"
+deleteFile: "Удалить файл"
 markAsSensitive: "Отметить как «не для всех»"
 unmarkAsSensitive: "Снять отметку «не для всех»"
 enterFileName: "Введите имя файла"
@@ -312,6 +313,7 @@ folderName: "Имя папки"
 createFolder: "Создать папку"
 renameFolder: "Переименовать папку"
 deleteFolder: "Удалить папку"
+folder: "Папка"
 addFile: "Добавить файл"
 emptyDrive: "Диск пуст"
 emptyFolder: "Папка пуста"
@@ -373,6 +375,8 @@ hcaptcha: "hCaptcha"
 enableHcaptcha: "Включить hCaptcha"
 hcaptchaSiteKey: "Ключ сайта"
 hcaptchaSecretKey: "Секретный ключ"
+mcaptcha: "mCaptcha"
+enableMcaptcha: "Включить mCaptcha"
 mcaptchaSiteKey: "Ключ сайта"
 mcaptchaSecretKey: "Секретный ключ"
 recaptcha: "reCAPTCHA"
@@ -542,6 +546,8 @@ showInPage: "Показать страницу"
 popout: "Развернуть"
 volume: "Громкость"
 masterVolume: "Основная регулировка громкости"
+notUseSound: "Выключить звук"
+useSoundOnlyWhenActive: "Использовать звук, когда Misskey активен."
 details: "Подробнее"
 chooseEmoji: "Выберите эмодзи"
 unableToProcess: "Не удаётся завершить операцию"
@@ -562,6 +568,10 @@ output: "Выходы"
 script: "Скрипт"
 disablePagesScript: "Отключить скрипты на «Страницах»"
 updateRemoteUser: "Обновить данные пользователя с его сервера"
+unsetUserAvatar: "Убрать аватар"
+unsetUserAvatarConfirm: "Вы точно хотите убрать аватар?"
+unsetUserBanner: "Убрать баннер"
+unsetUserBannerConfirm: "Вы точно хотите убрать баннер?"
 deleteAllFiles: "Удалить все файлы"
 deleteAllFilesConfirm: "Вы хотите удалить все файлы?"
 removeAllFollowing: "Удалить всех подписчиков"
@@ -612,6 +622,7 @@ medium: "Средне"
 small: "Мелко"
 generateAccessToken: "Создать токен доступа"
 permission: "Разрешения"
+adminPermission: "Доступ администратора"
 enableAll: "Включить все"
 disableAll: "Выключить всё"
 tokenRequested: "Открыть доступ к учётной записи"
@@ -633,6 +644,7 @@ smtpSecure: "Использовать SSL/TLS для SMTP-соединений"
 smtpSecureInfo: "Выключите при использовании STARTTLS."
 testEmail: "Проверка доставки электронной почты"
 wordMute: "Скрытие слов"
+hardWordMute: ""
 regexpError: "Ошибка в регулярном выражении"
 regexpErrorDescription: "В списке {tab} скрытых слов, в строке {line} обнаружена синтаксическая ошибка:"
 instanceMute: "Глушение инстансов"
@@ -1084,6 +1096,7 @@ renotes: "Репост"
 loadReplies: "Показать ответы"
 sourceCode: "Исходный код"
 flip: "Переворот"
+code: "Код"
 lastNDays: "Последние {n} сут"
 surrender: "Этот пост не может быть отменен."
 _initialAccountSetting:
@@ -1626,7 +1639,6 @@ _2fa:
   registerTOTP: "Начните настраивать приложение-аутентификатор"
   step1: "Прежде всего, установите на устройство приложение для аутентификации, например, {a} или {b}."
   step2: "Далее отсканируйте отображаемый QR-код при помощи приложения."
-  step2Click: "Нажав на QR-код, вы можете зарегистрироваться с помощью приложения для аутентификации или брелка для ключей, установленного на вашем устройстве."
   step3Title: "Введите проверочный код"
   step3: "И наконец, введите код, который покажет приложение."
   step4: "Теперь при каждом входе на сайт вам нужно будет вводить код из приложения аналогичным образом."
@@ -1975,4 +1987,3 @@ _moderationLogTypes:
   resetPassword: "Сброс пароля:"
 _reversi:
   total: "Всего"
-
diff --git a/locales/si-LK.yml b/locales/si-LK.yml
index cd21505a47..e130d68ed8 100644
--- a/locales/si-LK.yml
+++ b/locales/si-LK.yml
@@ -1,2 +1,19 @@
 ---
-
+_lang_: "සිංහල"
+monthAndDay: "{month}-{day}"
+username: "පරිශීලක නාමය"
+password: "මුරපදය"
+cancel: "අවලංගු කරන්න"
+instance: "සර්වර්"
+login: "පිවිසෙන්න"
+users: "පරිශීලක"
+note: "නෝට්"
+notes: "නෝට්"
+instances: "සර්වර්"
+smtpUser: "පරිශීලක නාමය"
+smtpPass: "මුරපදය"
+user: "පරිශීලක"
+_sfx:
+  note: "නෝට්"
+_profile:
+  username: "පරිශීලක නාමය"
diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml
index 251496b10b..0978701e55 100644
--- a/locales/sk-SK.yml
+++ b/locales/sk-SK.yml
@@ -1448,4 +1448,3 @@ _moderationLogTypes:
   resetPassword: "Resetovať heslo"
 _reversi:
   total: "Celkom"
-
diff --git a/locales/sv-SE.yml b/locales/sv-SE.yml
index 07d5509a6a..62bc71a13d 100644
--- a/locales/sv-SE.yml
+++ b/locales/sv-SE.yml
@@ -576,4 +576,3 @@ _webhookSettings:
 _moderationLogTypes:
   suspend: "Suspendera"
   resetPassword: "Återställ Lösenord"
-
diff --git a/locales/th-TH.yml b/locales/th-TH.yml
index c0e79d5e16..020b954854 100644
--- a/locales/th-TH.yml
+++ b/locales/th-TH.yml
@@ -33,7 +33,7 @@ logout: "ออกจากระบบ"
 signup: "สร้างบัญชีผู้ใช้"
 uploading: "กำลังอัปโหลด"
 save: "บันทึก"
-users: "ผู้ใช้งาน"
+users: "ผู้ใช้"
 addUser: "เพิ่มผู้ใช้"
 favorite: "รายการโปรด"
 favorites: "รายการโปรด"
@@ -400,6 +400,7 @@ name: "ชื่อ"
 antennaSource: "แหล่งเสาอากาศ"
 antennaKeywords: "คีย์เวิร์ดที่ควรฟัง"
 antennaExcludeKeywords: "คีย์เวิร์ดที่จะยกเว้น"
+antennaExcludeBots: "ยกเว้นบัญชีบอต"
 antennaKeywordsDescription: "คั่นด้วยช่องว่างสำหรับเงื่อนไข AND หรือด้วยการขึ้นบรรทัดใหม่สำหรับเงื่อนไข OR"
 notifyAntenna: "แจ้งเตือนเกี่ยวกับโน้ตใหม่"
 withFileAntenna: "เฉพาะโน้ตที่มีไฟล์"
@@ -494,6 +495,7 @@ emojiStyle: "สไตล์เอโมจิ"
 native: "ภาษาแม่"
 disableDrawer: "อย่าใช้ลิ้นชักสไตล์เมนู"
 showNoteActionsOnlyHover: "แสดงการดำเนินการเฉพาะโน้ตเมื่อโฮเวอร์"
+showReactionsCount: "แสดงจำนวนรีแอกชั่นในโน้ต"
 noHistory: "ไม่มีประวัติ"
 signinHistory: "ประวัติการเข้าสู่ระบบ"
 enableAdvancedMfm: "เปิดใช้งาน MFM ขั้นสูง"
@@ -825,7 +827,7 @@ switchAccount: "สลับบัญชีผู้ใช้"
 enabled: "เปิดใช้งาน"
 disabled: "ปิดการใช้งาน"
 quickAction: "ปุ่มลัด"
-user: "ผู้ใช้งาน"
+user: "ผู้ใช้"
 administration: "การจัดการ"
 accounts: "บัญชีผู้ใช้"
 switch: "สลับ"
@@ -1223,6 +1225,16 @@ enableHorizontalSwipe: "ปัดเพื่อสลับแท็บ"
 loading: "กำลังโหลด"
 surrender: "ยอมแพ้"
 gameRetry: "เริ่มเกมใหม่"
+notUsePleaseLeaveBlank: "หากไม่ได้ใช้กรุณาเว้นว่างไว้"
+useTotp: "ใช้รหัสผ่านแบบใช้ครั้งเดียว (TOTP)"
+useBackupCode: "ใช้รหัสสำรอง"
+launchApp: "เริ่มแอป"
+useNativeUIForVideoAudioPlayer: "ใช้ UI ของเบราว์เซอร์เพื่อเล่นวิดีโอ/เสียง"
+keepOriginalFilename: "คงชื่อไฟล์เดิมไว้"
+keepOriginalFilenameDescription: "หากปิดการตั้งค่านี้ ในระหว่างการอัปโหลดชื่อไฟล์จะถูกแทนที่ด้วยสตริงแบบสุ่มโดยอัตโนมัติ"
+noDescription: "ไม่มีข้อความอธิบาย"
+alwaysConfirmFollow: "แสดงข้อความยืนยันเมื่อกดติดตาม"
+inquiry: "ติดต่อเรา"
 _bubbleGame:
   howToPlay: "วิธีเล่น"
   hold: "หยุดชั่วคราว"
@@ -1351,7 +1363,7 @@ _serverSettings:
 _accountMigration:
   moveFrom: "ย้ายข้อมูลบัญชีอื่นไปยังอีกบัญชีนี้หนึ่ง"
   moveFromSub: "สร้างนามแฝงไปยังบัญชีอื่น"
-  moveFromLabel: "บัญชีที่จะย้ายจาก:"
+  moveFromLabel: "บัญชีที่จะย้ายจาก #{n}"
   moveFromDescription: "ถ้าหากคุณต้องการโอนข้อมูล คุณจำเป็นต้องสร้างบัญชีสำรองสำหรับการย้ายบัญชี  หลังจากนั้นป้อนบัญชีที่จะย้ายไปในรูปแบบต่อไปนี้: @person@instance.com"
   moveTo: "ย้ายข้อมูลบัญชีนี้ไปยังบัญชีอีกหนึ่ง"
   moveToLabel: "บัญชีที่จะย้ายไปที่:"
@@ -1682,6 +1694,11 @@ _role:
     roleAssignedTo: "มอบหมายให้มีบทบาทแบบทำมือ"
     isLocal: "ผู้ใช้ในพื้นที่"
     isRemote: "ผู้ใช้ระยะไกล"
+    isCat: "ผู้ใช้ที่เป็นแมว"
+    isBot: "ผู้ใช้ที่เป็นบอต"
+    isSuspended: "ผู้ใช้ที่ถูกระงับ"
+    isLocked: "ผู้ใช้บัญชีไม่เปิดเผยสาธารณะ"
+    isExplorable: "ผู้ใช้ที่เปิดใช้งาน “ทำให้บัญชีของฉันค้นหาได้ง่ายขึ้น”"
     createdLessThan: "สร้างน้อยกว่า"
     createdMoreThan: "สร้างมากกว่า"
     followersLessThanOrEq: "จำนวนผู้ติดตามน้อยกว่าหรือเท่ากับ\n"
@@ -1751,6 +1768,7 @@ _plugin:
   installWarn: "กรุณาอย่าติดตั้งปลั๊กอินที่ไม่น่าเชื่อถือนะคะ"
   manage: "จัดการปลั๊กอิน"
   viewSource: "ดูต้นฉบับ"
+  viewLog: "แสดงปูม"
 _preferencesBackups:
   list: "สร้างการสำรองข้อมูล"
   saveNew: "บันทึกข้อมูลสำรองใหม่"
@@ -1940,7 +1958,6 @@ _2fa:
   registerTOTP: "ลงทะเบียนแอพตัวตรวจสอบสิทธิ์"
   step1: "ขั้นตอนแรก ติดตั้งแอปยืนยันตัวตน (เช่น {a} หรือ {b}) บนอุปกรณ์ของคุณ"
   step2: "จากนั้นสแกนรหัส QR ที่แสดงบนหน้าจอนี้"
-  step2Click: "การคลิกที่รหัส QR นี้จะช่วยให้คุณนั้นสามารถลงทะเบียน 2FA กับคีย์ความปลอดภัยหรือแอปตรวจสอบความถูกต้องของโทรศัพท์ได้"
   step2Uri: "ป้อนใส่ URL ดังต่อไปนี้ถ้าหากคุณใช้โปรแกรมเดสก์ท็อป"
   step3Title: "ป้อนรหัสยืนยัน"
   step3: "ป้อนโทเค็นที่แอปของคุณให้มาเพื่อเสร็จสิ้นการตั้งค่า"
@@ -1964,6 +1981,7 @@ _2fa:
   backupCodesDescription: "หากแอปยืนยันตัวตนของคุณไม่พร้อมใช้งาน คุณสามารถใช้รหัสสำรองด้านล่างเพื่อเข้าถึงบัญชีของคุณได้ อย่าลืมเก็บรหัสเหล่านี้ไว้ในที่ปลอดภัย แต่ละรหัสสามารถใช้ได้เพียงครั้งเดียวเท่านั้น"
   backupCodeUsedWarning: "มีการใช้รหัสสำรองแล้ว โปรดกรุณากำหนดค่าการตรวจสอบสิทธิ์แบบสองปัจจัยโดยเร็วที่สุดถ้าหากคุณยังไม่สามารถใช้งานได้อีก"
   backupCodesExhaustedWarning: "รหัสสำรองทั้งหมดถูกใช้แล้ว ถ้าหากคุณยังสูญเสียการเข้าถึงแอปการตรวจสอบสิทธิ์แบบสองปัจจัยคุณจะยังไม่สามารถเข้าถึงบัญชีนี้ได้ กรุณากำหนดค่าการรับรองความถูกต้องด้วยการยืนยันสองชั้น"
+  moreDetailedGuideHere: "คลิกที่นี่เพื่อดูคำแนะนำโดยละเอียด"
 _permissions:
   "read:account": "ดูข้อมูลบัญชีของคุณ"
   "write:account": "แก้ไขข้อมูลบัญชีของคุณ"
@@ -2225,6 +2243,7 @@ _play:
   title: "หัวข้อ"
   script: "สคริปต์"
   summary: "รายละเอียด"
+  visibilityDescription: "หากตั้งค่าเป็นส่วนตัว มันจะไม่ปรากฏในโปรไฟล์อีกต่อไป แต่ผู้ที่ทราบ URL ของมันจะยังสามารถเข้าถึงได้"
 _pages:
   newPage: "สร้างหน้าเพจใหม่"
   editPage: "แก้ไขหน้าเพจ"
@@ -2269,6 +2288,8 @@ _pages:
     section: "ประเภท"
     image: "รูปภาพ"
     button: "ปุ่ม"
+    dynamic: "บล็อกแบบไดนามิก"
+    dynamicDescription: "บล็อกนี้ล้าสมัยแล้ว โปรดใช้ {play} แทน นับจากนี้เป็นต้นไป"
     note: "โน้ตที่ฝังตัว"
     _note:
       id: "โน้ต ID"
@@ -2298,6 +2319,7 @@ _notification:
   sendTestNotification: "ส่งทดสอบการแจ้งเตือน"
   notificationWillBeDisplayedLikeThis: "การแจ้งเตือนมีลักษณะแบบนี้"
   reactedBySomeUsers: "ถูกรีแอคชั่นโดยผู้ใช้ {n} ราย"
+  likedBySomeUsers: "{n} คนถูกใจ"
   renotedBySomeUsers: "รีโน้ตจากผู้ใช้ {n} ราย"
   followedBySomeUsers: "มีผู้ติดตาม {n} ราย"
   flushNotification: "ล้างประวัติการแจ้งเตือน"
@@ -2524,4 +2546,21 @@ _reversi:
 _offlineScreen:
   title: "ออฟไลน์ - ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้"
   header: "ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้"
-
+_urlPreviewSetting:
+  title: "การตั้งค่าการแสดงตัวอย่าง URL"
+  enable: "เปิดใช้งานการแสดงตัวอย่าง URL"
+  timeout: "เวลาจำกัดในการโหลดตัวอย่าง URL (ms)"
+  timeoutDescription: "หากเวลาที่ใช้ในการโหลดเกินค่านี้ จะไม่มีการสร้างการแสดงตัวอย่าง"
+  maximumContentLength: "ค่าสูงสุดของ Content-Length (byte)"
+  maximumContentLengthDescription: "หาก Content-Length เกินค่านี้ จะไม่มีการสร้างการแสดงตัวอย่าง"
+  requireContentLength: "สร้างการแสดงตัวอย่างเฉพาะในกรณีที่รับ Content-Length ไหว"
+  requireContentLengthDescription: "หากเซิร์ฟเวอร์อื่นไม่ส่งคืน Content-Length จะไม่มีการสร้างการแสดงตัวอย่าง"
+  userAgent: "User-Agent"
+  userAgentDescription: "ตั้งค่า User-Agent ที่ใช้ในการรับการแสดงตัวอย่าง หากเว้นว่างไว้ ระบบจะใช้ User-Agent เริ่มต้น"
+  summaryProxy: "endpoint ของพร็อกซีที่สร้างการแสดงตัวอย่าง"
+  summaryProxyDescription: "สร้างการแสดงตัวอย่างด้วย summary Proxy แทนที่จะใช้เนื้อหา Misskey"
+  summaryProxyDescription2: "พารามิเตอร์ต่อไปนี้จะถูกใช้เป็นสตริงการสืบค้นเพื่อเชื่อมต่อกับพร็อกซี หากฝั่งพร็อกซีไม่รองรับการตั้งค่าเหล่านี้จะถูกละเว้น"
+_mediaControls:
+  pip: "รูปภาพในรูปภาม"
+  playbackRate: "ความเร็วในการเล่น"
+  loop: "เล่นวนซ้ำ"
diff --git a/locales/tr-TR.yml b/locales/tr-TR.yml
index e93a6e43e1..0793592d34 100644
--- a/locales/tr-TR.yml
+++ b/locales/tr-TR.yml
@@ -455,4 +455,3 @@ _deck:
 _moderationLogTypes:
   suspend: "askıya al"
   resetPassword: "Şifre sıfırlama"
-
diff --git a/locales/ug-CN.yml b/locales/ug-CN.yml
index e06cee11a2..e48f64511c 100644
--- a/locales/ug-CN.yml
+++ b/locales/ug-CN.yml
@@ -17,4 +17,3 @@ _2fa:
   renewTOTPCancel: "ئۇنى توختىتىڭ"
 _widgets:
   profile: "profile"
-
diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml
index df36f43c06..0ce5dc1202 100644
--- a/locales/uk-UA.yml
+++ b/locales/uk-UA.yml
@@ -1623,4 +1623,3 @@ _moderationLogTypes:
   resetPassword: "Скинути пароль"
 _reversi:
   total: "Всього"
-
diff --git a/locales/uz-UZ.yml b/locales/uz-UZ.yml
index b87b596925..809e785492 100644
--- a/locales/uz-UZ.yml
+++ b/locales/uz-UZ.yml
@@ -1090,4 +1090,3 @@ _moderationLogTypes:
   resetPassword: "Parolni tiklash"
 _reversi:
   total: "Jami"
-
diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml
index 59883f4a6c..d9c21d29ad 100644
--- a/locales/vi-VN.yml
+++ b/locales/vi-VN.yml
@@ -121,9 +121,11 @@ sensitive: "Nhạy cảm"
 add: "Thêm"
 reaction: "Biểu cảm"
 reactions: "Biểu cảm"
+emojiPicker: "Bộ chọn biểu tượng cảm xúc"
 reactionSettingDescription2: "Kéo để sắp xếp, nhấn để xóa, nhấn \"+\" để thêm."
 rememberNoteVisibility: "Lưu kiểu tút mặc định"
 attachCancel: "Gỡ tập tin đính kèm"
+deleteFile: "Xoá tệp tin"
 markAsSensitive: "Đánh dấu là nhạy cảm"
 unmarkAsSensitive: "Bỏ đánh dấu nhạy cảm"
 enterFileName: "Nhập tên tập tin"
@@ -257,6 +259,7 @@ removed: "Đã xóa"
 removeAreYouSure: "Bạn có chắc muốn gỡ \"{x}\"?"
 deleteAreYouSure: "Bạn có chắc muốn xóa \"{x}\"?"
 resetAreYouSure: "Bạn có chắc muốn đặt lại?"
+areYouSure: "Bạn chắc chứ?"
 saved: "Đã lưu"
 messaging: "Trò chuyện"
 upload: "Tải lên"
@@ -307,6 +310,7 @@ folderName: "Tên thư mục"
 createFolder: "Tạo thư mục"
 renameFolder: "Đổi tên thư mục"
 deleteFolder: "Xóa thư mục"
+folder: "Thư mục"
 addFile: "Thêm tập tin"
 emptyDrive: "Ổ đĩa của bạn trống trơn"
 emptyFolder: "Thư mục trống"
@@ -368,6 +372,8 @@ hcaptcha: "hCaptcha"
 enableHcaptcha: "Bật hCaptcha"
 hcaptchaSiteKey: "Khóa của trang"
 hcaptchaSecretKey: "Khóa bí mật"
+mcaptcha: "mCaptcha"
+enableMcaptcha: "Bật mCaptcha"
 mcaptchaSiteKey: "Khóa của trang"
 mcaptchaSecretKey: "Khóa bí mật"
 recaptcha: "reCAPTCHA"
@@ -385,6 +391,7 @@ name: "Tên"
 antennaSource: "Nguồn trạm phát sóng"
 antennaKeywords: "Từ khóa để nghe"
 antennaExcludeKeywords: "Từ khóa để lọc ra"
+antennaExcludeBots: "Loại trừ các tài khoản bot"
 antennaKeywordsDescription: "Phân cách bằng dấu cách cho điều kiện AND hoặc bằng xuống dòng cho điều kiện OR."
 notifyAntenna: "Thông báo có tút mới"
 withFileAntenna: "Chỉ những tút có media"
@@ -537,6 +544,7 @@ showInPage: "Hiện trong trang"
 popout: "Pop-out"
 volume: "Âm lượng"
 masterVolume: "Âm thanh chung"
+notUseSound: "Tắt tiếng"
 details: "Chi tiết"
 chooseEmoji: "Chọn emoji"
 unableToProcess: "Không thể hoàn tất hành động"
@@ -557,6 +565,10 @@ output: "Nguồn ra"
 script: "Kịch bản"
 disablePagesScript: "Tắt AiScript trên Trang"
 updateRemoteUser: "Cập nhật thông tin người dùng ở máy chủ khác"
+unsetUserAvatar: "Gỡ ảnh đại diện"
+unsetUserAvatarConfirm: "Bạn có chắc muốn gỡ ảnh đại diện?"
+unsetUserBanner: "Gỡ ảnh bìa"
+unsetUserBannerConfirm: "Bạn có chắc muốn gỡ ảnh bìa?"
 deleteAllFiles: "Xóa toàn bộ tập tin"
 deleteAllFilesConfirm: "Bạn có chắc xóa toàn bộ tập tin?"
 removeAllFollowing: "Ngưng theo dõi tất cả mọi người"
@@ -859,6 +871,8 @@ makeReactionsPublicDescription: "Điều này sẽ hiển thị công khai danh
 classic: "Cổ điển"
 muteThread: "Không quan tâm nữa"
 unmuteThread: "Quan tâm tút này"
+followingVisibility: "Hiển thị lượt theo dõi"
+followersVisibility: "Hiển thị người theo dõi"
 continueThread: "Tiếp tục xem chuỗi tút"
 deleteAccountConfirm: "Điều này sẽ khiến tài khoản bị xóa vĩnh viễn. Vẫn tiếp tục?"
 incorrectPassword: "Sai mật khẩu."
@@ -968,6 +982,7 @@ assign: "Phân công"
 unassign: "Hủy phân công"
 color: "Màu sắc"
 manageCustomEmojis: "Quản lý CustomEmoji"
+manageAvatarDecorations: "Quản lý trang trí ảnh đại diện"
 youCannotCreateAnymore: "Bạn đã tới giới hạn tạo."
 cannotPerformTemporary: "Tạm thời không sử dụng được"
 cannotPerformTemporaryDescription: "Tạm thời không sử dụng được vì lần số điều kiện quá giới hạn. Thử lại sau mọt lát nữa."
@@ -991,18 +1006,24 @@ copyErrorInfo: "Sao chép thông tin lỗi"
 joinThisServer: "Đăng ký trên chủ máy này"
 exploreOtherServers: "Tìm chủ máy khác"
 letsLookAtTimeline: "Thử xem Timeline"
+disableFederationOk: "Vô hiệu hoá"
 emailNotSupported: "Máy chủ này không hỗ trợ gửi email"
 postToTheChannel: "Đăng lên kênh"
 cannotBeChangedLater: "Không thể thay đổi sau này."
+likeOnly: "Chỉ lượt thích"
 rolesAssignedToMe: "Vai trò được giao cho tôi"
 resetPasswordConfirm: "Bạn thực sự muốn đặt lại mật khẩu?"
 sensitiveWords: "Các từ nhạy cảm"
+prohibitedWords: "Các từ bị cấm"
 license: "Giấy phép"
 unfavoriteConfirm: "Bạn thực sự muốn xoá khỏi mục yêu thích?"
+retryAllQueuesConfirmTitle: "Bạn có muốn thử lại?"
 retryAllQueuesConfirmText: "Điều này sẽ tạm thời làm tăng mức độ tải của máy chủ."
 enableChartsForRemoteUser: "Tạo biểu đồ người dùng từ xa"
 video: "Video"
 videos: "Các video"
+audio: "Âm thanh"
+audioFiles: "Âm thanh"
 dataSaver: "Tiết kiệm dung lượng"
 accountMigration: "Chuyển tài khoản"
 accountMoved: "Người dùng này đã chuyển sang một tài khoản mới:"
@@ -1019,34 +1040,82 @@ vertical: "Dọc"
 horizontal: "Thanh bên"
 position: "Vị trí"
 serverRules: "Luật của máy chủ"
+pleaseConfirmBelowBeforeSignup: "Để đăng ký trên máy chủ này, bạn phải xem xét và đồng ý với những điều sau."
+pleaseAgreeAllToContinue: "Bạn phải đồng ý tất cả điều trên để tiếp tục."
+continue: "Tiếp tục"
+archive: "Lưu trữ"
+thisChannelArchived: "Kênh này đã được lưu trữ."
+initialAccountSetting: "Thiết lập hồ sơ"
 youFollowing: "Đang theo dõi"
+preventAiLearning: "Từ chối sử dụng công nghệ Máy Học (AI Sáng Tạo)"
+options: "Tùy chọn"
+specifyUser: "Người dùng chỉ định"
+failedToPreviewUrl: "Không thể xem trước"
+update: "Cập nhật"
 later: "Để sau"
 goToMisskey: "Tới Misskey"
 installed: "Đã tải xuống"
 branding: "Thương hiệu"
 turnOffToImprovePerformance: "Tắt mục này có thể cải thiện hiệu năng."
+createInviteCode: "Tạo lời mời"
+createWithOptions: "Tạo cùng tùy chọn"
+createCount: "Số lượng mời"
+inviteCodeCreated: "Lời mời đã được tạo"
+inviteLimitExceeded: "Bạn đã vượt quá số lượng mời mà bạn có thể tạo."
+createLimitRemaining: "Giới hạn lượt mời: Còn lại {limit}"
+inviteLimitResetCycle: "Giới hạn này sẽ được đặt lại về {limit} lúc {time}."
 expirationDate: "Ngày hết hạn"
 noExpirationDate: "Vô thời hạn"
+inviteCodeUsedAt: "Mã mời đã được sử dụng lúc"
+registeredUserUsingInviteCode: "Lời mời đã được sử dụng bởi"
 waitingForMailAuth: "Đang chờ xác nhận email"
+inviteCodeCreator: "Lời mời đã được tạo bởi"
+usedAt: "Sử dụng vào lúc"
 unused: "Chưa được sử dụng"
 used: "Đã được sử dụng"
 expired: "Đã hết hạn"
 doYouAgree: "Đồng ý?"
-iHaveReadXCarefullyAndAgree: "Tôi đã đọc và đồng ý với \"x\"."
+beSureToReadThisAsItIsImportant: "Hãy đọc kỹ vì nó rất quan trọng."
+iHaveReadXCarefullyAndAgree: "Tôi đã đọc và đồng ý với \"{x}\"."
 dialog: "Hộp thoại"
 icon: "Ảnh đại diện"
 forYou: "Dành cho bạn"
 currentAnnouncements: "Thông báo hiện tại"
 pastAnnouncements: "Thông báo trước đó"
 youHaveUnreadAnnouncements: "Có thông báo chưa đọc."
+useSecurityKey: "Làm theo hướng dẫn trên trình duyệt hoặc thiết bị của bạn để sử dụng khóa bảo mật hoặc mật mã."
 replies: "Trả lời"
 renotes: "Đăng lại"
 loadReplies: "Hiển thị các trả lời"
+loadConversation: "Xem cuộc trò chuyện"
 pinnedList: "Các mục đã được ghim"
 keepScreenOn: "Giữ màn hình luôn bật"
 verifiedLink: "Chúng tôi đã xác nhận bạn là chủ sở hữu của đường dẫn này"
+authentication: "Xác thực"
+authenticationRequiredToContinue: "Vui lòng xác thực để tiếp tục"
+dateAndTime: "Ngày và giờ"
+edited: "Đã chỉnh sửa"
+notificationRecieveConfig: "Cài đặt thông báo"
+mutualFollow: "Theo dõi lẫn nhau"
+followingOrFollower: "Đang theo dõi hoặc người theo dõi"
+externalServices: "Các dịch vụ bên ngoài"
 sourceCode: "Mã nguồn"
+feedback: "Phản hồi"
+feedbackUrl: "URL phản hồi"
+privacyPolicy: "Chính sách bảo mật"
+privacyPolicyUrl: "URL Chính sách bảo mật"
+tosAndPrivacyPolicy: "Điều khoản sử dụng và Chính sách bảo mật"
+avatarDecorations: "Trang trí ảnh đại diện"
+attach: "Mặc"
+detach: "Bỏ"
+detachAll: "Bỏ tất cả"
+angle: "Góc"
 flip: "Lật"
+showAvatarDecorations: "Hiển thị trang trí ảnh đại diện"
+releaseToRefresh: "Thả để làm mới"
+refreshing: "Đang làm mới"
+pullDownToRefresh: "Kéo xuống để làm mới"
+cwNotationRequired: "Nếu \"Ẩn nội dung\" được bật thì cần phải có chú thích."
 lastNDays: "{n} ngày trước"
 surrender: "Từ chối"
 _announcement:
@@ -1280,6 +1349,7 @@ _role:
     ltlAvailable: "Xem Timeline trong máy chủ này"
     canPublicNote: "Cho phép đăng bài công khai"
     canManageCustomEmojis: "Quản lý CustomEmoji"
+    canManageAvatarDecorations: "Quản lý trang trí ảnh đại diện"
     driveCapacity: "Dữ liệu Drive"
     pinMax: "Giới hạn ghim bài viết"
     antennaMax: "Giới hạn tạo ăng ten"
@@ -1508,7 +1578,6 @@ _2fa:
   registerTOTP: "Đăng ký ứng dụng xác thực"
   step1: "Trước tiên, hãy cài đặt một ứng dụng xác minh (chẳng hạn như {a} hoặc {b}) trên thiết bị của bạn."
   step2: "Sau đó, quét mã QR hiển thị trên màn hình này."
-  step2Click: "Quét mã QR trên ứng dụng xác thực (Authy, Google authenticator, v.v.)"
   step3Title: "Nhập mã xác thực"
   step3: "Nhập mã token do ứng dụng của bạn cung cấp để hoàn tất thiết lập."
   step4: "Kể từ bây giờ, những lần đăng nhập trong tương lai sẽ yêu cầu mã token đăng nhập đó."
@@ -1790,7 +1859,7 @@ _notification:
   youReceivedFollowRequest: "Bạn vừa có một yêu cầu theo dõi"
   yourFollowRequestAccepted: "Yêu cầu theo dõi của bạn đã được chấp nhận"
   pollEnded: "Cuộc bình chọn đã kết thúc"
-  unreadAntennaNote: "Ăng ten"
+  unreadAntennaNote: "Ăng ten {name}"
   emptyPushNotificationMessage: "Đã cập nhật thông báo đẩy"
   achievementEarned: "Hoàn thành Achievement"
   _types:
@@ -1852,6 +1921,6 @@ _webhookSettings:
 _moderationLogTypes:
   suspend: "Vô hiệu hóa"
   resetPassword: "Đặt lại mật khẩu"
+  createInvitation: "Tạo lời mời"
 _reversi:
   total: "Tổng cộng"
-
diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index 17ad6e7150..fb1ffc5a99 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -58,7 +58,7 @@ copyUserId: "复制用户 ID"
 copyNoteId: "复制帖子 ID"
 copyFileId: "复制文件ID"
 copyFolderId: "复制文件夹ID"
-copyProfileUrl: "复制配置文件URL"
+copyProfileUrl: "复制个人资料URL"
 searchUser: "搜索用户"
 reply: "回复"
 loadMore: "查看更多"
@@ -400,6 +400,7 @@ name: "名称"
 antennaSource: "接收来源"
 antennaKeywords: "包含关键字"
 antennaExcludeKeywords: "排除关键字"
+antennaExcludeBots: "排除机器人账户"
 antennaKeywordsDescription: "AND 条件用空格分隔,OR 条件用换行符分隔。"
 notifyAntenna: "开启通知"
 withFileAntenna: "仅带有附件的帖子"
@@ -494,6 +495,7 @@ emojiStyle: "表情符号的样式"
 native: "原生"
 disableDrawer: "不显示抽屉菜单"
 showNoteActionsOnlyHover: "仅在悬停时显示帖子操作"
+showReactionsCount: "显示帖子的回应数"
 noHistory: "没有历史记录"
 signinHistory: "登录历史"
 enableAdvancedMfm: "启用扩展 MFM"
@@ -614,7 +616,7 @@ disablePlayer: "关闭播放器"
 expandTweet: "展开帖子"
 themeEditor: "主题编辑器"
 description: "描述"
-describeFile: "添加标题"
+describeFile: "添加描述"
 enterFileDescription: "输入标题"
 author: "作者"
 leaveConfirm: "存在未保存的更改。要放弃更改吗?"
@@ -1201,7 +1203,7 @@ code: "代码"
 reloadRequiredToApplySettings: "需要重新载入来使设置生效"
 remainingN: "剩余:{n}"
 overwriteContentConfirm: "将覆盖现有内容。确定吗?"
-seasonalScreenEffect: "应景的画面效果"
+seasonalScreenEffect: "符合当前季节的画面效果"
 decorate: "装饰"
 addMfmFunction: "添加装饰"
 enableQuickAddMfmFunction: "显示高级 MFM 选择器"
@@ -1223,6 +1225,16 @@ enableHorizontalSwipe: "滑动切换标签页"
 loading: "读取中"
 surrender: "取消"
 gameRetry: "重试"
+notUsePleaseLeaveBlank: "如不使用请留空"
+useTotp: "使用一次性代码"
+useBackupCode: "使用备用代码"
+launchApp: "启动应用"
+useNativeUIForVideoAudioPlayer: "使用浏览器的 UI 播放动画及音频"
+keepOriginalFilename: "保持原文件名"
+keepOriginalFilenameDescription: "若关闭此设置,上传文件时文件名将被替换为随机字符。"
+noDescription: "没有描述"
+alwaysConfirmFollow: "总是确认关注"
+inquiry: "联系我们"
 _bubbleGame:
   howToPlay: "游戏说明"
   hold: "抓住"
@@ -1233,6 +1245,7 @@ _bubbleGame:
     maxChain: "最高连击数"
     yen: "{yen} 日元"
     estimatedQty: "约 {qty} 个"
+    scoreSweets: "相当于 {onigiriQtyWithUnit} 饭团"
   _howToPlay:
     section1: "对准位置将Emoji投入盒子。"
     section2: "相同的Emoji相互接触合成后会得到新的Emoji,以此获得分数。"
@@ -1350,7 +1363,7 @@ _serverSettings:
 _accountMigration:
   moveFrom: "从别的账号迁移到此账户"
   moveFromSub: "为另一个账户建立别名"
-  moveFromLabel: "迁移前的账户"
+  moveFromLabel: "迁移前的账户 #{n}"
   moveFromDescription: "如果迁移时需要继承其他账户的关注者,你需要创建一个别名。此操作需要在迁移前完成!\n请像这样输入要迁移的账户:@username@server.example.com\n如果要删除,请将输入字段留空,并保存(不推荐)。"
   moveTo: "把这个账户迁移到新的账户"
   moveToLabel: "迁移后的账户"
@@ -1680,6 +1693,9 @@ _role:
     roleAssignedTo: "已分配给手动角色"
     isLocal: "是本地用户"
     isRemote: "是远程用户"
+    isBot: "机器人用户"
+    isSuspended: "停用的用户"
+    isExplorable: "启用“使账号可见”的用户"
     createdLessThan: "账户创建时间少于"
     createdMoreThan: "账户创建时间超过"
     followersLessThanOrEq: "关注者不多于"
@@ -1749,6 +1765,7 @@ _plugin:
   installWarn: "请不要安装不可信的插件。"
   manage: "管理插件..."
   viewSource: "查看源代码"
+  viewLog: "显示日志"
 _preferencesBackups:
   list: "已创建的备份"
   saveNew: "另存为"
@@ -1938,7 +1955,6 @@ _2fa:
   registerTOTP: "开始设置认证应用"
   step1: "首先,在您的设备上安装验证应用,例如 {a} 或 {b}。"
   step2: "然后,扫描屏幕上显示的二维码。"
-  step2Click: "通过点击二维码,您可以使用设备上安装的身份验证器应用程序或密钥环进行注册"
   step2Uri: "如果使用桌面应用程序的话,请输入下面的 URI"
   step3Title: "输入验证码"
   step3: "输入您的应用提供的动态口令以完成设置。"
@@ -1962,6 +1978,7 @@ _2fa:
   backupCodesDescription: "如果无法使用认证应用,可以使用以下的备用代码来访问账户。请务必将这些代码保存在安全的地方。每个代码仅可使用一次。"
   backupCodeUsedWarning: "已使用备用代码。如果无法使用认证应用,请尽快重新设定。"
   backupCodesExhaustedWarning: "已使用完所有的备用代码。如果无法使用认证应用,将无法再访问您的账户。请再次设定认证应用。"
+  moreDetailedGuideHere: "此处为详细指南"
 _permissions:
   "read:account": "查看账户信息"
   "write:account": "更改帐户信息"
@@ -2223,6 +2240,7 @@ _play:
   title: "标题"
   script: "脚本"
   summary: "描述"
+  visibilityDescription: "设置为不公开后资料将不再显示,但知道 URL 的人仍可继续访问。"
 _pages:
   newPage: "创建页面"
   editPage: "编辑页面"
@@ -2267,6 +2285,8 @@ _pages:
     section: "章节"
     image: "图片"
     button: "按钮"
+    dynamic: "动态区块"
+    dynamicDescription: "这个区块已经废弃。以后请使用{play}。"
     note: "嵌入的帖子"
     _note:
       id: "帖子 ID"
@@ -2296,6 +2316,7 @@ _notification:
   sendTestNotification: "发送测试通知"
   notificationWillBeDisplayedLikeThis: "通知将会这样表示"
   reactedBySomeUsers: "{n} 人回应了"
+  likedBySomeUsers: "{n}人赞了你的帖子"
   renotedBySomeUsers: "{n} 人转发了"
   followedBySomeUsers: "被 {n} 人关注"
   flushNotification: "重置通知历史"
@@ -2478,6 +2499,7 @@ _hemisphere:
 _reversi:
   reversi: "黑白棋"
   gameSettings: "对局设置"
+  chooseBoard: "选择棋盘"
   blackOrWhite: "先手/后手"
   blackIs: "{name}执黑(先手)"
   rules: "规则"
@@ -2504,6 +2526,8 @@ _reversi:
   allGames: "所有对局"
   ended: "结束"
   playing: "对局中"
+  isLlotheo: "落子少的一方获胜(又名奥赛罗)"
+  loopedMap: "循环棋盘"
   canPutEverywhere: "无限制放置模式"
   timeLimitForEachTurn: "1回合的时间限制"
   freeMatch: "自由匹配"
@@ -2519,4 +2543,21 @@ _reversi:
 _offlineScreen:
   title: "离线——无法连接到服务器"
   header: "无法连接到服务器"
-
+_urlPreviewSetting:
+  title: "设置 URL 预览"
+  enable: "启用 URL 预览"
+  timeout: "超时阈值(ms)"
+  timeoutDescription: "如果获取预览所用时间超过这个值,则不生成预览。"
+  maximumContentLength: "Content-Length 的最大值(byte)"
+  maximumContentLengthDescription: "如果 Content-Length 超过这个值,则不生成预览。"
+  requireContentLength: "仅在能取得 Content-Length 时生成预览"
+  requireContentLengthDescription: "如果目标服务器不返回 Content-Length,则不生成预览。"
+  userAgent: "User-Agent"
+  userAgentDescription: "设定获取预览时使用的 User-Agent。留空时将使用默认的 User-Agent。"
+  summaryProxy: "用来生成预览的代理的 endpoint。"
+  summaryProxyDescription: "不使用 Misskey 本体,而是通过 Summaly Proxy 生成预览。"
+  summaryProxyDescription2: "下面的参数将作为查询字符串发送至代理。代理侧如果不支持此设置,则忽略设定值。"
+_mediaControls:
+  pip: "画中画"
+  playbackRate: "播放速度"
+  loop: "循环播放"
diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml
index 5cdecc10ac..8cde13052f 100644
--- a/locales/zh-TW.yml
+++ b/locales/zh-TW.yml
@@ -205,7 +205,7 @@ silenceThisInstance: "禁言此伺服器"
 operations: "操作"
 software: "軟體"
 version: "版本"
-metadata: "元資料"
+metadata: "詮釋資料"
 withNFiles: "{n} 個檔案"
 monitor: "監視器"
 jobQueue: "佇列"
@@ -400,6 +400,7 @@ name: "名稱"
 antennaSource: "接收來源"
 antennaKeywords: "包含關鍵字"
 antennaExcludeKeywords: "排除關鍵字"
+antennaExcludeBots: "排除機器人帳戶"
 antennaKeywordsDescription: "空格代表「以及」(AND),換行代表「或者」(OR)"
 notifyAntenna: "通知有新貼文"
 withFileAntenna: "僅帶有附件的貼文"
@@ -494,6 +495,7 @@ emojiStyle: "表情符號的風格"
 native: "原生"
 disableDrawer: "不顯示下拉式選單"
 showNoteActionsOnlyHover: "僅在游標停留時顯示貼文的操作選項"
+showReactionsCount: "顯示貼文的反應數目"
 noHistory: "沒有歷史紀錄"
 signinHistory: "登入歷史"
 enableAdvancedMfm: "啟用進階 MFM"
@@ -750,7 +752,7 @@ experimentalFeatures: "實驗中的功能"
 experimental: "實驗性"
 thisIsExperimentalFeature: "這是實驗性的功能。可能會有變更規格和不能正常動作的可能性。"
 developer: "開發者"
-makeExplorable: "使自己的帳戶能夠在「探索」頁面中顯示"
+makeExplorable: "使自己的帳戶更容易被找到"
 makeExplorableDescription: "如果關閉,帳戶將不會被顯示在「探索」頁面中。"
 showGapBetweenNotesInTimeline: "分開顯示時間軸上的貼文"
 duplicate: "複製"
@@ -1223,6 +1225,16 @@ enableHorizontalSwipe: "滑動切換時間軸"
 loading: "載入中"
 surrender: "退出"
 gameRetry: "再試一次"
+notUsePleaseLeaveBlank: "如不使用,請留空"
+useTotp: "使用一次性密碼"
+useBackupCode: "使用備用驗證碼"
+launchApp: "啟動 App"
+useNativeUIForVideoAudioPlayer: "使用瀏覽器的 UI 播放影片與音訊"
+keepOriginalFilename: "保留原始檔名"
+keepOriginalFilenameDescription: "如果關閉此設置,上傳時檔案名稱會自動替換為隨機字串。"
+noDescription: "沒有說明文字"
+alwaysConfirmFollow: "點擊追隨時總是顯示確認訊息"
+inquiry: "聯絡我們"
 _bubbleGame:
   howToPlay: "玩法說明"
   hold: "保留"
@@ -1351,7 +1363,7 @@ _serverSettings:
 _accountMigration:
   moveFrom: "從其他帳戶遷移到這個帳戶"
   moveFromSub: "為另一個帳戶建立別名"
-  moveFromLabel: "要遷移過來的帳戶:"
+  moveFromLabel: "要遷移過來的帳戶 #{n}"
   moveFromDescription: "如果你想把追隨者從別的帳戶遷移過來,必須先在這裡建立別名。請務必在執行遷移之前建立別名!請像這樣輸入要遷移的帳戶:@person@instance.com"
   moveTo: "將這個帳戶遷移至新的帳戶"
   moveToLabel: "要遷移到的帳戶:"
@@ -1682,6 +1694,11 @@ _role:
     roleAssignedTo: "手動指派角色完成"
     isLocal: "本地使用者"
     isRemote: "遠端使用者"
+    isCat: "使用者是貓"
+    isBot: "使用者是機器人"
+    isSuspended: "被停權的使用者"
+    isLocked: "上鎖的使用者"
+    isExplorable: "開啟了「使您的帳戶更容易被找到」功能的使用者"
     createdLessThan: "帳戶加入時間不超過"
     createdMoreThan: "帳戶加入時間已超過"
     followersLessThanOrEq: "追隨者人數在~以下"
@@ -1751,6 +1768,7 @@ _plugin:
   installWarn: "請不要安裝來源不明的外掛。"
   manage: "管理外掛"
   viewSource: "檢視原始碼"
+  viewLog: "顯示記錄 "
 _preferencesBackups:
   list: "已備份的設定檔"
   saveNew: "另存新檔"
@@ -1940,7 +1958,6 @@ _2fa:
   registerTOTP: "開始設定驗證應用程式"
   step1: "首先,在您的裝置上安裝驗證程式,例如 {a} 或 {b}。"
   step2: "然後,掃描螢幕上的 QR 碼。"
-  step2Click: "您可以點擊 QR 碼,以使用裝置上的驗證應用程式或金鑰環註冊。"
   step2Uri: "使用桌面版應用程式時,請輸入以下的 URI"
   step3Title: "輸入驗證碼"
   step3: "輸入應用程式所提供的權杖以完成設定。"
@@ -1964,6 +1981,7 @@ _2fa:
   backupCodesDescription: "如果驗證應用程式不能用了,可以使用以下的備用驗證碼存取您的帳戶。請務必妥善保管這個驗證碼。每個驗證碼只能使用一次。"
   backupCodeUsedWarning: "已使用備用驗證碼。如果無法使用驗證應用程式,請盡快重新設定。"
   backupCodesExhaustedWarning: "已使用所有備用驗證碼。如果無法使用驗證應用程式,則將無法再存取您的帳戶。請重新設定您的驗證應用程式。"
+  moreDetailedGuideHere: "請點擊此處查看詳細說明。"
 _permissions:
   "read:account": "查看我的帳戶資訊"
   "write:account": "更改我的帳戶資訊"
@@ -2007,7 +2025,7 @@ _permissions:
   "read:admin:index-stats": "查看資料庫索引的相關資訊"
   "read:admin:table-stats": "查看資料庫表格的相關資訊"
   "read:admin:user-ips": "查看使用者的 IP 位址"
-  "read:admin:meta": "查看實例的元資料"
+  "read:admin:meta": "查看實例的詮釋資料"
   "write:admin:reset-password": "重設使用者的密碼"
   "write:admin:resolve-abuse-user-report": "解決來自使用者的檢舉"
   "write:admin:send-email": "發送郵件"
@@ -2019,7 +2037,7 @@ _permissions:
   "write:admin:unset-user-avatar": "刪除使用者的頭像"
   "write:admin:unset-user-banner": "刪除使用者的橫幅"
   "write:admin:unsuspend-user": "解除凍結使用者"
-  "write:admin:meta": "編輯實例的元資料"
+  "write:admin:meta": "編輯實例的詮釋資料"
   "write:admin:user-note": "編輯審查筆記"
   "write:admin:roles": "編輯角色"
   "read:admin:roles": "查看角色"
@@ -2188,7 +2206,7 @@ _charts:
   notesIncDec: "貼文増減"
   localNotesIncDec: "本地貼文増減"
   remoteNotesIncDec: "遠端貼文數目增减"
-  notesTotal: "貼文合共"
+  notesTotal: "貼文總數"
   filesIncDec: "檔案增減"
   filesTotal: "檔案總數"
   storageUsageIncDec: "儲存空間增減"
@@ -2225,6 +2243,7 @@ _play:
   title: "標題"
   script: "腳本"
   summary: "描述"
+  visibilityDescription: "如果您將其設為私密,它將不再顯示在您的個人資料中,但知道該 URL 的人仍然可以存取它。"
 _pages:
   newPage: "建立頁面"
   editPage: "編輯頁面"
@@ -2269,6 +2288,8 @@ _pages:
     section: "區段"
     image: "圖片"
     button: "按鈕"
+    dynamic: "動態方塊"
+    dynamicDescription: "這個方塊已經廢止,現在開始請使用 {play}。"
     note: "嵌式貼文"
     _note:
       id: "貼文ID"
@@ -2298,6 +2319,7 @@ _notification:
   sendTestNotification: "發送測試通知"
   notificationWillBeDisplayedLikeThis: "通知會以這樣的方式顯示"
   reactedBySomeUsers: "{n}人做出了反應"
+  likedBySomeUsers: "{n} 人按了讚"
   renotedBySomeUsers: "{n}人做了轉發"
   followedBySomeUsers: "被{n}人追隨了"
   flushNotification: "重置通知歷史紀錄"
@@ -2524,4 +2546,21 @@ _reversi:
 _offlineScreen:
   title: "離線-無法連接伺服器"
   header: "無法連接伺服器"
-
+_urlPreviewSetting:
+  title: "URL 預覽設定"
+  enable: "啟用 URL 預覽"
+  timeout: "取得預覽的逾時時間 (ms)"
+  timeoutDescription: "若取得預覽所需的時間超過這個值,則不會產生預覽。"
+  maximumContentLength: "Content-Length 的最大値 (byte)"
+  maximumContentLengthDescription: "若 Content-Length 超過這個值,則不會產生預覽。"
+  requireContentLength: "僅在能夠取得 Content-Length 時,才產生預覽。"
+  requireContentLengthDescription: "若對方的伺服器未回傳 Content -Length,則不會產生預覽。"
+  userAgent: "User-Agent"
+  userAgentDescription: "設定獲取預覽時使用的 User-Agent 。如果留空,將使用預設的 User-Agent 。"
+  summaryProxy: "產生預覽的代理端點"
+  summaryProxyDescription: "使用摘要代理程式而不是 Misskey 本身產生預覽。"
+  summaryProxyDescription2: "以下參數會作為查詢字串連結到代理。如果代理端不支援,這些設定將被忽略。"
+_mediaControls:
+  pip: "畫中畫"
+  playbackRate: "播放速度"
+  loop: "循環播放"

From 7bde630820a9270e47f14fcfe5752c98d4716634 Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Tue, 21 May 2024 11:19:33 +0900
Subject: [PATCH 133/191] =?UTF-8?q?`/tags`=20=E3=81=A8=20`/user-tags`=20?=
 =?UTF-8?q?=E3=81=8C=E6=A4=9C=E7=B4=A2=E3=82=A8=E3=83=B3=E3=82=B8=E3=83=B3?=
 =?UTF-8?q?=E3=81=AB=E3=82=A4=E3=83=B3=E3=83=87=E3=83=83=E3=82=AF=E3=82=B9?=
 =?UTF-8?q?=E3=81=95=E3=82=8C=E3=81=AA=E3=81=84=E3=82=88=E3=81=86=E3=81=AB?=
 =?UTF-8?q?=20(#13847)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* chore(backend): noindex for tag search pages

* docs(changelog): `/tags` と `/user-tags` が検索エンジンにインデックスされないように

* chore: base.pug内でフラグでコントロールするように
---
 CHANGELOG.md                                      |  1 +
 .../backend/src/server/web/ClientServerService.ts | 15 ++++++++++++++-
 packages/backend/src/server/web/views/base.pug    |  3 +++
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8d1b0a010a..ecacefe84e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -85,6 +85,7 @@
 - Fix: FTTが有効かつsinceIdのみを指定した場合に帰って来るレスポンスが逆順である問題を修正
 - Fix: `/i/notifications`に `includeTypes`か`excludeTypes`を指定しているとき、通知が存在するのに空配列を返すことがある問題を修正
 - Fix: 複数idを指定する`users/show`が関係ないユーザを返すことがある問題を修正
+- Fix: `/tags` と `/user-tags` が検索エンジンにインデックスされないように
 
 ## 2024.3.1
 
diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts
index 1394616752..f35ec8ba31 100644
--- a/packages/backend/src/server/web/ClientServerService.ts
+++ b/packages/backend/src/server/web/ClientServerService.ts
@@ -438,7 +438,7 @@ export class ClientServerService {
 
 		//#endregion
 
-		const renderBase = async (reply: FastifyReply) => {
+		const renderBase = async (reply: FastifyReply, data: { [key: string]: any } = {}) => {
 			const meta = await this.metaService.fetch();
 			reply.header('Cache-Control', 'public, max-age=30');
 			return await reply.view('base', {
@@ -447,6 +447,7 @@ export class ClientServerService {
 				title: meta.name ?? 'Misskey',
 				desc: meta.description,
 				...await this.generateCommonPugData(meta),
+				...data,
 			});
 		};
 
@@ -744,6 +745,18 @@ export class ClientServerService {
 		});
 		//#endregion
 
+		//region noindex pages
+		// Tags
+		fastify.get<{ Params: { clip: string; } }>('/tags/:tag', async (request, reply) => {
+			return await renderBase(reply, { noindex: true });
+		});
+
+		// User with Tags
+		fastify.get<{ Params: { clip: string; } }>('/user-tags/:tag', async (request, reply) => {
+			return await renderBase(reply, { noindex: true });
+		});
+		//endregion
+
 		fastify.get('/_info_card_', async (request, reply) => {
 			const meta = await this.metaService.fetch(true);
 
diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug
index 1d9146e22a..ec1325e4e9 100644
--- a/packages/backend/src/server/web/views/base.pug
+++ b/packages/backend/src/server/web/views/base.pug
@@ -50,6 +50,9 @@ html
 			block title
 				= title || 'Misskey'
 
+		if noindex
+			meta(name='robots' content='noindex')
+
 		block desc
 			meta(name='description' content= desc || '✨🌎✨ A interplanetary communication platform ✨🚀✨')
 

From 37f2952af9ca417549ce8024bd3045a409347138 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Tue, 21 May 2024 13:33:43 +0900
Subject: [PATCH 134/191] Update about-misskey.vue

---
 packages/frontend/src/pages/about-misskey.vue | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/packages/frontend/src/pages/about-misskey.vue b/packages/frontend/src/pages/about-misskey.vue
index 92accd0117..a83510d7f7 100644
--- a/packages/frontend/src/pages/about-misskey.vue
+++ b/packages/frontend/src/pages/about-misskey.vue
@@ -231,6 +231,12 @@ const patronsWithIcon = [{
 }, {
 	name: 'Takeno',
 	icon: 'https://assets.misskey-hub.net/patrons/6fba81536aea48fe94a30909c502dfa1.jpg',
+}, {
+	name: 'くびすじ',
+	icon: 'https://assets.misskey-hub.net/patrons/aa5789850b2149aeb5b89ebe2e9083db.jpg',
+}, {
+	name: '古道京紗@ぷらいべったー',
+	icon: 'https://assets.misskey-hub.net/patrons/18346d0519704963a4beabe6abc170af.jpg',
 }];
 
 const patrons = [

From 3340631d434c48ecbc519b26f0e7888156f3c835 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Tue, 21 May 2024 13:35:32 +0900
Subject: [PATCH 135/191] Update about-misskey.vue

---
 packages/frontend/src/pages/about-misskey.vue | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/packages/frontend/src/pages/about-misskey.vue b/packages/frontend/src/pages/about-misskey.vue
index a83510d7f7..b55ae220d8 100644
--- a/packages/frontend/src/pages/about-misskey.vue
+++ b/packages/frontend/src/pages/about-misskey.vue
@@ -237,6 +237,9 @@ const patronsWithIcon = [{
 }, {
 	name: '古道京紗@ぷらいべったー',
 	icon: 'https://assets.misskey-hub.net/patrons/18346d0519704963a4beabe6abc170af.jpg',
+}, {
+	name: '越貝鯛丸',
+	icon: 'https://assets.misskey-hub.net/patrons/86c7374de37849b882d8ebbc833dc968.jpg',
 }];
 
 const patrons = [

From 126383dca2a80e35c2606dd5d3dcd62dad5869cd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Tue, 21 May 2024 15:07:37 +0900
Subject: [PATCH 136/191] =?UTF-8?q?deps:=20AiScript=20VSCode=E3=81=AE?=
 =?UTF-8?q?=E3=83=90=E3=83=BC=E3=82=B8=E3=83=A7=E3=83=B3=E3=82=92=E4=B8=8A?=
 =?UTF-8?q?=E3=81=92=E3=82=8B=20(#13851)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 packages/frontend/package.json |  2 +-
 pnpm-lock.yaml                 | 50 ++++++++++++----------------------
 2 files changed, 18 insertions(+), 34 deletions(-)

diff --git a/packages/frontend/package.json b/packages/frontend/package.json
index a482373200..530d077a4e 100644
--- a/packages/frontend/package.json
+++ b/packages/frontend/package.json
@@ -29,7 +29,7 @@
 		"@twemoji/parser": "15.1.1",
 		"@vitejs/plugin-vue": "5.0.4",
 		"@vue/compiler-sfc": "3.4.26",
-		"aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.4",
+		"aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.9",
 		"astring": "1.8.6",
 		"broadcast-channel": "7.0.0",
 		"buraha": "0.0.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 9ddc1f1160..f77aefc067 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -722,8 +722,8 @@ importers:
         specifier: 3.4.26
         version: 3.4.26
       aiscript-vscode:
-        specifier: github:aiscript-dev/aiscript-vscode#v0.1.4
-        version: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/3f79d6f0550369267220aa67702287948d885424
+        specifier: github:aiscript-dev/aiscript-vscode#v0.1.9
+        version: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/34bf4e1530efcf1efa855bd04e2dab39735e1b02
       astring:
         specifier: 1.8.6
         version: 1.8.6
@@ -919,7 +919,7 @@ importers:
         version: 8.0.9(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))(vue@3.4.26(typescript@5.4.5))
       '@testing-library/vue':
         specifier: 8.0.3
-        version: 8.0.3(@vue/compiler-sfc@3.4.26)(@vue/server-renderer@3.4.25(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))
+        version: 8.0.3(@vue/compiler-sfc@3.4.26)(@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))
       '@types/escape-regexp':
         specifier: 0.0.3
         version: 0.0.3
@@ -4819,9 +4819,6 @@ packages:
   '@vue/compiler-sfc@3.4.26':
     resolution: {integrity: sha512-It1dp+FAOCgluYSVYlDn5DtZBxk1NCiJJfu2mlQqa/b+k8GL6NG/3/zRbJnHdhV2VhxFghaDq5L4K+1dakW6cw==}
 
-  '@vue/compiler-ssr@3.4.25':
-    resolution: {integrity: sha512-H2ohvM/Pf6LelGxDBnfbbXFPyM4NE3hrw0e/EpwuSiYu8c819wx+SVGdJ65p/sFrYDd6OnSDxN1MB2mN07hRSQ==}
-
   '@vue/compiler-ssr@3.4.26':
     resolution: {integrity: sha512-FNwLfk7LlEPRY/g+nw2VqiDKcnDTVdCfBREekF8X74cPLiWHUX6oldktf/Vx28yh4STNy7t+/yuLoMBBF7YDiQ==}
 
@@ -4845,11 +4842,6 @@ packages:
   '@vue/runtime-dom@3.4.26':
     resolution: {integrity: sha512-UftYA2hUXR2UOZD/Fc3IndZuCOOJgFxJsWOxDkhfVcwLbsfh2CdXE2tG4jWxBZuDAs9J9PzRTUFt1PgydEtItw==}
 
-  '@vue/server-renderer@3.4.25':
-    resolution: {integrity: sha512-8VTwq0Zcu3K4dWV0jOwIVINESE/gha3ifYCOKEhxOj6MEl5K5y8J8clQncTcDhKF+9U765nRw4UdUEXvrGhyVQ==}
-    peerDependencies:
-      vue: 3.4.25
-
   '@vue/server-renderer@3.4.26':
     resolution: {integrity: sha512-xoGAqSjYDPGAeRWxeoYwqJFD/gw7mpgzOvSxEmjWaFO2rE6qpbD1PC172YRpvKhrihkyHJkNDADFXTfCyVGhKw==}
     peerDependencies:
@@ -4959,9 +4951,9 @@ packages:
     resolution: {integrity: sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==}
     engines: {node: '>=18'}
 
-  aiscript-vscode@https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/3f79d6f0550369267220aa67702287948d885424:
-    resolution: {tarball: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/3f79d6f0550369267220aa67702287948d885424}
-    version: 0.1.4
+  aiscript-vscode@https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/34bf4e1530efcf1efa855bd04e2dab39735e1b02:
+    resolution: {tarball: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/34bf4e1530efcf1efa855bd04e2dab39735e1b02}
+    version: 0.1.9
     engines: {vscode: ^1.83.0}
 
   ajv-draft-04@1.0.0:
@@ -10875,6 +10867,9 @@ packages:
   vue-component-type-helpers@2.0.16:
     resolution: {integrity: sha512-qisL/iAfdO++7w+SsfYQJVPj6QKvxp4i1MMxvsNO41z/8zu3KuAw9LkhKUfP/kcOWGDxESp+pQObWppXusejCA==}
 
+  vue-component-type-helpers@2.0.19:
+    resolution: {integrity: sha512-cN3f1aTxxKo4lzNeQAkVopswuImUrb5Iurll9Gaw5cqpnbTAxtEMM1mgi6ou4X79OCyqYv1U1mzBHJkzmiK82w==}
+
   vue-demi@0.14.7:
     resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
     engines: {node: '>=12'}
@@ -14956,7 +14951,7 @@ snapshots:
       ts-dedent: 2.2.0
       type-fest: 2.19.0
       vue: 3.4.26(typescript@5.4.5)
-      vue-component-type-helpers: 2.0.16
+      vue-component-type-helpers: 2.0.19
     transitivePeerDependencies:
       - encoding
       - supports-color
@@ -15217,11 +15212,11 @@ snapshots:
     dependencies:
       '@testing-library/dom': 9.3.4
 
-  '@testing-library/vue@8.0.3(@vue/compiler-sfc@3.4.26)(@vue/server-renderer@3.4.25(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))':
+  '@testing-library/vue@8.0.3(@vue/compiler-sfc@3.4.26)(@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))':
     dependencies:
       '@babel/runtime': 7.23.4
       '@testing-library/dom': 9.3.3
-      '@vue/test-utils': 2.4.1(@vue/server-renderer@3.4.25(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))
+      '@vue/test-utils': 2.4.1(@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))
       vue: 3.4.26(typescript@5.4.5)
     optionalDependencies:
       '@vue/compiler-sfc': 3.4.26
@@ -16012,12 +16007,6 @@ snapshots:
       postcss: 8.4.38
       source-map-js: 1.2.0
 
-  '@vue/compiler-ssr@3.4.25':
-    dependencies:
-      '@vue/compiler-dom': 3.4.25
-      '@vue/shared': 3.4.25
-    optional: true
-
   '@vue/compiler-ssr@3.4.26':
     dependencies:
       '@vue/compiler-dom': 3.4.26
@@ -16052,13 +16041,6 @@ snapshots:
       '@vue/shared': 3.4.26
       csstype: 3.1.3
 
-  '@vue/server-renderer@3.4.25(vue@3.4.26(typescript@5.4.5))':
-    dependencies:
-      '@vue/compiler-ssr': 3.4.25
-      '@vue/shared': 3.4.25
-      vue: 3.4.26(typescript@5.4.5)
-    optional: true
-
   '@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.4.5))':
     dependencies:
       '@vue/compiler-ssr': 3.4.26
@@ -16071,13 +16053,13 @@ snapshots:
 
   '@vue/shared@3.4.26': {}
 
-  '@vue/test-utils@2.4.1(@vue/server-renderer@3.4.25(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))':
+  '@vue/test-utils@2.4.1(@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))':
     dependencies:
       js-beautify: 1.14.9
       vue: 3.4.26(typescript@5.4.5)
       vue-component-type-helpers: 1.8.4
     optionalDependencies:
-      '@vue/server-renderer': 3.4.25(vue@3.4.26(typescript@5.4.5))
+      '@vue/server-renderer': 3.4.26(vue@3.4.26(typescript@5.4.5))
 
   '@webgpu/types@0.1.30': {}
 
@@ -16159,7 +16141,7 @@ snapshots:
       clean-stack: 5.2.0
       indent-string: 5.0.0
 
-  aiscript-vscode@https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/3f79d6f0550369267220aa67702287948d885424:
+  aiscript-vscode@https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/34bf4e1530efcf1efa855bd04e2dab39735e1b02:
     dependencies:
       '@aiscript-dev/aiscript-languageserver': https://github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz
       vscode-languageclient: 9.0.1
@@ -23223,6 +23205,8 @@ snapshots:
 
   vue-component-type-helpers@2.0.16: {}
 
+  vue-component-type-helpers@2.0.19: {}
+
   vue-demi@0.14.7(vue@3.4.26(typescript@5.4.5)):
     dependencies:
       vue: 3.4.26(typescript@5.4.5)

From 6a637db36b8a0c32774b5da5e40236c5f14a59e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Tue, 21 May 2024 17:23:20 +0900
Subject: [PATCH 137/191] =?UTF-8?q?enhance(frontend):=20=E9=80=9A=E5=B8=B8?=
 =?UTF-8?q?=E3=81=AE=E3=83=8E=E3=83=BC=E3=83=88=E3=81=A7=E3=82=82=E3=80=81?=
 =?UTF-8?q?=E3=81=8A=E6=B0=97=E3=81=AB=E5=85=A5=E3=82=8A=E3=81=AB=E7=99=BB?=
 =?UTF-8?q?=E9=8C=B2=E3=81=97=E3=81=9F=E3=83=81=E3=83=A3=E3=83=B3=E3=83=8D?=
 =?UTF-8?q?=E3=83=AB=E3=81=AB=E3=83=AA=E3=83=8E=E3=83=BC=E3=83=88=E3=81=A7?=
 =?UTF-8?q?=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=20(#13855)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance(frontend): チャンネルにリノートできるように

* Update Changelog
---
 CHANGELOG.md                                  |  1 +
 locales/index.d.ts                            | 12 ++++++
 locales/ja-JP.yml                             |  3 ++
 .../frontend/src/scripts/get-note-menu.ts     | 38 +++++++++++++++++++
 4 files changed, 54 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ecacefe84e..9bdc1d135a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -41,6 +41,7 @@
 - Enhance: 通報のコメント内のリンクをクリックした際、ウィンドウで開くように
 - Enhance: `Ui:C:postForm` および `Ui:C:postFormButton` に `localOnly` と `visibility` を設定できるように
 - Enhance: AiScriptを0.18.0にバージョンアップ
+- Enhance: 通常のノートでも、お気に入りに登録したチャンネルにリノートできるように
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
 - Fix: ローカルURLのプレビューポップアップが左上に表示される
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 779a5d2c3f..70741b6460 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -448,6 +448,10 @@ export interface Locale extends ILocale {
      * リノートしました。
      */
     "renoted": string;
+    /**
+     * {name} にリノートしました。
+     */
+    "renotedToX": ParameterizedString<"name">;
     /**
      * この投稿はリノートできません。
      */
@@ -468,6 +472,14 @@ export interface Locale extends ILocale {
      * チャンネル内引用
      */
     "inChannelQuote": string;
+    /**
+     * チャンネルにリノート
+     */
+    "renoteToChannel": string;
+    /**
+     * 他のチャンネルにリノート
+     */
+    "renoteToOtherChannel": string;
     /**
      * ピン留めされたノート
      */
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 8f17215802..b5808f7541 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -108,11 +108,14 @@ enterEmoji: "絵文字を入力"
 renote: "リノート"
 unrenote: "リノート解除"
 renoted: "リノートしました。"
+renotedToX: "{name} にリノートしました。"
 cantRenote: "この投稿はリノートできません。"
 cantReRenote: "リノートをリノートすることはできません。"
 quote: "引用"
 inChannelRenote: "チャンネル内リノート"
 inChannelQuote: "チャンネル内引用"
+renoteToChannel: "チャンネルにリノート"
+renoteToOtherChannel: "他のチャンネルにリノート"
 pinnedNote: "ピン留めされたノート"
 pinned: "ピン留め"
 you: "あなた"
diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts
index 2cd21c1edc..e7c9a848e0 100644
--- a/packages/frontend/src/scripts/get-note-menu.ts
+++ b/packages/frontend/src/scripts/get-note-menu.ts
@@ -518,6 +518,7 @@ export function getRenoteMenu(props: {
 
 	const channelRenoteItems: MenuItem[] = [];
 	const normalRenoteItems: MenuItem[] = [];
+	const normalExternalChannelRenoteItems: MenuItem[] = [];
 
 	if (appearNote.channel) {
 		channelRenoteItems.push(...[{
@@ -596,12 +597,49 @@ export function getRenoteMenu(props: {
 				});
 			},
 		}]);
+
+		normalExternalChannelRenoteItems.push({
+			type: 'parent',
+			icon: 'ti ti-repeat',
+			text: appearNote.channel ? i18n.ts.renoteToOtherChannel : i18n.ts.renoteToChannel,
+			children: async () => {
+				const channels = await misskeyApi('channels/my-favorites', {
+					limit: 30,
+				});
+				return channels.filter((channel) => {
+					if (!appearNote.channelId) return true;
+					return channel.id !== appearNote.channelId;
+				}).map((channel) => ({
+					text: channel.name,
+					action: () => {
+						const el = props.renoteButton.value;
+						if (el) {
+							const rect = el.getBoundingClientRect();
+							const x = rect.left + (el.offsetWidth / 2);
+							const y = rect.top + (el.offsetHeight / 2);
+							os.popup(MkRippleEffect, { x, y }, {}, 'end');
+						}
+
+						if (!props.mock) {
+							misskeyApi('notes/create', {
+								renoteId: appearNote.id,
+								channelId: channel.id,
+							}).then(() => {
+								os.toast(i18n.tsx.renotedToX({ name: channel.name }));
+							});
+						}
+					},
+				}));
+			},
+		});
 	}
 
 	const renoteItems = [
 		...normalRenoteItems,
 		...(channelRenoteItems.length > 0 && normalRenoteItems.length > 0) ? [{ type: 'divider' }] as MenuItem[] : [],
 		...channelRenoteItems,
+		...(normalExternalChannelRenoteItems.length > 0 && (normalRenoteItems.length > 0 || channelRenoteItems.length > 0)) ? [{ type: 'divider' }] as MenuItem[] : [],
+		...normalExternalChannelRenoteItems,
 	];
 
 	return {

From 20c0bd9ddb86cd194be52d3f7c297ad5fd148a12 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Tue, 21 May 2024 17:29:02 +0900
Subject: [PATCH 138/191] =?UTF-8?q?happy-dom=E3=81=AB=E3=83=A1=E3=83=A2?=
 =?UTF-8?q?=E3=83=AA=E3=83=AA=E3=83=BC=E3=82=AF=E3=81=8C=E3=81=82=E3=82=8A?=
 =?UTF-8?q?=E3=81=9D=E3=81=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 packages/backend/package.json  |  2 +-
 packages/frontend/package.json |  2 +-
 pnpm-lock.yaml                 | 60 ++++++++++++++++++++--------------
 3 files changed, 37 insertions(+), 27 deletions(-)

diff --git a/packages/backend/package.json b/packages/backend/package.json
index 23b3bfdb8b..8e29252d75 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -117,7 +117,7 @@
 		"fluent-ffmpeg": "2.1.2",
 		"form-data": "4.0.0",
 		"got": "14.2.1",
-		"happy-dom": "14.7.1",
+		"happy-dom": "10.0.3",
 		"hpagent": "1.2.0",
 		"htmlescape": "1.1.1",
 		"http-link-header": "1.1.3",
diff --git a/packages/frontend/package.json b/packages/frontend/package.json
index 530d077a4e..56b824c0c5 100644
--- a/packages/frontend/package.json
+++ b/packages/frontend/package.json
@@ -119,7 +119,7 @@
 		"eslint-plugin-import": "2.29.1",
 		"eslint-plugin-vue": "9.25.0",
 		"fast-glob": "3.3.2",
-		"happy-dom": "14.7.1",
+		"happy-dom": "10.0.3",
 		"intersection-observer": "0.12.2",
 		"micromatch": "4.0.5",
 		"msw": "2.2.14",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f77aefc067..465539b834 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -234,8 +234,8 @@ importers:
         specifier: 14.2.1
         version: 14.2.1
       happy-dom:
-        specifier: 14.7.1
-        version: 14.7.1
+        specifier: 10.0.3
+        version: 10.0.3
       hpagent:
         specifier: 1.2.0
         version: 1.2.0
@@ -871,7 +871,7 @@ importers:
         version: 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@storybook/addon-interactions':
         specifier: 8.0.9
-        version: 8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
+        version: 8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
       '@storybook/addon-links':
         specifier: 8.0.9
         version: 8.0.9(react@18.3.1)
@@ -904,7 +904,7 @@ importers:
         version: 8.0.9(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.17.2)(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))
       '@storybook/test':
         specifier: 8.0.9
-        version: 8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
+        version: 8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
       '@storybook/theming':
         specifier: 8.0.9
         version: 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -961,7 +961,7 @@ importers:
         version: 7.7.1(eslint@8.57.0)(typescript@5.4.5)
       '@vitest/coverage-v8':
         specifier: 0.34.6
-        version: 0.34.6(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
+        version: 0.34.6(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
       '@vue/runtime-core':
         specifier: 3.4.26
         version: 3.4.26
@@ -987,8 +987,8 @@ importers:
         specifier: 3.3.2
         version: 3.3.2
       happy-dom:
-        specifier: 14.7.1
-        version: 14.7.1
+        specifier: 10.0.3
+        version: 10.0.3
       intersection-observer:
         specifier: 0.12.2
         version: 0.12.2
@@ -1027,10 +1027,10 @@ importers:
         version: 1.0.3
       vitest:
         specifier: 0.34.6
-        version: 0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)
+        version: 0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)
       vitest-fetch-mock:
         specifier: 0.2.2
-        version: 0.2.2(encoding@0.1.13)(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
+        version: 0.2.2(encoding@0.1.13)(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
       vue-component-type-helpers:
         specifier: 2.0.16
         version: 2.0.16
@@ -6898,9 +6898,8 @@ packages:
     engines: {node: '>=0.4.7'}
     hasBin: true
 
-  happy-dom@14.7.1:
-    resolution: {integrity: sha512-v60Q0evZ4clvMcrAh5/F8EdxDdfHdFrtffz/CNe10jKD+nFweZVxM91tW+UyY2L4AtpgIaXdZ7TQmiO1pfcwbg==}
-    engines: {node: '>=16.0.0'}
+  happy-dom@10.0.3:
+    resolution: {integrity: sha512-WkCP+Z5fX6U5PY+yHP3ElV5D9PoxRAHRWPFq3pG9rg/6Hjf5ak7dozAgSCywsTRUq2qfa8vV8OQvUy5pRXy8EQ==}
 
   har-schema@2.0.0:
     resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==}
@@ -10967,6 +10966,10 @@ packages:
   webpack-virtual-modules@0.5.0:
     resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==}
 
+  whatwg-encoding@2.0.0:
+    resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==}
+    engines: {node: '>=12'}
+
   whatwg-encoding@3.1.1:
     resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
     engines: {node: '>=18'}
@@ -14375,11 +14378,11 @@ snapshots:
     dependencies:
       '@storybook/global': 5.0.0
 
-  '@storybook/addon-interactions@8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))':
+  '@storybook/addon-interactions@8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))':
     dependencies:
       '@storybook/global': 5.0.0
       '@storybook/instrumenter': 8.0.9
-      '@storybook/test': 8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
+      '@storybook/test': 8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
       '@storybook/types': 8.0.9
       polished: 4.2.2
       ts-dedent: 2.2.0
@@ -14883,14 +14886,14 @@ snapshots:
       - encoding
       - supports-color
 
-  '@storybook/test@8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))':
+  '@storybook/test@8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))':
     dependencies:
       '@storybook/client-logger': 8.0.9
       '@storybook/core-events': 8.0.9
       '@storybook/instrumenter': 8.0.9
       '@storybook/preview-api': 8.0.9
       '@testing-library/dom': 9.3.4
-      '@testing-library/jest-dom': 6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
+      '@testing-library/jest-dom': 6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
       '@testing-library/user-event': 14.5.2(@testing-library/dom@9.3.4)
       '@vitest/expect': 1.3.1
       '@vitest/spy': 1.6.0
@@ -15192,7 +15195,7 @@ snapshots:
       lz-string: 1.5.0
       pretty-format: 27.5.1
 
-  '@testing-library/jest-dom@6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))':
+  '@testing-library/jest-dom@6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))':
     dependencies:
       '@adobe/css-tools': 4.3.3
       '@babel/runtime': 7.23.4
@@ -15206,7 +15209,7 @@ snapshots:
       '@jest/globals': 29.7.0
       '@types/jest': 29.5.12
       jest: 29.7.0(@types/node@20.12.7)
-      vitest: 0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)
+      vitest: 0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)
 
   '@testing-library/user-event@14.5.2(@testing-library/dom@9.3.4)':
     dependencies:
@@ -15870,7 +15873,7 @@ snapshots:
       vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
       vue: 3.4.26(typescript@5.4.5)
 
-  '@vitest/coverage-v8@0.34.6(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))':
+  '@vitest/coverage-v8@0.34.6(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))':
     dependencies:
       '@ampproject/remapping': 2.2.1
       '@bcoe/v8-coverage': 0.2.3
@@ -15883,7 +15886,7 @@ snapshots:
       std-env: 3.7.0
       test-exclude: 6.0.0
       v8-to-istanbul: 9.2.0
-      vitest: 0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)
+      vitest: 0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)
     transitivePeerDependencies:
       - supports-color
 
@@ -18798,10 +18801,13 @@ snapshots:
     optionalDependencies:
       uglify-js: 3.17.4
 
-  happy-dom@14.7.1:
+  happy-dom@10.0.3:
     dependencies:
+      css.escape: 1.5.1
       entities: 4.5.0
+      iconv-lite: 0.6.3
       webidl-conversions: 7.0.0
+      whatwg-encoding: 2.0.0
       whatwg-mimetype: 3.0.0
 
   har-schema@2.0.0: {}
@@ -23124,14 +23130,14 @@ snapshots:
       sass: 1.76.0
       terser: 5.30.3
 
-  vitest-fetch-mock@0.2.2(encoding@0.1.13)(vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)):
+  vitest-fetch-mock@0.2.2(encoding@0.1.13)(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)):
     dependencies:
       cross-fetch: 3.1.6(encoding@0.1.13)
-      vitest: 0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)
+      vitest: 0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)
     transitivePeerDependencies:
       - encoding
 
-  vitest@0.34.6(happy-dom@14.7.1)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3):
+  vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3):
     dependencies:
       '@types/chai': 4.3.11
       '@types/chai-subset': 1.3.5
@@ -23158,7 +23164,7 @@ snapshots:
       vite-node: 0.34.6(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
       why-is-node-running: 2.2.2
     optionalDependencies:
-      happy-dom: 14.7.1
+      happy-dom: 10.0.3
       jsdom: 24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
     transitivePeerDependencies:
       - less
@@ -23324,6 +23330,10 @@ snapshots:
 
   webpack-virtual-modules@0.5.0: {}
 
+  whatwg-encoding@2.0.0:
+    dependencies:
+      iconv-lite: 0.6.3
+
   whatwg-encoding@3.1.1:
     dependencies:
       iconv-lite: 0.6.3

From c69de6b48cad0fb9f4af7a9b88f24aef9c3aeb08 Mon Sep 17 00:00:00 2001
From: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
Date: Tue, 21 May 2024 20:43:00 +0900
Subject: [PATCH 139/191] fix(l10n): fix wrong description of server silence
 (#13857)

---
 locales/ja-JP.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index b5808f7541..626e3f30f8 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -225,7 +225,7 @@ clearCachedFilesConfirm: "キャッシュされたリモートファイルをす
 blockedInstances: "ブロックしたサーバー"
 blockedInstancesDescription: "ブロックしたいサーバーのホストを改行で区切って設定します。ブロックされたサーバーは、このインスタンスとやり取りできなくなります。"
 silencedInstances: "サイレンスしたサーバー"
-silencedInstancesDescription: "サイレンスしたいサーバーのホストを改行で区切って設定します。サイレンスされたサーバーに所属するアカウントはすべて「サイレンス」として扱われ、フォローがすべてリクエストになり、フォロワーでないローカルアカウントにはメンションできなくなります。ブロックしたインスタンスには影響しません。"
+silencedInstancesDescription: "サイレンスしたいサーバーのホストを改行で区切って設定します。サイレンスされたサーバーに所属するアカウントはすべて「サイレンス」として扱われ、フォローがすべてリクエストになります。ブロックしたインスタンスには影響しません。"
 muteAndBlock: "ミュートとブロック"
 mutedUsers: "ミュートしたユーザー"
 blockedUsers: "ブロックしたユーザー"

From ed432d06d76c2cfc3d46b2d8f7931ec3fb0235d0 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Wed, 22 May 2024 06:40:05 +0900
Subject: [PATCH 140/191] New Crowdin updates (#13850)

* New translations ja-jp.yml (Polish)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Chinese Simplified)
---
 locales/de-DE.yml | 2 +-
 locales/pl-PL.yml | 2 +-
 locales/zh-CN.yml | 3 +++
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/locales/de-DE.yml b/locales/de-DE.yml
index 3b39938255..3e1c40512e 100644
--- a/locales/de-DE.yml
+++ b/locales/de-DE.yml
@@ -654,7 +654,7 @@ smtpSecureInfo: "Schalte dies aus, falls du STARTTLS verwendest."
 testEmail: "Emailversand testen"
 wordMute: "Wortstummschaltung"
 regexpError: "Fehler in einem regulären Ausdruck"
-regexpErrorDescription: "Im regulären Ausdruck deiner {tab}en Wortstummschaltungen ist ein Fehler aufgetreten:"
+regexpErrorDescription: "Im regulären Ausdruck deiner in Zeile {line} von {tab}en Wortstummschaltungen ist ein Fehler aufgetreten:"
 instanceMute: "Instanzstummschaltungen"
 userSaysSomething: "{name} hat etwas gesagt"
 makeActive: "Aktivieren"
diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml
index b7eb4683eb..2183aa3022 100644
--- a/locales/pl-PL.yml
+++ b/locales/pl-PL.yml
@@ -933,7 +933,7 @@ check: "Zweryfikuj"
 driveCapOverrideLabel: "Zmień limit pojemności dysku użytkownika"
 requireAdminForView: "Aby to zobaczyć, musisz być administratorem"
 isSystemAccount: "To jest konto stworzone i zarządzane przez system"
-typeToConfirm: "Wielki chuj "
+typeToConfirm: "Wprowadź {x}, aby potwierdzić"
 deleteAccount: "Usuń konto"
 document: "Dokumentacja"
 numberOfPageCache: "Ilość stron w cache"
diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index fb1ffc5a99..17164dfe98 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -108,11 +108,14 @@ enterEmoji: "输入表情符号"
 renote: "转发"
 unrenote: "取消转发"
 renoted: "已转发。"
+renotedToX: "转帖给 {name}"
 cantRenote: "该帖无法转发。"
 cantReRenote: "转发无法被再次转发。"
 quote: "引用"
 inChannelRenote: "在频道内转发"
 inChannelQuote: "在频道内引用"
+renoteToChannel: "转帖至频道"
+renoteToOtherChannel: "转帖至其它频道"
 pinnedNote: "已置顶的帖子"
 pinned: "置顶"
 you: "您"

From aafa669cf59778ed695632b45af0408cc9c3f038 Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Thu, 23 May 2024 13:15:22 +0900
Subject: [PATCH 141/191] =?UTF-8?q?feat(frontend):=20=E9=95=B7=E3=81=84?=
 =?UTF-8?q?=E3=83=86=E3=82=AD=E3=82=B9=E3=83=88=E3=82=92=E3=83=9A=E3=83=BC?=
 =?UTF-8?q?=E3=82=B9=E3=83=88=E3=81=97=E3=81=9F=E9=9A=9B=E3=81=AB=E3=83=86?=
 =?UTF-8?q?=E3=82=AD=E3=82=B9=E3=83=88=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB?=
 =?UTF-8?q?=E3=81=A8=E3=81=97=E3=81=A6=E6=B7=BB=E4=BB=98=E3=81=99=E3=82=8B?=
 =?UTF-8?q?=E3=81=8B=E3=81=A9=E3=81=86=E3=81=8B=E3=82=92=E9=81=B8=E6=8A=9E?=
 =?UTF-8?q?=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=20(#1386?=
 =?UTF-8?q?2)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* feat(frontend): ask if attach as file if clipboard text is very long

* docs(changelog): 長いテキストをペーストした際にテキストファイルとして添付するかどうかを選択できるように
---
 CHANGELOG.md                                    |  1 +
 locales/index.d.ts                              |  6 +++++-
 locales/ja-JP.yml                               |  1 +
 packages/frontend/src/components/MkPostForm.vue | 17 +++++++++++++++++
 4 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9bdc1d135a..ce66d779a3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -42,6 +42,7 @@
 - Enhance: `Ui:C:postForm` および `Ui:C:postFormButton` に `localOnly` と `visibility` を設定できるように
 - Enhance: AiScriptを0.18.0にバージョンアップ
 - Enhance: 通常のノートでも、お気に入りに登録したチャンネルにリノートできるように
+- Enhance: 長いテキストをペーストした際にテキストファイルとして添付するかどうかを選択できるように
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
 - Fix: ローカルURLのプレビューポップアップが左上に表示される
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 70741b6460..d5d6ef0f34 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -917,7 +917,7 @@ export interface Locale extends ILocale {
      */
     "silencedInstances": string;
     /**
-     * サイレンスしたいサーバーのホストを改行で区切って設定します。サイレンスされたサーバーに所属するアカウントはすべて「サイレンス」として扱われ、フォローがすべてリクエストになり、フォロワーでないローカルアカウントにはメンションできなくなります。ブロックしたインスタンスには影響しません。
+     * サイレンスしたいサーバーのホストを改行で区切って設定します。サイレンスされたサーバーに所属するアカウントはすべて「サイレンス」として扱われ、フォローがすべてリクエストになります。ブロックしたインスタンスには影響しません。
      */
     "silencedInstancesDescription": string;
     /**
@@ -1900,6 +1900,10 @@ export interface Locale extends ILocale {
      * 引用として添付しますか?
      */
     "quoteQuestion": string;
+    /**
+     * クリップボードのテキストが長いです。テキストファイルとして添付しますか?
+     */
+    "attachAsFileQuestion": string;
     /**
      * まだチャットはありません
      */
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 626e3f30f8..9aa1e6e6a0 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -471,6 +471,7 @@ retype: "再入力"
 noteOf: "{user}のノート"
 quoteAttached: "引用付き"
 quoteQuestion: "引用として添付しますか?"
+attachAsFileQuestion: "クリップボードのテキストが長いです。テキストファイルとして添付しますか?"
 noMessagesYet: "まだチャットはありません"
 newMessageExists: "新しいメッセージがあります"
 onlyOneFileCanBeAttached: "メッセージに添付できるファイルはひとつです"
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index 41d603e40f..1df9007681 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -612,6 +612,23 @@ async function onPaste(ev: ClipboardEvent) {
 			quoteId.value = paste.substring(url.length).match(/^\/notes\/(.+?)\/?$/)?.[1] ?? null;
 		});
 	}
+
+	if (paste.length > 1000) {
+		ev.preventDefault();
+		os.confirm({
+			type: 'info',
+			text: i18n.ts.attachAsFileQuestion,
+		}).then(({ canceled }) => {
+			if (canceled) {
+				insertTextAtCursor(textareaEl.value, paste);
+				return;
+			}
+
+			const fileName = formatTimeString(new Date(), defaultStore.state.pastedFileName).replace(/{{number}}/g, "0");
+			const file = new File([paste], `${fileName}.txt`, { type: "text/plain" });
+			upload(file, `${fileName}.txt`);
+		});
+	}
 }
 
 function onDragover(ev) {

From 8489d39372c571736881329d92a0dabeba3f3e69 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Thu, 23 May 2024 05:25:01 +0000
Subject: [PATCH 142/191] Bump version to 2024.5.0-beta.2

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index e05fbdcca7..b9ac4fc2a1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2024.5.0-beta.1",
+	"version": "2024.5.0-beta.2",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index cc5d5bdbf4..80ae84796a 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2024.5.0-beta.1",
+	"version": "2024.5.0-beta.2",
 	"description": "Misskey SDK for JavaScript",
 	"main": "./built/index.js",
 	"types": "./built/index.d.ts",

From 611e303bab1ace64c7ab1611e35d850a96f0bace Mon Sep 17 00:00:00 2001
From: Acid Chicken <root@acid-chicken.com>
Date: Thu, 23 May 2024 15:19:52 +0900
Subject: [PATCH 143/191] feat(backend): add /healthz endpoint (#13834)

* feat(backend): add /healthz endpoint

* feat(backend): also check meilisearch status if available

* style: header

* chore: no-store

* chore: healthcheck.sh

* style: format
---
 healthcheck.sh                                |  2 +-
 packages/backend/src/boot/entry.ts            |  3 ++
 packages/backend/src/boot/ready.ts            |  6 +++
 .../backend/src/server/HealthServerService.ts | 54 +++++++++++++++++++
 packages/backend/src/server/ServerModule.ts   |  2 +
 packages/backend/src/server/ServerService.ts  |  3 ++
 6 files changed, 69 insertions(+), 1 deletion(-)
 create mode 100644 packages/backend/src/boot/ready.ts
 create mode 100644 packages/backend/src/server/HealthServerService.ts

diff --git a/healthcheck.sh b/healthcheck.sh
index d6d416c7a1..dcfcf76786 100644
--- a/healthcheck.sh
+++ b/healthcheck.sh
@@ -4,4 +4,4 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 
 PORT=$(grep '^port:' /misskey/.config/default.yml | awk 'NR==1{print $2; exit}')
-curl -s -S -o /dev/null "http://localhost:${PORT}"
+curl -Sfso/dev/null "http://localhost:${PORT}/healthz"
diff --git a/packages/backend/src/boot/entry.ts b/packages/backend/src/boot/entry.ts
index 6b8e83d4f9..04c6ca9723 100644
--- a/packages/backend/src/boot/entry.ts
+++ b/packages/backend/src/boot/entry.ts
@@ -15,6 +15,7 @@ import Logger from '@/logger.js';
 import { envOption } from '../env.js';
 import { masterMain } from './master.js';
 import { workerMain } from './worker.js';
+import { readyRef } from './ready.js';
 
 import 'reflect-metadata';
 
@@ -79,6 +80,8 @@ if (cluster.isWorker || envOption.disableClustering) {
 	await workerMain();
 }
 
+readyRef.value = true;
+
 // ユニットテスト時にMisskeyが子プロセスで起動された時のため
 // それ以外のときは process.send は使えないので弾く
 if (process.send) {
diff --git a/packages/backend/src/boot/ready.ts b/packages/backend/src/boot/ready.ts
new file mode 100644
index 0000000000..591ae5cb58
--- /dev/null
+++ b/packages/backend/src/boot/ready.ts
@@ -0,0 +1,6 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export const readyRef = { value: false };
diff --git a/packages/backend/src/server/HealthServerService.ts b/packages/backend/src/server/HealthServerService.ts
new file mode 100644
index 0000000000..2c3ed85925
--- /dev/null
+++ b/packages/backend/src/server/HealthServerService.ts
@@ -0,0 +1,54 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Inject, Injectable } from '@nestjs/common';
+import * as Redis from 'ioredis';
+import { DataSource } from 'typeorm';
+import { bindThis } from '@/decorators.js';
+import { DI } from '@/di-symbols.js';
+import { readyRef } from '@/boot/ready.js';
+import type { FastifyInstance, FastifyPluginOptions } from 'fastify';
+import type { MeiliSearch } from 'meilisearch';
+
+@Injectable()
+export class HealthServerService {
+	constructor(
+		@Inject(DI.redis)
+		private redis: Redis.Redis,
+
+		@Inject(DI.redisForPub)
+		private redisForPub: Redis.Redis,
+
+		@Inject(DI.redisForSub)
+		private redisForSub: Redis.Redis,
+
+		@Inject(DI.redisForTimelines)
+		private redisForTimelines: Redis.Redis,
+
+		@Inject(DI.db)
+		private db: DataSource,
+
+		@Inject(DI.meilisearch)
+		private meilisearch: MeiliSearch | null,
+	) {}
+
+	@bindThis
+	public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) {
+		fastify.get('/', async (request, reply) => {
+			reply.code(await Promise.all([
+				new Promise<void>((resolve, reject) => readyRef.value ? resolve() : reject()),
+				this.redis.ping(),
+				this.redisForPub.ping(),
+				this.redisForSub.ping(),
+				this.redisForTimelines.ping(),
+				this.db.query('SELECT 1'),
+				...(this.meilisearch ? [this.meilisearch.health()] : []),
+			]).then(() => 200, () => 503));
+			reply.header('Cache-Control', 'no-store');
+		});
+
+		done();
+	}
+}
diff --git a/packages/backend/src/server/ServerModule.ts b/packages/backend/src/server/ServerModule.ts
index f43968d236..12d5061985 100644
--- a/packages/backend/src/server/ServerModule.ts
+++ b/packages/backend/src/server/ServerModule.ts
@@ -8,6 +8,7 @@ import { EndpointsModule } from '@/server/api/EndpointsModule.js';
 import { CoreModule } from '@/core/CoreModule.js';
 import { ApiCallService } from './api/ApiCallService.js';
 import { FileServerService } from './FileServerService.js';
+import { HealthServerService } from './HealthServerService.js';
 import { NodeinfoServerService } from './NodeinfoServerService.js';
 import { ServerService } from './ServerService.js';
 import { WellKnownServerService } from './WellKnownServerService.js';
@@ -55,6 +56,7 @@ import { ReversiGameChannelService } from './api/stream/channels/reversi-game.js
 		ClientServerService,
 		ClientLoggerService,
 		FeedService,
+		HealthServerService,
 		UrlPreviewService,
 		ActivityPubServerService,
 		FileServerService,
diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts
index da17a88e03..3572f16627 100644
--- a/packages/backend/src/server/ServerService.ts
+++ b/packages/backend/src/server/ServerService.ts
@@ -28,6 +28,7 @@ import { ApiServerService } from './api/ApiServerService.js';
 import { StreamingApiServerService } from './api/StreamingApiServerService.js';
 import { WellKnownServerService } from './WellKnownServerService.js';
 import { FileServerService } from './FileServerService.js';
+import { HealthServerService } from './HealthServerService.js';
 import { ClientServerService } from './web/ClientServerService.js';
 import { OpenApiServerService } from './api/openapi/OpenApiServerService.js';
 import { OAuth2ProviderService } from './oauth/OAuth2ProviderService.js';
@@ -61,6 +62,7 @@ export class ServerService implements OnApplicationShutdown {
 		private wellKnownServerService: WellKnownServerService,
 		private nodeinfoServerService: NodeinfoServerService,
 		private fileServerService: FileServerService,
+		private healthServerService: HealthServerService,
 		private clientServerService: ClientServerService,
 		private globalEventService: GlobalEventService,
 		private loggerService: LoggerService,
@@ -108,6 +110,7 @@ export class ServerService implements OnApplicationShutdown {
 		fastify.register(this.wellKnownServerService.createServer);
 		fastify.register(this.oauth2ProviderService.createServer, { prefix: '/oauth' });
 		fastify.register(this.oauth2ProviderService.createTokenServer, { prefix: '/oauth/token' });
+		fastify.register(this.healthServerService.createServer, { prefix: '/healthz' });
 
 		fastify.get<{ Params: { path: string }; Querystring: { static?: any; badge?: any; }; }>('/emoji/:path(.*)', async (request, reply) => {
 			const path = request.params.path;

From 83a9aa4533912c685a74a107be3894c4a85a338c Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Thu, 23 May 2024 15:55:47 +0900
Subject: [PATCH 144/191] feat: suspend instance improvements (#13861)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* feat(backend): dead instance detection

* feat(backend): suspend type detection

* feat(frontend): show suspend reason on frontend

* feat(backend): resume federation automatically if the server is automatically suspended

* docs(changelog): 配信停止まわりの改善

* lint: fix lint errors

* Update packages/frontend/src/pages/instance-info.vue

* lint: fix lint error

* chore: suspendedState => suspensionState

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 CHANGELOG.md                                  |  3 ++
 locales/index.d.ts                            | 32 ++++++++++++
 locales/ja-JP.yml                             | 10 ++++
 .../1716345015347-NotRespondingSince.js       | 16 ++++++
 ...8870-SuspensionStateInsteadOfIsSspended.js | 50 +++++++++++++++++++
 .../core/entities/InstanceEntityService.ts    |  3 +-
 packages/backend/src/models/Instance.ts       | 17 +++++--
 .../models/json-schema/federation-instance.ts |  5 ++
 .../processors/DeliverProcessorService.ts     | 14 +++++-
 .../queue/processors/InboxProcessorService.ts |  2 +
 .../src/server/api/ApiServerService.ts        |  2 +-
 .../admin/federation/update-instance.ts       | 11 +++-
 .../frontend/src/pages/admin/federation.vue   | 14 +++++-
 packages/frontend/src/pages/instance-info.vue | 29 +++++++++--
 packages/misskey-js/src/autogen/types.ts      |  2 +
 15 files changed, 193 insertions(+), 17 deletions(-)
 create mode 100644 packages/backend/migration/1716345015347-NotRespondingSince.js
 create mode 100644 packages/backend/migration/1716447138870-SuspensionStateInsteadOfIsSspended.js

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ce66d779a3..21bb3b2e8e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,9 @@
   - サスペンド済みユーザーか
   - 鍵アカウントユーザーか
   - 「アカウントを見つけやすくする」が有効なユーザーか
+- Enhance: Goneを出さずに終了したサーバーへの配信停止を自動的に行うように
+  - もしそのようなサーバーからから配信が届いた場合には自動的に配信を再開します
+- Enhance: 配信停止の理由を表示するように
 - Fix: Play作成時に設定した公開範囲が機能していない問題を修正
 - Fix: 正規化されていない状態のhashtagが連合されてきたhtmlに含まれているとhashtagが正しくhashtagに復元されない問題を修正
 - Fix: みつけるのアンケート欄にてチャンネルのアンケートが含まれてしまう問題を修正
diff --git a/locales/index.d.ts b/locales/index.d.ts
index d5d6ef0f34..991ec1ac1d 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -4972,6 +4972,38 @@ export interface Locale extends ILocale {
      * お問い合わせ
      */
     "inquiry": string;
+    "_delivery": {
+        /**
+         * 配信状態
+         */
+        "status": string;
+        /**
+         * 配信停止
+         */
+        "stop": string;
+        /**
+         * 配信再開
+         */
+        "resume": string;
+        "_type": {
+            /**
+             * 配信中
+             */
+            "none": string;
+            /**
+             * 手動停止中
+             */
+            "manuallySuspended": string;
+            /**
+             * サーバー削除のため停止中
+             */
+            "goneSuspended": string;
+            /**
+             * サーバー応答なしのため停止中
+             */
+            "autoSuspendedForNotResponding": string;
+        };
+    };
     "_bubbleGame": {
         /**
          * 遊び方
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 9aa1e6e6a0..d7635acc2e 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1240,6 +1240,16 @@ noDescription: "説明文はありません"
 alwaysConfirmFollow: "フォローの際常に確認する"
 inquiry: "お問い合わせ"
 
+_delivery:
+  status: "配信状態"
+  stop: "配信停止"
+  resume: "配信再開"
+  _type:
+    none: "配信中"
+    manuallySuspended: "手動停止中"
+    goneSuspended: "サーバー削除のため停止中"
+    autoSuspendedForNotResponding: "サーバー応答なしのため停止中"
+
 _bubbleGame:
   howToPlay: "遊び方"
   hold: "ホールド"
diff --git a/packages/backend/migration/1716345015347-NotRespondingSince.js b/packages/backend/migration/1716345015347-NotRespondingSince.js
new file mode 100644
index 0000000000..fc4ee6639a
--- /dev/null
+++ b/packages/backend/migration/1716345015347-NotRespondingSince.js
@@ -0,0 +1,16 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class NotRespondingSince1716345015347 {
+    name = 'NotRespondingSince1716345015347'
+
+    async up(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "instance" ADD "notRespondingSince" TIMESTAMP WITH TIME ZONE`);
+    }
+
+    async down(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "notRespondingSince"`);
+    }
+}
diff --git a/packages/backend/migration/1716447138870-SuspensionStateInsteadOfIsSspended.js b/packages/backend/migration/1716447138870-SuspensionStateInsteadOfIsSspended.js
new file mode 100644
index 0000000000..4808a9a3db
--- /dev/null
+++ b/packages/backend/migration/1716447138870-SuspensionStateInsteadOfIsSspended.js
@@ -0,0 +1,50 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class SuspensionStateInsteadOfIsSspended1716345771510 {
+    name = 'SuspensionStateInsteadOfIsSspended1716345771510'
+
+    async up(queryRunner) {
+        await queryRunner.query(`CREATE TYPE "public"."instance_suspensionstate_enum" AS ENUM('none', 'manuallySuspended', 'goneSuspended', 'autoSuspendedForNotResponding')`);
+
+        await queryRunner.query(`DROP INDEX "public"."IDX_34500da2e38ac393f7bb6b299c"`);
+
+        await queryRunner.query(`ALTER TABLE "instance" RENAME COLUMN "isSuspended" TO "suspensionState"`);
+
+        await queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "suspensionState" DROP DEFAULT`);
+
+        await queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "suspensionState" TYPE "public"."instance_suspensionstate_enum" USING (
+            CASE "suspensionState"
+               WHEN TRUE THEN 'manuallySuspended'::instance_suspensionstate_enum
+               ELSE 'none'::instance_suspensionstate_enum
+            END
+        )`);
+
+        await queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "suspensionState" SET DEFAULT 'none'`);
+
+        await queryRunner.query(`CREATE INDEX "IDX_3ede46f507c87ad698051d56a8" ON "instance" ("suspensionState") `);
+    }
+
+    async down(queryRunner) {
+        await queryRunner.query(`DROP INDEX "public"."IDX_3ede46f507c87ad698051d56a8"`);
+
+        await queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "suspensionState" DROP DEFAULT`);
+
+        await queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "suspensionState" TYPE boolean USING (
+            CASE "suspensionState"
+               WHEN 'none'::instance_suspensionstate_enum THEN FALSE
+               ELSE TRUE
+            END
+        )`);
+
+        await queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "suspensionState" SET DEFAULT false`);
+
+        await queryRunner.query(`ALTER TABLE "instance" RENAME COLUMN "suspensionState" TO "isSuspended"`);
+
+        await queryRunner.query(`CREATE INDEX "IDX_34500da2e38ac393f7bb6b299c" ON "instance" ("isSuspended") `);
+
+        await queryRunner.query(`DROP TYPE "public"."instance_suspensionstate_enum"`);
+    }
+}
diff --git a/packages/backend/src/core/entities/InstanceEntityService.ts b/packages/backend/src/core/entities/InstanceEntityService.ts
index e46bd8b963..9117b13914 100644
--- a/packages/backend/src/core/entities/InstanceEntityService.ts
+++ b/packages/backend/src/core/entities/InstanceEntityService.ts
@@ -39,7 +39,8 @@ export class InstanceEntityService {
 			followingCount: instance.followingCount,
 			followersCount: instance.followersCount,
 			isNotResponding: instance.isNotResponding,
-			isSuspended: instance.isSuspended,
+			isSuspended: instance.suspensionState !== 'none',
+			suspensionState: instance.suspensionState,
 			isBlocked: this.utilityService.isBlockedHost(meta.blockedHosts, instance.host),
 			softwareName: instance.softwareName,
 			softwareVersion: instance.softwareVersion,
diff --git a/packages/backend/src/models/Instance.ts b/packages/backend/src/models/Instance.ts
index 9863c9d75d..17cd5c6665 100644
--- a/packages/backend/src/models/Instance.ts
+++ b/packages/backend/src/models/Instance.ts
@@ -81,13 +81,22 @@ export class MiInstance {
 	public isNotResponding: boolean;
 
 	/**
-	 * このインスタンスへの配信を停止するか
+	 * このインスタンスと不通になった日時
+	 */
+	@Column('timestamp with time zone', {
+		nullable: true,
+	})
+	public notRespondingSince: Date | null;
+
+	/**
+	 * このインスタンスへの配信状態
 	 */
 	@Index()
-	@Column('boolean', {
-		default: false,
+	@Column('enum', {
+		default: 'none',
+		enum: ['none', 'manuallySuspended', 'goneSuspended', 'autoSuspendedForNotResponding'],
 	})
-	public isSuspended: boolean;
+	public suspensionState: 'none' | 'manuallySuspended' | 'goneSuspended' | 'autoSuspendedForNotResponding';
 
 	@Column('varchar', {
 		length: 64, nullable: true,
diff --git a/packages/backend/src/models/json-schema/federation-instance.ts b/packages/backend/src/models/json-schema/federation-instance.ts
index 42d98fe523..ed40d405c6 100644
--- a/packages/backend/src/models/json-schema/federation-instance.ts
+++ b/packages/backend/src/models/json-schema/federation-instance.ts
@@ -45,6 +45,11 @@ export const packedFederationInstanceSchema = {
 			type: 'boolean',
 			optional: false, nullable: false,
 		},
+		suspensionState: {
+			type: 'string',
+			nullable: false, optional: false,
+			enum: ['none', 'manuallySuspended', 'goneSuspended', 'autoSuspendedForNotResponding'],
+		},
 		isBlocked: {
 			type: 'boolean',
 			optional: false, nullable: false,
diff --git a/packages/backend/src/queue/processors/DeliverProcessorService.ts b/packages/backend/src/queue/processors/DeliverProcessorService.ts
index 5fed070929..b73195afc3 100644
--- a/packages/backend/src/queue/processors/DeliverProcessorService.ts
+++ b/packages/backend/src/queue/processors/DeliverProcessorService.ts
@@ -5,6 +5,7 @@
 
 import { Inject, Injectable } from '@nestjs/common';
 import * as Bull from 'bullmq';
+import { Not } from 'typeorm';
 import { DI } from '@/di-symbols.js';
 import type { InstancesRepository } from '@/models/_.js';
 import type Logger from '@/logger.js';
@@ -62,7 +63,7 @@ export class DeliverProcessorService {
 		if (suspendedHosts == null) {
 			suspendedHosts = await this.instancesRepository.find({
 				where: {
-					isSuspended: true,
+					suspensionState: Not('none'),
 				},
 			});
 			this.suspendedHostsCache.set(suspendedHosts);
@@ -79,6 +80,7 @@ export class DeliverProcessorService {
 				if (i.isNotResponding) {
 					this.federatedInstanceService.update(i.id, {
 						isNotResponding: false,
+						notRespondingSince: null,
 					});
 				}
 
@@ -98,7 +100,15 @@ export class DeliverProcessorService {
 				if (!i.isNotResponding) {
 					this.federatedInstanceService.update(i.id, {
 						isNotResponding: true,
+						notRespondingSince: new Date(),
 					});
+				} else if (i.notRespondingSince) {
+					// 1週間以上不通ならサスペンド
+					if (i.suspensionState === 'none' && i.notRespondingSince.getTime() <= Date.now() - 1000 * 60 * 60 * 24 * 7) {
+						this.federatedInstanceService.update(i.id, {
+							suspensionState: 'autoSuspendedForNotResponding',
+						});
+					}
 				}
 
 				this.apRequestChart.deliverFail();
@@ -116,7 +126,7 @@ export class DeliverProcessorService {
 					if (job.data.isSharedInbox && res.statusCode === 410) {
 						this.federatedInstanceService.fetch(host).then(i => {
 							this.federatedInstanceService.update(i.id, {
-								isSuspended: true,
+								suspensionState: 'goneSuspended',
 							});
 						});
 						throw new Bull.UnrecoverableError(`${host} is gone`);
diff --git a/packages/backend/src/queue/processors/InboxProcessorService.ts b/packages/backend/src/queue/processors/InboxProcessorService.ts
index 1d05f4ade1..f465339075 100644
--- a/packages/backend/src/queue/processors/InboxProcessorService.ts
+++ b/packages/backend/src/queue/processors/InboxProcessorService.ts
@@ -188,6 +188,8 @@ export class InboxProcessorService {
 			this.federatedInstanceService.update(i.id, {
 				latestRequestReceivedAt: new Date(),
 				isNotResponding: false,
+				// もしサーバーが死んでるために配信が止まっていた場合には自動的に復活させてあげる
+				suspensionState: i.suspensionState === 'autoSuspendedForNotResponding' ? 'none' : undefined,
 			});
 
 			this.fetchInstanceMetadataService.fetchInstanceMetadata(i);
diff --git a/packages/backend/src/server/api/ApiServerService.ts b/packages/backend/src/server/api/ApiServerService.ts
index e99244cdd0..4a5935f930 100644
--- a/packages/backend/src/server/api/ApiServerService.ts
+++ b/packages/backend/src/server/api/ApiServerService.ts
@@ -137,7 +137,7 @@ export class ApiServerService {
 			const instances = await this.instancesRepository.find({
 				select: ['host'],
 				where: {
-					isSuspended: false,
+					suspensionState: 'none',
 				},
 			});
 
diff --git a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts
index 0bcdc2a4b8..fed7bfbbde 100644
--- a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts
+++ b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts
@@ -46,12 +46,19 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				throw new Error('instance not found');
 			}
 
+			const isSuspendedBefore = instance.suspensionState !== 'none';
+			let suspensionState: undefined | 'manuallySuspended' | 'none';
+
+			if (ps.isSuspended != null && isSuspendedBefore !== ps.isSuspended) {
+				suspensionState = ps.isSuspended ? 'manuallySuspended' : 'none';
+			}
+
 			await this.federatedInstanceService.update(instance.id, {
-				isSuspended: ps.isSuspended,
+				suspensionState,
 				moderationNote: ps.moderationNote,
 			});
 
-			if (ps.isSuspended != null && instance.isSuspended !== ps.isSuspended) {
+			if (ps.isSuspended != null && isSuspendedBefore !== ps.isSuspended) {
 				if (ps.isSuspended) {
 					this.moderationLogService.log(me, 'suspendRemoteInstance', {
 						id: instance.id,
diff --git a/packages/frontend/src/pages/admin/federation.vue b/packages/frontend/src/pages/admin/federation.vue
index de27e1f67a..0aaa398584 100644
--- a/packages/frontend/src/pages/admin/federation.vue
+++ b/packages/frontend/src/pages/admin/federation.vue
@@ -58,6 +58,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
+import * as Misskey from 'misskey-js';
 import { computed, ref } from 'vue';
 import XHeader from './_header_.vue';
 import MkInput from '@/components/MkInput.vue';
@@ -90,8 +91,17 @@ const pagination = {
 	})),
 };
 
-function getStatus(instance) {
-	if (instance.isSuspended) return 'Suspended';
+function getStatus(instance: Misskey.entities.FederationInstance) {
+	switch (instance.suspensionState) {
+		case 'manuallySuspended':
+			return 'Manually Suspended';
+		case 'goneSuspended':
+			return 'Automatically Suspended (Gone)';
+		case 'autoSuspendedForNotResponding':
+			return 'Automatically Suspended (Not Responding)';
+		case 'none':
+			break;
+	}
 	if (instance.isBlocked) return 'Blocked';
 	if (instance.isSilenced) return 'Silenced';
 	if (instance.isNotResponding) return 'Error';
diff --git a/packages/frontend/src/pages/instance-info.vue b/packages/frontend/src/pages/instance-info.vue
index cb7fe2866c..26797ba85e 100644
--- a/packages/frontend/src/pages/instance-info.vue
+++ b/packages/frontend/src/pages/instance-info.vue
@@ -35,7 +35,16 @@ SPDX-License-Identifier: AGPL-3.0-only
 				<FormSection v-if="iAmModerator">
 					<template #label>Moderation</template>
 					<div class="_gaps_s">
-						<MkSwitch v-model="suspended" :disabled="!instance" @update:modelValue="toggleSuspend">{{ i18n.ts.stopActivityDelivery }}</MkSwitch>
+						<MkKeyValue>
+							<template #key>
+								{{ i18n.ts._delivery.status }}
+							</template>
+							<template #value>
+								{{ i18n.ts._delivery._type[suspensionState] }}
+							</template>
+						</MkKeyValue>
+						<MkButton v-if="suspensionState === 'none'" :disabled="!instance" danger @click="stopDelivery">{{ i18n.ts._delivery.stop }}</MkButton>
+						<MkButton v-if="suspensionState !== 'none'" :disabled="!instance" @click="resumeDelivery">{{ i18n.ts._delivery.resume }}</MkButton>
 						<MkSwitch v-model="isBlocked" :disabled="!meta || !instance" @update:modelValue="toggleBlock">{{ i18n.ts.blockThisInstance }}</MkSwitch>
 						<MkSwitch v-model="isSilenced" :disabled="!meta || !instance" @update:modelValue="toggleSilenced">{{ i18n.ts.silenceThisInstance }}</MkSwitch>
 						<MkButton @click="refreshMetadata"><i class="ti ti-refresh"></i> Refresh metadata</MkButton>
@@ -155,7 +164,7 @@ const tab = ref('overview');
 const chartSrc = ref('instance-requests');
 const meta = ref<Misskey.entities.AdminMetaResponse | null>(null);
 const instance = ref<Misskey.entities.FederationInstance | null>(null);
-const suspended = ref(false);
+const suspensionState = ref<'none' | 'manuallySuspended' | 'goneSuspended' | 'autoSuspendedForNotResponding'>('none');
 const isBlocked = ref(false);
 const isSilenced = ref(false);
 const faviconUrl = ref<string | null>(null);
@@ -183,7 +192,7 @@ async function fetch(): Promise<void> {
 	instance.value = await misskeyApi('federation/show-instance', {
 		host: props.host,
 	});
-	suspended.value = instance.value?.isSuspended ?? false;
+	suspensionState.value = instance.value?.suspensionState ?? 'none';
 	isBlocked.value = instance.value?.isBlocked ?? false;
 	isSilenced.value = instance.value?.isSilenced ?? false;
 	faviconUrl.value = getProxiedImageUrlNullable(instance.value?.faviconUrl, 'preview') ?? getProxiedImageUrlNullable(instance.value?.iconUrl, 'preview');
@@ -209,11 +218,21 @@ async function toggleSilenced(): Promise<void> {
 	});
 }
 
-async function toggleSuspend(): Promise<void> {
+async function stopDelivery(): Promise<void> {
 	if (!instance.value) throw new Error('No instance?');
+	suspensionState.value = 'manuallySuspended';
 	await misskeyApi('admin/federation/update-instance', {
 		host: instance.value.host,
-		isSuspended: suspended.value,
+		isSuspended: true,
+	});
+}
+
+async function resumeDelivery(): Promise<void> {
+	if (!instance.value) throw new Error('No instance?');
+	suspensionState.value = 'none';
+	await misskeyApi('admin/federation/update-instance', {
+		host: instance.value.host,
+		isSuspended: false,
 	});
 }
 
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 302587ccfa..5bd68af010 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -4475,6 +4475,8 @@ export type components = {
       followersCount: number;
       isNotResponding: boolean;
       isSuspended: boolean;
+      /** @enum {string} */
+      suspensionState: 'none' | 'manuallySuspended' | 'goneSuspended' | 'autoSuspendedForNotResponding';
       isBlocked: boolean;
       /** @example misskey */
       softwareName: string | null;

From e0b47999faf2536f7998e8ddf3558998b31aef82 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Thu, 23 May 2024 17:29:59 +0900
Subject: [PATCH 145/191] =?UTF-8?q?fix(backend):=20`read:admin:show-user`?=
 =?UTF-8?q?=20=E3=81=A8=20`read:admin:show-users`=20=E3=82=92=E7=B5=B1?=
 =?UTF-8?q?=E5=90=88=20(#13798)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(frontend): 同じdisplayNameの権限があるのを修正

* read:admin:show-user と read:admin:show-users を統合

* Update Changelog
---
 CHANGELOG.md                                                  | 1 +
 locales/index.d.ts                                            | 4 ----
 locales/ja-JP.yml                                             | 1 -
 packages/backend/src/server/api/endpoints/admin/show-users.ts | 2 +-
 packages/misskey-js/etc/misskey-js.api.md                     | 2 +-
 packages/misskey-js/src/autogen/apiClientJSDoc.ts             | 2 +-
 packages/misskey-js/src/autogen/types.ts                      | 4 ++--
 packages/misskey-js/src/consts.ts                             | 1 -
 8 files changed, 6 insertions(+), 11 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 21bb3b2e8e..681903a1f2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
 ### Note
 - コントロールパネル内にあるサマリープロキシの設定個所がセキュリティから全般へ変更となります。
 - 悪意のある第三者がリモートユーザーになりすましたアクティビティを受け取れてしまう問題を修正しました。詳しくは[GitHub security advisory](https://github.com/misskey-dev/misskey/security/advisories/GHSA-2vxv-pv3m-3wvj)をご覧ください。
+- 管理者向け権限 `read:admin:show-users` は `read:admin:show-user` に統合されました。必要に応じてAPIトークンを再発行してください。
 
 ### General
 - Enhance: URLプレビューの有効化・無効化を設定できるように #13569
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 991ec1ac1d..18d8eee18f 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -7935,10 +7935,6 @@ export interface Locale extends ILocale {
          * ユーザーのプライベートな情報を見る
          */
         "read:admin:show-user": string;
-        /**
-         * ユーザーのプライベートな情報を見る
-         */
-        "read:admin:show-users": string;
         /**
          * ユーザーを凍結する
          */
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index d7635acc2e..8b1738aebe 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -2085,7 +2085,6 @@ _permissions:
   "read:admin:server-info": "サーバーの情報を見る"
   "read:admin:show-moderation-log": "モデレーションログを見る"
   "read:admin:show-user": "ユーザーのプライベートな情報を見る"
-  "read:admin:show-users": "ユーザーのプライベートな情報を見る"
   "write:admin:suspend-user": "ユーザーを凍結する"
   "write:admin:unset-user-avatar": "ユーザーのアバターを削除する"
   "write:admin:unset-user-banner": "ユーザーのバーナーを削除する"
diff --git a/packages/backend/src/server/api/endpoints/admin/show-users.ts b/packages/backend/src/server/api/endpoints/admin/show-users.ts
index 424212ba24..2fef9abbf9 100644
--- a/packages/backend/src/server/api/endpoints/admin/show-users.ts
+++ b/packages/backend/src/server/api/endpoints/admin/show-users.ts
@@ -16,7 +16,7 @@ export const meta = {
 
 	requireCredential: true,
 	requireModerator: true,
-	kind: 'read:admin:show-users',
+	kind: 'read:admin:show-user',
 
 	res: {
 		type: 'array',
diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md
index 9720b04e39..9cdb61da87 100644
--- a/packages/misskey-js/etc/misskey-js.api.md
+++ b/packages/misskey-js/etc/misskey-js.api.md
@@ -2626,7 +2626,7 @@ type PagesUpdateRequest = operations['pages___update']['requestBody']['content']
 function parse(acct: string): Acct;
 
 // @public (undocumented)
-export const permissions: readonly ["read:account", "write:account", "read:blocks", "write:blocks", "read:drive", "write:drive", "read:favorites", "write:favorites", "read:following", "write:following", "read:messaging", "write:messaging", "read:mutes", "write:mutes", "write:notes", "read:notifications", "write:notifications", "read:reactions", "write:reactions", "write:votes", "read:pages", "write:pages", "write:page-likes", "read:page-likes", "read:user-groups", "write:user-groups", "read:channels", "write:channels", "read:gallery", "write:gallery", "read:gallery-likes", "write:gallery-likes", "read:flash", "write:flash", "read:flash-likes", "write:flash-likes", "read:admin:abuse-user-reports", "write:admin:delete-account", "write:admin:delete-all-files-of-a-user", "read:admin:index-stats", "read:admin:table-stats", "read:admin:user-ips", "read:admin:meta", "write:admin:reset-password", "write:admin:resolve-abuse-user-report", "write:admin:send-email", "read:admin:server-info", "read:admin:show-moderation-log", "read:admin:show-user", "read:admin:show-users", "write:admin:suspend-user", "write:admin:unset-user-avatar", "write:admin:unset-user-banner", "write:admin:unsuspend-user", "write:admin:meta", "write:admin:user-note", "write:admin:roles", "read:admin:roles", "write:admin:relays", "read:admin:relays", "write:admin:invite-codes", "read:admin:invite-codes", "write:admin:announcements", "read:admin:announcements", "write:admin:avatar-decorations", "read:admin:avatar-decorations", "write:admin:federation", "write:admin:account", "read:admin:account", "write:admin:emoji", "read:admin:emoji", "write:admin:queue", "read:admin:queue", "write:admin:promo", "write:admin:drive", "read:admin:drive", "write:admin:ad", "read:admin:ad", "write:invite-codes", "read:invite-codes", "write:clip-favorite", "read:clip-favorite", "read:federation", "write:report-abuse"];
+export const permissions: readonly ["read:account", "write:account", "read:blocks", "write:blocks", "read:drive", "write:drive", "read:favorites", "write:favorites", "read:following", "write:following", "read:messaging", "write:messaging", "read:mutes", "write:mutes", "write:notes", "read:notifications", "write:notifications", "read:reactions", "write:reactions", "write:votes", "read:pages", "write:pages", "write:page-likes", "read:page-likes", "read:user-groups", "write:user-groups", "read:channels", "write:channels", "read:gallery", "write:gallery", "read:gallery-likes", "write:gallery-likes", "read:flash", "write:flash", "read:flash-likes", "write:flash-likes", "read:admin:abuse-user-reports", "write:admin:delete-account", "write:admin:delete-all-files-of-a-user", "read:admin:index-stats", "read:admin:table-stats", "read:admin:user-ips", "read:admin:meta", "write:admin:reset-password", "write:admin:resolve-abuse-user-report", "write:admin:send-email", "read:admin:server-info", "read:admin:show-moderation-log", "read:admin:show-user", "write:admin:suspend-user", "write:admin:unset-user-avatar", "write:admin:unset-user-banner", "write:admin:unsuspend-user", "write:admin:meta", "write:admin:user-note", "write:admin:roles", "read:admin:roles", "write:admin:relays", "read:admin:relays", "write:admin:invite-codes", "read:admin:invite-codes", "write:admin:announcements", "read:admin:announcements", "write:admin:avatar-decorations", "read:admin:avatar-decorations", "write:admin:federation", "write:admin:account", "read:admin:account", "write:admin:emoji", "read:admin:emoji", "write:admin:queue", "read:admin:queue", "write:admin:promo", "write:admin:drive", "read:admin:drive", "write:admin:ad", "read:admin:ad", "write:invite-codes", "read:invite-codes", "write:clip-favorite", "read:clip-favorite", "read:federation", "write:report-abuse"];
 
 // @public (undocumented)
 type PingResponse = operations['ping']['responses']['200']['content']['application/json'];
diff --git a/packages/misskey-js/src/autogen/apiClientJSDoc.ts b/packages/misskey-js/src/autogen/apiClientJSDoc.ts
index 5309350100..729107a78d 100644
--- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts
+++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts
@@ -678,7 +678,7 @@ declare module '../api.js' {
     /**
      * No description provided.
      * 
-     * **Credential required**: *Yes* / **Permission**: *read:admin:show-users*
+     * **Credential required**: *Yes* / **Permission**: *read:admin:show-user*
      */
     request<E extends 'admin/show-users', P extends Endpoints[E]['req']>(
       endpoint: E,
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 5bd68af010..1e9c190ca5 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -567,7 +567,7 @@ export type paths = {
      * admin/show-users
      * @description No description provided.
      *
-     * **Credential required**: *Yes* / **Permission**: *read:admin:show-users*
+     * **Credential required**: *Yes* / **Permission**: *read:admin:show-user*
      */
     post: operations['admin___show-users'];
   };
@@ -8647,7 +8647,7 @@ export type operations = {
    * admin/show-users
    * @description No description provided.
    *
-   * **Credential required**: *Yes* / **Permission**: *read:admin:show-users*
+   * **Credential required**: *Yes* / **Permission**: *read:admin:show-user*
    */
   'admin___show-users': {
     requestBody: {
diff --git a/packages/misskey-js/src/consts.ts b/packages/misskey-js/src/consts.ts
index b690621e98..fd6ef4d68d 100644
--- a/packages/misskey-js/src/consts.ts
+++ b/packages/misskey-js/src/consts.ts
@@ -58,7 +58,6 @@ export const permissions = [
 	'read:admin:server-info',
 	'read:admin:show-moderation-log',
 	'read:admin:show-user',
-	'read:admin:show-users',
 	'write:admin:suspend-user',
 	'write:admin:unset-user-avatar',
 	'write:admin:unset-user-banner',

From 3ffbf6296f44c6f8837f0b8533a3b60b64403bf9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 27 May 2024 17:15:11 +0900
Subject: [PATCH 146/191] =?UTF-8?q?feat:=20=E5=80=8B=E5=88=A5=E3=81=AE?=
 =?UTF-8?q?=E3=81=8A=E7=9F=A5=E3=82=89=E3=81=9B=E3=81=AB=E3=83=AA=E3=83=B3?=
 =?UTF-8?q?=E3=82=AF=E3=81=A7=E9=A3=9B=E3=81=B9=E3=82=8B=E3=82=88=E3=81=86?=
 =?UTF-8?q?=E3=81=AB=20(#13885)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* feat(announcement): 個別のお知らせにリンクで飛べるように (MisskeyIO#639)

(cherry picked from commit f6bf7f992a78e54d86a4701dbd1e4fda7ef4eb27)

* fix

Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com>

* fix

Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com>

* 一覧ページではお知らせpanel全体を押せるように

* お知らせバーは個別ページに飛ばすように

* Update Changelog

* spdx

* attempt to fox test

* remove unnecessary thong

* `announcement` → `announcements/show`

* リンクを押せる場所をタイトルと日付部分のみに変更

---------

Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com>
---
 CHANGELOG.md                                  |   2 +
 .../backend/src/core/AnnouncementService.ts   |  49 +++---
 packages/backend/src/core/CoreModule.ts       |   6 +
 .../entities/AnnouncementEntityService.ts     |  71 +++++++++
 .../backend/src/server/api/EndpointsModule.ts |   4 +
 packages/backend/src/server/api/endpoints.ts  |   2 +
 .../src/server/api/endpoints/announcements.ts |  11 +-
 .../api/endpoints/announcements/show.ts       |  54 +++++++
 .../backend/test/unit/AnnouncementService.ts  |   2 +
 packages/frontend/src/pages/announcement.vue  | 142 ++++++++++++++++++
 packages/frontend/src/pages/announcements.vue |  25 +--
 packages/frontend/src/router/definition.ts    |   3 +
 .../src/ui/_common_/announcements.vue         |   2 +-
 packages/misskey-js/etc/misskey-js.api.md     |   8 +
 .../misskey-js/src/autogen/apiClientJSDoc.ts  |  11 ++
 packages/misskey-js/src/autogen/endpoint.ts   |   3 +
 packages/misskey-js/src/autogen/entities.ts   |   2 +
 packages/misskey-js/src/autogen/types.ts      |  63 ++++++++
 18 files changed, 415 insertions(+), 45 deletions(-)
 create mode 100644 packages/backend/src/core/entities/AnnouncementEntityService.ts
 create mode 100644 packages/backend/src/server/api/endpoints/announcements/show.ts
 create mode 100644 packages/frontend/src/pages/announcement.vue

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 681903a1f2..7e23fa8f72 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,6 +25,8 @@
 
 ### Client
 - Feat: アップロードするファイルの名前をランダム文字列にできるように
+- Feat: 個別のお知らせにリンクで飛べるように  
+  (Cherry-picked from https://github.com/MisskeyIO/misskey)
 - Enhance: 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるように
 - Enhance: 広告がMisskeyと同一ドメインの場合はRouterで遷移するように
 - Enhance: リアクション・いいねの総数を表示するように
diff --git a/packages/backend/src/core/AnnouncementService.ts b/packages/backend/src/core/AnnouncementService.ts
index b298a70929..9b60df2cae 100644
--- a/packages/backend/src/core/AnnouncementService.ts
+++ b/packages/backend/src/core/AnnouncementService.ts
@@ -4,13 +4,14 @@
  */
 
 import { Inject, Injectable } from '@nestjs/common';
-import { Brackets } from 'typeorm';
+import { Brackets, EntityNotFoundError } from 'typeorm';
 import { DI } from '@/di-symbols.js';
 import type { MiUser } from '@/models/User.js';
 import type { AnnouncementReadsRepository, AnnouncementsRepository, MiAnnouncement, MiAnnouncementRead, UsersRepository } from '@/models/_.js';
 import { bindThis } from '@/decorators.js';
 import { Packed } from '@/misc/json-schema.js';
 import { IdService } from '@/core/IdService.js';
+import { AnnouncementEntityService } from '@/core/entities/AnnouncementEntityService.js';
 import { GlobalEventService } from '@/core/GlobalEventService.js';
 import { ModerationLogService } from '@/core/ModerationLogService.js';
 
@@ -29,6 +30,7 @@ export class AnnouncementService {
 		private idService: IdService,
 		private globalEventService: GlobalEventService,
 		private moderationLogService: ModerationLogService,
+		private announcementEntityService: AnnouncementEntityService,
 	) {
 	}
 
@@ -79,7 +81,7 @@ export class AnnouncementService {
 			userId: values.userId,
 		}).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0]));
 
-		const packed = (await this.packMany([announcement]))[0];
+		const packed = await this.announcementEntityService.pack(announcement);
 
 		if (values.userId) {
 			this.globalEventService.publishMainStream(values.userId, 'announcementCreated', {
@@ -177,6 +179,24 @@ export class AnnouncementService {
 		}
 	}
 
+	@bindThis
+	public async getAnnouncement(announcementId: MiAnnouncement['id'], me: MiUser | null): Promise<Packed<'Announcement'>> {
+		const announcement = await this.announcementsRepository.findOneByOrFail({ id: announcementId });
+		if (me) {
+			if (announcement.userId && announcement.userId !== me.id) {
+				throw new EntityNotFoundError(this.announcementsRepository.metadata.target, { id: announcementId });
+			}
+
+			const read = await this.announcementReadsRepository.findOneBy({
+				announcementId: announcement.id,
+				userId: me.id,
+			});
+			return this.announcementEntityService.pack({ ...announcement, isRead: read !== null }, me);
+		} else {
+			return this.announcementEntityService.pack(announcement, null);
+		}
+	}
+
 	@bindThis
 	public async read(user: MiUser, announcementId: MiAnnouncement['id']): Promise<void> {
 		try {
@@ -193,29 +213,4 @@ export class AnnouncementService {
 			this.globalEventService.publishMainStream(user.id, 'readAllAnnouncements');
 		}
 	}
-
-	@bindThis
-	public async packMany(
-		announcements: MiAnnouncement[],
-		me?: { id: MiUser['id'] } | null | undefined,
-		options?: {
-			reads?: MiAnnouncementRead[];
-		},
-	): Promise<Packed<'Announcement'>[]> {
-		const reads = me ? (options?.reads ?? await this.getReads(me.id)) : [];
-		return announcements.map(announcement => ({
-			id: announcement.id,
-			createdAt: this.idService.parse(announcement.id).date.toISOString(),
-			updatedAt: announcement.updatedAt?.toISOString() ?? null,
-			text: announcement.text,
-			title: announcement.title,
-			imageUrl: announcement.imageUrl,
-			icon: announcement.icon,
-			display: announcement.display,
-			needConfirmationToRead: announcement.needConfirmationToRead,
-			silence: announcement.silence,
-			forYou: announcement.userId === me?.id,
-			isRead: reads.some(read => read.announcementId === announcement.id),
-		}));
-	}
 }
diff --git a/packages/backend/src/core/CoreModule.ts b/packages/backend/src/core/CoreModule.ts
index 5953155872..be80df6f1c 100644
--- a/packages/backend/src/core/CoreModule.ts
+++ b/packages/backend/src/core/CoreModule.ts
@@ -84,6 +84,7 @@ import ApRequestChart from './chart/charts/ap-request.js';
 import { ChartManagementService } from './chart/ChartManagementService.js';
 
 import { AbuseUserReportEntityService } from './entities/AbuseUserReportEntityService.js';
+import { AnnouncementEntityService } from './entities/AnnouncementEntityService.js';
 import { AntennaEntityService } from './entities/AntennaEntityService.js';
 import { AppEntityService } from './entities/AppEntityService.js';
 import { AuthSessionEntityService } from './entities/AuthSessionEntityService.js';
@@ -223,6 +224,7 @@ const $ApRequestChart: Provider = { provide: 'ApRequestChart', useExisting: ApRe
 const $ChartManagementService: Provider = { provide: 'ChartManagementService', useExisting: ChartManagementService };
 
 const $AbuseUserReportEntityService: Provider = { provide: 'AbuseUserReportEntityService', useExisting: AbuseUserReportEntityService };
+const $AnnouncementEntityService: Provider = { provide: 'AnnouncementEntityService', useExisting: AnnouncementEntityService };
 const $AntennaEntityService: Provider = { provide: 'AntennaEntityService', useExisting: AntennaEntityService };
 const $AppEntityService: Provider = { provide: 'AppEntityService', useExisting: AppEntityService };
 const $AuthSessionEntityService: Provider = { provide: 'AuthSessionEntityService', useExisting: AuthSessionEntityService };
@@ -363,6 +365,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
 		ChartManagementService,
 
 		AbuseUserReportEntityService,
+		AnnouncementEntityService,
 		AntennaEntityService,
 		AppEntityService,
 		AuthSessionEntityService,
@@ -499,6 +502,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
 		$ChartManagementService,
 
 		$AbuseUserReportEntityService,
+		$AnnouncementEntityService,
 		$AntennaEntityService,
 		$AppEntityService,
 		$AuthSessionEntityService,
@@ -635,6 +639,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
 		ChartManagementService,
 
 		AbuseUserReportEntityService,
+		AnnouncementEntityService,
 		AntennaEntityService,
 		AppEntityService,
 		AuthSessionEntityService,
@@ -770,6 +775,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
 		$ChartManagementService,
 
 		$AbuseUserReportEntityService,
+		$AnnouncementEntityService,
 		$AntennaEntityService,
 		$AppEntityService,
 		$AuthSessionEntityService,
diff --git a/packages/backend/src/core/entities/AnnouncementEntityService.ts b/packages/backend/src/core/entities/AnnouncementEntityService.ts
new file mode 100644
index 0000000000..90b04d0229
--- /dev/null
+++ b/packages/backend/src/core/entities/AnnouncementEntityService.ts
@@ -0,0 +1,71 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Inject, Injectable } from '@nestjs/common';
+import { DI } from '@/di-symbols.js';
+import type { AnnouncementsRepository, AnnouncementReadsRepository, MiAnnouncement, MiUser } from '@/models/_.js';
+import type { Packed } from '@/misc/json-schema.js';
+import { bindThis } from '@/decorators.js';
+import { IdService } from '@/core/IdService.js';
+
+@Injectable()
+export class AnnouncementEntityService {
+	constructor(
+		@Inject(DI.announcementsRepository)
+		private announcementsRepository: AnnouncementsRepository,
+
+		@Inject(DI.announcementReadsRepository)
+		private announcementReadsRepository: AnnouncementReadsRepository,
+
+		private idService: IdService,
+	) {
+	}
+
+	@bindThis
+	public async pack(
+		src: MiAnnouncement['id'] | MiAnnouncement & { isRead?: boolean | null },
+		me?: { id: MiUser['id'] } | null | undefined,
+	): Promise<Packed<'Announcement'>> {
+		const announcement = typeof src === 'object'
+			? src
+			: await this.announcementsRepository.findOneByOrFail({
+				id: src,
+			}) as MiAnnouncement & { isRead?: boolean | null };
+
+		if (me && announcement.isRead === undefined) {
+			announcement.isRead = await this.announcementReadsRepository
+				.countBy({
+					announcementId: announcement.id,
+					userId: me.id,
+				})
+				.then((count: number) => count > 0);
+		}
+
+		return {
+			id: announcement.id,
+			createdAt: this.idService.parse(announcement.id).date.toISOString(),
+			updatedAt: announcement.updatedAt?.toISOString() ?? null,
+			title: announcement.title,
+			text: announcement.text,
+			imageUrl: announcement.imageUrl,
+			icon: announcement.icon,
+			display: announcement.display,
+			forYou: announcement.userId === me?.id,
+			needConfirmationToRead: announcement.needConfirmationToRead,
+			silence: announcement.silence,
+			isRead: announcement.isRead !== null ? announcement.isRead : undefined,
+		};
+	}
+
+	@bindThis
+	public async packMany(
+		announcements: (MiAnnouncement['id'] | MiAnnouncement & { isRead?: boolean | null } | MiAnnouncement)[],
+		me?: { id: MiUser['id'] } | null | undefined,
+	) : Promise<Packed<'Announcement'>[]> {
+		return (await Promise.allSettled(announcements.map(x => this.pack(x, me))))
+			.filter(result => result.status === 'fulfilled')
+			.map(result => (result as PromiseFulfilledResult<Packed<'Announcement'>>).value);
+	}
+}
diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts
index 88d3999eb0..c645f4bcc6 100644
--- a/packages/backend/src/server/api/EndpointsModule.ts
+++ b/packages/backend/src/server/api/EndpointsModule.ts
@@ -83,6 +83,7 @@ import * as ep___admin_roles_unassign from './endpoints/admin/roles/unassign.js'
 import * as ep___admin_roles_updateDefaultPolicies from './endpoints/admin/roles/update-default-policies.js';
 import * as ep___admin_roles_users from './endpoints/admin/roles/users.js';
 import * as ep___announcements from './endpoints/announcements.js';
+import * as ep___announcements_show from './endpoints/announcements/show.js';
 import * as ep___antennas_create from './endpoints/antennas/create.js';
 import * as ep___antennas_delete from './endpoints/antennas/delete.js';
 import * as ep___antennas_list from './endpoints/antennas/list.js';
@@ -455,6 +456,7 @@ const $admin_roles_unassign: Provider = { provide: 'ep:admin/roles/unassign', us
 const $admin_roles_updateDefaultPolicies: Provider = { provide: 'ep:admin/roles/update-default-policies', useClass: ep___admin_roles_updateDefaultPolicies.default };
 const $admin_roles_users: Provider = { provide: 'ep:admin/roles/users', useClass: ep___admin_roles_users.default };
 const $announcements: Provider = { provide: 'ep:announcements', useClass: ep___announcements.default };
+const $announcements_show: Provider = { provide: 'ep:announcements/show', useClass: ep___announcements_show.default };
 const $antennas_create: Provider = { provide: 'ep:antennas/create', useClass: ep___antennas_create.default };
 const $antennas_delete: Provider = { provide: 'ep:antennas/delete', useClass: ep___antennas_delete.default };
 const $antennas_list: Provider = { provide: 'ep:antennas/list', useClass: ep___antennas_list.default };
@@ -831,6 +833,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
 		$admin_roles_updateDefaultPolicies,
 		$admin_roles_users,
 		$announcements,
+		$announcements_show,
 		$antennas_create,
 		$antennas_delete,
 		$antennas_list,
@@ -1201,6 +1204,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
 		$admin_roles_updateDefaultPolicies,
 		$admin_roles_users,
 		$announcements,
+		$announcements_show,
 		$antennas_create,
 		$antennas_delete,
 		$antennas_list,
diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts
index f7e64a7356..a38c62f35a 100644
--- a/packages/backend/src/server/api/endpoints.ts
+++ b/packages/backend/src/server/api/endpoints.ts
@@ -83,6 +83,7 @@ import * as ep___admin_roles_unassign from './endpoints/admin/roles/unassign.js'
 import * as ep___admin_roles_updateDefaultPolicies from './endpoints/admin/roles/update-default-policies.js';
 import * as ep___admin_roles_users from './endpoints/admin/roles/users.js';
 import * as ep___announcements from './endpoints/announcements.js';
+import * as ep___announcements_show from './endpoints/announcements/show.js';
 import * as ep___antennas_create from './endpoints/antennas/create.js';
 import * as ep___antennas_delete from './endpoints/antennas/delete.js';
 import * as ep___antennas_list from './endpoints/antennas/list.js';
@@ -453,6 +454,7 @@ const eps = [
 	['admin/roles/update-default-policies', ep___admin_roles_updateDefaultPolicies],
 	['admin/roles/users', ep___admin_roles_users],
 	['announcements', ep___announcements],
+	['announcements/show', ep___announcements_show],
 	['antennas/create', ep___antennas_create],
 	['antennas/delete', ep___antennas_delete],
 	['antennas/list', ep___antennas_list],
diff --git a/packages/backend/src/server/api/endpoints/announcements.ts b/packages/backend/src/server/api/endpoints/announcements.ts
index 3b12f5b62c..ff8dd73605 100644
--- a/packages/backend/src/server/api/endpoints/announcements.ts
+++ b/packages/backend/src/server/api/endpoints/announcements.ts
@@ -7,9 +7,9 @@ import { Inject, Injectable } from '@nestjs/common';
 import { Brackets } from 'typeorm';
 import { Endpoint } from '@/server/api/endpoint-base.js';
 import { QueryService } from '@/core/QueryService.js';
-import { AnnouncementService } from '@/core/AnnouncementService.js';
+import { AnnouncementEntityService } from '@/core/entities/AnnouncementEntityService.js';
 import { DI } from '@/di-symbols.js';
-import type { AnnouncementReadsRepository, AnnouncementsRepository } from '@/models/_.js';
+import type { AnnouncementsRepository } from '@/models/_.js';
 
 export const meta = {
 	tags: ['meta'],
@@ -44,11 +44,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 		@Inject(DI.announcementsRepository)
 		private announcementsRepository: AnnouncementsRepository,
 
-		@Inject(DI.announcementReadsRepository)
-		private announcementReadsRepository: AnnouncementReadsRepository,
-
 		private queryService: QueryService,
-		private announcementService: AnnouncementService,
+		private announcementEntityService: AnnouncementEntityService,
 	) {
 		super(meta, paramDef, async (ps, me) => {
 			const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId)
@@ -60,7 +57,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 
 			const announcements = await query.limit(ps.limit).getMany();
 
-			return this.announcementService.packMany(announcements, me);
+			return this.announcementEntityService.packMany(announcements, me);
 		});
 	}
 }
diff --git a/packages/backend/src/server/api/endpoints/announcements/show.ts b/packages/backend/src/server/api/endpoints/announcements/show.ts
new file mode 100644
index 0000000000..6312a0a54c
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/announcements/show.ts
@@ -0,0 +1,54 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Injectable } from '@nestjs/common';
+import { EntityNotFoundError } from 'typeorm';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { AnnouncementService } from '@/core/AnnouncementService.js';
+import { ApiError } from '../../error.js';
+
+export const meta = {
+	tags: ['meta'],
+
+	requireCredential: false,
+
+	res: {
+		type: 'object',
+		optional: false, nullable: false,
+		ref: 'Announcement',
+	},
+
+	errors: {
+		noSuchAnnouncement: {
+			message: 'No such announcement.',
+			code: 'NO_SUCH_ANNOUNCEMENT',
+			id: 'b57b5e1d-4f49-404a-9edb-46b00268f121',
+		},
+	},
+} as const;
+
+export const paramDef = {
+	type: 'object',
+	properties: {
+		announcementId: { type: 'string', format: 'misskey:id' },
+	},
+	required: ['announcementId'],
+} as const;
+
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
+	constructor(
+		private announcementService: AnnouncementService,
+	) {
+		super(meta, paramDef, async (ps, me) => {
+			try {
+				return await this.announcementService.getAnnouncement(ps.announcementId, me);
+			} catch (err) {
+				if (err instanceof EntityNotFoundError) throw new ApiError(meta.errors.noSuchAnnouncement);
+				throw err;
+			}
+		});
+	}
+}
diff --git a/packages/backend/test/unit/AnnouncementService.ts b/packages/backend/test/unit/AnnouncementService.ts
index aa082ff2f2..81da0fac31 100644
--- a/packages/backend/test/unit/AnnouncementService.ts
+++ b/packages/backend/test/unit/AnnouncementService.ts
@@ -10,6 +10,7 @@ import { ModuleMocker } from 'jest-mock';
 import { Test } from '@nestjs/testing';
 import { GlobalModule } from '@/GlobalModule.js';
 import { AnnouncementService } from '@/core/AnnouncementService.js';
+import { AnnouncementEntityService } from '@/core/entities/AnnouncementEntityService.js';
 import type {
 	AnnouncementReadsRepository,
 	AnnouncementsRepository,
@@ -67,6 +68,7 @@ describe('AnnouncementService', () => {
 			],
 			providers: [
 				AnnouncementService,
+				AnnouncementEntityService,
 				CacheService,
 				IdService,
 			],
diff --git a/packages/frontend/src/pages/announcement.vue b/packages/frontend/src/pages/announcement.vue
new file mode 100644
index 0000000000..85ae9062d4
--- /dev/null
+++ b/packages/frontend/src/pages/announcement.vue
@@ -0,0 +1,142 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<MkStickyContainer>
+	<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
+	<MkSpacer :contentMax="800">
+		<Transition
+			:enterActiveClass="defaultStore.state.animation ? $style.fadeEnterActive : ''"
+			:leaveActiveClass="defaultStore.state.animation ? $style.fadeLeaveActive : ''"
+			:enterFromClass="defaultStore.state.animation ? $style.fadeEnterFrom : ''"
+			:leaveToClass="defaultStore.state.animation ? $style.fadeLeaveTo : ''"
+			mode="out-in"
+		>
+			<div v-if="announcement" :key="announcement.id" class="_panel" :class="$style.announcement">
+				<div v-if="announcement.forYou" :class="$style.forYou"><i class="ti ti-pin"></i> {{ i18n.ts.forYou }}</div>
+				<div :class="$style.header">
+					<span v-if="$i && !announcement.silence && !announcement.isRead" style="margin-right: 0.5em;">🆕</span>
+					<span style="margin-right: 0.5em;">
+						<i v-if="announcement.icon === 'info'" class="ti ti-info-circle"></i>
+						<i v-else-if="announcement.icon === 'warning'" class="ti ti-alert-triangle" style="color: var(--warn);"></i>
+						<i v-else-if="announcement.icon === 'error'" class="ti ti-circle-x" style="color: var(--error);"></i>
+						<i v-else-if="announcement.icon === 'success'" class="ti ti-check" style="color: var(--success);"></i>
+					</span>
+					<Mfm :text="announcement.title"/>
+				</div>
+				<div :class="$style.content">
+					<Mfm :text="announcement.text"/>
+					<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/>
+					<div style="margin-top: 8px; opacity: 0.7; font-size: 85%;">
+						{{ i18n.ts.createdAt }}: <MkTime :time="announcement.createdAt" mode="detail"/>
+					</div>
+					<div v-if="announcement.updatedAt" style="opacity: 0.7; font-size: 85%;">
+						{{ i18n.ts.updatedAt }}: <MkTime :time="announcement.updatedAt" mode="detail"/>
+					</div>
+				</div>
+				<div v-if="$i && !announcement.silence && !announcement.isRead" :class="$style.footer">
+					<MkButton primary @click="read(announcement)"><i class="ti ti-check"></i> {{ i18n.ts.gotIt }}</MkButton>
+				</div>
+			</div>
+			<MkError v-else-if="error" @retry="fetch()"/>
+			<MkLoading v-else/>
+		</Transition>
+	</MkSpacer>
+</MkStickyContainer>
+</template>
+
+<script lang="ts" setup>
+import { ref, computed, watch } from 'vue';
+import * as Misskey from 'misskey-js';
+import MkButton from '@/components/MkButton.vue';
+import * as os from '@/os.js';
+import { misskeyApi } from '@/scripts/misskey-api.js';
+import { i18n } from '@/i18n.js';
+import { definePageMetadata } from '@/scripts/page-metadata.js';
+import { $i, updateAccount } from '@/account.js';
+import { defaultStore } from '@/store.js';
+
+const props = defineProps<{
+	announcementId: string;
+}>();
+
+const announcement = ref<Misskey.entities.Announcement | null>(null);
+const error = ref<any>(null);
+const path = computed(() => props.announcementId);
+
+function fetch() {
+	announcement.value = null;
+	misskeyApi('announcements/show', {
+		announcementId: props.announcementId,
+	}).then(async _announcement => {
+		announcement.value = _announcement;
+	}).catch(err => {
+		error.value = err;
+	});
+}
+
+async function read(target: Misskey.entities.Announcement): Promise<void> {
+	if (target.needConfirmationToRead) {
+		const confirm = await os.confirm({
+			type: 'question',
+			title: i18n.ts._announcement.readConfirmTitle,
+			text: i18n.tsx._announcement.readConfirmText({ title: target.title }),
+		});
+		if (confirm.canceled) return;
+	}
+
+	target.isRead = true;
+	await misskeyApi('i/read-announcement', { announcementId: target.id });
+	if ($i) {
+		updateAccount({
+			unreadAnnouncements: $i.unreadAnnouncements.filter((a: { id: string; }) => a.id !== target.id),
+		});
+	}
+}
+
+watch(() => path.value, fetch, { immediate: true });
+
+const headerActions = computed(() => []);
+
+const headerTabs = computed(() => []);
+
+definePageMetadata(() => ({
+	title: announcement.value ? `${i18n.ts.announcements}: ${announcement.value.title}` : i18n.ts.announcements,
+	icon: 'ti ti-speakerphone',
+}));
+</script>
+
+<style lang="scss" module>
+.announcement {
+	padding: 16px;
+}
+
+.forYou {
+	display: flex;
+	align-items: center;
+	line-height: 24px;
+	font-size: 90%;
+	white-space: pre;
+	color: #d28a3f;
+}
+
+.header {
+	margin-bottom: 16px;
+	font-weight: bold;
+	font-size: 120%;
+}
+
+.content {
+	> img {
+		display: block;
+		max-height: 300px;
+		max-width: 100%;
+	}
+}
+
+.footer {
+	margin-top: 16px;
+}
+</style>
diff --git a/packages/frontend/src/pages/announcements.vue b/packages/frontend/src/pages/announcements.vue
index bcd6eb7c0f..e50b208775 100644
--- a/packages/frontend/src/pages/announcements.vue
+++ b/packages/frontend/src/pages/announcements.vue
@@ -21,14 +21,19 @@ SPDX-License-Identifier: AGPL-3.0-only
 								<i v-else-if="announcement.icon === 'error'" class="ti ti-circle-x" style="color: var(--error);"></i>
 								<i v-else-if="announcement.icon === 'success'" class="ti ti-check" style="color: var(--success);"></i>
 							</span>
-							<span>{{ announcement.title }}</span>
+							<MkA :to="`/announcements/${announcement.id}`"><span>{{ announcement.title }}</span></MkA>
 						</div>
 						<div :class="$style.content">
 							<Mfm :text="announcement.text"/>
 							<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/>
-							<div style="opacity: 0.7; font-size: 85%;">
-								<MkTime :time="announcement.updatedAt ?? announcement.createdAt" mode="detail"/>
-							</div>
+							<MkA :to="`/announcements/${announcement.id}`">
+								<div style="margin-top: 8px; opacity: 0.7; font-size: 85%;">
+									{{ i18n.ts.createdAt }}: <MkTime :time="announcement.createdAt" mode="detail"/>
+								</div>
+								<div v-if="announcement.updatedAt" style="opacity: 0.7; font-size: 85%;">
+									{{ i18n.ts.updatedAt }}: <MkTime :time="announcement.updatedAt" mode="detail"/>
+								</div>
+							</MkA>
 						</div>
 						<div v-if="tab !== 'past' && $i && !announcement.silence && !announcement.isRead" :class="$style.footer">
 							<MkButton primary @click="read(announcement)"><i class="ti ti-check"></i> {{ i18n.ts.gotIt }}</MkButton>
@@ -73,24 +78,24 @@ const paginationEl = ref<InstanceType<typeof MkPagination>>();
 
 const tab = ref('current');
 
-async function read(announcement) {
-	if (announcement.needConfirmationToRead) {
+async function read(target) {
+	if (target.needConfirmationToRead) {
 		const confirm = await os.confirm({
 			type: 'question',
 			title: i18n.ts._announcement.readConfirmTitle,
-			text: i18n.tsx._announcement.readConfirmText({ title: announcement.title }),
+			text: i18n.tsx._announcement.readConfirmText({ title: target.title }),
 		});
 		if (confirm.canceled) return;
 	}
 
 	if (!paginationEl.value) return;
-	paginationEl.value.updateItem(announcement.id, a => {
+	paginationEl.value.updateItem(target.id, a => {
 		a.isRead = true;
 		return a;
 	});
-	misskeyApi('i/read-announcement', { announcementId: announcement.id });
+	misskeyApi('i/read-announcement', { announcementId: target.id });
 	updateAccount({
-		unreadAnnouncements: $i!.unreadAnnouncements.filter(a => a.id !== announcement.id),
+		unreadAnnouncements: $i!.unreadAnnouncements.filter(a => a.id !== target.id),
 	});
 }
 
diff --git a/packages/frontend/src/router/definition.ts b/packages/frontend/src/router/definition.ts
index c5b576f505..c12ae0fa57 100644
--- a/packages/frontend/src/router/definition.ts
+++ b/packages/frontend/src/router/definition.ts
@@ -193,6 +193,9 @@ const routes: RouteDef[] = [{
 }, {
 	path: '/announcements',
 	component: page(() => import('@/pages/announcements.vue')),
+}, {
+	path: '/announcements/:announcementId',
+	component: page(() => import('@/pages/announcement.vue')),
 }, {
 	path: '/about',
 	component: page(() => import('@/pages/about.vue')),
diff --git a/packages/frontend/src/ui/_common_/announcements.vue b/packages/frontend/src/ui/_common_/announcements.vue
index 362c29e6c2..374bc20b54 100644
--- a/packages/frontend/src/ui/_common_/announcements.vue
+++ b/packages/frontend/src/ui/_common_/announcements.vue
@@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 		v-for="announcement in $i.unreadAnnouncements.filter(x => x.display === 'banner')"
 		:key="announcement.id"
 		:class="$style.item"
-		to="/announcements"
+		:to="`/announcements/${announcement.id}`"
 	>
 		<span :class="$style.icon">
 			<i v-if="announcement.icon === 'info'" class="ti ti-info-circle"></i>
diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md
index 9cdb61da87..6ff711cabb 100644
--- a/packages/misskey-js/etc/misskey-js.api.md
+++ b/packages/misskey-js/etc/misskey-js.api.md
@@ -336,6 +336,12 @@ type AnnouncementsRequest = operations['announcements']['requestBody']['content'
 // @public (undocumented)
 type AnnouncementsResponse = operations['announcements']['responses']['200']['content']['application/json'];
 
+// @public (undocumented)
+type AnnouncementsShowRequest = operations['announcements___show']['requestBody']['content']['application/json'];
+
+// @public (undocumented)
+type AnnouncementsShowResponse = operations['announcements___show']['responses']['200']['content']['application/json'];
+
 // @public (undocumented)
 type Antenna = components['schemas']['Antenna'];
 
@@ -1224,6 +1230,8 @@ declare namespace entities {
         AdminRolesUsersResponse,
         AnnouncementsRequest,
         AnnouncementsResponse,
+        AnnouncementsShowRequest,
+        AnnouncementsShowResponse,
         AntennasCreateRequest,
         AntennasCreateResponse,
         AntennasDeleteRequest,
diff --git a/packages/misskey-js/src/autogen/apiClientJSDoc.ts b/packages/misskey-js/src/autogen/apiClientJSDoc.ts
index 729107a78d..181f7274b7 100644
--- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts
+++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts
@@ -851,6 +851,17 @@ declare module '../api.js' {
       credential?: string | null,
     ): Promise<SwitchCaseResponseType<E, P>>;
 
+    /**
+     * No description provided.
+     * 
+     * **Credential required**: *No*
+     */
+    request<E extends 'announcements/show', P extends Endpoints[E]['req']>(
+      endpoint: E,
+      params: P,
+      credential?: string | null,
+    ): Promise<SwitchCaseResponseType<E, P>>;
+
     /**
      * No description provided.
      * 
diff --git a/packages/misskey-js/src/autogen/endpoint.ts b/packages/misskey-js/src/autogen/endpoint.ts
index b0982e1e55..ab3baf1670 100644
--- a/packages/misskey-js/src/autogen/endpoint.ts
+++ b/packages/misskey-js/src/autogen/endpoint.ts
@@ -101,6 +101,8 @@ import type {
 	AdminRolesUsersResponse,
 	AnnouncementsRequest,
 	AnnouncementsResponse,
+	AnnouncementsShowRequest,
+	AnnouncementsShowResponse,
 	AntennasCreateRequest,
 	AntennasCreateResponse,
 	AntennasDeleteRequest,
@@ -631,6 +633,7 @@ export type Endpoints = {
 	'admin/roles/update-default-policies': { req: AdminRolesUpdateDefaultPoliciesRequest; res: EmptyResponse };
 	'admin/roles/users': { req: AdminRolesUsersRequest; res: AdminRolesUsersResponse };
 	'announcements': { req: AnnouncementsRequest; res: AnnouncementsResponse };
+	'announcements/show': { req: AnnouncementsShowRequest; res: AnnouncementsShowResponse };
 	'antennas/create': { req: AntennasCreateRequest; res: AntennasCreateResponse };
 	'antennas/delete': { req: AntennasDeleteRequest; res: EmptyResponse };
 	'antennas/list': { req: EmptyRequest; res: AntennasListResponse };
diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts
index 60bf6659c0..02ca932d8a 100644
--- a/packages/misskey-js/src/autogen/entities.ts
+++ b/packages/misskey-js/src/autogen/entities.ts
@@ -104,6 +104,8 @@ export type AdminRolesUsersRequest = operations['admin___roles___users']['reques
 export type AdminRolesUsersResponse = operations['admin___roles___users']['responses']['200']['content']['application/json'];
 export type AnnouncementsRequest = operations['announcements']['requestBody']['content']['application/json'];
 export type AnnouncementsResponse = operations['announcements']['responses']['200']['content']['application/json'];
+export type AnnouncementsShowRequest = operations['announcements___show']['requestBody']['content']['application/json'];
+export type AnnouncementsShowResponse = operations['announcements___show']['responses']['200']['content']['application/json'];
 export type AntennasCreateRequest = operations['antennas___create']['requestBody']['content']['application/json'];
 export type AntennasCreateResponse = operations['antennas___create']['responses']['200']['content']['application/json'];
 export type AntennasDeleteRequest = operations['antennas___delete']['requestBody']['content']['application/json'];
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 1e9c190ca5..208f03dc3e 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -706,6 +706,15 @@ export type paths = {
      */
     post: operations['announcements'];
   };
+  '/announcements/show': {
+    /**
+     * announcements/show
+     * @description No description provided.
+     *
+     * **Credential required**: *No*
+     */
+    post: operations['announcements___show'];
+  };
   '/antennas/create': {
     /**
      * antennas/create
@@ -9662,6 +9671,60 @@ export type operations = {
       };
     };
   };
+  /**
+   * announcements/show
+   * @description No description provided.
+   *
+   * **Credential required**: *No*
+   */
+  announcements___show: {
+    requestBody: {
+      content: {
+        'application/json': {
+          /** Format: misskey:id */
+          announcementId: string;
+        };
+      };
+    };
+    responses: {
+      /** @description OK (with results) */
+      200: {
+        content: {
+          'application/json': components['schemas']['Announcement'];
+        };
+      };
+      /** @description Client error */
+      400: {
+        content: {
+          'application/json': components['schemas']['Error'];
+        };
+      };
+      /** @description Authentication error */
+      401: {
+        content: {
+          'application/json': components['schemas']['Error'];
+        };
+      };
+      /** @description Forbidden error */
+      403: {
+        content: {
+          'application/json': components['schemas']['Error'];
+        };
+      };
+      /** @description I'm Ai */
+      418: {
+        content: {
+          'application/json': components['schemas']['Error'];
+        };
+      };
+      /** @description Internal server error */
+      500: {
+        content: {
+          'application/json': components['schemas']['Error'];
+        };
+      };
+    };
+  };
   /**
    * antennas/create
    * @description No description provided.

From 1df8ea824e5dace883f0d6855d7342984c8032d0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 27 May 2024 17:15:42 +0900
Subject: [PATCH 147/191] =?UTF-8?q?fix(backend):=20`/@`=20=E3=81=AB?=
 =?UTF-8?q?=E3=82=A2=E3=82=AF=E3=82=BB=E3=82=B9=E3=81=99=E3=82=8B=E3=81=A8?=
 =?UTF-8?q?=E3=82=B5=E3=83=BC=E3=83=90=E3=83=BC=E3=82=A8=E3=83=A9=E3=83=BC?=
 =?UTF-8?q?=E3=81=8C=E7=99=BA=E7=94=9F=E3=81=99=E3=82=8B=E5=95=8F=E9=A1=8C?=
 =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3=20(#13884)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../backend/src/server/web/ClientServerService.ts    | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts
index f35ec8ba31..ab03489c0d 100644
--- a/packages/backend/src/server/web/ClientServerService.ts
+++ b/packages/backend/src/server/web/ClientServerService.ts
@@ -466,7 +466,9 @@ export class ClientServerService {
 		};
 
 		// Atom
-		fastify.get<{ Params: { user: string; } }>('/@:user.atom', async (request, reply) => {
+		fastify.get<{ Params: { user?: string; } }>('/@:user.atom', async (request, reply) => {
+			if (request.params.user == null) return await renderBase(reply);
+
 			const feed = await getFeed(request.params.user);
 
 			if (feed) {
@@ -479,7 +481,9 @@ export class ClientServerService {
 		});
 
 		// RSS
-		fastify.get<{ Params: { user: string; } }>('/@:user.rss', async (request, reply) => {
+		fastify.get<{ Params: { user?: string; } }>('/@:user.rss', async (request, reply) => {
+			if (request.params.user == null) return await renderBase(reply);
+
 			const feed = await getFeed(request.params.user);
 
 			if (feed) {
@@ -492,7 +496,9 @@ export class ClientServerService {
 		});
 
 		// JSON
-		fastify.get<{ Params: { user: string; } }>('/@:user.json', async (request, reply) => {
+		fastify.get<{ Params: { user?: string; } }>('/@:user.json', async (request, reply) => {
+			if (request.params.user == null) return await renderBase(reply);
+
 			const feed = await getFeed(request.params.user);
 
 			if (feed) {

From 1b81ca45636db21166753e0aa00d91ab23e46ac5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 27 May 2024 17:16:47 +0900
Subject: [PATCH 148/191] =?UTF-8?q?enhance(frontend):=20=E3=80=8C=E8=A6=8B?=
 =?UTF-8?q?=E3=81=9F=E3=81=93=E3=81=A8=E3=81=AE=E3=81=82=E3=82=8B=E3=83=AA?=
 =?UTF-8?q?=E3=83=8E=E3=83=BC=E3=83=88=E3=82=92=E7=9C=81=E7=95=A5=E3=81=97?=
 =?UTF-8?q?=E3=81=A6=E8=A1=A8=E7=A4=BA=E3=80=8D=E3=81=AE=E5=90=8D=E7=A7=B0?=
 =?UTF-8?q?=E3=82=92=E5=A4=89=E6=9B=B4=20(#13883)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance(frontend): 「見たことのあるリノートを省略して表示」の名称を変更

* ひとつだけcaptionが入ってるやつが真ん中にいると不格好だったので場所変更
---
 locales/index.d.ts                               | 6 +++++-
 locales/ja-JP.yml                                | 3 ++-
 packages/frontend/src/pages/settings/general.vue | 5 ++++-
 3 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/locales/index.d.ts b/locales/index.d.ts
index 18d8eee18f..eb7e297aa3 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -4113,9 +4113,13 @@ export interface Locale extends ILocale {
      */
     "thisPostMayBeAnnoyingIgnore": string;
     /**
-     * 見たことのあるリノートを省略して表示
+     * リノートのスマート省略
      */
     "collapseRenotes": string;
+    /**
+     * リアクションやリノートをしたことがあるノートをたたんで表示します。
+     */
+    "collapseRenotesDescription": string;
     /**
      * サーバー内部エラー
      */
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 8b1738aebe..ebaf16745c 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1024,7 +1024,8 @@ thisPostMayBeAnnoying: "この投稿は迷惑になる可能性があります
 thisPostMayBeAnnoyingHome: "ホームに投稿"
 thisPostMayBeAnnoyingCancel: "やめる"
 thisPostMayBeAnnoyingIgnore: "このまま投稿"
-collapseRenotes: "見たことのあるリノートを省略して表示"
+collapseRenotes: "リノートのスマート省略"
+collapseRenotesDescription: "リアクションやリノートをしたことがあるノートをたたんで表示します。"
 internalServerError: "サーバー内部エラー"
 internalServerErrorDescription: "サーバー内部で予期しないエラーが発生しました。"
 copyErrorInfo: "エラー情報をコピー"
diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue
index 55d514ddf9..cfc63f2a08 100644
--- a/packages/frontend/src/pages/settings/general.vue
+++ b/packages/frontend/src/pages/settings/general.vue
@@ -50,9 +50,12 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 		<div class="_gaps_m">
 			<div class="_gaps_s">
+				<MkSwitch v-model="collapseRenotes">
+					<template #label>{{ i18n.ts.collapseRenotes }}</template>
+					<template #caption>{{ i18n.ts.collapseRenotesDescription }}</template>
+				</MkSwitch>
 				<MkSwitch v-model="showNoteActionsOnlyHover">{{ i18n.ts.showNoteActionsOnlyHover }}</MkSwitch>
 				<MkSwitch v-model="showClipButtonInNoteFooter">{{ i18n.ts.showClipButtonInNoteFooter }}</MkSwitch>
-				<MkSwitch v-model="collapseRenotes">{{ i18n.ts.collapseRenotes }}</MkSwitch>
 				<MkSwitch v-model="advancedMfm">{{ i18n.ts.enableAdvancedMfm }}</MkSwitch>
 				<MkSwitch v-if="advancedMfm" v-model="animatedMfm">{{ i18n.ts.enableAnimatedMfm }}</MkSwitch>
 				<MkSwitch v-if="advancedMfm" v-model="enableQuickAddMfmFunction">{{ i18n.ts.enableQuickAddMfmFunction }}</MkSwitch>

From 805a11aadbbc0f0a32531fd86443de514df74466 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 27 May 2024 17:18:12 +0900
Subject: [PATCH 149/191] =?UTF-8?q?enhance(backend):=20=E3=83=97=E3=83=AD?=
 =?UTF-8?q?=E3=83=95=E3=82=A3=E3=83=BC=E3=83=AB=E3=81=AE=E3=83=AA=E3=83=B3?=
 =?UTF-8?q?=E3=82=AF=E6=A4=9C=E8=A8=BC=E3=81=ABtry-catch=E3=82=92=E8=BF=BD?=
 =?UTF-8?q?=E5=8A=A0=20(#13882)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance(backend): プロフィールのリンク検証にtry-catchを追加

* :v:
---
 .../src/server/api/endpoints/i/update.ts      | 36 +++++++++++--------
 1 file changed, 21 insertions(+), 15 deletions(-)

diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts
index 84a1931a3d..a8e702f328 100644
--- a/packages/backend/src/server/api/endpoints/i/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/update.ts
@@ -498,26 +498,32 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 	private async verifyLink(url: string, user: MiLocalUser) {
 		if (!safeForSql(url)) return;
 
-		const html = await this.httpRequestService.getHtml(url);
+		try {
+			const html = await this.httpRequestService.getHtml(url);
 
-		const { window } = new JSDOM(html);
-		const doc = window.document;
+			const { window } = new JSDOM(html);
+			const doc = window.document;
 
-		const myLink = `${this.config.url}/@${user.username}`;
+			const myLink = `${this.config.url}/@${user.username}`;
 
-		const aEls = Array.from(doc.getElementsByTagName('a'));
-		const linkEls = Array.from(doc.getElementsByTagName('link'));
+			const aEls = Array.from(doc.getElementsByTagName('a'));
+			const linkEls = Array.from(doc.getElementsByTagName('link'));
 
-		const includesMyLink = aEls.some(a => a.href === myLink);
-		const includesRelMeLinks = [...aEls, ...linkEls].some(link => link.rel === 'me' && link.href === myLink);
+			const includesMyLink = aEls.some(a => a.href === myLink);
+			const includesRelMeLinks = [...aEls, ...linkEls].some(link => link.rel === 'me' && link.href === myLink);
 
-		if (includesMyLink || includesRelMeLinks) {
-			await this.userProfilesRepository.createQueryBuilder('profile').update()
-				.where('userId = :userId', { userId: user.id })
-				.set({
-					verifiedLinks: () => `array_append("verifiedLinks", '${url}')`, // ここでSQLインジェクションされそうなのでとりあえず safeForSql で弾いている
-				})
-				.execute();
+			if (includesMyLink || includesRelMeLinks) {
+				await this.userProfilesRepository.createQueryBuilder('profile').update()
+					.where('userId = :userId', { userId: user.id })
+					.set({
+						verifiedLinks: () => `array_append("verifiedLinks", '${url}')`, // ここでSQLインジェクションされそうなのでとりあえず safeForSql で弾いている
+					})
+					.execute();
+			}
+
+			window.close();
+		} catch (err) {
+			// なにもしない
 		}
 	}
 }

From d013e4516d7afb6ed4362467f69df2d79b9f0f9f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 27 May 2024 17:19:09 +0900
Subject: [PATCH 150/191] =?UTF-8?q?enhance(frontend):=20=E3=81=8A=E6=B0=97?=
 =?UTF-8?q?=E3=81=AB=E5=85=A5=E3=82=8A=E3=83=81=E3=83=A3=E3=83=B3=E3=83=8D?=
 =?UTF-8?q?=E3=83=AB=E3=82=92=E3=82=AD=E3=83=A3=E3=83=83=E3=82=B7=E3=83=A5?=
 =?UTF-8?q?=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=20(#13881)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 packages/frontend/src/cache.ts                   |  1 +
 packages/frontend/src/pages/channel.vue          |  3 +++
 packages/frontend/src/pages/timeline.vue         |  6 ++----
 packages/frontend/src/scripts/get-note-menu.ts   |  6 ++----
 packages/frontend/src/ui/deck/channel-column.vue | 13 ++++++-------
 5 files changed, 14 insertions(+), 15 deletions(-)

diff --git a/packages/frontend/src/cache.ts b/packages/frontend/src/cache.ts
index b286528de6..bfe8fbe0e4 100644
--- a/packages/frontend/src/cache.ts
+++ b/packages/frontend/src/cache.ts
@@ -11,3 +11,4 @@ export const clipsCache = new Cache<Misskey.entities.Clip[]>(1000 * 60 * 30, ()
 export const rolesCache = new Cache(1000 * 60 * 30, () => misskeyApi('admin/roles/list'));
 export const userListsCache = new Cache<Misskey.entities.UserList[]>(1000 * 60 * 30, () => misskeyApi('users/lists/list'));
 export const antennasCache = new Cache<Misskey.entities.Antenna[]>(1000 * 60 * 30, () => misskeyApi('antennas/list'));
+export const favoritedChannelsCache = new Cache<Misskey.entities.Channel[]>(1000 * 60 * 30, () => misskeyApi('channels/my-favorites', { limit: 100 }));
diff --git a/packages/frontend/src/pages/channel.vue b/packages/frontend/src/pages/channel.vue
index 611ae6feca..a895df76e8 100644
--- a/packages/frontend/src/pages/channel.vue
+++ b/packages/frontend/src/pages/channel.vue
@@ -83,6 +83,7 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
 import { deviceKind } from '@/scripts/device-kind.js';
 import MkNotes from '@/components/MkNotes.vue';
 import { url } from '@/config.js';
+import { favoritedChannelsCache } from '@/cache.js';
 import MkButton from '@/components/MkButton.vue';
 import MkInput from '@/components/MkInput.vue';
 import { defaultStore } from '@/store.js';
@@ -153,6 +154,7 @@ function favorite() {
 		channelId: channel.value.id,
 	}).then(() => {
 		favorited.value = true;
+		favoritedChannelsCache.delete();
 	});
 }
 
@@ -168,6 +170,7 @@ async function unfavorite() {
 		channelId: channel.value.id,
 	}).then(() => {
 		favorited.value = false;
+		favoritedChannelsCache.delete();
 	});
 }
 
diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue
index 48dfc1fd44..98744c6318 100644
--- a/packages/frontend/src/pages/timeline.vue
+++ b/packages/frontend/src/pages/timeline.vue
@@ -48,7 +48,7 @@ import { i18n } from '@/i18n.js';
 import { instance } from '@/instance.js';
 import { $i } from '@/account.js';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
-import { antennasCache, userListsCache } from '@/cache.js';
+import { antennasCache, userListsCache, favoritedChannelsCache } from '@/cache.js';
 import { deviceKind } from '@/scripts/device-kind.js';
 import { deepMerge } from '@/scripts/merge.js';
 import { MenuItem } from '@/types/menu.js';
@@ -173,9 +173,7 @@ async function chooseAntenna(ev: MouseEvent): Promise<void> {
 }
 
 async function chooseChannel(ev: MouseEvent): Promise<void> {
-	const channels = await misskeyApi('channels/my-favorites', {
-		limit: 100,
-	});
+	const channels = await favoritedChannelsCache.fetch();
 	const items: MenuItem[] = [
 		...channels.map(channel => {
 			const lastReadedAt = miLocalStorage.getItemAsJson(`channelLastReadedAt:${channel.id}`) ?? null;
diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts
index e7c9a848e0..71ad299f50 100644
--- a/packages/frontend/src/scripts/get-note-menu.ts
+++ b/packages/frontend/src/scripts/get-note-menu.ts
@@ -16,7 +16,7 @@ import { url } from '@/config.js';
 import { defaultStore, noteActions } from '@/store.js';
 import { miLocalStorage } from '@/local-storage.js';
 import { getUserMenu } from '@/scripts/get-user-menu.js';
-import { clipsCache } from '@/cache.js';
+import { clipsCache, favoritedChannelsCache } from '@/cache.js';
 import { MenuItem } from '@/types/menu.js';
 import MkRippleEffect from '@/components/MkRippleEffect.vue';
 import { isSupportShare } from '@/scripts/navigator.js';
@@ -603,9 +603,7 @@ export function getRenoteMenu(props: {
 			icon: 'ti ti-repeat',
 			text: appearNote.channel ? i18n.ts.renoteToOtherChannel : i18n.ts.renoteToChannel,
 			children: async () => {
-				const channels = await misskeyApi('channels/my-favorites', {
-					limit: 30,
-				});
+				const channels = await favoritedChannelsCache.fetch();
 				return channels.filter((channel) => {
 					if (!appearNote.channelId) return true;
 					return channel.id !== appearNote.channelId;
diff --git a/packages/frontend/src/ui/deck/channel-column.vue b/packages/frontend/src/ui/deck/channel-column.vue
index bd3b059497..28c741bba2 100644
--- a/packages/frontend/src/ui/deck/channel-column.vue
+++ b/packages/frontend/src/ui/deck/channel-column.vue
@@ -26,6 +26,7 @@ import { updateColumn, Column } from './deck-store.js';
 import MkTimeline from '@/components/MkTimeline.vue';
 import MkButton from '@/components/MkButton.vue';
 import * as os from '@/os.js';
+import { favoritedChannelsCache } from '@/cache.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { i18n } from '@/i18n.js';
 
@@ -42,20 +43,18 @@ if (props.column.channelId == null) {
 }
 
 async function setChannel() {
-	const channels = await misskeyApi('channels/my-favorites', {
-		limit: 100,
-	});
-	const { canceled, result: channel } = await os.select({
+	const channels = await favoritedChannelsCache.fetch();
+	const { canceled, result: chosenChannel } = await os.select({
 		title: i18n.ts.selectChannel,
 		items: channels.map(x => ({
 			value: x, text: x.name,
 		})),
 		default: props.column.channelId,
 	});
-	if (canceled) return;
+	if (canceled || chosenChannel == null) return;
 	updateColumn(props.column.id, {
-		channelId: channel.id,
-		name: channel.name,
+		channelId: chosenChannel.id,
+		name: chosenChannel.name,
 	});
 }
 

From 6af9492ea5492c02a11302afe7c6a6e83c00de1b Mon Sep 17 00:00:00 2001
From: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
Date: Mon, 27 May 2024 17:21:05 +0900
Subject: [PATCH 151/191] Quick action implement (#13878)

* enhance(frontend): quick action for file admin-lookup

* docs(changelog): update changelog

* enhance(frontend): quick action for general admin-lookup, remove unimplemented note, instance admin-lookup

* docs(changelog): update changelog

* chore: fix lint
---
 CHANGELOG.md                                  |  2 ++
 packages/frontend/src/pages/admin/files.vue   | 27 ++-----------------
 packages/frontend/src/pages/admin/index.vue   | 21 ++++++---------
 packages/frontend/src/pages/admin/users.vue   |  2 +-
 .../{lookup-user.ts => admin-lookup.ts}       | 23 ++++++++++++++++
 5 files changed, 36 insertions(+), 39 deletions(-)
 rename packages/frontend/src/scripts/{lookup-user.ts => admin-lookup.ts} (72%)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7e23fa8f72..d23f512e3d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -49,6 +49,8 @@
 - Enhance: AiScriptを0.18.0にバージョンアップ
 - Enhance: 通常のノートでも、お気に入りに登録したチャンネルにリノートできるように
 - Enhance: 長いテキストをペーストした際にテキストファイルとして添付するかどうかを選択できるように
+- Enhance: コントロールパネルのクイックアクションからファイルを照会できるように
+- Enhance: コントロールパネルのクイックアクションから通常の照会を行えるように
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
 - Fix: 周年の実績が閏年を考慮しない問題を修正
 - Fix: ローカルURLのプレビューポップアップが左上に表示される
diff --git a/packages/frontend/src/pages/admin/files.vue b/packages/frontend/src/pages/admin/files.vue
index 3fe021e771..5132b85c64 100644
--- a/packages/frontend/src/pages/admin/files.vue
+++ b/packages/frontend/src/pages/admin/files.vue
@@ -42,7 +42,7 @@ import MkInput from '@/components/MkInput.vue';
 import MkSelect from '@/components/MkSelect.vue';
 import MkFileListForAdmin from '@/components/MkFileListForAdmin.vue';
 import * as os from '@/os.js';
-import { misskeyApi } from '@/scripts/misskey-api.js';
+import { lookupFile } from '@/scripts/admin-lookup.js';
 import { i18n } from '@/i18n.js';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
 
@@ -73,33 +73,10 @@ function clear() {
 	});
 }
 
-function show(file) {
-	os.pageWindow(`/admin/file/${file.id}`);
-}
-
-async function find() {
-	const { canceled, result: q } = await os.inputText({
-		title: i18n.ts.fileIdOrUrl,
-		minLength: 1,
-	});
-	if (canceled) return;
-
-	misskeyApi('admin/drive/show-file', q.startsWith('http://') || q.startsWith('https://') ? { url: q.trim() } : { fileId: q.trim() }).then(file => {
-		show(file);
-	}).catch(err => {
-		if (err.code === 'NO_SUCH_FILE') {
-			os.alert({
-				type: 'error',
-				text: i18n.ts.notFound,
-			});
-		}
-	});
-}
-
 const headerActions = computed(() => [{
 	text: i18n.ts.lookup,
 	icon: 'ti ti-search',
-	handler: find,
+	handler: lookupFile,
 }, {
 	text: i18n.ts.clearCachedFiles,
 	icon: 'ti ti-trash',
diff --git a/packages/frontend/src/pages/admin/index.vue b/packages/frontend/src/pages/admin/index.vue
index d4a41c66cc..eef1c8afa9 100644
--- a/packages/frontend/src/pages/admin/index.vue
+++ b/packages/frontend/src/pages/admin/index.vue
@@ -33,9 +33,10 @@ import { i18n } from '@/i18n.js';
 import MkSuperMenu from '@/components/MkSuperMenu.vue';
 import MkInfo from '@/components/MkInfo.vue';
 import { instance } from '@/instance.js';
+import { lookup } from '@/scripts/lookup.js';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
-import { lookupUser, lookupUserByEmail } from '@/scripts/lookup-user.js';
+import { lookupUser, lookupUserByEmail, lookupFile } from '@/scripts/admin-lookup.js';
 import { PageMetadata, definePageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
 import { useRouter } from '@/router/supplier.js';
 
@@ -82,7 +83,7 @@ const menuDef = computed(() => [{
 		type: 'button',
 		icon: 'ti ti-search',
 		text: i18n.ts.lookup,
-		action: lookup,
+		action: adminLookup,
 	}, ...(instance.disableRegistration ? [{
 		type: 'button',
 		icon: 'ti ti-user-plus',
@@ -282,7 +283,7 @@ function invite() {
 	});
 }
 
-function lookup(ev: MouseEvent) {
+function adminLookup(ev: MouseEvent) {
 	os.popupMenu([{
 		text: i18n.ts.user,
 		icon: 'ti ti-user',
@@ -295,23 +296,17 @@ function lookup(ev: MouseEvent) {
 		action: () => {
 			lookupUserByEmail();
 		},
-	}, {
-		text: i18n.ts.note,
-		icon: 'ti ti-pencil',
-		action: () => {
-			alert('TODO');
-		},
 	}, {
 		text: i18n.ts.file,
 		icon: 'ti ti-cloud',
 		action: () => {
-			alert('TODO');
+			lookupFile();
 		},
 	}, {
-		text: i18n.ts.instance,
-		icon: 'ti ti-planet',
+		text: i18n.ts.lookup,
+		icon: 'ti ti-world-search',
 		action: () => {
-			alert('TODO');
+			lookup();
 		},
 	}], ev.currentTarget ?? ev.target);
 }
diff --git a/packages/frontend/src/pages/admin/users.vue b/packages/frontend/src/pages/admin/users.vue
index 06317760d2..7d87b97a36 100644
--- a/packages/frontend/src/pages/admin/users.vue
+++ b/packages/frontend/src/pages/admin/users.vue
@@ -63,7 +63,7 @@ import MkInput from '@/components/MkInput.vue';
 import MkSelect from '@/components/MkSelect.vue';
 import MkPagination from '@/components/MkPagination.vue';
 import * as os from '@/os.js';
-import { lookupUser } from '@/scripts/lookup-user.js';
+import { lookupUser } from '@/scripts/admin-lookup.js';
 import { i18n } from '@/i18n.js';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
 import MkUserCardMini from '@/components/MkUserCardMini.vue';
diff --git a/packages/frontend/src/scripts/lookup-user.ts b/packages/frontend/src/scripts/admin-lookup.ts
similarity index 72%
rename from packages/frontend/src/scripts/lookup-user.ts
rename to packages/frontend/src/scripts/admin-lookup.ts
index efc9132e75..1b57b853c9 100644
--- a/packages/frontend/src/scripts/lookup-user.ts
+++ b/packages/frontend/src/scripts/admin-lookup.ts
@@ -63,3 +63,26 @@ export async function lookupUserByEmail() {
 		}
 	}
 }
+
+export async function lookupFile() {
+	const { canceled, result: q } = await os.inputText({
+		title: i18n.ts.fileIdOrUrl,
+		minLength: 1,
+	});
+	if (canceled) return;
+
+	const show = (file) => {
+		os.pageWindow(`/admin/file/${file.id}`);
+	};
+
+	misskeyApi('admin/drive/show-file', q.startsWith('http://') || q.startsWith('https://') ? { url: q.trim() } : { fileId: q.trim() }).then(file => {
+		show(file);
+	}).catch(err => {
+		if (err.code === 'NO_SUCH_FILE') {
+			os.alert({
+				type: 'error',
+				text: i18n.ts.notFound,
+			});
+		}
+	});
+}

From 140df4b5e050f1c2b55e08f9c5b511588b0370d2 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Mon, 27 May 2024 08:27:39 +0000
Subject: [PATCH 152/191] Bump version to 2024.5.0-beta.3

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index b9ac4fc2a1..22e5217ea2 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2024.5.0-beta.2",
+	"version": "2024.5.0-beta.3",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index 80ae84796a..d72004862c 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2024.5.0-beta.2",
+	"version": "2024.5.0-beta.3",
 	"description": "Misskey SDK for JavaScript",
 	"main": "./built/index.js",
 	"types": "./built/index.d.ts",

From e50107792c870098ac78a64d8a92e69d5f11893a Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Mon, 27 May 2024 08:37:07 +0000
Subject: [PATCH 153/191] Bump version to 2024.5.0-beta.4

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 22e5217ea2..ca3883b804 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2024.5.0-beta.3",
+	"version": "2024.5.0-beta.4",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index d72004862c..bad0142899 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2024.5.0-beta.3",
+	"version": "2024.5.0-beta.4",
 	"description": "Misskey SDK for JavaScript",
 	"main": "./built/index.js",
 	"types": "./built/index.d.ts",

From 28e0e20879d2b2834b5f3f47fdf8663afa8a07f8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 27 May 2024 19:22:46 +0900
Subject: [PATCH 154/191] [ci skip] Delete .github/FUNDING.yml

use misskey-dev/.github repository
---
 .github/FUNDING.yml | 4 ----
 1 file changed, 4 deletions(-)
 delete mode 100644 .github/FUNDING.yml

diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index d42b58abc0..0000000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-# These are supported funding model platforms
-
-github: [misskey-dev]
-patreon: syuilo

From cf2256cf4162f0f58fea3afbe08d9805451a9efc Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Mon, 27 May 2024 20:11:39 +0900
Subject: [PATCH 155/191] fix: CHANGELOG not reflecting correctly (#13888)

* fix: CHANGELOG not reflecting correctly

* Update .github/workflows/release-edit-with-push.yml

Co-authored-by: anatawa12 <anatawa12@icloud.com>

---------

Co-authored-by: anatawa12 <anatawa12@icloud.com>
---
 .github/workflows/release-edit-with-push.yml | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/release-edit-with-push.yml b/.github/workflows/release-edit-with-push.yml
index 944b98eb7c..890cb047bd 100644
--- a/.github/workflows/release-edit-with-push.yml
+++ b/.github/workflows/release-edit-with-push.yml
@@ -37,4 +37,7 @@ jobs:
       # PRのnotesを更新
       - name: Update PR
         run: |
-          gh pr edit ${{ steps.get_pr.outputs.pr_number }} --body "${{ steps.changelog.outputs.changelog }}"
+          gh pr edit "$PR_NUMBER" --body "$CHANGELOG"
+        env:
+          CHANGELOG: ${{ steps.changelog.outputs.changelog }}
+          PR_NUMBER: ${{ steps.get_pr.outputs.pr_number }}

From a7a8dc4dbbab075cdee140f468fd7e3559cde475 Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Mon, 27 May 2024 20:12:25 +0900
Subject: [PATCH 156/191] =?UTF-8?q?=E3=82=82=E3=81=A8=E3=82=82=E3=81=A8?=
 =?UTF-8?q?=E3=82=BB=E3=83=B3=E3=82=B7=E3=83=86=E3=82=A3=E3=83=96=E3=81=A7?=
 =?UTF-8?q?=E3=81=AF=E3=81=AA=E3=81=84=E3=81=A8=E9=80=A3=E5=90=88=E3=81=95?=
 =?UTF-8?q?=E3=82=8C=E3=81=A6=E3=81=84=E3=81=9F=E3=83=95=E3=82=A1=E3=82=A4?=
 =?UTF-8?q?=E3=83=AB=E3=81=8C=E3=82=BB=E3=83=B3=E3=82=B7=E3=83=86=E3=82=A3?=
 =?UTF-8?q?=E3=83=96=E3=81=A8=E3=81=97=E3=81=A6=E9=80=A3=E5=90=88=E3=81=95?=
 =?UTF-8?q?=E3=82=8C=E3=81=9F=E5=A0=B4=E5=90=88=E3=81=AB=E3=82=BB=E3=83=B3?=
 =?UTF-8?q?=E3=82=B7=E3=83=86=E3=82=A3=E3=83=96=E3=81=A8=E3=81=97=E3=81=A6?=
 =?UTF-8?q?=E3=81=9D=E3=81=AE=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=82=92?=
 =?UTF-8?q?=E6=89=B1=E3=81=86=E3=82=88=E3=81=86=E3=81=AB=20(#13879)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* feat(backend): mark an file as sensitive if the file was newly federated as sensitive

* docs(changelog): もともとセンシティブではないと連合されていたファイルがセンシティブとして連合された場合にセンシティブとしてそのファイルを扱うように

* fix: change way to update federated image

* Update packages/backend/src/core/DriveService.ts

Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>

* update isSensitive of existing record object

---------

Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
---
 CHANGELOG.md                              | 2 ++
 packages/backend/src/core/DriveService.ts | 6 ++++++
 2 files changed, 8 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d23f512e3d..f8463f8cbf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -96,6 +96,8 @@
 - Fix: `/i/notifications`に `includeTypes`か`excludeTypes`を指定しているとき、通知が存在するのに空配列を返すことがある問題を修正
 - Fix: 複数idを指定する`users/show`が関係ないユーザを返すことがある問題を修正
 - Fix: `/tags` と `/user-tags` が検索エンジンにインデックスされないように
+- Fix: もともとセンシティブではないと連合されていたファイルがセンシティブとして連合された場合にセンシティブとしてそのファイルを扱うように
+  - センシティブとして連合したファイルは非センシティブとして連合されてもセンシティブとして扱われます
 
 ## 2024.3.1
 
diff --git a/packages/backend/src/core/DriveService.ts b/packages/backend/src/core/DriveService.ts
index 1bc1df1dda..63fa26f69d 100644
--- a/packages/backend/src/core/DriveService.ts
+++ b/packages/backend/src/core/DriveService.ts
@@ -504,6 +504,12 @@ export class DriveService {
 
 			if (much) {
 				this.registerLogger.info(`file with same hash is found: ${much.id}`);
+				if (sensitive && !much.isSensitive) {
+					// The file is federated as sensitive for this time, but was federated as non-sensitive before.
+					// Therefore, update the file to sensitive.
+					await this.driveFilesRepository.update({ id: much.id }, { isSensitive: true });
+					much.isSensitive = true;
+				}
 				return much;
 			}
 		}

From d7982e471c11d0656fa1266b2e4747ca5179647d Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Mon, 27 May 2024 20:24:15 +0900
Subject: [PATCH 157/191] New Crowdin updates (#13860)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Japanese, Kansai)

* New translations ja-jp.yml (Indonesian)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (Czech)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Polish)

* New translations ja-jp.yml (Portuguese)

* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (Arabic)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Dutch)

* New translations ja-jp.yml (Norwegian)

* New translations ja-jp.yml (Russian)

* New translations ja-jp.yml (Slovak)

* New translations ja-jp.yml (Swedish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Ukrainian)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Bengali)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Uzbek)

* New translations ja-jp.yml (Lao)

* New translations ja-jp.yml (Korean (Gyeongsang))

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Japanese, Kansai)

* New translations ja-jp.yml (Indonesian)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Danish)

* New translations ja-jp.yml (Chinese Simplified)
---
 locales/ar-SA.yml |   2 +
 locales/bn-BD.yml |   4 ++
 locales/ca-ES.yml |   5 +-
 locales/cs-CZ.yml |   4 ++
 locales/da-DK.yml |   2 +
 locales/de-DE.yml |   4 ++
 locales/en-US.yml |  14 +++++-
 locales/es-ES.yml |   5 +-
 locales/fr-FR.yml |   4 ++
 locales/id-ID.yml |  14 +++++-
 locales/it-IT.yml |   5 +-
 locales/ja-KS.yml |   5 +-
 locales/ko-GS.yml |   4 ++
 locales/ko-KR.yml |   5 +-
 locales/lo-LA.yml |   4 ++
 locales/nl-NL.yml |   4 ++
 locales/no-NO.yml |   2 +
 locales/pl-PL.yml |   4 ++
 locales/pt-PT.yml |   4 ++
 locales/ro-RO.yml |   4 ++
 locales/ru-RU.yml |   4 ++
 locales/sk-SK.yml |   4 ++
 locales/sv-SE.yml |   4 ++
 locales/th-TH.yml |   5 +-
 locales/tr-TR.yml |   4 ++
 locales/uk-UA.yml |   4 ++
 locales/uz-UZ.yml |   4 ++
 locales/vi-VN.yml |   4 ++
 locales/zh-CN.yml |  14 +++++-
 locales/zh-TW.yml | 124 +++++++++++++++++++++++++---------------------
 30 files changed, 205 insertions(+), 65 deletions(-)

diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml
index 88707fe111..955d672c1d 100644
--- a/locales/ar-SA.yml
+++ b/locales/ar-SA.yml
@@ -1016,6 +1016,8 @@ sourceCode: "الشفرة المصدرية"
 flip: "اقلب"
 lastNDays: "آخر {n} أيام"
 surrender: "ألغِ"
+_delivery:
+  stop: "مُعلّق"
 _initialAccountSetting:
   accountCreated: "نجح إنشاء حسابك!"
   letsStartAccountSetup: "إذا كنت جديدًا لنعدّ حسابك الشخصي."
diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml
index dc5d315aed..abcf07da83 100644
--- a/locales/bn-BD.yml
+++ b/locales/bn-BD.yml
@@ -857,6 +857,10 @@ replies: "জবাব"
 renotes: "রিনোট"
 sourceCode: "সোর্স কোড"
 flip: "উল্টান"
+_delivery:
+  stop: "স্থগিত করা হয়েছে"
+  _type:
+    none: "প্রকাশ করা হচ্ছে"
 _role:
   priority: "অগ্রাধিকার"
   _priority:
diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml
index d035555c73..0345ee0326 100644
--- a/locales/ca-ES.yml
+++ b/locales/ca-ES.yml
@@ -1224,6 +1224,10 @@ gameRetry: "Torna a provar"
 notUsePleaseLeaveBlank: "Si no voleu usar-ho, deixeu-ho en blanc"
 useTotp: "Usa una contrasenya d'un sol ús"
 useBackupCode: "Usa un codi de recuperació"
+_delivery:
+  stop: "Suspés"
+  _type:
+    none: "S'està publicant"
 _bubbleGame:
   howToPlay: "Com es juga"
   _howToPlay:
@@ -2001,7 +2005,6 @@ _permissions:
   "read:admin:server-info": "Veure informació del servidor"
   "read:admin:show-moderation-log": "Veure registre de moderació "
   "read:admin:show-user": "Veure informació privada de l'usuari "
-  "read:admin:show-users": "Veure informació privada de l'usuari "
   "write:admin:suspend-user": "Suspendre usuari"
   "write:admin:unset-user-avatar": "Esborrar avatar d'usuari "
   "write:admin:unset-user-banner": "Esborrar bàner de l'usuari "
diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml
index cff533976e..c8a0b0cb28 100644
--- a/locales/cs-CZ.yml
+++ b/locales/cs-CZ.yml
@@ -1099,6 +1099,10 @@ sourceCode: "Zdrojový kód"
 flip: "Otočit"
 lastNDays: "Posledních {n} dnů"
 surrender: "Zrušit"
+_delivery:
+  stop: "Suspendováno"
+  _type:
+    none: "Publikuji"
 _initialAccountSetting:
   accountCreated: "Váš účet byl úspěšně vytvořen!"
   letsStartAccountSetup: "Pro začátek si nastavte svůj profil."
diff --git a/locales/da-DK.yml b/locales/da-DK.yml
index 08c15ed092..5eb7a5a5f4 100644
--- a/locales/da-DK.yml
+++ b/locales/da-DK.yml
@@ -1,2 +1,4 @@
 ---
 _lang_: "Dansk"
+headlineMisskey: ""
+introMisskey: "ようこそ!Misskeyは、オープンソースの分散型マイクロブログサービスです。\n「ノート」を作成して、いま起こっていることを共有したり、あなたについて皆に発信しよう📡\n「リアクション」機能で、皆のノートに素早く反応を追加することもできます👍\n新しい世界を探検しよう🚀"
diff --git a/locales/de-DE.yml b/locales/de-DE.yml
index 3e1c40512e..9e42e01252 100644
--- a/locales/de-DE.yml
+++ b/locales/de-DE.yml
@@ -1185,6 +1185,10 @@ addMfmFunction: "MFM hinzufügen"
 sfx: "Soundeffekte"
 lastNDays: "Letzten {n} Tage"
 surrender: "Abbrechen"
+_delivery:
+  stop: "Gesperrt"
+  _type:
+    none: "Wird veröffentlicht"
 _announcement:
   forExistingUsers: "Nur für existierende Nutzer"
   forExistingUsersDescription: "Ist diese Option aktiviert, wird diese Ankündigung nur Nutzern angezeigt, die zum Zeitpunkt der Ankündigung bereits registriert sind. Ist sie deaktiviert, wird sie auch Nutzern, die sich nach dessen Veröffentlichung registrieren, angezeigt."
diff --git a/locales/en-US.yml b/locales/en-US.yml
index 10e9fd778e..c20a1ac7d8 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -108,11 +108,14 @@ enterEmoji: "Enter an emoji"
 renote: "Renote"
 unrenote: "Remove renote"
 renoted: "Renoted."
+renotedToX: "Renote from {name} users。"
 cantRenote: "This post can't be renoted."
 cantReRenote: "A renote can't be renoted."
 quote: "Quote"
 inChannelRenote: "Channel-only Renote"
 inChannelQuote: "Channel-only Quote"
+renoteToChannel: "Renote to channel"
+renoteToOtherChannel: "Renote to other channel"
 pinnedNote: "Pinned note"
 pinned: "Pin to profile"
 you: "You"
@@ -468,6 +471,7 @@ retype: "Enter again"
 noteOf: "Note by {user}"
 quoteAttached: "Quote"
 quoteQuestion: "Append as quote?"
+attachAsFileQuestion: "The text in clipboard is long. Would you want to attach it as text file?"
 noMessagesYet: "No messages yet"
 newMessageExists: "There are new messages"
 onlyOneFileCanBeAttached: "You can only attach one file to a message"
@@ -1235,6 +1239,15 @@ keepOriginalFilenameDescription: "If you turn off this setting, files names will
 noDescription: "There is not the explanation"
 alwaysConfirmFollow: "Always confirm when following"
 inquiry: "Contact"
+_delivery:
+  status: "Delivery status"
+  stop: "Suspended"
+  resume: "Delivery resume"
+  _type:
+    none: "Publishing"
+    manuallySuspended: "Manually suspended"
+    goneSuspended: "Server is suspended due to server deletion"
+    autoSuspendedForNotResponding: "Server is suspended due to no responding"
 _bubbleGame:
   howToPlay: "How to play"
   hold: "Hold"
@@ -2032,7 +2045,6 @@ _permissions:
   "read:admin:server-info": "View server info"
   "read:admin:show-moderation-log": "View moderation log"
   "read:admin:show-user": "View private user info"
-  "read:admin:show-users": "View private user info"
   "write:admin:suspend-user": "Suspend user"
   "write:admin:unset-user-avatar": "Remove user avatar"
   "write:admin:unset-user-banner": "Remove user banner"
diff --git a/locales/es-ES.yml b/locales/es-ES.yml
index 2e05364c31..5c8249ded5 100644
--- a/locales/es-ES.yml
+++ b/locales/es-ES.yml
@@ -1233,6 +1233,10 @@ useNativeUIForVideoAudioPlayer: "Usar la interfaz del navegador cuando se reprod
 keepOriginalFilename: "Mantener el nombre original del archivo"
 noDescription: "No hay descripción"
 alwaysConfirmFollow: "Confirmar siempre cuando se sigue a alguien"
+_delivery:
+  stop: "Suspendido"
+  _type:
+    none: "Publicando"
 _bubbleGame:
   howToPlay: "Cómo jugar"
   hold: "Mantener"
@@ -2029,7 +2033,6 @@ _permissions:
   "read:admin:server-info": "Ver información del servidor"
   "read:admin:show-moderation-log": "Ver log de moderación"
   "read:admin:show-user": "Ver información privada de usuario"
-  "read:admin:show-users": "Ver información privada de usuario"
   "write:admin:suspend-user": "Suspender cuentas de usuario"
   "write:admin:unset-user-avatar": "Quitar avatares de usuario"
   "write:admin:unset-user-banner": "Quitar banner de usuarios"
diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml
index 58a11a5cc4..8d66c3d375 100644
--- a/locales/fr-FR.yml
+++ b/locales/fr-FR.yml
@@ -1224,6 +1224,10 @@ enableHorizontalSwipe: "Glisser pour changer d'onglet"
 loading: "Chargement en cours"
 surrender: "Annuler"
 gameRetry: "Réessayer"
+_delivery:
+  stop: "Suspendu·e"
+  _type:
+    none: "Publié"
 _bubbleGame:
   howToPlay: "Comment jouer"
   hold: "Réserver"
diff --git a/locales/id-ID.yml b/locales/id-ID.yml
index f8e645d63b..7f509afa50 100644
--- a/locales/id-ID.yml
+++ b/locales/id-ID.yml
@@ -108,11 +108,14 @@ enterEmoji: "Masukkan emoji"
 renote: "Renote"
 unrenote: "Hapus renote"
 renoted: "Telah direnote"
+renotedToX: "{name} telah merenote"
 cantRenote: "Postingan ini tidak dapat direnote"
 cantReRenote: "Renote tidak dapat direnote"
 quote: "Kutip"
 inChannelRenote: "Hanya renote dalam kanal"
 inChannelQuote: "Hanya kutip dalam kanal"
+renoteToChannel: "Renote ke kanal"
+renoteToOtherChannel: "Renote ke kanal lainnya"
 pinnedNote: "Catatan yang disematkan"
 pinned: "Sematkan ke profil"
 you: "Kamu"
@@ -468,6 +471,7 @@ retype: "Masukkan ulang"
 noteOf: "Catatan milik {user}"
 quoteAttached: "Dikutip"
 quoteQuestion: "Apakah kamu ingin menambahkan kutipan?"
+attachAsFileQuestion: "Teks dalam papan klip terlalu panjang. Apakah kamu ingin melampirkannya sebagai berkas teks?"
 noMessagesYet: "Tidak ada pesan"
 newMessageExists: "Kamu mendapatkan pesan baru"
 onlyOneFileCanBeAttached: "Kamu hanya dapat melampirkan satu berkas ke dalam pesan"
@@ -1235,6 +1239,15 @@ keepOriginalFilenameDescription: "Apabila pengaturan ini dimatikan, nama berkas
 noDescription: "Tidak ada deskripsi"
 alwaysConfirmFollow: "Selalu konfirmasi ketika mengikuti"
 inquiry: "Hubungi kami"
+_delivery:
+  status: "Status pengiriman"
+  stop: "Ditangguhkan"
+  resume: "Lanjutkan pengiriman"
+  _type:
+    none: "Sedang menyiarkan langsung"
+    manuallySuspended: "Ditangguhkan manual"
+    goneSuspended: "Sedang ditangguhkan untuk penghapusan peladen"
+    autoSuspendedForNotResponding: "Sedang ditangguhkan karena peladen tidak menjawab"
 _bubbleGame:
   howToPlay: "Cara bermain"
   hold: "Tahan"
@@ -2032,7 +2045,6 @@ _permissions:
   "read:admin:server-info": "Lihat informasi peladen"
   "read:admin:show-moderation-log": "Lihat log moderasi"
   "read:admin:show-user": "Lihat informasi pengguna privat"
-  "read:admin:show-users": "Lihat informasi pengguna privat"
   "write:admin:suspend-user": "Tangguhkan pengguna"
   "write:admin:unset-user-avatar": "Hapus avatar pengguna"
   "write:admin:unset-user-banner": "Hapus banner pengguna"
diff --git a/locales/it-IT.yml b/locales/it-IT.yml
index 0a250a2e28..1d12a62cca 100644
--- a/locales/it-IT.yml
+++ b/locales/it-IT.yml
@@ -1233,6 +1233,10 @@ useNativeUIForVideoAudioPlayer: "Riprodurre audio/video usando le funzionalità
 keepOriginalFilename: "Mantieni il nome file originale"
 keepOriginalFilenameDescription: "Disattivandola, i file verranno caricati usando nomi casuali."
 noDescription: "Manca la descrizione"
+_delivery:
+  stop: "Sospensione"
+  _type:
+    none: "Pubblicazione"
 _bubbleGame:
   howToPlay: "Come giocare"
   hold: "Tieni"
@@ -2025,7 +2029,6 @@ _permissions:
   "read:admin:server-info": "Vedere le informazioni sul server"
   "read:admin:show-moderation-log": "Vedere lo storico di moderazione"
   "read:admin:show-user": "Vedere le informazioni private degli account utente"
-  "read:admin:show-users": "Vedere le informazioni private degli account utente"
   "write:admin:suspend-user": "Sospendere i profili"
   "write:admin:unset-user-avatar": "Rimuovere la foto profilo dai profili"
   "write:admin:unset-user-banner": "Rimuovere l'immagine testata dai profili"
diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml
index e6a23a34d7..7a33968e9e 100644
--- a/locales/ja-KS.yml
+++ b/locales/ja-KS.yml
@@ -1235,6 +1235,10 @@ keepOriginalFilenameDescription: "この設定をオフにすると、アップ
 noDescription: "説明文はあらへんで"
 alwaysConfirmFollow: "フォローの際常に確認する"
 inquiry: "問い合わせ"
+_delivery:
+  stop: "配信せぇへん"
+  _type:
+    none: "配信しとる"
 _bubbleGame:
   howToPlay: "遊び方"
   hold: "ホールド"
@@ -2032,7 +2036,6 @@ _permissions:
   "read:admin:server-info": "サーバーの情報見る"
   "read:admin:show-moderation-log": "モデレーションログ見る"
   "read:admin:show-user": "ユーザーのプライベートな情報見る"
-  "read:admin:show-users": "ユーザーのプライベートな情報見る"
   "write:admin:suspend-user": "ユーザーを凍結"
   "write:admin:unset-user-avatar": "ユーザーのアバターを削除"
   "write:admin:unset-user-banner": "ユーザーのバナーを削除"
diff --git a/locales/ko-GS.yml b/locales/ko-GS.yml
index c80a4d3997..9466aff01f 100644
--- a/locales/ko-GS.yml
+++ b/locales/ko-GS.yml
@@ -649,6 +649,10 @@ replies: "답하기"
 renotes: "리노트"
 attach: "옇기"
 surrender: "아이예"
+_delivery:
+  stop: "고만 보내예"
+  _type:
+    none: "보내고 잇어예"
 _initialAccountSetting:
   startTutorial: "길라잡이 하기"
 _initialTutorial:
diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml
index fc3a64acab..294a5a1520 100644
--- a/locales/ko-KR.yml
+++ b/locales/ko-KR.yml
@@ -1230,6 +1230,10 @@ useTotp: "일회용 비밀번호 사용"
 useBackupCode: "백업 코드 사용"
 launchApp: "앱 실행"
 useNativeUIForVideoAudioPlayer: "브라우저 UI에서 미디어 재생"
+_delivery:
+  stop: "정지됨"
+  _type:
+    none: "배포 중"
 _bubbleGame:
   howToPlay: "설명"
   hold: "홀드"
@@ -2021,7 +2025,6 @@ _permissions:
   "read:admin:server-info": "서버 정보 보기"
   "read:admin:show-moderation-log": "조정 기록 보기"
   "read:admin:show-user": "사용자 개인정보 보기"
-  "read:admin:show-users": "사용자 개인정보 보기"
   "write:admin:suspend-user": "사용자 정지하기"
   "write:admin:unset-user-avatar": "사용자 아바타 삭제하기"
   "write:admin:unset-user-banner": "사용자 배너 삭제하기"
diff --git a/locales/lo-LA.yml b/locales/lo-LA.yml
index fa4b3b6f9a..087bac3745 100644
--- a/locales/lo-LA.yml
+++ b/locales/lo-LA.yml
@@ -395,6 +395,10 @@ searchByGoogle: "ຄົ້ນຫາ"
 file: "ໄຟລ໌"
 replies: "ຕອບ​ໄປ​ທີ"
 renotes: "Renote"
+_delivery:
+  stop: "ໂຈະ"
+  _type:
+    none: "ການ​ພິມ​ເຜີຍ​ແຜ່"
 _role:
   _priority:
     middle: "ປານກາງ"
diff --git a/locales/nl-NL.yml b/locales/nl-NL.yml
index e33b978bc8..eb48cf72da 100644
--- a/locales/nl-NL.yml
+++ b/locales/nl-NL.yml
@@ -429,6 +429,10 @@ loggedInAsBot: "Momenteel als bot ingelogd"
 icon: "Avatar"
 replies: "Antwoord"
 renotes: "Herdelen"
+_delivery:
+  stop: "Opgeschort"
+  _type:
+    none: "Publiceren"
 _email:
   _follow:
     title: "volgde jou"
diff --git a/locales/no-NO.yml b/locales/no-NO.yml
index 475f93267b..2b4c9b7776 100644
--- a/locales/no-NO.yml
+++ b/locales/no-NO.yml
@@ -464,6 +464,8 @@ icon: "Avatar"
 replies: "Svar"
 renotes: "Renote"
 surrender: "Avbryt"
+_delivery:
+  stop: "Suspendert"
 _initialAccountSetting:
   theseSettingsCanEditLater: "Du kan endre disse innstillingene senere."
 _achievements:
diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml
index 2183aa3022..9d75f7a9d7 100644
--- a/locales/pl-PL.yml
+++ b/locales/pl-PL.yml
@@ -1023,6 +1023,10 @@ flip: "Odwróć"
 lastNDays: "W ciągu ostatnich {n} dni"
 surrender: "Odrzuć"
 gameRetry: "Spróbuj ponownie"
+_delivery:
+  stop: "Zawieszono"
+  _type:
+    none: "Publikowanie"
 _bubbleGame:
   _score:
     score: "Wynik"
diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml
index e00f5750dd..cfc576b6e1 100644
--- a/locales/pt-PT.yml
+++ b/locales/pt-PT.yml
@@ -1012,6 +1012,10 @@ keepScreenOn: "Manter a tela do dispositivo sempre ligada"
 flip: "Inversão"
 lastNDays: "Últimos {n} dias"
 surrender: "Cancelar"
+_delivery:
+  stop: "Suspenso"
+  _type:
+    none: "Publicando"
 _initialAccountSetting:
   followUsers: "Siga usuários que lhe interessam para criar a sua linha do tempo."
 _serverSettings:
diff --git a/locales/ro-RO.yml b/locales/ro-RO.yml
index 695eb2501f..328d34405e 100644
--- a/locales/ro-RO.yml
+++ b/locales/ro-RO.yml
@@ -651,6 +651,10 @@ show: "Arată"
 icon: "Avatar"
 replies: "Răspunde"
 renotes: "Re-notează"
+_delivery:
+  stop: "Suspendat"
+  _type:
+    none: "Publicare"
 _role:
   _priority:
     middle: "Mediu"
diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml
index 66e032f16f..71f5cad601 100644
--- a/locales/ru-RU.yml
+++ b/locales/ru-RU.yml
@@ -1099,6 +1099,10 @@ flip: "Переворот"
 code: "Код"
 lastNDays: "Последние {n} сут"
 surrender: "Этот пост не может быть отменен."
+_delivery:
+  stop: "Заморожено"
+  _type:
+    none: "Публикация"
 _initialAccountSetting:
   accountCreated: "Аккаунт успешно создан!"
   letsStartAccountSetup: "Давайте настроим вашу учётную запись."
diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml
index 0978701e55..52f6bf142c 100644
--- a/locales/sk-SK.yml
+++ b/locales/sk-SK.yml
@@ -922,6 +922,10 @@ renotes: "Preposlať"
 sourceCode: "Zdrojový kód"
 flip: "Preklopiť"
 lastNDays: "Posledných {n} dní"
+_delivery:
+  stop: "Zmrazené"
+  _type:
+    none: "Zverejňovanie"
 _role:
   priority: "Priorita"
   _priority:
diff --git a/locales/sv-SE.yml b/locales/sv-SE.yml
index 62bc71a13d..089dc3949f 100644
--- a/locales/sv-SE.yml
+++ b/locales/sv-SE.yml
@@ -488,6 +488,10 @@ dataSaver: "Databesparing"
 icon: "Profilbild"
 replies: "Svara"
 renotes: "Omnotera"
+_delivery:
+  stop: "Suspenderad"
+  _type:
+    none: "Publiceras"
 _achievements:
   _types:
     _open3windows:
diff --git a/locales/th-TH.yml b/locales/th-TH.yml
index 020b954854..ab09ac4d5a 100644
--- a/locales/th-TH.yml
+++ b/locales/th-TH.yml
@@ -1235,6 +1235,10 @@ keepOriginalFilenameDescription: "หากปิดการตั้งค่
 noDescription: "ไม่มีข้อความอธิบาย"
 alwaysConfirmFollow: "แสดงข้อความยืนยันเมื่อกดติดตาม"
 inquiry: "ติดต่อเรา"
+_delivery:
+  stop: "ถูกระงับ"
+  _type:
+    none: "กำลังเผยแพร่"
 _bubbleGame:
   howToPlay: "วิธีเล่น"
   hold: "หยุดชั่วคราว"
@@ -2032,7 +2036,6 @@ _permissions:
   "read:admin:server-info": "ดูข้อมูลเซิร์ฟเวอร์"
   "read:admin:show-moderation-log": "ดูปูมการแก้ไข"
   "read:admin:show-user": "ดูข้อมูลส่วนตัวของผู้ใช้"
-  "read:admin:show-users": "ดูข้อมูลส่วนตัวของผู้ใช้"
   "write:admin:suspend-user": "ระงับผู้ใช้"
   "write:admin:unset-user-avatar": "ลบอวตารผู้ใช้"
   "write:admin:unset-user-banner": "ลบแบนเนอร์ผู้ใช้"
diff --git a/locales/tr-TR.yml b/locales/tr-TR.yml
index 0793592d34..cf6729a81d 100644
--- a/locales/tr-TR.yml
+++ b/locales/tr-TR.yml
@@ -378,6 +378,10 @@ addMemo: "Kısa not ekle"
 icon: "Avatar"
 replies: "yanıt"
 renotes: "vazgeçme"
+_delivery:
+  stop: "Askıya alınmış"
+  _type:
+    none: "Paylaşım"
 _accountDelete:
   started: "Silme işlemi başlatıldı"
 _email:
diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml
index 0ce5dc1202..661ecf19d7 100644
--- a/locales/uk-UA.yml
+++ b/locales/uk-UA.yml
@@ -914,6 +914,10 @@ renotes: "Поширити"
 sourceCode: "Вихідний код"
 flip: "Перевернути"
 lastNDays: "Останні {n} днів"
+_delivery:
+  stop: "Призупинено"
+  _type:
+    none: "Публікація"
 _achievements:
   earnedAt: "Відкрито"
   _types:
diff --git a/locales/uz-UZ.yml b/locales/uz-UZ.yml
index 809e785492..4a930626f4 100644
--- a/locales/uz-UZ.yml
+++ b/locales/uz-UZ.yml
@@ -846,6 +846,10 @@ icon: "Avatar"
 replies: "Javob berish"
 renotes: "Qayta qayd etish"
 flip: "Teskari"
+_delivery:
+  stop: "To'xtatilgan"
+  _type:
+    none: "Yuborilmoqda"
 _achievements:
   _types:
     _viewInstanceChart:
diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml
index d9c21d29ad..acc2e0c6a9 100644
--- a/locales/vi-VN.yml
+++ b/locales/vi-VN.yml
@@ -1118,6 +1118,10 @@ pullDownToRefresh: "Kéo xuống để làm mới"
 cwNotationRequired: "Nếu \"Ẩn nội dung\" được bật thì cần phải có chú thích."
 lastNDays: "{n} ngày trước"
 surrender: "Từ chối"
+_delivery:
+  stop: "Đã vô hiệu hóa"
+  _type:
+    none: "Đang đăng"
 _announcement:
   forExistingUsers: "Chỉ những người dùng đã tồn tại"
   forExistingUsersDescription: "Nếu được bật, thông báo này sẽ chỉ hiển thị với những người dùng đã tồn tại vào lúc thông báo được tạo. Nếu tắt đi, những tài khoản mới đăng ký sau khi thông báo được đăng lên cũng sẽ thấy nó."
diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index 17164dfe98..3e500f8642 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -471,6 +471,7 @@ retype: "重新输入"
 noteOf: "{user} 的帖子"
 quoteAttached: "已引用"
 quoteQuestion: "是否引用此链接内容?"
+attachAsFileQuestion: "剪贴板内的文字过长。要转换为文本文件并添加吗?"
 noMessagesYet: "现在没有新的聊天"
 newMessageExists: "新信息"
 onlyOneFileCanBeAttached: "只能添加一个附件"
@@ -1024,6 +1025,7 @@ thisPostMayBeAnnoyingHome: "发到首页"
 thisPostMayBeAnnoyingCancel: "取消"
 thisPostMayBeAnnoyingIgnore: "就这样发布"
 collapseRenotes: "省略显示已经看过的转发内容"
+collapseRenotesDescription: "将回应过或转贴过的贴子折叠表示。"
 internalServerError: "内部服务器错误"
 internalServerErrorDescription: "内部服务器发生了预期外的错误"
 copyErrorInfo: "复制错误信息"
@@ -1238,6 +1240,15 @@ keepOriginalFilenameDescription: "若关闭此设置,上传文件时文件名
 noDescription: "没有描述"
 alwaysConfirmFollow: "总是确认关注"
 inquiry: "联系我们"
+_delivery:
+  status: "投递状态"
+  stop: "停止投递"
+  resume: "继续投递"
+  _type:
+    none: "投递中"
+    manuallySuspended: "手动停止中"
+    goneSuspended: "因服务器被删除而停止"
+    autoSuspendedForNotResponding: "因服务器无应答而停止"
 _bubbleGame:
   howToPlay: "游戏说明"
   hold: "抓住"
@@ -1696,8 +1707,10 @@ _role:
     roleAssignedTo: "已分配给手动角色"
     isLocal: "是本地用户"
     isRemote: "是远程用户"
+    isCat: "猫猫用户"
     isBot: "机器人用户"
     isSuspended: "停用的用户"
+    isLocked: "锁推用户"
     isExplorable: "启用“使账号可见”的用户"
     createdLessThan: "账户创建时间少于"
     createdMoreThan: "账户创建时间超过"
@@ -2032,7 +2045,6 @@ _permissions:
   "read:admin:server-info": "查看服务器信息"
   "read:admin:show-moderation-log": "查看管理日志"
   "read:admin:show-user": "查看用户的非公开信息"
-  "read:admin:show-users": "查看用户的非公开信息"
   "write:admin:suspend-user": "冻结用户"
   "write:admin:unset-user-avatar": "删除用户头像"
   "write:admin:unset-user-banner": "删除用户横幅"
diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml
index 8cde13052f..fed7b642dc 100644
--- a/locales/zh-TW.yml
+++ b/locales/zh-TW.yml
@@ -108,11 +108,14 @@ enterEmoji: "輸入表情符號"
 renote: "轉發"
 unrenote: "取消轉發"
 renoted: "轉發成功。"
+renotedToX: "轉發給 {name} 了。"
 cantRenote: "無法轉發此貼文。"
 cantReRenote: "無法轉發之前已經轉發過的內容。"
 quote: "引用"
 inChannelRenote: "在頻道內轉發"
 inChannelQuote: "在頻道內引用"
+renoteToChannel: "轉發至頻道"
+renoteToOtherChannel: "轉發至其他頻道"
 pinnedNote: "已置頂的貼文"
 pinned: "置頂"
 you: "您"
@@ -169,7 +172,7 @@ cacheRemoteSensitiveFilesDescription: "若停用這個設定,則不會快取
 flagAsBot: "此使用者是機器人"
 flagAsBotDescription: "如果本帳戶是由程式控制,請啟用此選項。啟用後,會作為標示幫助其他開發者防止機器人之間產生無限互動的行為,並會調整 Misskey 內部系統將本帳戶識別為機器人。"
 flagAsCat: "此帳戶是一隻貓,喵~~~!!!"
-flagAsCatDescription: "如果想將本帳戶標示為一隻貓,請開啟此標示"
+flagAsCatDescription: "喵喵喵??"
 flagShowTimelineReplies: "在時間軸上顯示貼文的回覆"
 flagShowTimelineRepliesDescription: "啟用後,時間軸除了顯示使用者的貼文以外,還會顯示使用者對其他貼文的回覆。"
 autoAcceptFollowed: "自動允許來自追隨中使用者的追隨請求"
@@ -366,7 +369,7 @@ enableRegistration: "開放新使用者註冊"
 invite: "邀請"
 driveCapacityPerLocalAccount: "每個本地使用者的雲端硬碟容量"
 driveCapacityPerRemoteAccount: "每個非本地用戶的雲端空間大小"
-inMb: "以Mbps為單位"
+inMb: "以 MB 為單位"
 bannerUrl: "橫幅圖片URL"
 backgroundImageUrl: "背景圖片的來源網址 "
 basicInfo: "基本資訊"
@@ -378,12 +381,12 @@ pinnedClipId: "置頂的摘錄ID"
 pinnedNotes: "已置頂的貼文"
 hcaptcha: "hCaptcha"
 enableHcaptcha: "啟用 hCaptcha"
-hcaptchaSiteKey: "網站金鑰"
-hcaptchaSecretKey: "金鑰"
+hcaptchaSiteKey: "hcaptchaSiteKey"
+hcaptchaSecretKey: "hcaptchaSecretKey"
 mcaptcha: "mCaptcha"
 enableMcaptcha: "啟用 mCaptcha"
 mcaptchaSiteKey: "網站金鑰"
-mcaptchaSecretKey: "金鑰"
+mcaptchaSecretKey: "私密金鑰"
 mcaptchaInstanceUrl: "mCaptcha 的實例網址"
 recaptcha: "reCAPTCHA"
 enableRecaptcha: "啟用 reCAPTCHA"
@@ -391,8 +394,8 @@ recaptchaSiteKey: "網站金鑰"
 recaptchaSecretKey: "金鑰"
 turnstile: "Turnstile"
 enableTurnstile: "啟用 Turnstile"
-turnstileSiteKey: "網站金鑰"
-turnstileSecretKey: "金鑰"
+turnstileSiteKey: "turnstileSiteKey"
+turnstileSecretKey: "turnstileSecretKey"
 avoidMultiCaptchaConfirm: "使用多種驗證方式可能會造成干擾,您要關閉其他驗證方式嗎?您可以按「取消」保留多種驗證方式。"
 antennas: "天線"
 manageAntennas: "管理天線"
@@ -464,10 +467,11 @@ title: "標題"
 text: "文字"
 enable: "啟用"
 next: "下一步"
-retype: "再次輸入"
+retype: "重新輸入"
 noteOf: "{user}的貼文"
 quoteAttached: "引用"
 quoteQuestion: "是否要引用?"
+attachAsFileQuestion: "剪貼簿的文字較長。請問是否要改成附加檔案呢?"
 noMessagesYet: "沒有訊息"
 newMessageExists: "有新的訊息"
 onlyOneFileCanBeAttached: "只能加入一個附件"
@@ -602,7 +606,7 @@ addItem: "新增項目"
 rearrange: "排序方式"
 relays: "中繼器"
 addRelay: "新增中繼器"
-inboxUrl: "收件夾URL"
+inboxUrl: "收件夾 URL"
 addedRelays: "已加入的中繼器"
 serviceworkerInfo: "如要使用推播通知,需要啟用此選項並設定金鑰。"
 deletedNote: "已刪除的貼文"
@@ -791,7 +795,7 @@ newVersionOfClientAvailable: "新版本的客戶端可用。"
 usageAmount: "使用量"
 capacity: "容量"
 inUse: "已使用"
-editCode: "編輯代碼"
+editCode: "編輯程式碼"
 apply: "套用"
 receiveAnnouncementFromInstance: "接收來自伺服器的通知"
 emailNotification: "郵件通知"
@@ -1062,7 +1066,7 @@ enableChartsForFederatedInstances: "生成遠端伺服器的圖表"
 showClipButtonInNoteFooter: "新增摘錄按鈕至貼文"
 reactionsDisplaySize: "反應的顯示尺寸"
 limitWidthOfReaction: "限制反應的最大寬度,並縮小顯示尺寸。"
-noteIdOrUrl: "貼文ID或URL"
+noteIdOrUrl: "貼文 ID 或 URL"
 video: "影片"
 videos: "影片"
 audio: "音效"
@@ -1077,7 +1081,7 @@ addMemo: "新增備註"
 editMemo: "編輯備註"
 reactionsList: "反應列表"
 renotesList: "轉發貼文列表"
-notificationDisplay: "通知的顯示"
+notificationDisplay: "通知"
 leftTop: "左上"
 rightTop: "右上"
 leftBottom: "左下"
@@ -1179,15 +1183,15 @@ repositoryUrlOrTarballRequired: "如果儲存庫不是公開的,則必須提
 feedback: "意見回饋"
 feedbackUrl: "意見回饋 URL"
 impressum: "營運者資訊"
-impressumUrl: "營運者資訊網址"
+impressumUrl: "營運者資訊 URL"
 impressumDescription: "在德國與部份地區必須要明確顯示營運者資訊。"
 privacyPolicy: "隱私政策"
-privacyPolicyUrl: "隱私政策網址"
+privacyPolicyUrl: "隱私政策 URL"
 tosAndPrivacyPolicy: "服務條款和隱私政策"
 avatarDecorations: "頭像裝飾"
 attach: "裝上"
 detach: "取下"
-detachAll: "移除所有裝飾"
+detachAll: "全部移除"
 angle: "角度"
 flip: "翻轉"
 showAvatarDecorations: "顯示頭像裝飾"
@@ -1205,7 +1209,7 @@ remainingN: "剩餘:{n}"
 overwriteContentConfirm: "確定要覆蓋目前的內容嗎?"
 seasonalScreenEffect: "隨季節變換畫面的呈現"
 decorate: "設置頭像裝飾"
-addMfmFunction: "插入MFM功能語法"
+addMfmFunction: "插入 MFM 功能語法"
 enableQuickAddMfmFunction: "顯示高級 MFM 選擇器"
 bubbleGame: "氣泡遊戲"
 sfx: "音效"
@@ -1225,16 +1229,25 @@ enableHorizontalSwipe: "滑動切換時間軸"
 loading: "載入中"
 surrender: "退出"
 gameRetry: "再試一次"
-notUsePleaseLeaveBlank: "如不使用,請留空"
+notUsePleaseLeaveBlank: "如果不使用的話請留白"
 useTotp: "使用一次性密碼"
 useBackupCode: "使用備用驗證碼"
-launchApp: "啟動 App"
+launchApp: "啟動 APP"
 useNativeUIForVideoAudioPlayer: "使用瀏覽器的 UI 播放影片與音訊"
 keepOriginalFilename: "保留原始檔名"
 keepOriginalFilenameDescription: "如果關閉此設置,上傳時檔案名稱會自動替換為隨機字串。"
 noDescription: "沒有說明文字"
 alwaysConfirmFollow: "點擊追隨時總是顯示確認訊息"
 inquiry: "聯絡我們"
+_delivery:
+  status: "傳送狀態"
+  stop: "已凍結"
+  resume: "繼續傳送"
+  _type:
+    none: "直播中"
+    manuallySuspended: "手動暫停中"
+    goneSuspended: "因為伺服器刪除所以暫停中"
+    autoSuspendedForNotResponding: "因為伺服器沒有回應所以暫停中"
 _bubbleGame:
   howToPlay: "玩法說明"
   hold: "保留"
@@ -1243,7 +1256,7 @@ _bubbleGame:
     scoreYen: "賺取的金額"
     highScore: "最高分"
     maxChain: "最大結合數"
-    yen: "{yen} 日圓"
+    yen: "{yen}円"
     estimatedQty: "{qty}個"
     scoreSweets: "飯糰 {onigiriQtyWithUnit}"
   _howToPlay:
@@ -1271,7 +1284,7 @@ _initialAccountSetting:
   privacySetting: "隱私設定"
   theseSettingsCanEditLater: "這裡的設定可以在之後變更。"
   youCanEditMoreSettingsInSettingsPageLater: "除此之外,還可以在「設定」頁面進行各種設定。之後請確認看看。"
-  followUsers: "為了構築時間軸,試著追蹤您感興趣的使用者吧。"
+  followUsers: "為了構築時間軸,試著追隨您感興趣的使用者吧。"
   pushNotificationDescription: "啟用推送通知,就可以在設備上接收{name}的通知。"
   initialAccountSettingCompleted: "初始設定完成了!"
   haveFun: "盡情享受{name}吧!"
@@ -1326,7 +1339,7 @@ _initialTutorial:
       title: "隱藏內容(CW)"
       description: "將顯示「註釋」中寫入的內容而不是本文。按一下「顯示內容」以顯示本文。"
       _exampleNote:
-        cw: "美食恐怖主義注意"
+        cw: "注意消夜文"
         note: "我吃了一個巧克力甜甜圈🍩😋"
       useCases: "伺服器的服務條款可能會規範特定的貼文需要使用隱藏內容,除此之外也會用在隱藏劇情洩漏與敏感內容的貼文。"
   _howToMakeAttachmentsSensitive:
@@ -1351,7 +1364,7 @@ _serverRules:
 _serverSettings:
   iconUrl: "圖示的 URL"
   appIconDescription: "指定顯示 {host} 為應用程式時的圖示。"
-  appIconUsageExample: "例如:漸進式網路應用程式(PWA)、於手機桌面新增書籤"
+  appIconUsageExample: "例如:PWA 或是在手機桌面作為書籤等"
   appIconStyleRecommendation: "因為可能會裁剪成圓形或圓角,所以建議用單色填滿邊框及背景。"
   appIconResolutionMustBe: "解析度必須為 {resolution}。"
   manifestJsonOverride: "覆寫 manifest.json"
@@ -1559,7 +1572,7 @@ _achievements:
     _postedAt0min0sec:
       title: "報時"
       description: "在零分零秒發佈貼文"
-      flavor: "啵、啵、啵、嗶ーー"
+      flavor: "啵.啵.啵.嗶ー"
     _selfQuote:
       title: "自我引用"
       description: "引用了自己的貼文"
@@ -1694,8 +1707,8 @@ _role:
     roleAssignedTo: "手動指派角色完成"
     isLocal: "本地使用者"
     isRemote: "遠端使用者"
-    isCat: "使用者是貓"
-    isBot: "使用者是機器人"
+    isCat: "貓使用者"
+    isBot: "機器人使用者"
     isSuspended: "被停權的使用者"
     isLocked: "上鎖的使用者"
     isExplorable: "開啟了「使您的帳戶更容易被找到」功能的使用者"
@@ -1857,7 +1870,7 @@ _theme:
   invalid: "佈景主題格式錯誤"
   make: "製作佈景主題"
   base: "基於"
-  addConstant: "添加常數"
+  addConstant: "新增常數"
   constant: "常數"
   defaultValue: "預設值"
   color: "顏色"
@@ -1932,22 +1945,22 @@ _soundSettings:
 _ago:
   future: "未來"
   justNow: "剛剛"
-  secondsAgo: "{n} 秒前"
-  minutesAgo: "{n} 分鐘前 "
-  hoursAgo: "{n} 小時前"
-  daysAgo: "{n} 天前"
-  weeksAgo: "{n} 週前"
-  monthsAgo: "{n} 個月前"
-  yearsAgo: "{n} 年前"
+  secondsAgo: "{n}秒前"
+  minutesAgo: "{n}分鐘前"
+  hoursAgo: "{n}小時前"
+  daysAgo: "{n}天前"
+  weeksAgo: "{n}周前"
+  monthsAgo: "{n}個月前"
+  yearsAgo: "{n}年前"
   invalid: "無"
 _timeIn:
-  seconds: "{n} 秒後"
-  minutes: "{n} 分後"
-  hours: "{n} 小時後"
-  days: "{n} 日後"
-  weeks: "{n} 週後"
-  months: "{n} 個月後"
-  years: "{n} 年後"
+  seconds: "{n}秒後"
+  minutes: "{n}分鐘後"
+  hours: "{n}小時後"
+  days: "{n}天後"
+  weeks: "{n}周後"
+  months: "{n}個月後"
+  years: "{n}年後"
 _time:
   second: "秒"
   minute: "分鐘"
@@ -2032,7 +2045,6 @@ _permissions:
   "read:admin:server-info": "查看伺服器的資訊"
   "read:admin:show-moderation-log": "查看審查紀錄"
   "read:admin:show-user": "查看使用者的私密資訊"
-  "read:admin:show-users": "查看使用者的私密資訊"
   "write:admin:suspend-user": "凍結使用者"
   "write:admin:unset-user-avatar": "刪除使用者的頭像"
   "write:admin:unset-user-banner": "刪除使用者的橫幅"
@@ -2085,13 +2097,13 @@ _antennaSources:
   userList: "來自特定清單中的貼文"
   userBlacklist: "除指定使用者外的所有貼文"
 _weekday:
-  sunday: "週日"
-  monday: "週一"
-  tuesday: "週二"
-  wednesday: "週三"
-  thursday: "週四"
-  friday: "週五"
-  saturday: "週六"
+  sunday: "星期天"
+  monday: "星期一"
+  tuesday: "星期二"
+  wednesday: "星期三"
+  thursday: "星期四"
+  friday: "星期五"
+  saturday: "星期六"
 _widgets:
   profile: "個人檔案"
   instanceInfo: "伺服器資訊"
@@ -2140,7 +2152,7 @@ _poll:
   deadlineDate: "截止日期"
   deadlineTime: "小時"
   duration: "時長"
-  votesCount: "{n} 票"
+  votesCount: "{n}票"
   totalVotes: "合計 {n} 票"
   vote: "投票"
   showResult: "顯示結果"
@@ -2173,7 +2185,7 @@ _postForm:
     e: "寫些什麼吧……"
     f: "靜待發文……"
 _profile:
-  name: "名稱"
+  name: "名字"
   username: "使用者名稱"
   description: "關於我"
   youCanIncludeHashtags: "你也可以在「關於我」中加上 #tag"
@@ -2231,10 +2243,10 @@ _timelines:
 _play:
   new: "新增 Play"
   edit: "編輯 Play"
-  created: "已新增Play "
-  updated: "已更新Play "
+  created: "已新增 Play "
+  updated: "已更新 Play "
   deleted: "已刪除 Play"
-  pageSetting: "Play設定"
+  pageSetting: "Play 設定"
   editThisPage: "編輯此 Play"
   viewSource: "檢視原始碼"
   my: "自己的 Play"
@@ -2247,7 +2259,7 @@ _play:
 _pages:
   newPage: "建立頁面"
   editPage: "編輯頁面"
-  readPage: "正檢視原始碼"
+  readPage: "正在檢視原始碼"
   created: "頁面已建立"
   updated: "頁面已更新"
   deleted: "頁面已被刪除"
@@ -2274,7 +2286,7 @@ _pages:
   hideTitleWhenPinned: "被置頂於個人資料時隱藏頁面標題"
   font: "字型"
   fontSerif: "襯線體"
-  fontSansSerif: "無襯線體"
+  fontSansSerif: "黑體"
   eyeCatchingImageSet: "設定封面影像"
   eyeCatchingImageRemove: "刪除封面影像"
   chooseBlock: "新增方塊"
@@ -2384,7 +2396,7 @@ _drivecleaner:
   orderByCreatedAtAsc: "按新增日期降序排列"
 _webhookSettings:
   createWebhook: "建立 Webhook"
-  name: "名稱"
+  name: "名字"
   secret: "密鑰"
   events: "何時運行 Webhook"
   active: "已啟用"

From 4579be0f5401001bcfc27c4d56133cc910f3f581 Mon Sep 17 00:00:00 2001
From: anatawa12 <anatawa12@icloud.com>
Date: Mon, 27 May 2024 20:54:53 +0900
Subject: [PATCH 158/191] =?UTF-8?q?=E6=96=B0=E7=9D=80=E3=83=8E=E3=83=BC?=
 =?UTF-8?q?=E3=83=88=E3=82=92=E3=82=B5=E3=82=A6=E3=83=B3=E3=83=89=E3=81=A7?=
 =?UTF-8?q?=E9=80=9A=E7=9F=A5=E3=81=99=E3=82=8B=E6=A9=9F=E8=83=BD=E3=82=92?=
 =?UTF-8?q?deck=20UI=E3=81=AB=E8=BF=BD=E5=8A=A0=20(#13867)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* feat(deck-ui): implement note notification

* chore: remove notify in antenna

* docs(changelog): 新着ノートをサウンドで通知する機能をdeck UIに追加

* fix: type error in test

* lint: key order

* fix: remove notify column

* test: remove test for notify

* chore: make sound selectable

* fix: add license header

* fix: add license header again

* Unnecessary await

Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>

* ファイルを選択してください -> ファイルが選択されていません

* fix: i18n忘れ

* fix: i18n忘れ

* pleaseSelectFile > fileNotSelected

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>
---
 CHANGELOG.md                                  |   1 +
 locales/index.d.ts                            |   8 ++
 locales/ja-JP.yml                             |   2 +
 .../1716450883149-RemoveAntennaNotify.js      |  16 +++
 .../src/core/entities/AntennaEntityService.ts |   1 -
 packages/backend/src/models/Antenna.ts        |   3 -
 .../backend/src/models/json-schema/antenna.ts |   4 -
 .../ExportAntennasProcessorService.ts         |   1 -
 .../ImportAntennasProcessorService.ts         |   4 +-
 .../server/api/endpoints/antennas/create.ts   |   4 +-
 .../server/api/endpoints/antennas/update.ts   |   2 -
 packages/backend/test/e2e/antennas.ts         |   4 -
 packages/backend/test/e2e/move.ts             |   2 -
 .../src/components/MkFormDialog.file.vue      |  71 ++++++++++++
 .../frontend/src/components/MkFormDialog.vue  |  12 +-
 packages/frontend/src/os.ts                   |   2 +-
 .../frontend/src/pages/my-antennas/editor.vue |   3 -
 packages/frontend/src/scripts/form.ts         |  30 +++--
 .../frontend/src/ui/deck/antenna-column.vue   |  24 +++-
 .../frontend/src/ui/deck/channel-column.vue   |  23 +++-
 packages/frontend/src/ui/deck/deck-store.ts   |   2 +
 packages/frontend/src/ui/deck/list-column.vue |  22 +++-
 .../src/ui/deck/role-timeline-column.vue      |  23 +++-
 packages/frontend/src/ui/deck/tl-column.vue   |  20 +++-
 .../src/ui/deck/tl-note-notification.ts       | 107 ++++++++++++++++++
 packages/misskey-js/src/autogen/types.ts      |   3 -
 26 files changed, 341 insertions(+), 53 deletions(-)
 create mode 100644 packages/backend/migration/1716450883149-RemoveAntennaNotify.js
 create mode 100644 packages/frontend/src/components/MkFormDialog.file.vue
 create mode 100644 packages/frontend/src/ui/deck/tl-note-notification.ts

diff --git a/CHANGELOG.md b/CHANGELOG.md
index f8463f8cbf..0a70fc7a8a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -49,6 +49,7 @@
 - Enhance: AiScriptを0.18.0にバージョンアップ
 - Enhance: 通常のノートでも、お気に入りに登録したチャンネルにリノートできるように
 - Enhance: 長いテキストをペーストした際にテキストファイルとして添付するかどうかを選択できるように
+- Enhance: 新着ノートをサウンドで通知する機能をdeck UIに追加しました
 - Enhance: コントロールパネルのクイックアクションからファイルを照会できるように
 - Enhance: コントロールパネルのクイックアクションから通常の照会を行えるように
 - Fix: 一部のページ内リンクが正しく動作しない問題を修正
diff --git a/locales/index.d.ts b/locales/index.d.ts
index eb7e297aa3..d4ded0bb5b 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -1280,6 +1280,10 @@ export interface Locale extends ILocale {
      * フォルダーを選択
      */
     "selectFolders": string;
+    /**
+     * ファイルが選択されていません
+     */
+    "fileNotSelected": string;
     /**
      * ファイル名を変更
      */
@@ -9143,6 +9147,10 @@ export interface Locale extends ILocale {
          * カラムを追加
          */
         "addColumn": string;
+        /**
+         * 新着ノート通知の設定
+         */
+        "newNoteNotificationSettings": string;
         /**
          * カラムの設定
          */
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index ebaf16745c..d7ceb971af 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -316,6 +316,7 @@ selectFile: "ファイルを選択"
 selectFiles: "ファイルを選択"
 selectFolder: "フォルダーを選択"
 selectFolders: "フォルダーを選択"
+fileNotSelected: "ファイルが選択されていません"
 renameFile: "ファイル名を変更"
 folderName: "フォルダー名"
 createFolder: "フォルダーを作成"
@@ -2420,6 +2421,7 @@ _deck:
   alwaysShowMainColumn: "常にメインカラムを表示"
   columnAlign: "カラムの寄せ"
   addColumn: "カラムを追加"
+  newNoteNotificationSettings: "新着ノート通知の設定"
   configureColumn: "カラムの設定"
   swapLeft: "左に移動"
   swapRight: "右に移動"
diff --git a/packages/backend/migration/1716450883149-RemoveAntennaNotify.js b/packages/backend/migration/1716450883149-RemoveAntennaNotify.js
new file mode 100644
index 0000000000..b5a2441855
--- /dev/null
+++ b/packages/backend/migration/1716450883149-RemoveAntennaNotify.js
@@ -0,0 +1,16 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class RemoveAntennaNotify1716450883149 {
+    name = 'RemoveAntennaNotify1716450883149'
+
+    async up(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "notify"`);
+    }
+
+    async down(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "antenna" ADD "notify" boolean NOT NULL`);
+    }
+}
diff --git a/packages/backend/src/core/entities/AntennaEntityService.ts b/packages/backend/src/core/entities/AntennaEntityService.ts
index 3ec8efa6bf..4a17a3d80f 100644
--- a/packages/backend/src/core/entities/AntennaEntityService.ts
+++ b/packages/backend/src/core/entities/AntennaEntityService.ts
@@ -38,7 +38,6 @@ export class AntennaEntityService {
 			users: antenna.users,
 			caseSensitive: antenna.caseSensitive,
 			localOnly: antenna.localOnly,
-			notify: antenna.notify,
 			excludeBots: antenna.excludeBots,
 			withReplies: antenna.withReplies,
 			withFile: antenna.withFile,
diff --git a/packages/backend/src/models/Antenna.ts b/packages/backend/src/models/Antenna.ts
index f5e819059e..33e6f48189 100644
--- a/packages/backend/src/models/Antenna.ts
+++ b/packages/backend/src/models/Antenna.ts
@@ -90,9 +90,6 @@ export class MiAntenna {
 	})
 	public expression: string | null;
 
-	@Column('boolean')
-	public notify: boolean;
-
 	@Index()
 	@Column('boolean', {
 		default: true,
diff --git a/packages/backend/src/models/json-schema/antenna.ts b/packages/backend/src/models/json-schema/antenna.ts
index 78cf6d3ba2..c4ac358fa6 100644
--- a/packages/backend/src/models/json-schema/antenna.ts
+++ b/packages/backend/src/models/json-schema/antenna.ts
@@ -72,10 +72,6 @@ export const packedAntennaSchema = {
 			optional: false, nullable: false,
 			default: false,
 		},
-		notify: {
-			type: 'boolean',
-			optional: false, nullable: false,
-		},
 		excludeBots: {
 			type: 'boolean',
 			optional: false, nullable: false,
diff --git a/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts b/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts
index 1d8e90f367..88c4ea29c0 100644
--- a/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts
+++ b/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts
@@ -84,7 +84,6 @@ export class ExportAntennasProcessorService {
 					excludeBots: antenna.excludeBots,
 					withReplies: antenna.withReplies,
 					withFile: antenna.withFile,
-					notify: antenna.notify,
 				}));
 				if (antennas.length - 1 !== index) {
 					write(', ');
diff --git a/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts b/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts
index ff1c04de06..e5b7c5ac52 100644
--- a/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts
+++ b/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts
@@ -47,9 +47,8 @@ const validate = new Ajv().compile({
 		excludeBots: { type: 'boolean' },
 		withReplies: { type: 'boolean' },
 		withFile: { type: 'boolean' },
-		notify: { type: 'boolean' },
 	},
-	required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile', 'notify'],
+	required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile'],
 });
 
 @Injectable()
@@ -92,7 +91,6 @@ export class ImportAntennasProcessorService {
 					excludeBots: antenna.excludeBots,
 					withReplies: antenna.withReplies,
 					withFile: antenna.withFile,
-					notify: antenna.notify,
 				}).then(x => this.antennasRepository.findOneByOrFail(x.identifiers[0]));
 				this.logger.succ('Antenna created: ' + result.id);
 				this.globalEventService.publishInternalEvent('antennaCreated', result);
diff --git a/packages/backend/src/server/api/endpoints/antennas/create.ts b/packages/backend/src/server/api/endpoints/antennas/create.ts
index 57c8eb4958..6b7bacb054 100644
--- a/packages/backend/src/server/api/endpoints/antennas/create.ts
+++ b/packages/backend/src/server/api/endpoints/antennas/create.ts
@@ -67,9 +67,8 @@ export const paramDef = {
 		excludeBots: { type: 'boolean' },
 		withReplies: { type: 'boolean' },
 		withFile: { type: 'boolean' },
-		notify: { type: 'boolean' },
 	},
-	required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile', 'notify'],
+	required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile'],
 } as const;
 
 @Injectable()
@@ -128,7 +127,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				excludeBots: ps.excludeBots,
 				withReplies: ps.withReplies,
 				withFile: ps.withFile,
-				notify: ps.notify,
 			}).then(x => this.antennasRepository.findOneByOrFail(x.identifiers[0]));
 
 			this.globalEventService.publishInternalEvent('antennaCreated', antenna);
diff --git a/packages/backend/src/server/api/endpoints/antennas/update.ts b/packages/backend/src/server/api/endpoints/antennas/update.ts
index e6720aacf8..0c30bca9e0 100644
--- a/packages/backend/src/server/api/endpoints/antennas/update.ts
+++ b/packages/backend/src/server/api/endpoints/antennas/update.ts
@@ -66,7 +66,6 @@ export const paramDef = {
 		excludeBots: { type: 'boolean' },
 		withReplies: { type: 'boolean' },
 		withFile: { type: 'boolean' },
-		notify: { type: 'boolean' },
 	},
 	required: ['antennaId'],
 } as const;
@@ -124,7 +123,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				excludeBots: ps.excludeBots,
 				withReplies: ps.withReplies,
 				withFile: ps.withFile,
-				notify: ps.notify,
 				isActive: true,
 				lastUsedAt: new Date(),
 			});
diff --git a/packages/backend/test/e2e/antennas.ts b/packages/backend/test/e2e/antennas.ts
index cf5c7dd130..4f78cc999d 100644
--- a/packages/backend/test/e2e/antennas.ts
+++ b/packages/backend/test/e2e/antennas.ts
@@ -38,7 +38,6 @@ describe('アンテナ', () => {
 		excludeKeywords: [['']],
 		keywords: [['keyword']],
 		name: 'test',
-		notify: false,
 		src: 'all' as const,
 		userListId: null,
 		users: [''],
@@ -151,7 +150,6 @@ describe('アンテナ', () => {
 			isActive: true,
 			keywords: [['keyword']],
 			name: 'test',
-			notify: false,
 			src: 'all',
 			userListId: null,
 			users: [''],
@@ -219,8 +217,6 @@ describe('アンテナ', () => {
 		{ parameters: () => ({ withReplies: true }) },
 		{ parameters: () => ({ withFile: false }) },
 		{ parameters: () => ({ withFile: true }) },
-		{ parameters: () => ({ notify: false }) },
-		{ parameters: () => ({ notify: true }) },
 	];
 	test.each(antennaParamPattern)('を作成できること($#)', async ({ parameters }) => {
 		const response = await successfulApiCall({
diff --git a/packages/backend/test/e2e/move.ts b/packages/backend/test/e2e/move.ts
index 4e5306da97..35050130dc 100644
--- a/packages/backend/test/e2e/move.ts
+++ b/packages/backend/test/e2e/move.ts
@@ -191,7 +191,6 @@ describe('Account Move', () => {
 				localOnly: false,
 				withReplies: false,
 				withFile: false,
-				notify: false,
 			}, alice);
 			antennaId = antenna.body.id;
 
@@ -435,7 +434,6 @@ describe('Account Move', () => {
 				localOnly: false,
 				withReplies: false,
 				withFile: false,
-				notify: false,
 			}, alice);
 
 			assert.strictEqual(res.status, 403);
diff --git a/packages/frontend/src/components/MkFormDialog.file.vue b/packages/frontend/src/components/MkFormDialog.file.vue
new file mode 100644
index 0000000000..9360594236
--- /dev/null
+++ b/packages/frontend/src/components/MkFormDialog.file.vue
@@ -0,0 +1,71 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<div>
+	<MkButton inline rounded primary @click="selectButton($event)">{{ i18n.ts.selectFile }}</MkButton>
+	<div :class="['_nowrap', !fileName && $style.fileNotSelected]">{{ friendlyFileName }}</div>
+</div>
+</template>
+
+<script setup lang="ts">
+import * as Misskey from 'misskey-js';
+import { computed, ref } from 'vue';
+import { i18n } from '@/i18n.js';
+import MkButton from '@/components/MkButton.vue';
+import { selectFile } from '@/scripts/select-file.js';
+import { misskeyApi } from '@/scripts/misskey-api.js';
+
+const props = defineProps<{
+	fileId?: string | null;
+	validate?: (file: Misskey.entities.DriveFile) => Promise<boolean>;
+}>();
+
+const emit = defineEmits<{
+	(ev: 'update', result: Misskey.entities.DriveFile): void;
+}>();
+
+const fileUrl = ref('');
+const fileName = ref<string>('');
+
+const friendlyFileName = computed<string>(() => {
+	if (fileName.value) {
+		return fileName.value;
+	}
+	if (fileUrl.value) {
+		return fileUrl.value;
+	}
+
+	return i18n.ts.fileNotSelected;
+});
+
+if (props.fileId) {
+	misskeyApi('drive/files/show', {
+		fileId: props.fileId,
+	}).then((apiRes) => {
+		fileName.value = apiRes.name;
+		fileUrl.value = apiRes.url;
+	});
+}
+
+function selectButton(ev: MouseEvent) {
+	selectFile(ev.currentTarget ?? ev.target).then(async (file) => {
+		if (!file) return;
+		if (props.validate && !await props.validate(file)) return;
+
+		emit('update', file);
+		fileName.value = file.name;
+		fileUrl.value = file.url;
+	});
+}
+
+</script>
+
+<style module>
+.fileNotSelected {
+	font-weight: 700;
+	color: var(--infoWarnFg);
+}
+</style>
diff --git a/packages/frontend/src/components/MkFormDialog.vue b/packages/frontend/src/components/MkFormDialog.vue
index deedc5badb..124f114111 100644
--- a/packages/frontend/src/components/MkFormDialog.vue
+++ b/packages/frontend/src/components/MkFormDialog.vue
@@ -21,8 +21,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 	<MkSpacer :marginMin="20" :marginMax="32">
 		<div v-if="Object.keys(form).filter(item => !form[item].hidden).length > 0" class="_gaps_m">
-			<template v-for="(v, k) in Object.fromEntries(Object.entries(form).filter(([_, v]) => !('hidden' in v) || 'hidden' in v && !v.hidden))">
-				<MkInput v-if="v.type === 'number'" v-model="values[k]" type="number" :step="v.step || 1">
+			<template v-for="(v, k) in Object.fromEntries(Object.entries(form))">
+				<template v-if="typeof v.hidden == 'function' ? v.hidden(values) : v.hidden"></template>
+				<MkInput v-else-if="v.type === 'number'" v-model="values[k]" type="number" :step="v.step || 1">
 					<template #label><span v-text="v.label || k"></span><span v-if="v.required === false"> ({{ i18n.ts.optional }})</span></template>
 					<template v-if="v.description" #caption>{{ v.description }}</template>
 				</MkInput>
@@ -53,6 +54,12 @@ SPDX-License-Identifier: AGPL-3.0-only
 				<MkButton v-else-if="v.type === 'button'" @click="v.action($event, values)">
 					<span v-text="v.content || k"></span>
 				</MkButton>
+				<XFile
+					v-else-if="v.type === 'drive-file'"
+					:fileId="v.defaultFileId"
+					:validate="async f => !v.validate || await v.validate(f)"
+					@update="f => values[k] = f"
+				/>
 			</template>
 		</div>
 		<div v-else class="_fullinfo">
@@ -72,6 +79,7 @@ import MkSelect from './MkSelect.vue';
 import MkRange from './MkRange.vue';
 import MkButton from './MkButton.vue';
 import MkRadios from './MkRadios.vue';
+import XFile from './MkFormDialog.file.vue';
 import type { Form } from '@/scripts/form.js';
 import MkModalWindow from '@/components/MkModalWindow.vue';
 import { i18n } from '@/i18n.js';
diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts
index c561e84a23..f656a52371 100644
--- a/packages/frontend/src/os.ts
+++ b/packages/frontend/src/os.ts
@@ -518,7 +518,7 @@ export function waiting(): Promise<void> {
 	});
 }
 
-export function form<F extends Form>(title: string, f: F): Promise<{ canceled: true } | { result: GetFormResultType<F> }> {
+export function form<F extends Form>(title: string, f: F): Promise<{ canceled: true, result?: undefined } | { canceled?: false, result: GetFormResultType<F> }> {
 	return new Promise(resolve => {
 		popup(defineAsyncComponent(() => import('@/components/MkFormDialog.vue')), { title, form: f }, {
 			done: result => {
diff --git a/packages/frontend/src/pages/my-antennas/editor.vue b/packages/frontend/src/pages/my-antennas/editor.vue
index 97edbc44ce..2949bfc02c 100644
--- a/packages/frontend/src/pages/my-antennas/editor.vue
+++ b/packages/frontend/src/pages/my-antennas/editor.vue
@@ -39,7 +39,6 @@ SPDX-License-Identifier: AGPL-3.0-only
 			<MkSwitch v-model="localOnly">{{ i18n.ts.localOnly }}</MkSwitch>
 			<MkSwitch v-model="caseSensitive">{{ i18n.ts.caseSensitive }}</MkSwitch>
 			<MkSwitch v-model="withFile">{{ i18n.ts.withFileAntenna }}</MkSwitch>
-			<MkSwitch v-model="notify">{{ i18n.ts.notifyAntenna }}</MkSwitch>
 		</div>
 		<div :class="$style.actions">
 			<MkButton inline primary @click="saveAntenna()"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
@@ -82,7 +81,6 @@ const localOnly = ref<boolean>(props.antenna.localOnly);
 const excludeBots = ref<boolean>(props.antenna.excludeBots);
 const withReplies = ref<boolean>(props.antenna.withReplies);
 const withFile = ref<boolean>(props.antenna.withFile);
-const notify = ref<boolean>(props.antenna.notify);
 const userLists = ref<Misskey.entities.UserList[] | null>(null);
 
 watch(() => src.value, async () => {
@@ -99,7 +97,6 @@ async function saveAntenna() {
 		excludeBots: excludeBots.value,
 		withReplies: withReplies.value,
 		withFile: withFile.value,
-		notify: notify.value,
 		caseSensitive: caseSensitive.value,
 		localOnly: localOnly.value,
 		users: users.value.trim().split('\n').map(x => x.trim()),
diff --git a/packages/frontend/src/scripts/form.ts b/packages/frontend/src/scripts/form.ts
index b0db404f28..242a504c3b 100644
--- a/packages/frontend/src/scripts/form.ts
+++ b/packages/frontend/src/scripts/form.ts
@@ -3,18 +3,22 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
+import * as Misskey from 'misskey-js';
+
 type EnumItem = string | {
 	label: string;
 	value: string;
 };
 
+type Hidden = boolean | ((v: any) => boolean);
+
 export type FormItem = {
 	label?: string;
 	type: 'string';
 	default: string | null;
 	description?: string;
 	required?: boolean;
-	hidden?: boolean;
+	hidden?: Hidden;
 	multiline?: boolean;
 	treatAsMfm?: boolean;
 } | {
@@ -23,27 +27,27 @@ export type FormItem = {
 	default: number | null;
 	description?: string;
 	required?: boolean;
-	hidden?: boolean;
+	hidden?: Hidden;
 	step?: number;
 } | {
 	label?: string;
 	type: 'boolean';
 	default: boolean | null;
 	description?: string;
-	hidden?: boolean;
+	hidden?: Hidden;
 } | {
 	label?: string;
 	type: 'enum';
 	default: string | null;
 	required?: boolean;
-	hidden?: boolean;
+	hidden?: Hidden;
 	enum: EnumItem[];
 } | {
 	label?: string;
 	type: 'radio';
 	default: unknown | null;
 	required?: boolean;
-	hidden?: boolean;
+	hidden?: Hidden;
 	options: {
 		label: string;
 		value: unknown;
@@ -58,20 +62,27 @@ export type FormItem = {
 	min: number;
 	max: number;
 	textConverter?: (value: number) => string;
+	hidden?: Hidden;
 } | {
 	label?: string;
 	type: 'object';
 	default: Record<string, unknown> | null;
-	hidden: boolean;
+	hidden: Hidden;
 } | {
 	label?: string;
 	type: 'array';
 	default: unknown[] | null;
-	hidden: boolean;
+	hidden: Hidden;
 } | {
 	type: 'button';
 	content?: string;
+	hidden?: Hidden;
 	action: (ev: MouseEvent, v: any) => void;
+} | {
+	type: 'drive-file';
+	defaultFileId?: string | null;
+	hidden?: Hidden;
+	validate?: (v: Misskey.entities.DriveFile) => Promise<boolean>;
 };
 
 export type Form = Record<string, FormItem>;
@@ -84,8 +95,9 @@ type GetItemType<Item extends FormItem> =
 	Item['type'] extends 'range' ? number :
 	Item['type'] extends 'enum' ? string :
 	Item['type'] extends 'array' ? unknown[] :
-	Item['type'] extends 'object' ? Record<string, unknown>
-	: never;
+	Item['type'] extends 'object' ? Record<string, unknown> :
+	Item['type'] extends 'drive-file' ? Misskey.entities.DriveFile | undefined :
+	never;
 
 export type GetFormResultType<F extends Form> = {
 	[P in keyof F]: GetItemType<F[P]>;
diff --git a/packages/frontend/src/ui/deck/antenna-column.vue b/packages/frontend/src/ui/deck/antenna-column.vue
index b42a21bf6f..c3dc1e4fce 100644
--- a/packages/frontend/src/ui/deck/antenna-column.vue
+++ b/packages/frontend/src/ui/deck/antenna-column.vue
@@ -9,18 +9,22 @@ SPDX-License-Identifier: AGPL-3.0-only
 		<i class="ti ti-antenna"></i><span style="margin-left: 8px;">{{ column.name }}</span>
 	</template>
 
-	<MkTimeline v-if="column.antennaId" ref="timeline" src="antenna" :antenna="column.antennaId"/>
+	<MkTimeline v-if="column.antennaId" ref="timeline" src="antenna" :antenna="column.antennaId" @note="onNote"/>
 </XColumn>
 </template>
 
 <script lang="ts" setup>
-import { onMounted, shallowRef } from 'vue';
+import { onMounted, ref, shallowRef, watch } from 'vue';
 import XColumn from './column.vue';
 import { updateColumn, Column } from './deck-store.js';
 import MkTimeline from '@/components/MkTimeline.vue';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { i18n } from '@/i18n.js';
+import { MenuItem } from '@/types/menu.js';
+import { SoundStore } from '@/store.js';
+import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
+import * as sound from '@/scripts/sound.js';
 
 const props = defineProps<{
 	column: Column;
@@ -28,6 +32,7 @@ const props = defineProps<{
 }>();
 
 const timeline = shallowRef<InstanceType<typeof MkTimeline>>();
+const soundSetting = ref<SoundStore>(props.column.soundSetting ?? { type: null, volume: 1 });
 
 onMounted(() => {
 	if (props.column.antennaId == null) {
@@ -35,6 +40,10 @@ onMounted(() => {
 	}
 });
 
+watch(soundSetting, v => {
+	updateColumn(props.column.id, { soundSetting: v });
+});
+
 async function setAntenna() {
 	const antennas = await misskeyApi('antennas/list');
 	const { canceled, result: antenna } = await os.select({
@@ -54,7 +63,11 @@ function editAntenna() {
 	os.pageWindow('my/antennas/' + props.column.antennaId);
 }
 
-const menu = [
+function onNote() {
+	sound.playMisskeySfxFile(soundSetting.value);
+}
+
+const menu: MenuItem[] = [
 	{
 		icon: 'ti ti-pencil',
 		text: i18n.ts.selectAntenna,
@@ -65,6 +78,11 @@ const menu = [
 		text: i18n.ts.editAntenna,
 		action: editAntenna,
 	},
+	{
+		icon: 'ti ti-bell',
+		text: i18n.ts._deck.newNoteNotificationSettings,
+		action: () => soundSettingsButton(soundSetting),
+	},
 ];
 
 /*
diff --git a/packages/frontend/src/ui/deck/channel-column.vue b/packages/frontend/src/ui/deck/channel-column.vue
index 28c741bba2..7c5b13eaf1 100644
--- a/packages/frontend/src/ui/deck/channel-column.vue
+++ b/packages/frontend/src/ui/deck/channel-column.vue
@@ -13,13 +13,13 @@ SPDX-License-Identifier: AGPL-3.0-only
 		<div style="padding: 8px; text-align: center;">
 			<MkButton primary gradate rounded inline small @click="post"><i class="ti ti-pencil"></i></MkButton>
 		</div>
-		<MkTimeline ref="timeline" src="channel" :channel="column.channelId"/>
+		<MkTimeline ref="timeline" src="channel" :channel="column.channelId" @note="onNote"/>
 	</template>
 </XColumn>
 </template>
 
 <script lang="ts" setup>
-import { shallowRef } from 'vue';
+import { ref, shallowRef, watch } from 'vue';
 import * as Misskey from 'misskey-js';
 import XColumn from './column.vue';
 import { updateColumn, Column } from './deck-store.js';
@@ -29,6 +29,10 @@ import * as os from '@/os.js';
 import { favoritedChannelsCache } from '@/cache.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { i18n } from '@/i18n.js';
+import { MenuItem } from '@/types/menu.js';
+import { SoundStore } from '@/store.js';
+import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
+import * as sound from '@/scripts/sound.js';
 
 const props = defineProps<{
 	column: Column;
@@ -37,11 +41,16 @@ const props = defineProps<{
 
 const timeline = shallowRef<InstanceType<typeof MkTimeline>>();
 const channel = shallowRef<Misskey.entities.Channel>();
+const soundSetting = ref<SoundStore>(props.column.soundSetting ?? { type: null, volume: 1 });
 
 if (props.column.channelId == null) {
 	setChannel();
 }
 
+watch(soundSetting, v => {
+	updateColumn(props.column.id, { soundSetting: v });
+});
+
 async function setChannel() {
 	const channels = await favoritedChannelsCache.fetch();
 	const { canceled, result: chosenChannel } = await os.select({
@@ -70,9 +79,17 @@ async function post() {
 	});
 }
 
-const menu = [{
+function onNote() {
+	sound.playMisskeySfxFile(soundSetting.value);
+}
+
+const menu: MenuItem[] = [{
 	icon: 'ti ti-pencil',
 	text: i18n.ts.selectChannel,
 	action: setChannel,
+}, {
+	icon: 'ti ti-bell',
+	text: i18n.ts._deck.newNoteNotificationSettings,
+	action: () => soundSettingsButton(soundSetting),
 }];
 </script>
diff --git a/packages/frontend/src/ui/deck/deck-store.ts b/packages/frontend/src/ui/deck/deck-store.ts
index 70b55e8172..bb3c04cd5c 100644
--- a/packages/frontend/src/ui/deck/deck-store.ts
+++ b/packages/frontend/src/ui/deck/deck-store.ts
@@ -9,6 +9,7 @@ import { notificationTypes } from 'misskey-js';
 import { Storage } from '@/pizzax.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { deepClone } from '@/scripts/clone.js';
+import { SoundStore } from '@/store.js';
 
 type ColumnWidget = {
 	name: string;
@@ -33,6 +34,7 @@ export type Column = {
 	withRenotes?: boolean;
 	withReplies?: boolean;
 	onlyFiles?: boolean;
+	soundSetting: SoundStore;
 };
 
 export const deckStore = markRaw(new Storage('deck', {
diff --git a/packages/frontend/src/ui/deck/list-column.vue b/packages/frontend/src/ui/deck/list-column.vue
index 70ea54326f..5369112494 100644
--- a/packages/frontend/src/ui/deck/list-column.vue
+++ b/packages/frontend/src/ui/deck/list-column.vue
@@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 		<i class="ti ti-list"></i><span style="margin-left: 8px;">{{ column.name }}</span>
 	</template>
 
-	<MkTimeline v-if="column.listId" ref="timeline" src="list" :list="column.listId" :withRenotes="withRenotes"/>
+	<MkTimeline v-if="column.listId" ref="timeline" src="list" :list="column.listId" :withRenotes="withRenotes" @note="onNote"/>
 </XColumn>
 </template>
 
@@ -21,6 +21,10 @@ import MkTimeline from '@/components/MkTimeline.vue';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { i18n } from '@/i18n.js';
+import { MenuItem } from '@/types/menu.js';
+import { SoundStore } from '@/store.js';
+import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
+import * as sound from '@/scripts/sound.js';
 
 const props = defineProps<{
 	column: Column;
@@ -29,6 +33,7 @@ const props = defineProps<{
 
 const timeline = shallowRef<InstanceType<typeof MkTimeline>>();
 const withRenotes = ref(props.column.withRenotes ?? true);
+const soundSetting = ref<SoundStore>(props.column.soundSetting ?? { type: null, volume: 1 });
 
 if (props.column.listId == null) {
 	setList();
@@ -40,6 +45,10 @@ watch(withRenotes, v => {
 	});
 });
 
+watch(soundSetting, v => {
+	updateColumn(props.column.id, { soundSetting: v });
+});
+
 async function setList() {
 	const lists = await misskeyApi('users/lists/list');
 	const { canceled, result: list } = await os.select({
@@ -59,7 +68,11 @@ function editList() {
 	os.pageWindow('my/lists/' + props.column.listId);
 }
 
-const menu = [
+function onNote() {
+	sound.playMisskeySfxFile(soundSetting.value);
+}
+
+const menu: MenuItem[] = [
 	{
 		icon: 'ti ti-pencil',
 		text: i18n.ts.selectList,
@@ -75,5 +88,10 @@ const menu = [
 		text: i18n.ts.showRenotes,
 		ref: withRenotes,
 	},
+	{
+		icon: 'ti ti-bell',
+		text: i18n.ts._deck.newNoteNotificationSettings,
+		action: () => soundSettingsButton(soundSetting),
+	},
 ];
 </script>
diff --git a/packages/frontend/src/ui/deck/role-timeline-column.vue b/packages/frontend/src/ui/deck/role-timeline-column.vue
index eae2ee13f3..32ab7527b4 100644
--- a/packages/frontend/src/ui/deck/role-timeline-column.vue
+++ b/packages/frontend/src/ui/deck/role-timeline-column.vue
@@ -9,18 +9,22 @@ SPDX-License-Identifier: AGPL-3.0-only
 		<i class="ti ti-badge"></i><span style="margin-left: 8px;">{{ column.name }}</span>
 	</template>
 
-	<MkTimeline v-if="column.roleId" ref="timeline" src="role" :role="column.roleId"/>
+	<MkTimeline v-if="column.roleId" ref="timeline" src="role" :role="column.roleId" @note="onNote"/>
 </XColumn>
 </template>
 
 <script lang="ts" setup>
-import { onMounted, shallowRef } from 'vue';
+import { onMounted, ref, shallowRef, watch } from 'vue';
 import XColumn from './column.vue';
 import { updateColumn, Column } from './deck-store.js';
 import MkTimeline from '@/components/MkTimeline.vue';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { i18n } from '@/i18n.js';
+import { MenuItem } from '@/types/menu.js';
+import { SoundStore } from '@/store.js';
+import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
+import * as sound from '@/scripts/sound.js';
 
 const props = defineProps<{
 	column: Column;
@@ -28,6 +32,7 @@ const props = defineProps<{
 }>();
 
 const timeline = shallowRef<InstanceType<typeof MkTimeline>>();
+const soundSetting = ref<SoundStore>(props.column.soundSetting ?? { type: null, volume: 1 });
 
 onMounted(() => {
 	if (props.column.roleId == null) {
@@ -35,6 +40,10 @@ onMounted(() => {
 	}
 });
 
+watch(soundSetting, v => {
+	updateColumn(props.column.id, { soundSetting: v });
+});
+
 async function setRole() {
 	const roles = (await misskeyApi('roles/list')).filter(x => x.isExplorable);
 	const { canceled, result: role } = await os.select({
@@ -50,10 +59,18 @@ async function setRole() {
 	});
 }
 
-const menu = [{
+function onNote() {
+	sound.playMisskeySfxFile(soundSetting.value);
+}
+
+const menu: MenuItem[] = [{
 	icon: 'ti ti-pencil',
 	text: i18n.ts.role,
 	action: setRole,
+}, {
+	icon: 'ti ti-bell',
+	text: i18n.ts._deck.newNoteNotificationSettings,
+	action: () => soundSettingsButton(soundSetting),
 }];
 
 /*
diff --git a/packages/frontend/src/ui/deck/tl-column.vue b/packages/frontend/src/ui/deck/tl-column.vue
index f9066d9db7..a967335edf 100644
--- a/packages/frontend/src/ui/deck/tl-column.vue
+++ b/packages/frontend/src/ui/deck/tl-column.vue
@@ -28,6 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 		:withRenotes="withRenotes"
 		:withReplies="withReplies"
 		:onlyFiles="onlyFiles"
+		@note="onNote"
 	/>
 </XColumn>
 </template>
@@ -41,6 +42,10 @@ import * as os from '@/os.js';
 import { $i } from '@/account.js';
 import { i18n } from '@/i18n.js';
 import { instance } from '@/instance.js';
+import { MenuItem } from '@/types/menu.js';
+import { SoundStore } from '@/store.js';
+import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
+import * as sound from '@/scripts/sound.js';
 
 const props = defineProps<{
 	column: Column;
@@ -52,6 +57,7 @@ const timeline = shallowRef<InstanceType<typeof MkTimeline>>();
 
 const isLocalTimelineAvailable = (($i == null && instance.policies.ltlAvailable) || ($i != null && $i.policies.ltlAvailable));
 const isGlobalTimelineAvailable = (($i == null && instance.policies.gtlAvailable) || ($i != null && $i.policies.gtlAvailable));
+const soundSetting = ref<SoundStore>(props.column.soundSetting ?? { type: null, volume: 1 });
 const withRenotes = ref(props.column.withRenotes ?? true);
 const withReplies = ref(props.column.withReplies ?? false);
 const onlyFiles = ref(props.column.onlyFiles ?? false);
@@ -74,6 +80,10 @@ watch(onlyFiles, v => {
 	});
 });
 
+watch(soundSetting, v => {
+	updateColumn(props.column.id, { soundSetting: v });
+});
+
 onMounted(() => {
 	if (props.column.tl == null) {
 		setType();
@@ -108,10 +118,18 @@ async function setType() {
 	});
 }
 
-const menu = [{
+function onNote() {
+	sound.playMisskeySfxFile(soundSetting.value);
+}
+
+const menu: MenuItem[] = [{
 	icon: 'ti ti-pencil',
 	text: i18n.ts.timeline,
 	action: setType,
+}, {
+	icon: 'ti ti-bell',
+	text: i18n.ts._deck.newNoteNotificationSettings,
+	action: () => soundSettingsButton(soundSetting),
 }, {
 	type: 'switch',
 	text: i18n.ts.showRenotes,
diff --git a/packages/frontend/src/ui/deck/tl-note-notification.ts b/packages/frontend/src/ui/deck/tl-note-notification.ts
new file mode 100644
index 0000000000..275ea56ba0
--- /dev/null
+++ b/packages/frontend/src/ui/deck/tl-note-notification.ts
@@ -0,0 +1,107 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import * as Misskey from 'misskey-js';
+import { Ref } from 'vue';
+import { SoundStore } from '@/store.js';
+import { getSoundDuration, playMisskeySfxFile, soundsTypes, SoundType } from '@/scripts/sound.js';
+import { i18n } from '@/i18n.js';
+import * as os from '@/os.js';
+
+export async function soundSettingsButton(soundSetting: Ref<SoundStore>): Promise<void> {
+	function getSoundTypeName(f: SoundType): string {
+		switch (f) {
+			case null:
+				return i18n.ts.none;
+			case '_driveFile_':
+				return i18n.ts._soundSettings.driveFile;
+			default:
+				return f;
+		}
+	}
+
+	const { canceled, result } = await os.form(i18n.ts.sound, {
+		type: {
+			type: 'enum',
+			label: i18n.ts.sound,
+			default: soundSetting.value.type ?? 'none',
+			enum: soundsTypes.map(f => ({
+				value: f ?? 'none', label: getSoundTypeName(f),
+			})),
+		},
+		soundFile: {
+			type: 'drive-file',
+			label: i18n.ts.file,
+			defaultFileId: soundSetting.value.type === '_driveFile_' ? soundSetting.value.fileId : null,
+			hidden: v => v.type !== '_driveFile_',
+			validate: async (file: Misskey.entities.DriveFile) => {
+				if (!file.type.startsWith('audio')) {
+					os.alert({
+						type: 'warning',
+						title: i18n.ts._soundSettings.driveFileTypeWarn,
+						text: i18n.ts._soundSettings.driveFileTypeWarnDescription,
+					});
+					return false;
+				}
+
+				const duration = await getSoundDuration(file.url);
+				if (duration >= 2000) {
+					const { canceled } = await os.confirm({
+						type: 'warning',
+						title: i18n.ts._soundSettings.driveFileDurationWarn,
+						text: i18n.ts._soundSettings.driveFileDurationWarnDescription,
+						okText: i18n.ts.continue,
+						cancelText: i18n.ts.cancel,
+					});
+					if (canceled) return false;
+				}
+
+				return true;
+			},
+		},
+		volume: {
+			type: 'range',
+			label: i18n.ts.volume,
+			default: soundSetting.value.volume ?? 1,
+			textConverter: (v) => `${Math.floor(v * 100)}%`,
+			min: 0,
+			max: 1,
+			step: 0.05,
+		},
+		listen: {
+			type: 'button',
+			content: i18n.ts.listen,
+			action: (_, v) => {
+				const sound = buildSoundStore(v);
+				if (!sound) return;
+				playMisskeySfxFile(sound);
+			},
+		},
+	});
+	if (canceled) return;
+
+	const res = buildSoundStore(result);
+	if (res) soundSetting.value = res;
+
+	function buildSoundStore(result: any): SoundStore | null {
+		const type = (result.type === 'none' ? null : result.type) as SoundType;
+		const volume = result.volume as number;
+		const fileId = result.soundFile?.id ?? (soundSetting.value.type === '_driveFile_' ? soundSetting.value.fileId : undefined);
+		const fileUrl = result.soundFile?.url ?? (soundSetting.value.type === '_driveFile_' ? soundSetting.value.fileUrl : undefined);
+
+		if (type === '_driveFile_') {
+			if (!fileUrl || !fileId) {
+				os.alert({
+					type: 'warning',
+					text: i18n.ts._soundSettings.driveFileWarn,
+				});
+				return null;
+			}
+			return { type, volume, fileId, fileUrl };
+		} else {
+			return { type, volume };
+		}
+	}
+}
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 208f03dc3e..11567677c9 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -4441,7 +4441,6 @@ export type components = {
       caseSensitive: boolean;
       /** @default false */
       localOnly: boolean;
-      notify: boolean;
       /** @default false */
       excludeBots: boolean;
       /** @default false */
@@ -9748,7 +9747,6 @@ export type operations = {
           excludeBots?: boolean;
           withReplies: boolean;
           withFile: boolean;
-          notify: boolean;
         };
       };
     };
@@ -10030,7 +10028,6 @@ export type operations = {
           excludeBots?: boolean;
           withReplies?: boolean;
           withFile?: boolean;
-          notify?: boolean;
         };
       };
     };

From 4704dfe0611767fda8917a1a544475ba7bdd7cb8 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Mon, 27 May 2024 12:00:25 +0000
Subject: [PATCH 159/191] Bump version to 2024.5.0-beta.5

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index ca3883b804..6caf4fc114 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2024.5.0-beta.4",
+	"version": "2024.5.0-beta.5",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index bad0142899..f010699ec6 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2024.5.0-beta.4",
+	"version": "2024.5.0-beta.5",
 	"description": "Misskey SDK for JavaScript",
 	"main": "./built/index.js",
 	"types": "./built/index.d.ts",

From 934f9f80bd23c09842862784294dcde41fda4738 Mon Sep 17 00:00:00 2001
From: Kisaragi <48310258+KisaragiEffective@users.noreply.github.com>
Date: Mon, 27 May 2024 21:25:07 +0900
Subject: [PATCH 160/191] =?UTF-8?q?docs:=20=E3=80=8CFeat:=20=E5=80=8B?=
 =?UTF-8?q?=E5=88=A5=E3=81=AE=E3=81=8A=E7=9F=A5=E3=82=89=E3=81=9B=E3=81=AB?=
 =?UTF-8?q?=E3=83=AA=E3=83=B3=E3=82=AF=E3=81=A7=E9=A3=9B=E3=81=B9=E3=82=8B?=
 =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB=E3=80=8D=E3=81=AEcherry-pick?=
 =?UTF-8?q?=E5=85=83=E3=82=92=E6=8C=87=E5=AE=9A=20(#13891)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* docs: 「Feat: 個別のお知らせにリンクで飛べるように」のcherry-pick元を指定
cc misskey-dev#13885

* Update CHANGELOG.md

Co-authored-by: Kisaragi <48310258+KisaragiEffective@users.noreply.github.com>

---------

Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>
---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0a70fc7a8a..3904ab1057 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,7 +26,7 @@
 ### Client
 - Feat: アップロードするファイルの名前をランダム文字列にできるように
 - Feat: 個別のお知らせにリンクで飛べるように  
-  (Cherry-picked from https://github.com/MisskeyIO/misskey)
+  (Based on https://github.com/MisskeyIO/misskey/pull/639)
 - Enhance: 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるように
 - Enhance: 広告がMisskeyと同一ドメインの場合はRouterで遷移するように
 - Enhance: リアクション・いいねの総数を表示するように

From de9e391e3486d8cb1bcf33744076c9ee17fa2aba Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Tue, 28 May 2024 00:02:22 +0900
Subject: [PATCH 161/191] [skip ci] update release manager actions

---
 .github/workflows/release-with-ready.yml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/release-with-ready.yml b/.github/workflows/release-with-ready.yml
index 139503e563..a0fad0e336 100644
--- a/.github/workflows/release-with-ready.yml
+++ b/.github/workflows/release-with-ready.yml
@@ -22,9 +22,11 @@ jobs:
       # PR情報を取得
       - name: Get PR
         run: |
-          pr_json=$(gh pr view ${{ github.event.pull_request.number }} --json isDraft,headRefName)
+          pr_json=$(gh pr view "$PR_NUMBER" --json isDraft,headRefName)
           echo "ref=$(echo $pr_json | jq -r '.headRefName')" >> $GITHUB_OUTPUT
         id: get_pr
+        env:
+          PR_NUMBER: ${{ github.event.pull_request.number }}
   release:
     uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v1
     needs: check

From 1bb1a3298645c2d5a3f678cb6676e19519ec1e48 Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Tue, 28 May 2024 00:03:12 +0900
Subject: [PATCH 162/191] [skip ci] update release manager actions

---
 .github/workflows/release-edit-with-push.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/release-edit-with-push.yml b/.github/workflows/release-edit-with-push.yml
index 890cb047bd..86ee0b3fb5 100644
--- a/.github/workflows/release-edit-with-push.yml
+++ b/.github/workflows/release-edit-with-push.yml
@@ -23,7 +23,7 @@ jobs:
       # headがrelease/かつopenのPRを1つ取得
       - name: Get PR
         run: |
-          echo "pr_number=$(gh pr list --limit 1 --head "${{ github.ref_name }}" --json number  --jq '.[] | .number')" >> $GITHUB_OUTPUT
+          echo "pr_number=$(gh pr list --limit 1 --head "$GITHUB_REF_NAME" --json number --jq '.[] | .number')" >> $GITHUB_OUTPUT
         id: get_pr
       - name: Get target version
         uses: misskey-dev/release-manager-actions/.github/actions/get-target-version@v1

From 89b27d8587221a321b6ff9cdae4b714bbedd151a Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Tue, 28 May 2024 14:36:06 +0900
Subject: [PATCH 163/191] =?UTF-8?q?fix(federation):=20Inbox=E3=81=AB?=
 =?UTF-8?q?=E3=81=8D=E3=81=9FCreate,=20Announce=E3=81=AEobject=E3=81=8CBea?=
 =?UTF-8?q?rcaps=20url=E3=81=A0=E3=81=A3=E3=81=9F=E9=9A=9B=E3=81=AF?=
 =?UTF-8?q?=E3=82=B9=E3=82=AD=E3=83=83=E3=83=97=E3=81=99=E3=82=8B=E3=82=88?=
 =?UTF-8?q?=E3=81=86=E3=81=AB=20(#13610)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(federation): AnnounceのobjectがLike出なかったらキューにためない
Fix https://github.com/misskey-dev/misskey/issues/13552

* revert

* better reason handlings

* result

* improve announce handling

* skip bearcaps

* also announce
---
 .../src/core/activitypub/ApInboxService.ts    | 119 ++++++++++--------
 .../core/activitypub/models/ApNoteService.ts  |   8 +-
 packages/backend/src/core/activitypub/type.ts |   1 +
 .../queue/processors/InboxProcessorService.ts |  13 +-
 4 files changed, 85 insertions(+), 56 deletions(-)

diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts
index 1621c41bcc..d0d206760c 100644
--- a/packages/backend/src/core/activitypub/ApInboxService.ts
+++ b/packages/backend/src/core/activitypub/ApInboxService.ts
@@ -28,6 +28,7 @@ import type { UsersRepository, NotesRepository, FollowingsRepository, AbuseUserR
 import { bindThis } from '@/decorators.js';
 import type { MiRemoteUser } from '@/models/User.js';
 import { isNotNull } from '@/misc/is-not-null.js';
+import { GlobalEventService } from '@/core/GlobalEventService.js';
 import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
 import { ApNoteService } from './models/ApNoteService.js';
 import { ApLoggerService } from './ApLoggerService.js';
@@ -36,9 +37,8 @@ import { ApResolverService } from './ApResolverService.js';
 import { ApAudienceService } from './ApAudienceService.js';
 import { ApPersonService } from './models/ApPersonService.js';
 import { ApQuestionService } from './models/ApQuestionService.js';
-import { GlobalEventService } from '@/core/GlobalEventService.js';
 import type { Resolver } from './ApResolverService.js';
-import type { IAccept, IAdd, IAnnounce, IBlock, ICreate, IDelete, IFlag, IFollow, ILike, IObject, IReject, IRemove, IUndo, IUpdate, IMove } from './type.js';
+import type { IAccept, IAdd, IAnnounce, IBlock, ICreate, IDelete, IFlag, IFollow, ILike, IObject, IReject, IRemove, IUndo, IUpdate, IMove, IPost } from './type.js';
 
 @Injectable()
 export class ApInboxService {
@@ -90,13 +90,15 @@ export class ApInboxService {
 	}
 
 	@bindThis
-	public async performActivity(actor: MiRemoteUser, activity: IObject): Promise<void> {
+	public async performActivity(actor: MiRemoteUser, activity: IObject): Promise<string | void> {
+		let result = undefined as string | void;
 		if (isCollectionOrOrderedCollection(activity)) {
+			const results = [] as [string, string | void][];
 			const resolver = this.apResolverService.createResolver();
 			for (const item of toArray(isCollection(activity) ? activity.items : activity.orderedItems)) {
 				const act = await resolver.resolve(item);
 				try {
-					await this.performOneActivity(actor, act);
+					results.push([getApId(item), await this.performOneActivity(actor, act)]);
 				} catch (err) {
 					if (err instanceof Error || typeof err === 'string') {
 						this.logger.error(err);
@@ -105,8 +107,13 @@ export class ApInboxService {
 					}
 				}
 			}
+
+			const hasReason = results.some(([, reason]) => (reason != null && !reason.startsWith('ok')));
+			if (hasReason) {
+				result = results.map(([id, reason]) => `${id}: ${reason}`).join('\n');
+			}
 		} else {
-			await this.performOneActivity(actor, activity);
+			result = await this.performOneActivity(actor, activity);
 		}
 
 		// ついでにリモートユーザーの情報が古かったら更新しておく
@@ -117,42 +124,43 @@ export class ApInboxService {
 				});
 			}
 		}
+		return result;
 	}
 
 	@bindThis
-	public async performOneActivity(actor: MiRemoteUser, activity: IObject): Promise<void> {
+	public async performOneActivity(actor: MiRemoteUser, activity: IObject): Promise<string | void> {
 		if (actor.isSuspended) return;
 
 		if (isCreate(activity)) {
-			await this.create(actor, activity);
+			return await this.create(actor, activity);
 		} else if (isDelete(activity)) {
-			await this.delete(actor, activity);
+			return await this.delete(actor, activity);
 		} else if (isUpdate(activity)) {
-			await this.update(actor, activity);
+			return await this.update(actor, activity);
 		} else if (isFollow(activity)) {
-			await this.follow(actor, activity);
+			return await this.follow(actor, activity);
 		} else if (isAccept(activity)) {
-			await this.accept(actor, activity);
+			return await this.accept(actor, activity);
 		} else if (isReject(activity)) {
-			await this.reject(actor, activity);
+			return await this.reject(actor, activity);
 		} else if (isAdd(activity)) {
-			await this.add(actor, activity).catch(err => this.logger.error(err));
+			return await this.add(actor, activity);
 		} else if (isRemove(activity)) {
-			await this.remove(actor, activity).catch(err => this.logger.error(err));
+			return await this.remove(actor, activity);
 		} else if (isAnnounce(activity)) {
-			await this.announce(actor, activity);
+			return await this.announce(actor, activity);
 		} else if (isLike(activity)) {
-			await this.like(actor, activity);
+			return await this.like(actor, activity);
 		} else if (isUndo(activity)) {
-			await this.undo(actor, activity);
+			return await this.undo(actor, activity);
 		} else if (isBlock(activity)) {
-			await this.block(actor, activity);
+			return await this.block(actor, activity);
 		} else if (isFlag(activity)) {
-			await this.flag(actor, activity);
+			return await this.flag(actor, activity);
 		} else if (isMove(activity)) {
-			await this.move(actor, activity);
+			return await this.move(actor, activity);
 		} else {
-			this.logger.warn(`unrecognized activity type: ${activity.type}`);
+			return `unrecognized activity type: ${activity.type}`;
 		}
 	}
 
@@ -234,38 +242,49 @@ export class ApInboxService {
 	}
 
 	@bindThis
-	private async add(actor: MiRemoteUser, activity: IAdd): Promise<void> {
+	private async add(actor: MiRemoteUser, activity: IAdd): Promise<string | void> {
 		if (actor.uri !== activity.actor) {
-			throw new Error('invalid actor');
+			return 'invalid actor';
 		}
 
 		if (activity.target == null) {
-			throw new Error('target is null');
+			return 'target is null';
 		}
 
 		if (activity.target === actor.featured) {
 			const note = await this.apNoteService.resolveNote(activity.object);
-			if (note == null) throw new Error('note not found');
+			if (note == null) return 'note not found';
 			await this.notePiningService.addPinned(actor, note.id);
 			return;
 		}
 
-		throw new Error(`unknown target: ${activity.target}`);
+		return `unknown target: ${activity.target}`;
 	}
 
 	@bindThis
-	private async announce(actor: MiRemoteUser, activity: IAnnounce): Promise<void> {
+	private async announce(actor: MiRemoteUser, activity: IAnnounce): Promise<string | void> {
 		const uri = getApId(activity);
 
 		this.logger.info(`Announce: ${uri}`);
 
-		const targetUri = getApId(activity.object);
+		const resolver = this.apResolverService.createResolver();
 
-		await this.announceNote(actor, activity, targetUri);
+		if (!activity.object) return 'skip: activity has no object property';
+		const targetUri = getApId(activity.object);
+		if (targetUri.startsWith('bear:')) return 'skip: bearcaps url not supported.';
+
+		const target = await resolver.resolve(activity.object).catch(e => {
+			this.logger.error(`Resolution failed: ${e}`);
+			return e;
+		});
+
+		if (isPost(target)) return await this.announceNote(actor, activity, target);
+
+		return `skip: unknown object type ${getApType(target)}`;
 	}
 
 	@bindThis
-	private async announceNote(actor: MiRemoteUser, activity: IAnnounce, targetUri: string): Promise<void> {
+	private async announceNote(actor: MiRemoteUser, activity: IAnnounce, target: IPost): Promise<string | void> {
 		const uri = getApId(activity);
 
 		if (actor.isSuspended) {
@@ -288,24 +307,21 @@ export class ApInboxService {
 			// Announce対象をresolve
 			let renote;
 			try {
-				renote = await this.apNoteService.resolveNote(targetUri);
-				if (renote == null) throw new Error('announce target is null');
+				renote = await this.apNoteService.resolveNote(target);
+				if (renote == null) return 'announce target is null';
 			} catch (err) {
 				// 対象が4xxならスキップ
 				if (err instanceof StatusError) {
 					if (!err.isRetryable) {
-						this.logger.warn(`Ignored announce target ${targetUri} - ${err.statusCode}`);
-						return;
+						return `Ignored announce target ${target.id} - ${err.statusCode}`;
 					}
-
-					this.logger.warn(`Error in announce target ${targetUri} - ${err.statusCode}`);
+					return `Error in announce target ${target.id} - ${err.statusCode}`;
 				}
 				throw err;
 			}
 
 			if (!await this.noteEntityService.isVisibleForMe(renote, actor.id)) {
-				this.logger.warn('skip: invalid actor for this activity');
-				return;
+				return 'skip: invalid actor for this activity';
 			}
 
 			this.logger.info(`Creating the (Re)Note: ${uri}`);
@@ -314,8 +330,7 @@ export class ApInboxService {
 			const createdAt = activity.published ? new Date(activity.published) : null;
 
 			if (createdAt && createdAt < this.idService.parse(renote.id).date) {
-				this.logger.warn('skip: malformed createdAt');
-				return;
+				return 'skip: malformed createdAt';
 			}
 
 			await this.noteCreateService.create(actor, {
@@ -349,11 +364,15 @@ export class ApInboxService {
 	}
 
 	@bindThis
-	private async create(actor: MiRemoteUser, activity: ICreate): Promise<void> {
+	private async create(actor: MiRemoteUser, activity: ICreate): Promise<string | void> {
 		const uri = getApId(activity);
 
 		this.logger.info(`Create: ${uri}`);
 
+		if (!activity.object) return 'skip: activity has no object property';
+		const targetUri = getApId(activity.object);
+		if (targetUri.startsWith('bear:')) return 'skip: bearcaps url not supported.';
+
 		// copy audiences between activity <=> object.
 		if (typeof activity.object === 'object') {
 			const to = unique(concat([toArray(activity.to), toArray(activity.object.to)]));
@@ -380,7 +399,7 @@ export class ApInboxService {
 		if (isPost(object)) {
 			await this.createNote(resolver, actor, object, false, activity);
 		} else {
-			this.logger.warn(`Unknown type: ${getApType(object)}`);
+			return `Unknown type: ${getApType(object)}`;
 		}
 	}
 
@@ -422,7 +441,7 @@ export class ApInboxService {
 	@bindThis
 	private async delete(actor: MiRemoteUser, activity: IDelete): Promise<string> {
 		if (actor.uri !== activity.actor) {
-			throw new Error('invalid actor');
+			return 'invalid actor';
 		}
 
 		// 削除対象objectのtype
@@ -581,29 +600,29 @@ export class ApInboxService {
 	}
 
 	@bindThis
-	private async remove(actor: MiRemoteUser, activity: IRemove): Promise<void> {
+	private async remove(actor: MiRemoteUser, activity: IRemove): Promise<string | void> {
 		if (actor.uri !== activity.actor) {
-			throw new Error('invalid actor');
+			return 'invalid actor';
 		}
 
 		if (activity.target == null) {
-			throw new Error('target is null');
+			return 'target is null';
 		}
 
 		if (activity.target === actor.featured) {
 			const note = await this.apNoteService.resolveNote(activity.object);
-			if (note == null) throw new Error('note not found');
+			if (note == null) return 'note not found';
 			await this.notePiningService.removePinned(actor, note.id);
 			return;
 		}
 
-		throw new Error(`unknown target: ${activity.target}`);
+		return `unknown target: ${activity.target}`;
 	}
 
 	@bindThis
 	private async undo(actor: MiRemoteUser, activity: IUndo): Promise<string> {
 		if (actor.uri !== activity.actor) {
-			throw new Error('invalid actor');
+			return 'invalid actor';
 		}
 
 		const uri = activity.id ?? activity;
@@ -614,7 +633,7 @@ export class ApInboxService {
 
 		const object = await resolver.resolve(activity.object).catch(e => {
 			this.logger.error(`Resolution failed: ${e}`);
-			throw e;
+			return e;
 		});
 
 		// don't queue because the sender may attempt again when timeout
diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts
index 4e361b57bc..e6dff067f3 100644
--- a/packages/backend/src/core/activitypub/models/ApNoteService.ts
+++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts
@@ -81,20 +81,20 @@ export class ApNoteService {
 		const expectHost = this.utilityService.extractDbHost(uri);
 
 		if (!validPost.includes(getApType(object))) {
-			return new Error(`invalid Note: invalid object type ${getApType(object)}`);
+			return new IdentifiableError('d450b8a9-48e4-4dab-ae36-f4db763fda7c', `invalid Note: invalid object type ${getApType(object)}`);
 		}
 
 		if (object.id && this.utilityService.extractDbHost(object.id) !== expectHost) {
-			return new Error(`invalid Note: id has different host. expected: ${expectHost}, actual: ${this.utilityService.extractDbHost(object.id)}`);
+			return new IdentifiableError('d450b8a9-48e4-4dab-ae36-f4db763fda7c', `invalid Note: id has different host. expected: ${expectHost}, actual: ${this.utilityService.extractDbHost(object.id)}`);
 		}
 
 		const actualHost = object.attributedTo && this.utilityService.extractDbHost(getOneApId(object.attributedTo));
 		if (object.attributedTo && actualHost !== expectHost) {
-			return new Error(`invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${actualHost}`);
+			return new IdentifiableError('d450b8a9-48e4-4dab-ae36-f4db763fda7c', `invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${actualHost}`);
 		}
 
 		if (object.published && !this.idService.isSafeT(new Date(object.published).valueOf())) {
-			return new Error('invalid Note: published timestamp is malformed');
+			return new IdentifiableError('d450b8a9-48e4-4dab-ae36-f4db763fda7c', 'invalid Note: published timestamp is malformed');
 		}
 
 		return null;
diff --git a/packages/backend/src/core/activitypub/type.ts b/packages/backend/src/core/activitypub/type.ts
index 09322888d5..5b6c6c8ca6 100644
--- a/packages/backend/src/core/activitypub/type.ts
+++ b/packages/backend/src/core/activitypub/type.ts
@@ -328,3 +328,4 @@ export const isAnnounce = (object: IObject): object is IAnnounce => getApType(ob
 export const isBlock = (object: IObject): object is IBlock => getApType(object) === 'Block';
 export const isFlag = (object: IObject): object is IFlag => getApType(object) === 'Flag';
 export const isMove = (object: IObject): object is IMove => getApType(object) === 'Move';
+export const isNote = (object: IObject): object is IPost => getApType(object) === 'Note';
diff --git a/packages/backend/src/queue/processors/InboxProcessorService.ts b/packages/backend/src/queue/processors/InboxProcessorService.ts
index f465339075..fa7009f8f5 100644
--- a/packages/backend/src/queue/processors/InboxProcessorService.ts
+++ b/packages/backend/src/queue/processors/InboxProcessorService.ts
@@ -204,13 +204,22 @@ export class InboxProcessorService {
 
 		// アクティビティを処理
 		try {
-			await this.apInboxService.performActivity(authUser.user, activity);
+			const result = await this.apInboxService.performActivity(authUser.user, activity);
+			if (result && !result.startsWith('ok')) {
+				this.logger.warn(`inbox activity ignored (maybe): id=${activity.id} reason=${result}`);
+				return result;
+			}
 		} catch (e) {
 			if (e instanceof IdentifiableError) {
 				if (e.id === '689ee33f-f97c-479a-ac49-1b9f8140af99') {
 					return 'blocked notes with prohibited words';
 				}
-				if (e.id === '85ab9bd7-3a41-4530-959d-f07073900109') return 'actor has been suspended';
+				if (e.id === '85ab9bd7-3a41-4530-959d-f07073900109') {
+					return 'actor has been suspended';
+				}
+				if (e.id === 'd450b8a9-48e4-4dab-ae36-f4db763fda7c') { // invalid Note
+					return e.message;
+				}
 			}
 			throw e;
 		}

From 80f3cb96b02eaaeb513670224d33b8842414963e Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Tue, 28 May 2024 17:06:33 +0900
Subject: [PATCH 164/191] feat: sentry integration (#13897)

* wip

* wip

* wip

* wip

* Update CHANGELOG.md

* Update ApiCallService.ts

* Update config.ts
---
 .config/docker_example.yml                    |  19 +-
 .config/example.yml                           |  15 +
 .devcontainer/devcontainer.yml                |  15 +
 CHANGELOG.md                                  |   1 +
 chart/files/default.yml                       |  16 +
 packages/backend/package.json                 |   4 +-
 packages/backend/src/boot/master.ts           |  20 +
 packages/backend/src/config.ts                |   7 +
 .../backend/src/server/api/ApiCallService.ts  |  77 ++-
 pnpm-lock.yaml                                | 630 ++++++++++++++++++
 10 files changed, 776 insertions(+), 28 deletions(-)

diff --git a/.config/docker_example.yml b/.config/docker_example.yml
index acd169bf43..42ac18de1b 100644
--- a/.config/docker_example.yml
+++ b/.config/docker_example.yml
@@ -106,7 +106,7 @@ redis:
 #   ┌───────────────────────────┐
 #───┘ MeiliSearch configuration └─────────────────────────────
 
-# You can set scope to local (default value) or global 
+# You can set scope to local (default value) or global
 # (include notes from remote).
 
 #meilisearch:
@@ -136,6 +136,21 @@ redis:
 
 id: 'aidx'
 
+#   ┌────────────────┐
+#───┘ Error tracking └──────────────────────────────────────────
+
+# Sentry is available for error tracking.
+# See the Sentry documentation for more details on options.
+
+#sentryForBackend:
+#  enableNodeProfiling: true
+#  options:
+#    dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
+
+#sentryForFrontend:
+#  options:
+#    dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
+
 #   ┌─────────────────────┐
 #───┘ Other configuration └─────────────────────────────────────
 
@@ -185,7 +200,7 @@ proxyRemoteFiles: true
 signToActivityPubGet: true
 
 # For security reasons, uploading attachments from the intranet is prohibited,
-# but exceptions can be made from the following settings. Default value is "undefined". 
+# but exceptions can be made from the following settings. Default value is "undefined".
 # Read changelog to learn more (Improvements of 12.90.0 (2021/09/04)).
 #allowedPrivateNetworks: [
 #  '127.0.0.1/32'
diff --git a/.config/example.yml b/.config/example.yml
index b0b7f14059..b11cbd1373 100644
--- a/.config/example.yml
+++ b/.config/example.yml
@@ -205,6 +205,21 @@ redis:
 
 id: 'aidx'
 
+#   ┌────────────────┐
+#───┘ Error tracking └──────────────────────────────────────────
+
+# Sentry is available for error tracking.
+# See the Sentry documentation for more details on options.
+
+#sentryForBackend:
+#  enableNodeProfiling: true
+#  options:
+#    dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
+
+#sentryForFrontend:
+#  options:
+#    dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
+
 #   ┌─────────────────────┐
 #───┘ Other configuration └─────────────────────────────────────
 
diff --git a/.devcontainer/devcontainer.yml b/.devcontainer/devcontainer.yml
index 7ea0929469..beefcfd0a2 100644
--- a/.devcontainer/devcontainer.yml
+++ b/.devcontainer/devcontainer.yml
@@ -132,6 +132,21 @@ redis:
 
 id: 'aidx'
 
+#   ┌────────────────┐
+#───┘ Error tracking └──────────────────────────────────────────
+
+# Sentry is available for error tracking.
+# See the Sentry documentation for more details on options.
+
+#sentryForBackend:
+#  enableNodeProfiling: true
+#  options:
+#    dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
+
+#sentryForFrontend:
+#  options:
+#    dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
+
 #   ┌─────────────────────┐
 #───┘ Other configuration └─────────────────────────────────────
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3904ab1057..4091668b54 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@
 - 管理者向け権限 `read:admin:show-users` は `read:admin:show-user` に統合されました。必要に応じてAPIトークンを再発行してください。
 
 ### General
+- Feat: エラートラッキングにSentryを使用できるようになりました
 - Enhance: URLプレビューの有効化・無効化を設定できるように #13569
 - Enhance: アンテナでBotによるノートを除外できるように  
   (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/545)
diff --git a/chart/files/default.yml b/chart/files/default.yml
index 4cc291e80a..f98b8ebfee 100644
--- a/chart/files/default.yml
+++ b/chart/files/default.yml
@@ -152,6 +152,22 @@ redis:
 # ID SETTINGS AFTER THAT!
 
 id: "aidx"
+
+#   ┌────────────────┐
+#───┘ Error tracking └──────────────────────────────────────────
+
+# Sentry is available for error tracking.
+# See the Sentry documentation for more details on options.
+
+#sentryForBackend:
+#  enableNodeProfiling: true
+#  options:
+#    dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
+
+#sentryForFrontend:
+#  options:
+#    dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
+
 #   ┌─────────────────────┐
 #───┘ Other configuration └─────────────────────────────────────
 
diff --git a/packages/backend/package.json b/packages/backend/package.json
index 8e29252d75..e034f75dc5 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -4,7 +4,7 @@
 	"private": true,
 	"type": "module",
 	"engines": {
-		"node": ">=20.10.0"
+		"node": "^20.10.0"
 	},
 	"scripts": {
 		"start": "node ./built/boot/entry.js",
@@ -86,6 +86,8 @@
 		"@nestjs/core": "10.3.8",
 		"@nestjs/testing": "10.3.8",
 		"@peertube/http-signature": "1.7.0",
+		"@sentry/node": "^8.5.0",
+		"@sentry/profiling-node": "^8.5.0",
 		"@simplewebauthn/server": "10.0.0",
 		"@sinonjs/fake-timers": "11.2.2",
 		"@smithy/node-http-handler": "2.5.0",
diff --git a/packages/backend/src/boot/master.ts b/packages/backend/src/boot/master.ts
index 30f9477ccf..75e1a80cd1 100644
--- a/packages/backend/src/boot/master.ts
+++ b/packages/backend/src/boot/master.ts
@@ -10,6 +10,8 @@ import * as os from 'node:os';
 import cluster from 'node:cluster';
 import chalk from 'chalk';
 import chalkTemplate from 'chalk-template';
+import * as Sentry from '@sentry/node';
+import { nodeProfilingIntegration } from '@sentry/profiling-node';
 import Logger from '@/logger.js';
 import { loadConfig } from '@/config.js';
 import type { Config } from '@/config.js';
@@ -71,6 +73,24 @@ export async function masterMain() {
 
 	bootLogger.succ('Misskey initialized');
 
+	if (config.sentryForBackend) {
+		Sentry.init({
+			integrations: [
+				...(config.sentryForBackend.enableNodeProfiling ? [nodeProfilingIntegration()] : []),
+			],
+
+			// Performance Monitoring
+			tracesSampleRate: 1.0, //  Capture 100% of the transactions
+
+			// Set sampling rate for profiling - this is relative to tracesSampleRate
+			profilesSampleRate: 1.0,
+
+			maxBreadcrumbs: 0,
+
+			...config.sentryForBackend.options,
+		});
+	}
+
 	if (envOption.disableClustering) {
 		if (envOption.onlyServer) {
 			await server();
diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts
index 0ca1fa55c1..0ac521d409 100644
--- a/packages/backend/src/config.ts
+++ b/packages/backend/src/config.ts
@@ -7,6 +7,7 @@ import * as fs from 'node:fs';
 import { fileURLToPath } from 'node:url';
 import { dirname, resolve } from 'node:path';
 import * as yaml from 'js-yaml';
+import * as Sentry from '@sentry/node';
 import type { RedisOptions } from 'ioredis';
 
 type RedisOptionsSource = Partial<RedisOptions> & {
@@ -56,6 +57,8 @@ type Source = {
 		index: string;
 		scope?: 'local' | 'global' | string[];
 	};
+	sentryForBackend?: { options: Partial<Sentry.NodeOptions>; enableNodeProfiling: boolean; };
+	sentryForFrontend?: { options: Partial<Sentry.NodeOptions> };
 
 	publishTarballInsteadOfProvideRepositoryUrl?: boolean;
 
@@ -166,6 +169,8 @@ export type Config = {
 	redisForPubsub: RedisOptions & RedisOptionsSource;
 	redisForJobQueue: RedisOptions & RedisOptionsSource;
 	redisForTimelines: RedisOptions & RedisOptionsSource;
+	sentryForBackend: { options: Partial<Sentry.NodeOptions>; enableNodeProfiling: boolean; } | undefined;
+	sentryForFrontend: { options: Partial<Sentry.NodeOptions> } | undefined;
 	perChannelMaxNoteCacheCount: number;
 	perUserNotificationsMaxCount: number;
 	deactivateAntennaThreshold: number;
@@ -234,6 +239,8 @@ 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,
+		sentryForBackend: config.sentryForBackend,
+		sentryForFrontend: config.sentryForFrontend,
 		id: config.id,
 		proxy: config.proxy,
 		proxySmtp: config.proxySmtp,
diff --git a/packages/backend/src/server/api/ApiCallService.ts b/packages/backend/src/server/api/ApiCallService.ts
index 9836689872..271ef80554 100644
--- a/packages/backend/src/server/api/ApiCallService.ts
+++ b/packages/backend/src/server/api/ApiCallService.ts
@@ -7,6 +7,7 @@ import { randomUUID } from 'node:crypto';
 import * as fs from 'node:fs';
 import * as stream from 'node:stream/promises';
 import { Inject, Injectable } from '@nestjs/common';
+import * as Sentry from '@sentry/node';
 import { DI } from '@/di-symbols.js';
 import { getIpHash } from '@/misc/get-ip-hash.js';
 import type { MiLocalUser, MiUser } from '@/models/User.js';
@@ -17,6 +18,7 @@ import { MetaService } from '@/core/MetaService.js';
 import { createTemp } from '@/misc/create-temp.js';
 import { bindThis } from '@/decorators.js';
 import { RoleService } from '@/core/RoleService.js';
+import type { Config } from '@/config.js';
 import { ApiError } from './error.js';
 import { RateLimiterService } from './RateLimiterService.js';
 import { ApiLoggerService } from './ApiLoggerService.js';
@@ -38,6 +40,9 @@ export class ApiCallService implements OnApplicationShutdown {
 	private userIpHistoriesClearIntervalId: NodeJS.Timeout;
 
 	constructor(
+		@Inject(DI.config)
+		private config: Config,
+
 		@Inject(DI.userIpsRepository)
 		private userIpsRepository: UserIpsRepository,
 
@@ -88,6 +93,48 @@ export class ApiCallService implements OnApplicationShutdown {
 		}
 	}
 
+	#onExecError(ep: IEndpoint, data: any, err: Error): void {
+		if (err instanceof ApiError || err instanceof AuthenticationError) {
+			throw err;
+		} else {
+			const errId = randomUUID();
+			this.logger.error(`Internal error occurred in ${ep.name}: ${err.message}`, {
+				ep: ep.name,
+				ps: data,
+				e: {
+					message: err.message,
+					code: err.name,
+					stack: err.stack,
+					id: errId,
+				},
+			});
+			console.error(err, errId);
+
+			if (this.config.sentryForBackend) {
+				Sentry.captureMessage(`Internal error occurred in ${ep.name}: ${err.message}`, {
+					extra: {
+						ep: ep.name,
+						ps: data,
+						e: {
+							message: err.message,
+							code: err.name,
+							stack: err.stack,
+							id: errId,
+						},
+					},
+				});
+			}
+
+			throw new ApiError(null, {
+				e: {
+					message: err.message,
+					code: err.name,
+					id: errId,
+				},
+			});
+		}
+	}
+
 	@bindThis
 	public handleRequest(
 		endpoint: IEndpoint & { exec: any },
@@ -362,31 +409,11 @@ export class ApiCallService implements OnApplicationShutdown {
 		}
 
 		// API invoking
-		return await ep.exec(data, user, token, file, request.ip, request.headers).catch((err: Error) => {
-			if (err instanceof ApiError || err instanceof AuthenticationError) {
-				throw err;
-			} else {
-				const errId = randomUUID();
-				this.logger.error(`Internal error occurred in ${ep.name}: ${err.message}`, {
-					ep: ep.name,
-					ps: data,
-					e: {
-						message: err.message,
-						code: err.name,
-						stack: err.stack,
-						id: errId,
-					},
-				});
-				console.error(err, errId);
-				throw new ApiError(null, {
-					e: {
-						message: err.message,
-						code: err.name,
-						id: errId,
-					},
-				});
-			}
-		});
+		if (this.config.sentryForBackend) {
+			return await Sentry.startSpan({ name: 'API: ' + ep.name }, () => ep.exec(data, user, token, file, request.ip, request.headers).catch((err: Error) => this.#onExecError(ep, data, err)));
+		} else {
+			return await ep.exec(data, user, token, file, request.ip, request.headers).catch((err: Error) => this.#onExecError(ep, data, err));
+		}
 	}
 
 	@bindThis
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 465539b834..6bf1cf158c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -140,6 +140,12 @@ importers:
       '@peertube/http-signature':
         specifier: 1.7.0
         version: 1.7.0
+      '@sentry/node':
+        specifier: ^8.5.0
+        version: 8.5.0
+      '@sentry/profiling-node':
+        specifier: ^8.5.0
+        version: 8.5.0
       '@simplewebauthn/server':
         specifier: 10.0.0
         version: 10.0.0(encoding@0.1.13)
@@ -3264,6 +3270,154 @@ packages:
   '@open-draft/until@2.1.0':
     resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==}
 
+  '@opentelemetry/api-logs@0.51.1':
+    resolution: {integrity: sha512-E3skn949Pk1z2XtXu/lxf6QAZpawuTM/IUEXcAzpiUkTd73Hmvw26FiN3cJuTmkpM5hZzHwkomVdtrh/n/zzwA==}
+    engines: {node: '>=14'}
+
+  '@opentelemetry/api@1.8.0':
+    resolution: {integrity: sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==}
+    engines: {node: '>=8.0.0'}
+
+  '@opentelemetry/context-async-hooks@1.24.1':
+    resolution: {integrity: sha512-R5r6DO4kgEOVBxFXhXjwospLQkv+sYxwCfjvoZBe7Zm6KKXAV9kDSJhi/D1BweowdZmO+sdbENLs374gER8hpQ==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': '>=1.0.0 <1.9.0'
+
+  '@opentelemetry/core@1.24.1':
+    resolution: {integrity: sha512-wMSGfsdmibI88K9wB498zXY04yThPexo8jvwNNlm542HZB7XrrMRBbAyKJqG8qDRJwIBdBrPMi4V9ZPW/sqrcg==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': '>=1.0.0 <1.9.0'
+
+  '@opentelemetry/instrumentation-connect@0.36.0':
+    resolution: {integrity: sha512-k9++bmJZ9zDEs3u3DnKTn2l7QTiNFg3gPx7G9rW0TPnP+xZoBSBTrEcGYBaqflQlrFG23Q58+X1sM2ayWPv5Fg==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/instrumentation-express@0.39.0':
+    resolution: {integrity: sha512-AG8U7z7D0JcBu/7dDcwb47UMEzj9/FMiJV2iQZqrsZnxR3FjB9J9oIH2iszJYci2eUdp2WbdvtpD9RV/zmME5A==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/instrumentation-fastify@0.36.1':
+    resolution: {integrity: sha512-3Nfm43PI0I+3EX+1YbSy6xbDu276R1Dh1tqAk68yd4yirnIh52Kd5B+nJ8CgHA7o3UKakpBjj6vSzi5vNCzJIA==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/instrumentation-graphql@0.40.0':
+    resolution: {integrity: sha512-LVRdEHWACWOczv2imD+mhUrLMxsEjPPi32vIZJT57zygR5aUiA4em8X3aiGOCycgbMWkIu8xOSGSxdx3JmzN+w==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/instrumentation-hapi@0.38.0':
+    resolution: {integrity: sha512-ZcOqEuwuutTDYIjhDIStix22ECblG/i9pHje23QGs4Q4YS4RMaZ5hKCoQJxW88Z4K7T53rQkdISmoXFKDV8xMg==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/instrumentation-http@0.51.1':
+    resolution: {integrity: sha512-6b3nZnFFEz/3xZ6w8bVxctPUWIPWiXuPQ725530JgxnN1cvYFd8CJ75PrHZNjynmzSSnqBkN3ef4R9N+RpMh8Q==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/instrumentation-ioredis@0.40.0':
+    resolution: {integrity: sha512-Jv/fH7KhpWe4KBirsiqeUJIYrsdR2iu2l4nWhfOlRvaZ+zYIiLEzTQR6QhBbyRoAbU4OuYJzjWusOmmpGBnwng==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/instrumentation-koa@0.40.0':
+    resolution: {integrity: sha512-dJc3H/bKMcgUYcQpLF+1IbmUKus0e5Fnn/+ru/3voIRHwMADT3rFSUcGLWSczkg68BCgz0vFWGDTvPtcWIFr7A==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/instrumentation-mongodb@0.43.0':
+    resolution: {integrity: sha512-bMKej7Y76QVUD3l55Q9YqizXybHUzF3pujsBFjqbZrRn2WYqtsDtTUlbCK7fvXNPwFInqZ2KhnTqd0gwo8MzaQ==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/instrumentation-mongoose@0.38.1':
+    resolution: {integrity: sha512-zaeiasdnRjXe6VhYCBMdkmAVh1S5MmXC/0spet+yqoaViGnYst/DOxPvhwg3yT4Yag5crZNWsVXnA538UjP6Ow==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/instrumentation-mysql2@0.38.1':
+    resolution: {integrity: sha512-qkpHMgWSDTYVB1vlZ9sspf7l2wdS5DDq/rbIepDwX5BA0N0068JTQqh0CgAh34tdFqSCnWXIhcyOXC2TtRb0sg==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/instrumentation-mysql@0.38.1':
+    resolution: {integrity: sha512-+iBAawUaTfX/HAlvySwozx0C2B6LBfNPXX1W8Z2On1Uva33AGkw2UjL9XgIg1Pj4eLZ9R4EoJ/aFz+Xj4E/7Fw==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/instrumentation-nestjs-core@0.37.1':
+    resolution: {integrity: sha512-ebYQjHZEmGHWEALwwDGhSQVLBaurFnuLIkZD5igPXrt7ohfF4lc5/4al1LO+vKc0NHk8SJWStuRueT86ISA8Vg==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/instrumentation-pg@0.41.0':
+    resolution: {integrity: sha512-BSlhpivzBD77meQNZY9fS4aKgydA8AJBzv2dqvxXFy/Hq64b7HURgw/ztbmwFeYwdF5raZZUifiiNSMLpOJoSA==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/instrumentation@0.43.0':
+    resolution: {integrity: sha512-S1uHE+sxaepgp+t8lvIDuRgyjJWisAb733198kwQTUc9ZtYQ2V2gmyCtR1x21ePGVLoMiX/NWY7WA290hwkjJQ==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/instrumentation@0.51.1':
+    resolution: {integrity: sha512-JIrvhpgqY6437QIqToyozrUG1h5UhwHkaGK/WAX+fkrpyPtc+RO5FkRtUd9BH0MibabHHvqsnBGKfKVijbmp8w==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/redis-common@0.36.2':
+    resolution: {integrity: sha512-faYX1N0gpLhej/6nyp6bgRjzAKXn5GOEMYY7YhciSfCoITAktLUtQ36d24QEWNA1/WA1y6qQunCe0OhHRkVl9g==}
+    engines: {node: '>=14'}
+
+  '@opentelemetry/resources@1.24.1':
+    resolution: {integrity: sha512-cyv0MwAaPF7O86x5hk3NNgenMObeejZFLJJDVuSeSMIsknlsj3oOZzRv3qSzlwYomXsICfBeFFlxwHQte5mGXQ==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': '>=1.0.0 <1.9.0'
+
+  '@opentelemetry/sdk-metrics@1.24.1':
+    resolution: {integrity: sha512-FrAqCbbGao9iKI+Mgh+OsC9+U2YMoXnlDHe06yH7dvavCKzE3S892dGtX54+WhSFVxHR/TMRVJiK/CV93GR0TQ==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': '>=1.3.0 <1.9.0'
+
+  '@opentelemetry/sdk-trace-base@1.24.1':
+    resolution: {integrity: sha512-zz+N423IcySgjihl2NfjBf0qw1RWe11XIAWVrTNOSSI6dtSPJiVom2zipFB2AEEtJWpv0Iz6DY6+TjnyTV5pWg==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': '>=1.0.0 <1.9.0'
+
+  '@opentelemetry/semantic-conventions@1.24.1':
+    resolution: {integrity: sha512-VkliWlS4/+GHLLW7J/rVBA00uXus1SWvwFvcUDxDwmFxYfg/2VI6ekwdXS28cjI8Qz2ky2BzG8OUHo+WeYIWqw==}
+    engines: {node: '>=14'}
+
+  '@opentelemetry/sql-common@0.40.1':
+    resolution: {integrity: sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.1.0
+
   '@peculiar/asn1-android@2.3.10':
     resolution: {integrity: sha512-z9Rx9cFJv7UUablZISe7uksNbFJCq13hO0yEAOoIpAymALTLlvUOSLnGiQS7okPaM5dP42oTLhezH6XDXRXjGw==}
 
@@ -3287,6 +3441,9 @@ packages:
     resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
     engines: {node: '>=14'}
 
+  '@prisma/instrumentation@5.14.0':
+    resolution: {integrity: sha512-DeybWvIZzu/mUsOYP9MVd6AyBj+MP7xIMrcuIn25MX8FiQX39QBnET5KhszTAip/ToctUuDwSJ46QkIoyo3RFA==}
+
   '@radix-ui/react-compose-refs@1.0.1':
     resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==}
     peerDependencies:
@@ -3449,6 +3606,37 @@ packages:
   '@rushstack/ts-command-line@4.19.2':
     resolution: {integrity: sha512-cqmXXmBEBlzo9WtyUrHtF9e6kl0LvBY7aTSVX4jfnBfXWZQWnPq9JTFPlQZ+L/ZwjZ4HrNwQsOVvhe9oOucZkw==}
 
+  '@sentry/core@8.5.0':
+    resolution: {integrity: sha512-SO3ddBzGdha+Oflp+IKwBxj+7ds1q69OAT3VsypTd+WUFQdI9DIhR92Bjf+QQZCIzUNOi79VWOh3aOi3f6hMnw==}
+    engines: {node: '>=14.18'}
+
+  '@sentry/node@8.5.0':
+    resolution: {integrity: sha512-t9cHAx/wLJYtdVf2XlzKlRJGvwdAp1wjzG0tC4E1Znx74OuUS1cFNo5WrGuOi0/YcWSxiJaxBvtUcsWK86fIgw==}
+    engines: {node: '>=14.18'}
+
+  '@sentry/opentelemetry@8.5.0':
+    resolution: {integrity: sha512-AbxFUNjuTKQ9ugZrssmGtPxWkBr4USNoP7GjaaGCNwNzvIVYCa+i8dv7BROJiW2lsxNAremULEbh+nbVmhGxDA==}
+    engines: {node: '>=14.18'}
+    peerDependencies:
+      '@opentelemetry/api': ^1.8.0
+      '@opentelemetry/core': ^1.24.1
+      '@opentelemetry/instrumentation': ^0.51.1
+      '@opentelemetry/sdk-trace-base': ^1.23.0
+      '@opentelemetry/semantic-conventions': ^1.23.0
+
+  '@sentry/profiling-node@8.5.0':
+    resolution: {integrity: sha512-nEXJqVNfZWYi4PakQXBZCJeH59UlnBv+zaYftDNUUXttCmzRXpL1ujNm5mJrJHlWjV7tgIFw02HW3nh2yyKOkw==}
+    engines: {node: '>=14.18'}
+    hasBin: true
+
+  '@sentry/types@8.5.0':
+    resolution: {integrity: sha512-eDgkSmKI4+XL0QZm4H3j/n1RgnrbnjXZmjj+LsfccRZQwbPu9bWlc8q7Y7Ty1gOsoUpX+TecNLp2a8CRID4KHA==}
+    engines: {node: '>=14.18'}
+
+  '@sentry/utils@8.5.0':
+    resolution: {integrity: sha512-fdrCzo8SAYiw9JBhkJPqYqJkDXZ/wICzN7+zcXIuzKNhE1hdoFjeKcPnpUI3bKZCG6e3hT1PTYQXhVw7GIZV9w==}
+    engines: {node: '>=14.18'}
+
   '@shikijs/core@1.4.0':
     resolution: {integrity: sha512-CxpKLntAi64h3j+TwWqVIQObPTED0FyXLHTTh3MKXtqiQNn2JGcMQQ362LftDbc9kYbDtrksNMNoVmVXzKFYUQ==}
 
@@ -4254,12 +4442,18 @@ packages:
   '@types/connect@3.4.35':
     resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==}
 
+  '@types/connect@3.4.36':
+    resolution: {integrity: sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==}
+
   '@types/content-disposition@0.5.8':
     resolution: {integrity: sha512-QVSSvno3dE0MgO76pJhmv4Qyi/j0Yk9pBp0Y7TJ2Tlj+KCgJWY6qX7nnxCOLkZ3VYRSIk1WTxCvwUSdx6CCLdg==}
 
   '@types/cookie@0.6.0':
     resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
 
+  '@types/cookies@0.9.0':
+    resolution: {integrity: sha512-40Zk8qR147RABiQ7NQnBzWzDcjKzNrntB5BAmeGCb2p/MIyOE+4BVvc17wumsUqUw00bJYqoXFHYygQnEFh4/Q==}
+
   '@types/cross-spawn@6.0.2':
     resolution: {integrity: sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==}
 
@@ -4323,9 +4517,15 @@ packages:
   '@types/htmlescape@1.1.3':
     resolution: {integrity: sha512-tuC81YJXGUe0q8WRtBNW+uyx79rkkzWK651ALIXXYq5/u/IxjX4iHneGF2uUqzsNp+F+9J2mFZOv9jiLTtIq0w==}
 
+  '@types/http-assert@1.5.5':
+    resolution: {integrity: sha512-4+tE/lwdAahgZT1g30Jkdm9PzFRde0xwxBNUyRsCitRvCQB90iuA2uJYdUnhnANRcqGXaWOGY4FEoxeElNAK2g==}
+
   '@types/http-cache-semantics@4.0.4':
     resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
 
+  '@types/http-errors@2.0.4':
+    resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
+
   '@types/http-link-header@1.0.5':
     resolution: {integrity: sha512-AxhIKR8UbyoqCTNp9rRepkktHuUOw3DjfOfDCaO9kwI8AYzjhxyrvZq4+mRw/2daD3hYDknrtSeV6SsPwmc71w==}
 
@@ -4362,9 +4562,21 @@ packages:
   '@types/jsrsasign@10.5.14':
     resolution: {integrity: sha512-lppSlfK6etu+cuKs40K4rg8As79PH6hzIB+v55zSqImbSH3SE6Fm8MBHCiI91cWlAP3Z4igtJK1VL3fSN09blQ==}
 
+  '@types/keygrip@1.0.6':
+    resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==}
+
   '@types/keyv@3.1.4':
     resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
 
+  '@types/koa-compose@3.2.8':
+    resolution: {integrity: sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA==}
+
+  '@types/koa@2.14.0':
+    resolution: {integrity: sha512-DTDUyznHGNHAl+wd1n0z1jxNajduyTh8R53xoewuerdBzGo6Ogj6F2299BFtrexJw4NtgjsI5SMPCmV9gZwGXA==}
+
+  '@types/koa__router@12.0.3':
+    resolution: {integrity: sha512-5YUJVv6NwM1z7m6FuYpKfNLTZ932Z6EF6xy2BbtpJSyn13DKNQEkXVffFVSnJHxvwwWh2SAeumpjAYUELqgjyw==}
+
   '@types/lodash@4.14.191':
     resolution: {integrity: sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==}
 
@@ -4401,6 +4613,9 @@ packages:
   '@types/mute-stream@0.0.4':
     resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==}
 
+  '@types/mysql@2.15.22':
+    resolution: {integrity: sha512-wK1pzsJVVAjYCSZWQoWHziQZbNggXFDUEIGf54g4ZM/ERuP86uGdWeKZWMYlqTPMZfHJJvLPyogXGvCOg87yLQ==}
+
   '@types/node-fetch@2.6.4':
     resolution: {integrity: sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==}
 
@@ -4441,9 +4656,15 @@ packages:
   '@types/offscreencanvas@2019.7.0':
     resolution: {integrity: sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==}
 
+  '@types/pg-pool@2.0.4':
+    resolution: {integrity: sha512-qZAvkv1K3QbmHHFYSNRYPkRjOWRLBYrL4B9c+wG0GSVGBw0NtJwPcgx/DSddeDJvRGMHCEQ4VMEVfuJ/0gZ3XQ==}
+
   '@types/pg@8.11.5':
     resolution: {integrity: sha512-2xMjVviMxneZHDHX5p5S6tsRRs7TpDHeeK7kTTMe/kAC/mRRNjWHjZg0rkiY+e17jXSZV3zJYDxXV8Cy72/Vuw==}
 
+  '@types/pg@8.6.1':
+    resolution: {integrity: sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==}
+
   '@types/pretty-hrtime@1.0.1':
     resolution: {integrity: sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ==}
 
@@ -4507,6 +4728,9 @@ packages:
   '@types/serviceworker@0.0.67':
     resolution: {integrity: sha512-7TCH7iNsCSNb+aUD9M/36TekrWFSLCjNK8zw/3n5kOtRjbLtDfGYMXTrDnGhSfqXNwpqmt9Vd90w5C/ad1tX6Q==}
 
+  '@types/shimmer@1.0.5':
+    resolution: {integrity: sha512-9Hp0ObzwwO57DpLFF0InUjUm/II8GmKAvzbefxQTihCb7KI6yc9yzf0nLc4mVdby5N4DRCgQM2wCup9KTieeww==}
+
   '@types/simple-oauth2@5.0.7':
     resolution: {integrity: sha512-8JbWVJbiTSBQP/7eiyGKyXWAqp3dKQZpaA+pdW16FCi32ujkzRMG8JfjoAzdWt6W8U591ZNdHcPtP2D7ILTKuA==}
 
@@ -4900,6 +5124,16 @@ packages:
     resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
     engines: {node: '>= 0.6'}
 
+  acorn-import-assertions@1.9.0:
+    resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==}
+    peerDependencies:
+      acorn: ^8
+
+  acorn-import-attributes@1.9.5:
+    resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==}
+    peerDependencies:
+      acorn: ^8
+
   acorn-jsx@5.3.2:
     resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
     peerDependencies:
@@ -7111,6 +7345,12 @@ packages:
     resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
     engines: {node: '>=6'}
 
+  import-in-the-middle@1.4.2:
+    resolution: {integrity: sha512-9WOz1Yh/cvO/p69sxRmhyQwrIGGSp7EIdcb+fFNVi7CzQGQB8U1/1XrKVSbEd/GNOAeM0peJtmi7+qphe7NvAw==}
+
+  import-in-the-middle@1.7.4:
+    resolution: {integrity: sha512-Lk+qzWmiQuRPPulGQeK5qq0v32k2bHnWrRPFgqyvhw7Kkov5L6MOLOIU3pcWeujc9W4q54Cp3Q2WV16eQkc7Bg==}
+
   import-lazy@4.0.0:
     resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==}
     engines: {node: '>=8'}
@@ -8275,6 +8515,9 @@ packages:
     resolution: {integrity: sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==}
     engines: {node: '>= 8'}
 
+  module-details-from-path@1.0.3:
+    resolution: {integrity: sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==}
+
   mri@1.2.0:
     resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
     engines: {node: '>=4'}
@@ -8393,6 +8636,10 @@ packages:
   nise@5.1.4:
     resolution: {integrity: sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==}
 
+  node-abi@3.62.0:
+    resolution: {integrity: sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==}
+    engines: {node: '>=10'}
+
   node-abort-controller@3.1.1:
     resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==}
 
@@ -8626,6 +8873,10 @@ packages:
     resolution: {integrity: sha512-es3mGcDXV6TKPo6n3aohzHm0qxhLyR39MhF6mkD1FwFGjhxnqMqfSIgM0eCpInZvqatve4CxmXcMZw3jnnsaXw==}
     hasBin: true
 
+  opentelemetry-instrumentation-fetch-node@1.2.0:
+    resolution: {integrity: sha512-aiSt/4ubOTyb1N5C2ZbGrBvaJOXIZhZvpRPYuUVxQJe27wJZqf/o65iPrqgLcgfeOLaQ8cS2Q+762jrYvniTrA==}
+    engines: {node: '>18.0.0'}
+
   optionator@0.9.3:
     resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
     engines: {node: '>= 0.8.0'}
@@ -9570,6 +9821,10 @@ packages:
     resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
     engines: {node: '>=0.10.0'}
 
+  require-in-the-middle@7.3.0:
+    resolution: {integrity: sha512-nQFEv9gRw6SJAwWD2LrL0NmQvAcO7FBwJbwmr2ttPAacfy0xuiOjE5zt+zM4xDyuyvUaxBi/9gb2SoCyNEVJcw==}
+    engines: {node: '>=8.6.0'}
+
   require-main-filename@2.0.0:
     resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
 
@@ -9784,6 +10039,9 @@ packages:
   shiki@1.4.0:
     resolution: {integrity: sha512-5WIn0OL8PWm7JhnTwRWXniy6eEDY234mRrERVlFa646V2ErQqwIFd2UML7e0Pq9eqSKLoMa3Ke+xbsF+DAuy+Q==}
 
+  shimmer@1.2.1:
+    resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==}
+
   side-channel@1.0.4:
     resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
 
@@ -13733,6 +13991,203 @@ snapshots:
 
   '@open-draft/until@2.1.0': {}
 
+  '@opentelemetry/api-logs@0.51.1':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+
+  '@opentelemetry/api@1.8.0': {}
+
+  '@opentelemetry/context-async-hooks@1.24.1(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+
+  '@opentelemetry/core@1.24.1(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/semantic-conventions': 1.24.1
+
+  '@opentelemetry/instrumentation-connect@0.36.0(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/semantic-conventions': 1.24.1
+      '@types/connect': 3.4.36
+    transitivePeerDependencies:
+      - supports-color
+
+  '@opentelemetry/instrumentation-express@0.39.0(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/semantic-conventions': 1.24.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@opentelemetry/instrumentation-fastify@0.36.1(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/semantic-conventions': 1.24.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@opentelemetry/instrumentation-graphql@0.40.0(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+    transitivePeerDependencies:
+      - supports-color
+
+  '@opentelemetry/instrumentation-hapi@0.38.0(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/semantic-conventions': 1.24.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@opentelemetry/instrumentation-http@0.51.1(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/semantic-conventions': 1.24.1
+      semver: 7.6.0
+    transitivePeerDependencies:
+      - supports-color
+
+  '@opentelemetry/instrumentation-ioredis@0.40.0(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/redis-common': 0.36.2
+      '@opentelemetry/semantic-conventions': 1.24.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@opentelemetry/instrumentation-koa@0.40.0(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/semantic-conventions': 1.24.1
+      '@types/koa': 2.14.0
+      '@types/koa__router': 12.0.3
+    transitivePeerDependencies:
+      - supports-color
+
+  '@opentelemetry/instrumentation-mongodb@0.43.0(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/sdk-metrics': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/semantic-conventions': 1.24.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@opentelemetry/instrumentation-mongoose@0.38.1(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/semantic-conventions': 1.24.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@opentelemetry/instrumentation-mysql2@0.38.1(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/semantic-conventions': 1.24.1
+      '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.8.0)
+    transitivePeerDependencies:
+      - supports-color
+
+  '@opentelemetry/instrumentation-mysql@0.38.1(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/semantic-conventions': 1.24.1
+      '@types/mysql': 2.15.22
+    transitivePeerDependencies:
+      - supports-color
+
+  '@opentelemetry/instrumentation-nestjs-core@0.37.1(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/semantic-conventions': 1.24.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@opentelemetry/instrumentation-pg@0.41.0(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/semantic-conventions': 1.24.1
+      '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.8.0)
+      '@types/pg': 8.6.1
+      '@types/pg-pool': 2.0.4
+    transitivePeerDependencies:
+      - supports-color
+
+  '@opentelemetry/instrumentation@0.43.0(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@types/shimmer': 1.0.5
+      import-in-the-middle: 1.4.2
+      require-in-the-middle: 7.3.0
+      semver: 7.6.0
+      shimmer: 1.2.1
+    transitivePeerDependencies:
+      - supports-color
+    optional: true
+
+  '@opentelemetry/instrumentation@0.51.1(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/api-logs': 0.51.1
+      '@types/shimmer': 1.0.5
+      import-in-the-middle: 1.7.4
+      require-in-the-middle: 7.3.0
+      semver: 7.6.0
+      shimmer: 1.2.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@opentelemetry/redis-common@0.36.2': {}
+
+  '@opentelemetry/resources@1.24.1(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/semantic-conventions': 1.24.1
+
+  '@opentelemetry/sdk-metrics@1.24.1(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/resources': 1.24.1(@opentelemetry/api@1.8.0)
+      lodash.merge: 4.6.2
+
+  '@opentelemetry/sdk-trace-base@1.24.1(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/resources': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/semantic-conventions': 1.24.1
+
+  '@opentelemetry/semantic-conventions@1.24.1': {}
+
+  '@opentelemetry/sql-common@0.40.1(@opentelemetry/api@1.8.0)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
+
   '@peculiar/asn1-android@2.3.10':
     dependencies:
       '@peculiar/asn1-schema': 2.3.8
@@ -13776,6 +14231,14 @@ snapshots:
   '@pkgjs/parseargs@0.11.0':
     optional: true
 
+  '@prisma/instrumentation@5.14.0':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/sdk-trace-base': 1.24.1(@opentelemetry/api@1.8.0)
+    transitivePeerDependencies:
+      - supports-color
+
   '@radix-ui/react-compose-refs@1.0.1(@types/react@18.0.28)(react@18.3.1)':
     dependencies:
       '@babel/runtime': 7.23.4
@@ -13922,6 +14385,72 @@ snapshots:
     transitivePeerDependencies:
       - '@types/node'
 
+  '@sentry/core@8.5.0':
+    dependencies:
+      '@sentry/types': 8.5.0
+      '@sentry/utils': 8.5.0
+
+  '@sentry/node@8.5.0':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/context-async-hooks': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation-connect': 0.36.0(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation-express': 0.39.0(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation-fastify': 0.36.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation-graphql': 0.40.0(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation-hapi': 0.38.0(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation-http': 0.51.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation-ioredis': 0.40.0(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation-koa': 0.40.0(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation-mongodb': 0.43.0(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation-mongoose': 0.38.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation-mysql': 0.38.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation-mysql2': 0.38.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation-nestjs-core': 0.37.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation-pg': 0.41.0(@opentelemetry/api@1.8.0)
+      '@opentelemetry/resources': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/sdk-trace-base': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/semantic-conventions': 1.24.1
+      '@prisma/instrumentation': 5.14.0
+      '@sentry/core': 8.5.0
+      '@sentry/opentelemetry': 8.5.0(@opentelemetry/api@1.8.0)(@opentelemetry/core@1.24.1(@opentelemetry/api@1.8.0))(@opentelemetry/instrumentation@0.51.1(@opentelemetry/api@1.8.0))(@opentelemetry/sdk-trace-base@1.24.1(@opentelemetry/api@1.8.0))(@opentelemetry/semantic-conventions@1.24.1)
+      '@sentry/types': 8.5.0
+      '@sentry/utils': 8.5.0
+    optionalDependencies:
+      opentelemetry-instrumentation-fetch-node: 1.2.0
+    transitivePeerDependencies:
+      - supports-color
+
+  '@sentry/opentelemetry@8.5.0(@opentelemetry/api@1.8.0)(@opentelemetry/core@1.24.1(@opentelemetry/api@1.8.0))(@opentelemetry/instrumentation@0.51.1(@opentelemetry/api@1.8.0))(@opentelemetry/sdk-trace-base@1.24.1(@opentelemetry/api@1.8.0))(@opentelemetry/semantic-conventions@1.24.1)':
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/sdk-trace-base': 1.24.1(@opentelemetry/api@1.8.0)
+      '@opentelemetry/semantic-conventions': 1.24.1
+      '@sentry/core': 8.5.0
+      '@sentry/types': 8.5.0
+      '@sentry/utils': 8.5.0
+
+  '@sentry/profiling-node@8.5.0':
+    dependencies:
+      '@sentry/core': 8.5.0
+      '@sentry/node': 8.5.0
+      '@sentry/types': 8.5.0
+      '@sentry/utils': 8.5.0
+      detect-libc: 2.0.3
+      node-abi: 3.62.0
+    transitivePeerDependencies:
+      - supports-color
+
+  '@sentry/types@8.5.0': {}
+
+  '@sentry/utils@8.5.0':
+    dependencies:
+      '@sentry/types': 8.5.0
+
   '@shikijs/core@1.4.0': {}
 
   '@sideway/address@4.1.4':
@@ -15301,10 +15830,21 @@ snapshots:
     dependencies:
       '@types/node': 20.12.7
 
+  '@types/connect@3.4.36':
+    dependencies:
+      '@types/node': 20.12.7
+
   '@types/content-disposition@0.5.8': {}
 
   '@types/cookie@0.6.0': {}
 
+  '@types/cookies@0.9.0':
+    dependencies:
+      '@types/connect': 3.4.35
+      '@types/express': 4.17.17
+      '@types/keygrip': 1.0.6
+      '@types/node': 20.12.7
+
   '@types/cross-spawn@6.0.2':
     dependencies:
       '@types/node': 20.12.7
@@ -15372,8 +15912,12 @@ snapshots:
 
   '@types/htmlescape@1.1.3': {}
 
+  '@types/http-assert@1.5.5': {}
+
   '@types/http-cache-semantics@4.0.4': {}
 
+  '@types/http-errors@2.0.4': {}
+
   '@types/http-link-header@1.0.5':
     dependencies:
       '@types/node': 20.12.7
@@ -15411,10 +15955,31 @@ snapshots:
 
   '@types/jsrsasign@10.5.14': {}
 
+  '@types/keygrip@1.0.6': {}
+
   '@types/keyv@3.1.4':
     dependencies:
       '@types/node': 20.12.7
 
+  '@types/koa-compose@3.2.8':
+    dependencies:
+      '@types/koa': 2.14.0
+
+  '@types/koa@2.14.0':
+    dependencies:
+      '@types/accepts': 1.3.7
+      '@types/content-disposition': 0.5.8
+      '@types/cookies': 0.9.0
+      '@types/http-assert': 1.5.5
+      '@types/http-errors': 2.0.4
+      '@types/keygrip': 1.0.6
+      '@types/koa-compose': 3.2.8
+      '@types/node': 20.12.7
+
+  '@types/koa__router@12.0.3':
+    dependencies:
+      '@types/koa': 2.14.0
+
   '@types/lodash@4.14.191': {}
 
   '@types/long@4.0.2': {}
@@ -15445,6 +16010,10 @@ snapshots:
     dependencies:
       '@types/node': 20.12.7
 
+  '@types/mysql@2.15.22':
+    dependencies:
+      '@types/node': 20.12.7
+
   '@types/node-fetch@2.6.4':
     dependencies:
       '@types/node': 20.12.7
@@ -15491,12 +16060,22 @@ snapshots:
 
   '@types/offscreencanvas@2019.7.0': {}
 
+  '@types/pg-pool@2.0.4':
+    dependencies:
+      '@types/pg': 8.11.5
+
   '@types/pg@8.11.5':
     dependencies:
       '@types/node': 20.12.7
       pg-protocol: 1.6.0
       pg-types: 4.0.1
 
+  '@types/pg@8.6.1':
+    dependencies:
+      '@types/node': 20.12.7
+      pg-protocol: 1.6.1
+      pg-types: 2.2.0
+
   '@types/pretty-hrtime@1.0.1': {}
 
   '@types/prop-types@15.7.5': {}
@@ -15554,6 +16133,8 @@ snapshots:
 
   '@types/serviceworker@0.0.67': {}
 
+  '@types/shimmer@1.0.5': {}
+
   '@types/simple-oauth2@5.0.7': {}
 
   '@types/sinon@10.0.13':
@@ -16096,6 +16677,15 @@ snapshots:
       mime-types: 2.1.35
       negotiator: 0.6.3
 
+  acorn-import-assertions@1.9.0(acorn@8.11.3):
+    dependencies:
+      acorn: 8.11.3
+    optional: true
+
+  acorn-import-attributes@1.9.5(acorn@8.11.3):
+    dependencies:
+      acorn: 8.11.3
+
   acorn-jsx@5.3.2(acorn@7.4.1):
     dependencies:
       acorn: 7.4.1
@@ -19001,6 +19591,21 @@ snapshots:
       parent-module: 1.0.1
       resolve-from: 4.0.0
 
+  import-in-the-middle@1.4.2:
+    dependencies:
+      acorn: 8.11.3
+      acorn-import-assertions: 1.9.0(acorn@8.11.3)
+      cjs-module-lexer: 1.2.2
+      module-details-from-path: 1.0.3
+    optional: true
+
+  import-in-the-middle@1.7.4:
+    dependencies:
+      acorn: 8.11.3
+      acorn-import-attributes: 1.9.5(acorn@8.11.3)
+      cjs-module-lexer: 1.2.2
+      module-details-from-path: 1.0.3
+
   import-lazy@4.0.0: {}
 
   import-local@3.1.0:
@@ -20509,6 +21114,8 @@ snapshots:
 
   mock-socket@9.3.1: {}
 
+  module-details-from-path@1.0.3: {}
+
   mri@1.2.0: {}
 
   ms@2.0.0: {}
@@ -20645,6 +21252,10 @@ snapshots:
       just-extend: 4.2.1
       path-to-regexp: 1.8.0
 
+  node-abi@3.62.0:
+    dependencies:
+      semver: 7.6.0
+
   node-abort-controller@3.1.1: {}
 
   node-addon-api@3.2.1:
@@ -20897,6 +21508,15 @@ snapshots:
       undici: 5.28.2
       yargs-parser: 21.1.1
 
+  opentelemetry-instrumentation-fetch-node@1.2.0:
+    dependencies:
+      '@opentelemetry/api': 1.8.0
+      '@opentelemetry/instrumentation': 0.43.0(@opentelemetry/api@1.8.0)
+      '@opentelemetry/semantic-conventions': 1.24.1
+    transitivePeerDependencies:
+      - supports-color
+    optional: true
+
   optionator@0.9.3:
     dependencies:
       '@aashutoshrathi/word-wrap': 1.2.6
@@ -21910,6 +22530,14 @@ snapshots:
 
   require-from-string@2.0.2: {}
 
+  require-in-the-middle@7.3.0:
+    dependencies:
+      debug: 4.3.4(supports-color@8.1.1)
+      module-details-from-path: 1.0.3
+      resolve: 1.22.8
+    transitivePeerDependencies:
+      - supports-color
+
   require-main-filename@2.0.0: {}
 
   requires-port@1.0.0: {}
@@ -22168,6 +22796,8 @@ snapshots:
     dependencies:
       '@shikijs/core': 1.4.0
 
+  shimmer@1.2.1: {}
+
   side-channel@1.0.4:
     dependencies:
       call-bind: 1.0.2

From 244adef70e29a77cc65864ca4a8b46babd4bc38d Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Tue, 28 May 2024 09:18:05 +0000
Subject: [PATCH 165/191] Bump version to 2024.5.0-rc.6

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 6caf4fc114..a7d5f7eb51 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2024.5.0-beta.5",
+	"version": "2024.5.0-rc.6",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index f010699ec6..f3bbb48999 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2024.5.0-beta.5",
+	"version": "2024.5.0-rc.6",
 	"description": "Misskey SDK for JavaScript",
 	"main": "./built/index.js",
 	"types": "./built/index.d.ts",

From f75e46752e2911f48d856657cb458de2b1967730 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Tue, 28 May 2024 09:18:21 +0000
Subject: [PATCH 166/191] Bump version to 2024.5.0-rc.7

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index a7d5f7eb51..ccaa597322 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2024.5.0-rc.6",
+	"version": "2024.5.0-rc.7",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index f3bbb48999..e72f929d6b 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2024.5.0-rc.6",
+	"version": "2024.5.0-rc.7",
 	"description": "Misskey SDK for JavaScript",
 	"main": "./built/index.js",
 	"types": "./built/index.d.ts",

From 44cafbb9f238e13e079135b96c4a791fb3b7faf0 Mon Sep 17 00:00:00 2001
From: Kisaragi <48310258+KisaragiEffective@users.noreply.github.com>
Date: Wed, 29 May 2024 07:11:29 +0900
Subject: [PATCH 167/191] refactor: avoid `as any[]` on
 FetchInstanceMetadataService.ts (#13905)

* refactor: avoid `as any[]` on FetchInstanceMetadataService.ts

* apply suggestion

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 packages/backend/src/core/FetchInstanceMetadataService.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/backend/src/core/FetchInstanceMetadataService.ts b/packages/backend/src/core/FetchInstanceMetadataService.ts
index 8d173855f3..aa16468ecb 100644
--- a/packages/backend/src/core/FetchInstanceMetadataService.ts
+++ b/packages/backend/src/core/FetchInstanceMetadataService.ts
@@ -154,7 +154,7 @@ export class FetchInstanceMetadataService {
 				throw new Error('No wellknown links');
 			}
 
-			const links = wellknown.links as any[];
+			const links = wellknown.links as ({ rel: string, href: string; })[];
 
 			const link1_0 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/1.0');
 			const link2_0 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/2.0');

From e57ce4fa0f663210514ecda728562a73c0fe9c5e Mon Sep 17 00:00:00 2001
From: Kisaragi <48310258+KisaragiEffective@users.noreply.github.com>
Date: Wed, 29 May 2024 07:12:20 +0900
Subject: [PATCH 168/191] chore(backend): rename local variable (#13904)

much -> matched
---
 packages/backend/src/core/DriveService.ts | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/packages/backend/src/core/DriveService.ts b/packages/backend/src/core/DriveService.ts
index 63fa26f69d..26cf532c70 100644
--- a/packages/backend/src/core/DriveService.ts
+++ b/packages/backend/src/core/DriveService.ts
@@ -497,20 +497,20 @@ export class DriveService {
 
 		if (user && !force) {
 		// Check if there is a file with the same hash
-			const much = await this.driveFilesRepository.findOneBy({
+			const matched = await this.driveFilesRepository.findOneBy({
 				md5: info.md5,
 				userId: user.id,
 			});
 
-			if (much) {
-				this.registerLogger.info(`file with same hash is found: ${much.id}`);
-				if (sensitive && !much.isSensitive) {
+			if (matched) {
+				this.registerLogger.info(`file with same hash is found: ${matched.id}`);
+				if (sensitive && !matched.isSensitive) {
 					// The file is federated as sensitive for this time, but was federated as non-sensitive before.
 					// Therefore, update the file to sensitive.
-					await this.driveFilesRepository.update({ id: much.id }, { isSensitive: true });
-					much.isSensitive = true;
+					await this.driveFilesRepository.update({ id: matched.id }, { isSensitive: true });
+					matched.isSensitive = true;
 				}
-				return much;
+				return matched;
 			}
 		}
 

From cf670e8a3dc9830110312b54eceaea29cf20495c Mon Sep 17 00:00:00 2001
From: Kisaragi <48310258+KisaragiEffective@users.noreply.github.com>
Date: Wed, 29 May 2024 07:12:50 +0900
Subject: [PATCH 169/191] refactor(backend): avoid `as any` on
 CustomEmojiService.ts (#13903)

---
 packages/backend/src/core/CustomEmojiService.ts | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts
index 1c75566755..b1feca7fb4 100644
--- a/packages/backend/src/core/CustomEmojiService.ts
+++ b/packages/backend/src/core/CustomEmojiService.ts
@@ -346,10 +346,11 @@ export class CustomEmojiService implements OnApplicationShutdown {
 	@bindThis
 	public async populateEmojis(emojiNames: string[], noteUserHost: string | null): Promise<Record<string, string>> {
 		const emojis = await Promise.all(emojiNames.map(x => this.populateEmoji(x, noteUserHost)));
-		const res = {} as any;
+		const res = {} as Record<string, string>;
 		for (let i = 0; i < emojiNames.length; i++) {
-			if (emojis[i] != null) {
-				res[emojiNames[i]] = emojis[i];
+			const resolvedEmoji = emojis[i];
+			if (resolvedEmoji != null) {
+				res[emojiNames[i]] = resolvedEmoji;
 			}
 		}
 		return res;

From eaadd643ebdfb7b9cc5bd04eb68af740ced52c87 Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Wed, 29 May 2024 20:57:48 +0900
Subject: [PATCH 170/191] chore(misskey-js): fix `repository` and add `license`
 in `package.json` (#13902)

---
 packages/misskey-js/package.json | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index 6badc7f3ee..f496d8bb1d 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -3,6 +3,7 @@
 	"name": "misskey-js",
 	"version": "2024.3.1",
 	"description": "Misskey SDK for JavaScript",
+	"license": "MIT",
 	"main": "./built/index.js",
 	"types": "./built/index.d.ts",
 	"exports": {
@@ -30,7 +31,8 @@
 	},
 	"repository": {
 		"type": "git",
-		"url": "git+https://github.com/misskey-dev/misskey.js.git"
+		"url": "https://github.com/misskey-dev/misskey.git",
+		"directory": "packages/misskey-js"
 	},
 	"devDependencies": {
 		"@microsoft/api-extractor": "7.43.1",

From 24d4124ffcd3b26d2f9fbec87f917b584f494ece Mon Sep 17 00:00:00 2001
From: KanariKanaru <93921745+kanarikanaru@users.noreply.github.com>
Date: Thu, 30 May 2024 17:36:58 +0900
Subject: [PATCH 171/191] =?UTF-8?q?fix(frontend):=20=E3=83=8E=E3=83=BC?=
 =?UTF-8?q?=E3=83=88=E3=81=AB=E3=83=86=E3=82=AD=E3=82=B9=E3=83=88=E3=81=8C?=
 =?UTF-8?q?=E3=81=AA=E3=81=8F=E3=81=A6=E3=82=82=E3=83=95=E3=82=A1=E3=82=A4?=
 =?UTF-8?q?=E3=83=AB=E3=81=8C5=E3=81=A4=E4=BB=A5=E4=B8=8A=E3=81=82?=
 =?UTF-8?q?=E3=82=8B=E3=81=A8=E3=81=8D=E3=81=AF=E6=8A=98=E3=82=8A=E3=81=9F?=
 =?UTF-8?q?=E3=81=9F=E3=82=80=E3=82=88=E3=81=86=E3=81=AB=20(#13907)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix: ノートにテキストがなくてもファイルが5つ以上あるときは折りたたむように

* 冗長な記述を修正

* Update CHANGELOG.md
---
 CHANGELOG.md                               |  1 +
 packages/frontend/src/scripts/collapsed.ts | 19 ++++++++++---------
 2 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4091668b54..865684aa20 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -73,6 +73,7 @@
 - Fix: 通知をグループ化している際に、人数が正常に表示されないことがある問題を修正
 - Fix: 連合なしの状態の読み書きができない問題を修正
 - Fix: `/share` で日本語等を含むurlがurlエンコードされない問題を修正
+- Fix: ファイルを5つ以上添付してもテキストがないとノートが折りたたまれない問題を修正
 
 ### Server
 - Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
diff --git a/packages/frontend/src/scripts/collapsed.ts b/packages/frontend/src/scripts/collapsed.ts
index 237bd37c7a..4ec88a3c65 100644
--- a/packages/frontend/src/scripts/collapsed.ts
+++ b/packages/frontend/src/scripts/collapsed.ts
@@ -6,15 +6,16 @@
 import * as Misskey from 'misskey-js';
 
 export function shouldCollapsed(note: Misskey.entities.Note, urls: string[]): boolean {
-	const collapsed = note.cw == null && note.text != null && (
-		(note.text.includes('$[x2')) ||
-		(note.text.includes('$[x3')) ||
-		(note.text.includes('$[x4')) ||
-		(note.text.includes('$[scale')) ||
-		(note.text.split('\n').length > 9) ||
-		(note.text.length > 500) ||
-		(note.files.length >= 5) ||
-		(urls.length >= 4)
+	const collapsed = note.cw == null && (
+		note.text != null && (
+			(note.text.includes('$[x2')) ||
+			(note.text.includes('$[x3')) ||
+			(note.text.includes('$[x4')) ||
+			(note.text.includes('$[scale')) ||
+			(note.text.split('\n').length > 9) ||
+			(note.text.length > 500) ||
+			(urls.length >= 4)
+		) || note.files.length >= 5
 	);
 
 	return collapsed;

From ac4a001e9f193e4727a8e65e59978a9464a56d75 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Fri, 31 May 2024 10:11:11 +0900
Subject: [PATCH 172/191] fix code style

---
 .../MkCustomEmojiDetailedDialog.vue           | 108 +++++++++---------
 1 file changed, 56 insertions(+), 52 deletions(-)

diff --git a/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue b/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue
index 84b5375a41..c7f1288729 100644
--- a/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue
+++ b/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue
@@ -4,77 +4,81 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-  <MkModalWindow ref="dialogEl" @close="cancel()" @closed="$emit('closed')">
-    <template #header>:{{ emoji.name }}:</template>
-    <template #default>
-      <MkSpacer>
-        <div style="display: flex; flex-direction: column; gap: 1em;">
-          <div :class="$style.emojiImgWrapper">
-            <MkCustomEmoji :name="emoji.name" :normal="true" :useOriginalSize="true" style="height: 100%;"></MkCustomEmoji>
-          </div>
-          <MkKeyValue :copy="`:${emoji.name}:`">
-            <template #key>{{ i18n.ts.name }}</template>
-            <template #value>{{ emoji.name }}</template>
-          </MkKeyValue>
-          <MkKeyValue>
-            <template #key>{{ i18n.ts.tags }}</template>
-            <template #value>
-              <div v-if="emoji.aliases.length === 0">{{ i18n.ts.none }}</div>
-              <div v-else :class="$style.aliases">
-                <span v-for="alias in emoji.aliases" :key="alias" :class="$style.alias">
-                  {{ alias }}
-                </span>
-              </div>
-            </template>
-          </MkKeyValue>
-          <MkKeyValue>
-            <template #key>{{ i18n.ts.category }}</template>
-            <template #value>{{ emoji.category ?? i18n.ts.none }}</template>
-          </MkKeyValue>
-          <MkKeyValue>
-            <template #key>{{ i18n.ts.sensitive }}</template>
-            <template #value>{{ emoji.isSensitive ? i18n.ts.yes : i18n.ts.no }}</template>
-          </MkKeyValue>
-          <MkKeyValue>
-            <template #key>{{ i18n.ts.localOnly }}</template>
-            <template #value>{{ emoji.localOnly ? i18n.ts.yes : i18n.ts.no }}</template>
-          </MkKeyValue>
-          <MkKeyValue>
-            <template #key>{{ i18n.ts.license }}</template>
-            <template #value><Mfm :text="emoji.license ?? i18n.ts.none" /></template>
-          </MkKeyValue>
-          <MkKeyValue :copy="emoji.url">
-            <template #key>{{ i18n.ts.emojiUrl }}</template>
-            <template #value>
-              <MkLink :url="emoji.url" target="_blank">{{ emoji.url }}</MkLink>
-            </template>
-          </MkKeyValue>
-        </div>
-      </MkSpacer>
-    </template>
-  </MkModalWindow>
+<MkModalWindow ref="dialogEl" @close="cancel()" @closed="$emit('closed')">
+	<template #header>:{{ emoji.name }}:</template>
+	<template #default>
+		<MkSpacer>
+			<div style="display: flex; flex-direction: column; gap: 1em;">
+				<div :class="$style.emojiImgWrapper">
+					<MkCustomEmoji :name="emoji.name" :normal="true" :useOriginalSize="true" style="height: 100%;"></MkCustomEmoji>
+				</div>
+				<MkKeyValue :copy="`:${emoji.name}:`">
+					<template #key>{{ i18n.ts.name }}</template>
+					<template #value>{{ emoji.name }}</template>
+				</MkKeyValue>
+				<MkKeyValue>
+					<template #key>{{ i18n.ts.tags }}</template>
+					<template #value>
+						<div v-if="emoji.aliases.length === 0">{{ i18n.ts.none }}</div>
+						<div v-else :class="$style.aliases">
+							<span v-for="alias in emoji.aliases" :key="alias" :class="$style.alias">
+								{{ alias }}
+							</span>
+						</div>
+					</template>
+				</MkKeyValue>
+				<MkKeyValue>
+					<template #key>{{ i18n.ts.category }}</template>
+					<template #value>{{ emoji.category ?? i18n.ts.none }}</template>
+				</MkKeyValue>
+				<MkKeyValue>
+					<template #key>{{ i18n.ts.sensitive }}</template>
+					<template #value>{{ emoji.isSensitive ? i18n.ts.yes : i18n.ts.no }}</template>
+				</MkKeyValue>
+				<MkKeyValue>
+					<template #key>{{ i18n.ts.localOnly }}</template>
+					<template #value>{{ emoji.localOnly ? i18n.ts.yes : i18n.ts.no }}</template>
+				</MkKeyValue>
+				<MkKeyValue>
+					<template #key>{{ i18n.ts.license }}</template>
+					<template #value><Mfm :text="emoji.license ?? i18n.ts.none"/></template>
+				</MkKeyValue>
+				<MkKeyValue :copy="emoji.url">
+					<template #key>{{ i18n.ts.emojiUrl }}</template>
+					<template #value>
+						<MkLink :url="emoji.url" target="_blank">{{ emoji.url }}</MkLink>
+					</template>
+				</MkKeyValue>
+			</div>
+		</MkSpacer>
+	</template>
+</MkModalWindow>
 </template>
 
 <script lang="ts" setup>
 import * as Misskey from 'misskey-js';
 import { defineProps, shallowRef } from 'vue';
+import MkLink from '@/components/MkLink.vue';
 import { i18n } from '@/i18n.js';
 import MkModalWindow from '@/components/MkModalWindow.vue';
 import MkKeyValue from '@/components/MkKeyValue.vue';
-import MkLink from './MkLink.vue';
+
 const props = defineProps<{
   emoji: Misskey.entities.EmojiDetailed,
 }>();
+
 const emit = defineEmits<{
 	(ev: 'ok', cropped: Misskey.entities.DriveFile): void;
 	(ev: 'cancel'): void;
 	(ev: 'closed'): void;
 }>();
+
 const dialogEl = shallowRef<InstanceType<typeof MkModalWindow>>();
-const cancel = () => {
+
+function cancel() {
 	emit('cancel');
 	dialogEl.value!.close();
-};
+}
 </script>
 
 <style lang="scss" module>

From be11fd75085e8f8c000a42b40bd583894121a708 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Fri, 31 May 2024 10:12:23 +0900
Subject: [PATCH 173/191] =?UTF-8?q?enhance:=20=E3=82=B5=E3=83=BC=E3=83=90?=
 =?UTF-8?q?=E3=83=BC=E3=81=AE=E3=81=8A=E5=95=8F=E3=81=84=E5=90=88=E3=82=8F?=
 =?UTF-8?q?=E3=81=9B=E5=85=88URL=E3=82=92=E8=A8=AD=E5=AE=9A=E3=81=A7?=
 =?UTF-8?q?=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 CHANGELOG.md                                  |  1 +
 locales/index.d.ts                            |  8 ++++++++
 locales/ja-JP.yml                             |  2 ++
 .../migration/1717117195275-inquiryUrl.js     | 20 +++++++++++++++++++
 .../src/core/entities/MetaEntityService.ts    |  1 +
 packages/backend/src/models/Meta.ts           |  6 ++++++
 .../backend/src/models/json-schema/meta.ts    |  4 ++++
 .../src/server/NodeinfoServerService.ts       | 13 ++++++------
 .../src/server/api/endpoints/admin/meta.ts    |  5 +++++
 .../server/api/endpoints/admin/update-meta.ts |  5 +++++
 .../frontend/src/pages/admin/moderation.vue   |  9 +++++++++
 packages/frontend/src/pages/contact.vue       | 18 ++++++++++++++++-
 packages/misskey-js/src/autogen/types.ts      |  3 +++
 13 files changed, 88 insertions(+), 7 deletions(-)
 create mode 100644 packages/backend/migration/1717117195275-inquiryUrl.js

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 865684aa20..efd07da891 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,6 +20,7 @@
 - Enhance: Goneを出さずに終了したサーバーへの配信停止を自動的に行うように
   - もしそのようなサーバーからから配信が届いた場合には自動的に配信を再開します
 - Enhance: 配信停止の理由を表示するように
+- Enhance: サーバーのお問い合わせ先URLを設定できるようになりました
 - Fix: Play作成時に設定した公開範囲が機能していない問題を修正
 - Fix: 正規化されていない状態のhashtagが連合されてきたhtmlに含まれているとhashtagが正しくhashtagに復元されない問題を修正
 - Fix: みつけるのアンケート欄にてチャンネルのアンケートが含まれてしまう問題を修正
diff --git a/locales/index.d.ts b/locales/index.d.ts
index d4ded0bb5b..91bbe4ccb6 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -5471,6 +5471,14 @@ export interface Locale extends ILocale {
          * 有効にすると、タイムラインがキャッシュされていない場合にDBへ追加で問い合わせを行うフォールバック処理を行います。無効にすると、フォールバック処理を行わないことでさらにサーバーの負荷を軽減することができますが、タイムラインが取得できる範囲に制限が生じます。
          */
         "fanoutTimelineDbFallbackDescription": string;
+        /**
+         * 問い合わせ先URL
+         */
+        "inquiryUrl": string;
+        /**
+         * サーバー運営者へのお問い合わせフォームのURLや、運営者の連絡先等が記載されたWebページのURLを指定します。
+         */
+        "inquiryUrlDescription": string;
     };
     "_accountMigration": {
         /**
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index d7ceb971af..b7083b4942 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1383,6 +1383,8 @@ _serverSettings:
   fanoutTimelineDescription: "有効にすると、各種タイムラインを取得する際のパフォーマンスが大幅に向上し、データベースへの負荷を軽減することが可能です。ただし、Redisのメモリ使用量は増加します。サーバーのメモリ容量が少ない場合、または動作が不安定な場合は無効にすることができます。"
   fanoutTimelineDbFallback: "データベースへのフォールバック"
   fanoutTimelineDbFallbackDescription: "有効にすると、タイムラインがキャッシュされていない場合にDBへ追加で問い合わせを行うフォールバック処理を行います。無効にすると、フォールバック処理を行わないことでさらにサーバーの負荷を軽減することができますが、タイムラインが取得できる範囲に制限が生じます。"
+  inquiryUrl: "問い合わせ先URL"
+  inquiryUrlDescription: "サーバー運営者へのお問い合わせフォームのURLや、運営者の連絡先等が記載されたWebページのURLを指定します。"
 
 _accountMigration:
   moveFrom: "別のアカウントからこのアカウントに移行"
diff --git a/packages/backend/migration/1717117195275-inquiryUrl.js b/packages/backend/migration/1717117195275-inquiryUrl.js
new file mode 100644
index 0000000000..3834df06d4
--- /dev/null
+++ b/packages/backend/migration/1717117195275-inquiryUrl.js
@@ -0,0 +1,20 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class InquiryUrl1717117195275 {
+    name = 'InquiryUrl1717117195275'
+
+    async up(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "meta" RENAME COLUMN "trustedLinkUrlPatterns" TO "inquiryUrl"`);
+        await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "inquiryUrl"`);
+        await queryRunner.query(`ALTER TABLE "meta" ADD "inquiryUrl" character varying(1024)`);
+    }
+
+    async down(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "inquiryUrl"`);
+        await queryRunner.query(`ALTER TABLE "meta" ADD "inquiryUrl" character varying(3072) array NOT NULL DEFAULT '{}'`);
+        await queryRunner.query(`ALTER TABLE "meta" RENAME COLUMN "inquiryUrl" TO "trustedLinkUrlPatterns"`);
+    }
+}
diff --git a/packages/backend/src/core/entities/MetaEntityService.ts b/packages/backend/src/core/entities/MetaEntityService.ts
index 9d054ab6a1..5dfec589e1 100644
--- a/packages/backend/src/core/entities/MetaEntityService.ts
+++ b/packages/backend/src/core/entities/MetaEntityService.ts
@@ -67,6 +67,7 @@ export class MetaEntityService {
 			feedbackUrl: instance.feedbackUrl,
 			impressumUrl: instance.impressumUrl,
 			privacyPolicyUrl: instance.privacyPolicyUrl,
+			inquiryUrl: instance.inquiryUrl,
 			disableRegistration: instance.disableRegistration,
 			emailRequiredForSignup: instance.emailRequiredForSignup,
 			enableHcaptcha: instance.enableHcaptcha,
diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts
index 04a34bbbb4..ad306fcad6 100644
--- a/packages/backend/src/models/Meta.ts
+++ b/packages/backend/src/models/Meta.ts
@@ -376,6 +376,12 @@ export class MiMeta {
 	})
 	public privacyPolicyUrl: string | null;
 
+	@Column('varchar', {
+		length: 1024,
+		nullable: true,
+	})
+	public inquiryUrl: string | null;
+
 	@Column('varchar', {
 		length: 8192,
 		nullable: true,
diff --git a/packages/backend/src/models/json-schema/meta.ts b/packages/backend/src/models/json-schema/meta.ts
index 473339a1ad..e7bc6356e5 100644
--- a/packages/backend/src/models/json-schema/meta.ts
+++ b/packages/backend/src/models/json-schema/meta.ts
@@ -227,6 +227,10 @@ export const packedMetaLiteSchema = {
 			type: 'string',
 			optional: false, nullable: true,
 		},
+		inquiryUrl: {
+			type: 'string',
+			optional: false, nullable: true,
+		},
 		serverRules: {
 			type: 'array',
 			optional: false, nullable: false,
diff --git a/packages/backend/src/server/NodeinfoServerService.ts b/packages/backend/src/server/NodeinfoServerService.ts
index c1e5af08c9..cc18997fdc 100644
--- a/packages/backend/src/server/NodeinfoServerService.ts
+++ b/packages/backend/src/server/NodeinfoServerService.ts
@@ -37,12 +37,12 @@ export class NodeinfoServerService {
 	@bindThis
 	public getLinks() {
 		return [{
-				rel: 'http://nodeinfo.diaspora.software/ns/schema/2.1',
-				href: this.config.url + nodeinfo2_1path
-			}, {
-				rel: 'http://nodeinfo.diaspora.software/ns/schema/2.0',
-				href: this.config.url + nodeinfo2_0path,
-			}];
+			rel: 'http://nodeinfo.diaspora.software/ns/schema/2.1',
+			href: this.config.url + nodeinfo2_1path,
+		}, {
+			rel: 'http://nodeinfo.diaspora.software/ns/schema/2.0',
+			href: this.config.url + nodeinfo2_0path,
+		}];
 	}
 
 	@bindThis
@@ -108,6 +108,7 @@ export class NodeinfoServerService {
 					langs: meta.langs,
 					tosUrl: meta.termsOfServiceUrl,
 					privacyPolicyUrl: meta.privacyPolicyUrl,
+					inquiryUrl: meta.inquiryUrl,
 					impressumUrl: meta.impressumUrl,
 					repositoryUrl: meta.repositoryUrl,
 					feedbackUrl: meta.feedbackUrl,
diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts
index f4ff573271..eee02a7123 100644
--- a/packages/backend/src/server/api/endpoints/admin/meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/meta.ts
@@ -427,6 +427,10 @@ export const meta = {
 				type: 'string',
 				optional: false, nullable: true,
 			},
+			inquiryUrl: {
+				type: 'string',
+				optional: false, nullable: true,
+			},
 			repositoryUrl: {
 				type: 'string',
 				optional: false, nullable: true,
@@ -513,6 +517,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				feedbackUrl: instance.feedbackUrl,
 				impressumUrl: instance.impressumUrl,
 				privacyPolicyUrl: instance.privacyPolicyUrl,
+				inquiryUrl: instance.inquiryUrl,
 				disableRegistration: instance.disableRegistration,
 				emailRequiredForSignup: instance.emailRequiredForSignup,
 				enableHcaptcha: instance.enableHcaptcha,
diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
index 2f62d30ada..4e28ee6877 100644
--- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
@@ -107,6 +107,7 @@ export const paramDef = {
 		feedbackUrl: { type: 'string', nullable: true },
 		impressumUrl: { type: 'string', nullable: true },
 		privacyPolicyUrl: { type: 'string', nullable: true },
+		inquiryUrl: { type: 'string', nullable: true },
 		useObjectStorage: { type: 'boolean' },
 		objectStorageBaseUrl: { type: 'string', nullable: true },
 		objectStorageBucket: { type: 'string', nullable: true },
@@ -422,6 +423,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				set.privacyPolicyUrl = ps.privacyPolicyUrl;
 			}
 
+			if (ps.inquiryUrl !== undefined) {
+				set.inquiryUrl = ps.inquiryUrl;
+			}
+
 			if (ps.useObjectStorage !== undefined) {
 				set.useObjectStorage = ps.useObjectStorage;
 			}
diff --git a/packages/frontend/src/pages/admin/moderation.vue b/packages/frontend/src/pages/admin/moderation.vue
index 9efb34ac9a..a75799696d 100644
--- a/packages/frontend/src/pages/admin/moderation.vue
+++ b/packages/frontend/src/pages/admin/moderation.vue
@@ -30,6 +30,12 @@ SPDX-License-Identifier: AGPL-3.0-only
 						<template #label>{{ i18n.ts.privacyPolicyUrl }}</template>
 					</MkInput>
 
+					<MkInput v-model="inquiryUrl" type="url">
+						<template #prefix><i class="ti ti-link"></i></template>
+						<template #label>{{ i18n.ts._serverSettings.inquiryUrl }}</template>
+						<template #caption>{{ i18n.ts._serverSettings.inquiryUrlDescription }}</template>
+					</MkInput>
+
 					<MkTextarea v-model="preservedUsernames">
 						<template #label>{{ i18n.ts.preservedUsernames }}</template>
 						<template #caption>{{ i18n.ts.preservedUsernamesDescription }}</template>
@@ -86,6 +92,7 @@ const hiddenTags = ref<string>('');
 const preservedUsernames = ref<string>('');
 const tosUrl = ref<string | null>(null);
 const privacyPolicyUrl = ref<string | null>(null);
+const inquiryUrl = ref<string | null>(null);
 
 async function init() {
 	const meta = await misskeyApi('admin/meta');
@@ -97,6 +104,7 @@ async function init() {
 	preservedUsernames.value = meta.preservedUsernames.join('\n');
 	tosUrl.value = meta.tosUrl;
 	privacyPolicyUrl.value = meta.privacyPolicyUrl;
+	inquiryUrl.value = meta.inquiryUrl;
 }
 
 function save() {
@@ -105,6 +113,7 @@ function save() {
 		emailRequiredForSignup: emailRequiredForSignup.value,
 		tosUrl: tosUrl.value,
 		privacyPolicyUrl: privacyPolicyUrl.value,
+		inquiryUrl: inquiryUrl.value,
 		sensitiveWords: sensitiveWords.value.split('\n'),
 		prohibitedWords: prohibitedWords.value.split('\n'),
 		hiddenTags: hiddenTags.value.split('\n'),
diff --git a/packages/frontend/src/pages/contact.vue b/packages/frontend/src/pages/contact.vue
index 3a694a7132..bcdcf43275 100644
--- a/packages/frontend/src/pages/contact.vue
+++ b/packages/frontend/src/pages/contact.vue
@@ -7,7 +7,21 @@ SPDX-License-Identifier: AGPL-3.0-only
 <MkStickyContainer>
 	<template #header><MkPageHeader/></template>
 	<MkSpacer :contentMax="600" :marginMin="20">
-		<div>{{ instance.maintainerEmail }}</div>
+		<div class="_gaps">
+			<MkKeyValue>
+				<template #key>{{ i18n.ts.inquiry }}</template>
+				<template #value>
+					<MkLink :url="instance.inquiryUrl" target="_blank">{{ instance.inquiryUrl }}</MkLink>
+				</template>
+			</MkKeyValue>
+
+			<MkKeyValue>
+				<template #key>{{ i18n.ts.email }}</template>
+				<template #value>
+					<div>{{ instance.maintainerEmail }}</div>
+				</template>
+			</MkKeyValue>
+		</div>
 	</MkSpacer>
 </MkStickyContainer>
 </template>
@@ -16,6 +30,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 import { i18n } from '@/i18n.js';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
 import { instance } from '@/instance.js';
+import MkKeyValue from '@/components/MkKeyValue.vue';
+import MkLink from '@/components/MkLink.vue';
 
 definePageMetadata(() => ({
 	title: i18n.ts.inquiry,
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 11567677c9..9beb49fb64 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -4831,6 +4831,7 @@ export type components = {
       impressumUrl: string | null;
       logoImageUrl: string | null;
       privacyPolicyUrl: string | null;
+      inquiryUrl: string | null;
       serverRules: string[];
       themeColor: string | null;
       policies: components['schemas']['RolePolicies'];
@@ -4978,6 +4979,7 @@ export type operations = {
             shortName: string | null;
             objectStorageS3ForcePathStyle: boolean;
             privacyPolicyUrl: string | null;
+            inquiryUrl: string | null;
             repositoryUrl: string | null;
             /**
              * @deprecated
@@ -8906,6 +8908,7 @@ export type operations = {
           feedbackUrl?: string | null;
           impressumUrl?: string | null;
           privacyPolicyUrl?: string | null;
+          inquiryUrl?: string | null;
           useObjectStorage?: boolean;
           objectStorageBaseUrl?: string | null;
           objectStorageBucket?: string | null;

From 5b8f8e7087cb447e43724bd28b4bdfdf03d328c2 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Fri, 31 May 2024 11:24:17 +0900
Subject: [PATCH 174/191] fix(backend): fix backward compatibility of antenna

---
 packages/backend/src/core/entities/AntennaEntityService.ts | 1 +
 packages/backend/src/models/json-schema/antenna.ts         | 5 +++++
 2 files changed, 6 insertions(+)

diff --git a/packages/backend/src/core/entities/AntennaEntityService.ts b/packages/backend/src/core/entities/AntennaEntityService.ts
index 4a17a3d80f..e770028af3 100644
--- a/packages/backend/src/core/entities/AntennaEntityService.ts
+++ b/packages/backend/src/core/entities/AntennaEntityService.ts
@@ -43,6 +43,7 @@ export class AntennaEntityService {
 			withFile: antenna.withFile,
 			isActive: antenna.isActive,
 			hasUnreadNote: false, // TODO
+			notify: false, // 後方互換性のため
 		};
 	}
 }
diff --git a/packages/backend/src/models/json-schema/antenna.ts b/packages/backend/src/models/json-schema/antenna.ts
index c4ac358fa6..b5b9a5b42c 100644
--- a/packages/backend/src/models/json-schema/antenna.ts
+++ b/packages/backend/src/models/json-schema/antenna.ts
@@ -95,5 +95,10 @@ export const packedAntennaSchema = {
 			optional: false, nullable: false,
 			default: false,
 		},
+		notify: {
+			type: 'boolean',
+			optional: false, nullable: false,
+			default: false,
+		},
 	},
 } as const;

From 00827472374554c9795fe372d1a605ea733441fc Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Fri, 31 May 2024 13:19:37 +0900
Subject: [PATCH 175/191] New Crowdin updates (#13892)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Chinese Traditional)
---
 locales/zh-CN.yml |  2 ++
 locales/zh-TW.yml | 11 ++++++++---
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index 3e500f8642..f92d997b5a 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -316,6 +316,7 @@ selectFile: "选择文件"
 selectFiles: "选择文件"
 selectFolder: "选择文件夹"
 selectFolders: "选择多个文件夹"
+fileNotSelected: "未选择文件"
 renameFile: "重命名文件"
 folderName: "文件夹名称"
 createFolder: "创建文件夹"
@@ -2358,6 +2359,7 @@ _deck:
   alwaysShowMainColumn: "总是显示主列"
   columnAlign: "列对齐"
   addColumn: "添加列"
+  newNoteNotificationSettings: "新帖子通知设定"
   configureColumn: "列设置"
   swapLeft: "向左移动"
   swapRight: "向右移动"
diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml
index fed7b642dc..aac3f7662c 100644
--- a/locales/zh-TW.yml
+++ b/locales/zh-TW.yml
@@ -316,6 +316,7 @@ selectFile: "選擇檔案"
 selectFiles: "選擇檔案"
 selectFolder: "選擇資料夾"
 selectFolders: "選擇資料夾"
+fileNotSelected: "尚未選擇檔案"
 renameFile: "重新命名檔案"
 folderName: "資料夾名稱"
 createFolder: "新增資料夾"
@@ -471,7 +472,7 @@ retype: "重新輸入"
 noteOf: "{user}的貼文"
 quoteAttached: "引用"
 quoteQuestion: "是否要引用?"
-attachAsFileQuestion: "剪貼簿的文字較長。請問是否要改成附加檔案呢?"
+attachAsFileQuestion: "剪貼簿的文字較長。請問是否要將其以文字檔的方式附加呢?"
 noMessagesYet: "沒有訊息"
 newMessageExists: "有新的訊息"
 onlyOneFileCanBeAttached: "只能加入一個附件"
@@ -1025,6 +1026,7 @@ thisPostMayBeAnnoyingHome: "發佈到首頁"
 thisPostMayBeAnnoyingCancel: "退出"
 thisPostMayBeAnnoyingIgnore: "直接發佈貼文"
 collapseRenotes: "省略顯示已看過的轉發貼文"
+collapseRenotesDescription: "將已做過反應和轉發的貼文折疊顯示。"
 internalServerError: "內部伺服器錯誤"
 internalServerErrorDescription: "內部伺服器出現意外錯誤。"
 copyErrorInfo: "複製錯誤資訊"
@@ -1241,8 +1243,8 @@ alwaysConfirmFollow: "點擊追隨時總是顯示確認訊息"
 inquiry: "聯絡我們"
 _delivery:
   status: "傳送狀態"
-  stop: "已凍結"
-  resume: "繼續傳送"
+  stop: "停止傳送"
+  resume: "恢復傳送"
   _type:
     none: "直播中"
     manuallySuspended: "手動暫停中"
@@ -1373,6 +1375,8 @@ _serverSettings:
   fanoutTimelineDescription: "如果啟用的話,檢索各個時間軸的性能會顯著提昇,資料庫的負荷也會減少。不過,Redis 的記憶體使用量會增加。如果伺服器的記憶體容量比較少或者運行不穩定,可以停用。"
   fanoutTimelineDbFallback: "資料庫的回退"
   fanoutTimelineDbFallbackDescription: "若啟用,在時間軸沒有快取的情況下將執行回退處理以額外查詢資料庫。若停用,可以透過不執行回退處理來進一步減少伺服器的負荷,但會限制可取得的時間軸範圍。"
+  inquiryUrl: "聯絡表單網址"
+  inquiryUrlDescription: "指定伺服器運營者的聯絡表單網址或包含運營者聯絡資訊網頁的網址。"
 _accountMigration:
   moveFrom: "從其他帳戶遷移到這個帳戶"
   moveFromSub: "為另一個帳戶建立別名"
@@ -2358,6 +2362,7 @@ _deck:
   alwaysShowMainColumn: "總是顯示主欄"
   columnAlign: "對齊欄位"
   addColumn: "新增欄位"
+  newNoteNotificationSettings: "新貼文通知的設定"
   configureColumn: "欄位的設定"
   swapLeft: "向左移動"
   swapRight: "向右移動"

From eaa85f5aa3fb936725fc9326e3cdae62f696c2e7 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Fri, 31 May 2024 13:28:11 +0900
Subject: [PATCH 176/191] fix test

---
 packages/backend/test/e2e/antennas.ts    | 1 +
 packages/misskey-js/src/autogen/types.ts | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/packages/backend/test/e2e/antennas.ts b/packages/backend/test/e2e/antennas.ts
index 4f78cc999d..101238b601 100644
--- a/packages/backend/test/e2e/antennas.ts
+++ b/packages/backend/test/e2e/antennas.ts
@@ -157,6 +157,7 @@ describe('アンテナ', () => {
 			withReplies: false,
 			excludeBots: false,
 			localOnly: false,
+			notify: false,
 		};
 		assert.deepStrictEqual(response, expected);
 	});
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 9beb49fb64..2c80676f3e 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -4449,6 +4449,8 @@ export type components = {
       isActive: boolean;
       /** @default false */
       hasUnreadNote: boolean;
+      /** @default false */
+      notify: boolean;
     };
     Clip: {
       /**

From 1e007b63aadc6bba6858539bef3b559b2811d232 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Fri, 31 May 2024 04:38:45 +0000
Subject: [PATCH 177/191] Bump version to 2024.5.0-rc.8

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index ccaa597322..04942d16bf 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2024.5.0-rc.7",
+	"version": "2024.5.0-rc.8",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index e3c9c0ff06..1a611d8f10 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2024.5.0-rc.7",
+	"version": "2024.5.0-rc.8",
 	"description": "Misskey SDK for JavaScript",
 	"license": "MIT",
 	"main": "./built/index.js",

From 97be1a53adec9edeeb83a8095b24efd4e8675787 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Fri, 31 May 2024 14:59:02 +0900
Subject: [PATCH 178/191] Update 1717117195275-inquiryUrl.js

---
 packages/backend/migration/1717117195275-inquiryUrl.js | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/packages/backend/migration/1717117195275-inquiryUrl.js b/packages/backend/migration/1717117195275-inquiryUrl.js
index 3834df06d4..29ca31af14 100644
--- a/packages/backend/migration/1717117195275-inquiryUrl.js
+++ b/packages/backend/migration/1717117195275-inquiryUrl.js
@@ -7,14 +7,10 @@ export class InquiryUrl1717117195275 {
     name = 'InquiryUrl1717117195275'
 
     async up(queryRunner) {
-        await queryRunner.query(`ALTER TABLE "meta" RENAME COLUMN "trustedLinkUrlPatterns" TO "inquiryUrl"`);
-        await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "inquiryUrl"`);
         await queryRunner.query(`ALTER TABLE "meta" ADD "inquiryUrl" character varying(1024)`);
     }
 
     async down(queryRunner) {
         await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "inquiryUrl"`);
-        await queryRunner.query(`ALTER TABLE "meta" ADD "inquiryUrl" character varying(3072) array NOT NULL DEFAULT '{}'`);
-        await queryRunner.query(`ALTER TABLE "meta" RENAME COLUMN "inquiryUrl" TO "trustedLinkUrlPatterns"`);
     }
 }

From 514a65e45330f09ad58cac3cab16bd888be80866 Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Fri, 31 May 2024 15:32:42 +0900
Subject: [PATCH 179/191] perf(backend): avoid N+1 selects from `user` table
 when packing many entities (#13911)

* perf(backend): avoid N+1 selects from `user` table when packing many entities

* perf(backend): use `packMany` instead of mapping to `pack`
---
 .../entities/AbuseUserReportEntityService.ts  | 34 ++++++++--
 .../core/entities/BlockingEntityService.ts    | 14 ++--
 .../src/core/entities/ClipEntityService.ts    | 12 +++-
 .../core/entities/DriveFileEntityService.ts   | 10 ++-
 .../src/core/entities/FlashEntityService.ts   | 14 ++--
 .../entities/FollowRequestEntityService.ts    | 27 +++++++-
 .../core/entities/FollowingEntityService.ts   | 24 +++++--
 .../core/entities/GalleryPostEntityService.ts | 12 +++-
 .../core/entities/InviteCodeEntityService.ts  | 25 +++++--
 .../entities/ModerationLogEntityService.ts    | 17 +++--
 .../src/core/entities/MutingEntityService.ts  | 14 ++--
 .../src/core/entities/NoteEntityService.ts    | 12 +++-
 .../entities/NoteReactionEntityService.ts     | 11 +++-
 .../src/core/entities/PageEntityService.ts    | 12 +++-
 .../entities/RenoteMutingEntityService.ts     | 14 ++--
 .../core/entities/ReversiGameEntityService.ts | 66 +++++++++++++------
 .../core/entities/UserListEntityService.ts    |  5 +-
 .../server/api/endpoints/admin/roles/users.ts |  5 +-
 .../server/api/endpoints/drive/files/find.ts  |  2 +-
 .../api/endpoints/following/requests/list.ts  |  2 +-
 .../server/api/endpoints/notes/reactions.ts   |  2 +-
 .../src/server/api/endpoints/roles/users.ts   |  5 +-
 .../users/get-frequently-replied-users.ts     | 10 +--
 .../src/server/api/endpoints/users/show.ts    |  6 +-
 24 files changed, 268 insertions(+), 87 deletions(-)

diff --git a/packages/backend/src/core/entities/AbuseUserReportEntityService.ts b/packages/backend/src/core/entities/AbuseUserReportEntityService.ts
index 49f256d870..b0e1d1ab36 100644
--- a/packages/backend/src/core/entities/AbuseUserReportEntityService.ts
+++ b/packages/backend/src/core/entities/AbuseUserReportEntityService.ts
@@ -10,6 +10,8 @@ import { awaitAll } from '@/misc/prelude/await-all.js';
 import type { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
 import { bindThis } from '@/decorators.js';
 import { IdService } from '@/core/IdService.js';
+import { isNotNull } from '@/misc/is-not-null.js';
+import type { Packed } from '@/misc/json-schema.js';
 import { UserEntityService } from './UserEntityService.js';
 
 @Injectable()
@@ -26,6 +28,11 @@ export class AbuseUserReportEntityService {
 	@bindThis
 	public async pack(
 		src: MiAbuseUserReport['id'] | MiAbuseUserReport,
+		hint?: {
+			packedReporter?: Packed<'UserDetailedNotMe'>,
+			packedTargetUser?: Packed<'UserDetailedNotMe'>,
+			packedAssignee?: Packed<'UserDetailedNotMe'>,
+		},
 	) {
 		const report = typeof src === 'object' ? src : await this.abuseUserReportsRepository.findOneByOrFail({ id: src });
 
@@ -37,13 +44,13 @@ export class AbuseUserReportEntityService {
 			reporterId: report.reporterId,
 			targetUserId: report.targetUserId,
 			assigneeId: report.assigneeId,
-			reporter: this.userEntityService.pack(report.reporter ?? report.reporterId, null, {
+			reporter: hint?.packedReporter ?? this.userEntityService.pack(report.reporter ?? report.reporterId, null, {
 				schema: 'UserDetailedNotMe',
 			}),
-			targetUser: this.userEntityService.pack(report.targetUser ?? report.targetUserId, null, {
+			targetUser: hint?.packedTargetUser ?? this.userEntityService.pack(report.targetUser ?? report.targetUserId, null, {
 				schema: 'UserDetailedNotMe',
 			}),
-			assignee: report.assigneeId ? this.userEntityService.pack(report.assignee ?? report.assigneeId, null, {
+			assignee: report.assigneeId ? hint?.packedAssignee ?? this.userEntityService.pack(report.assignee ?? report.assigneeId, null, {
 				schema: 'UserDetailedNotMe',
 			}) : null,
 			forwarded: report.forwarded,
@@ -51,9 +58,24 @@ export class AbuseUserReportEntityService {
 	}
 
 	@bindThis
-	public packMany(
-		reports: any[],
+	public async packMany(
+		reports: MiAbuseUserReport[],
 	) {
-		return Promise.all(reports.map(x => this.pack(x)));
+		const _reporters = reports.map(({ reporter, reporterId }) => reporter ?? reporterId);
+		const _targetUsers = reports.map(({ targetUser, targetUserId }) => targetUser ?? targetUserId);
+		const _assignees = reports.map(({ assignee, assigneeId }) => assignee ?? assigneeId).filter(isNotNull);
+		const _userMap = await this.userEntityService.packMany(
+			[..._reporters, ..._targetUsers, ..._assignees],
+			null,
+			{ schema: 'UserDetailedNotMe' },
+		).then(users => new Map(users.map(u => [u.id, u])));
+		return Promise.all(
+			reports.map(report => {
+				const packedReporter = _userMap.get(report.reporterId);
+				const packedTargetUser = _userMap.get(report.targetUserId);
+				const packedAssignee = report.assigneeId != null ? _userMap.get(report.assigneeId) : undefined;
+				return this.pack(report, { packedReporter, packedTargetUser, packedAssignee });
+			}),
+		);
 	}
 }
diff --git a/packages/backend/src/core/entities/BlockingEntityService.ts b/packages/backend/src/core/entities/BlockingEntityService.ts
index c8c1520ceb..1e699032e2 100644
--- a/packages/backend/src/core/entities/BlockingEntityService.ts
+++ b/packages/backend/src/core/entities/BlockingEntityService.ts
@@ -29,6 +29,9 @@ export class BlockingEntityService {
 	public async pack(
 		src: MiBlocking['id'] | MiBlocking,
 		me?: { id: MiUser['id'] } | null | undefined,
+		hint?: {
+			blockee?: Packed<'UserDetailedNotMe'>,
+		},
 	): Promise<Packed<'Blocking'>> {
 		const blocking = typeof src === 'object' ? src : await this.blockingsRepository.findOneByOrFail({ id: src });
 
@@ -36,17 +39,20 @@ export class BlockingEntityService {
 			id: blocking.id,
 			createdAt: this.idService.parse(blocking.id).date.toISOString(),
 			blockeeId: blocking.blockeeId,
-			blockee: this.userEntityService.pack(blocking.blockeeId, me, {
+			blockee: hint?.blockee ?? this.userEntityService.pack(blocking.blockeeId, me, {
 				schema: 'UserDetailedNotMe',
 			}),
 		});
 	}
 
 	@bindThis
-	public packMany(
-		blockings: any[],
+	public async packMany(
+		blockings: MiBlocking[],
 		me: { id: MiUser['id'] },
 	) {
-		return Promise.all(blockings.map(x => this.pack(x, me)));
+		const _blockees = blockings.map(({ blockee, blockeeId }) => blockee ?? blockeeId);
+		const _userMap = await this.userEntityService.packMany(_blockees, me, { schema: 'UserDetailedNotMe' })
+			.then(users => new Map(users.map(u => [u.id, u])));
+		return Promise.all(blockings.map(blocking => this.pack(blocking, me, { blockee: _userMap.get(blocking.blockeeId) })));
 	}
 }
diff --git a/packages/backend/src/core/entities/ClipEntityService.ts b/packages/backend/src/core/entities/ClipEntityService.ts
index ce49c3458c..3855a28436 100644
--- a/packages/backend/src/core/entities/ClipEntityService.ts
+++ b/packages/backend/src/core/entities/ClipEntityService.ts
@@ -35,6 +35,9 @@ export class ClipEntityService {
 	public async pack(
 		src: MiClip['id'] | MiClip,
 		me?: { id: MiUser['id'] } | null | undefined,
+		hint?: {
+			packedUser?: Packed<'UserLite'>
+		},
 	): Promise<Packed<'Clip'>> {
 		const meId = me ? me.id : null;
 		const clip = typeof src === 'object' ? src : await this.clipsRepository.findOneByOrFail({ id: src });
@@ -44,7 +47,7 @@ export class ClipEntityService {
 			createdAt: this.idService.parse(clip.id).date.toISOString(),
 			lastClippedAt: clip.lastClippedAt ? clip.lastClippedAt.toISOString() : null,
 			userId: clip.userId,
-			user: this.userEntityService.pack(clip.user ?? clip.userId),
+			user: hint?.packedUser ?? this.userEntityService.pack(clip.user ?? clip.userId),
 			name: clip.name,
 			description: clip.description,
 			isPublic: clip.isPublic,
@@ -55,11 +58,14 @@ export class ClipEntityService {
 	}
 
 	@bindThis
-	public packMany(
+	public async packMany(
 		clips: MiClip[],
 		me?: { id: MiUser['id'] } | null | undefined,
 	) {
-		return Promise.all(clips.map(x => this.pack(x, me)));
+		const _users = clips.map(({ user, userId }) => user ?? userId);
+		const _userMap = await this.userEntityService.packMany(_users, me)
+			.then(users => new Map(users.map(u => [u.id, u])));
+		return Promise.all(clips.map(clip => this.pack(clip, me, { packedUser: _userMap.get(clip.userId) })));
 	}
 }
 
diff --git a/packages/backend/src/core/entities/DriveFileEntityService.ts b/packages/backend/src/core/entities/DriveFileEntityService.ts
index 26bf386cbc..02ff2e7754 100644
--- a/packages/backend/src/core/entities/DriveFileEntityService.ts
+++ b/packages/backend/src/core/entities/DriveFileEntityService.ts
@@ -222,6 +222,9 @@ export class DriveFileEntityService {
 	public async packNullable(
 		src: MiDriveFile['id'] | MiDriveFile,
 		options?: PackOptions,
+		hint?: {
+			packedUser?: Packed<'UserLite'>
+		},
 	): Promise<Packed<'DriveFile'> | null> {
 		const opts = Object.assign({
 			detail: false,
@@ -249,7 +252,7 @@ export class DriveFileEntityService {
 				detail: true,
 			}) : null,
 			userId: file.userId,
-			user: (opts.withUser && file.userId) ? this.userEntityService.pack(file.userId) : null,
+			user: (opts.withUser && file.userId) ? hint?.packedUser ?? this.userEntityService.pack(file.userId) : null,
 		});
 	}
 
@@ -258,7 +261,10 @@ export class DriveFileEntityService {
 		files: MiDriveFile[],
 		options?: PackOptions,
 	): Promise<Packed<'DriveFile'>[]> {
-		const items = await Promise.all(files.map(f => this.packNullable(f, options)));
+		const _user = files.map(({ user, userId }) => user ?? userId).filter(isNotNull);
+		const _userMap = await this.userEntityService.packMany(_user)
+			.then(users => new Map(users.map(user => [user.id, user])));
+		const items = await Promise.all(files.map(f => this.packNullable(f, options, f.userId ? { packedUser: _userMap.get(f.userId) } : {})));
 		return items.filter(isNotNull);
 	}
 
diff --git a/packages/backend/src/core/entities/FlashEntityService.ts b/packages/backend/src/core/entities/FlashEntityService.ts
index db4cf6d360..d110f7afc6 100644
--- a/packages/backend/src/core/entities/FlashEntityService.ts
+++ b/packages/backend/src/core/entities/FlashEntityService.ts
@@ -33,6 +33,9 @@ export class FlashEntityService {
 	public async pack(
 		src: MiFlash['id'] | MiFlash,
 		me?: { id: MiUser['id'] } | null | undefined,
+		hint?: {
+			packedUser?: Packed<'UserLite'>
+		},
 	): Promise<Packed<'Flash'>> {
 		const meId = me ? me.id : null;
 		const flash = typeof src === 'object' ? src : await this.flashsRepository.findOneByOrFail({ id: src });
@@ -42,7 +45,7 @@ export class FlashEntityService {
 			createdAt: this.idService.parse(flash.id).date.toISOString(),
 			updatedAt: flash.updatedAt.toISOString(),
 			userId: flash.userId,
-			user: this.userEntityService.pack(flash.user ?? flash.userId, me), // { schema: 'UserDetailed' } すると無限ループするので注意
+			user: hint?.packedUser ?? this.userEntityService.pack(flash.user ?? flash.userId, me), // { schema: 'UserDetailed' } すると無限ループするので注意
 			title: flash.title,
 			summary: flash.summary,
 			script: flash.script,
@@ -52,11 +55,14 @@ export class FlashEntityService {
 	}
 
 	@bindThis
-	public packMany(
-		flashs: MiFlash[],
+	public async packMany(
+		flashes: MiFlash[],
 		me?: { id: MiUser['id'] } | null | undefined,
 	) {
-		return Promise.all(flashs.map(x => this.pack(x, me)));
+		const _users = flashes.map(({ user, userId }) => user ?? userId);
+		const _userMap = await this.userEntityService.packMany(_users, me)
+			.then(users => new Map(users.map(u => [u.id, u])));
+		return Promise.all(flashes.map(flash => this.pack(flash, me, { packedUser: _userMap.get(flash.userId) })));
 	}
 }
 
diff --git a/packages/backend/src/core/entities/FollowRequestEntityService.ts b/packages/backend/src/core/entities/FollowRequestEntityService.ts
index 763b75101f..0101ec8aa7 100644
--- a/packages/backend/src/core/entities/FollowRequestEntityService.ts
+++ b/packages/backend/src/core/entities/FollowRequestEntityService.ts
@@ -10,6 +10,7 @@ import type { } from '@/models/Blocking.js';
 import type { MiUser } from '@/models/User.js';
 import type { MiFollowRequest } from '@/models/FollowRequest.js';
 import { bindThis } from '@/decorators.js';
+import type { Packed } from '@/misc/json-schema.js';
 import { UserEntityService } from './UserEntityService.js';
 
 @Injectable()
@@ -26,14 +27,36 @@ export class FollowRequestEntityService {
 	public async pack(
 		src: MiFollowRequest['id'] | MiFollowRequest,
 		me?: { id: MiUser['id'] } | null | undefined,
+		hint?: {
+			packedFollower?: Packed<'UserLite'>,
+			packedFollowee?: Packed<'UserLite'>,
+		},
 	) {
 		const request = typeof src === 'object' ? src : await this.followRequestsRepository.findOneByOrFail({ id: src });
 
 		return {
 			id: request.id,
-			follower: await this.userEntityService.pack(request.followerId, me),
-			followee: await this.userEntityService.pack(request.followeeId, me),
+			follower: hint?.packedFollower ?? await this.userEntityService.pack(request.followerId, me),
+			followee: hint?.packedFollowee ?? await this.userEntityService.pack(request.followeeId, me),
 		};
 	}
+
+	@bindThis
+	public async packMany(
+		requests: MiFollowRequest[],
+		me?: { id: MiUser['id'] } | null | undefined,
+	) {
+		const _followers = requests.map(({ follower, followerId }) => follower ?? followerId);
+		const _followees = requests.map(({ followee, followeeId }) => followee ?? followeeId);
+		const _userMap = await this.userEntityService.packMany([..._followers, ..._followees], me)
+			.then(users => new Map(users.map(u => [u.id, u])));
+		return Promise.all(
+			requests.map(req => {
+				const packedFollower = _userMap.get(req.followerId);
+				const packedFollowee = _userMap.get(req.followeeId);
+				return this.pack(req, me, { packedFollower, packedFollowee });
+			}),
+		);
+	}
 }
 
diff --git a/packages/backend/src/core/entities/FollowingEntityService.ts b/packages/backend/src/core/entities/FollowingEntityService.ts
index 24cd33e3f7..d2dbaf2270 100644
--- a/packages/backend/src/core/entities/FollowingEntityService.ts
+++ b/packages/backend/src/core/entities/FollowingEntityService.ts
@@ -78,6 +78,10 @@ export class FollowingEntityService {
 			populateFollowee?: boolean;
 			populateFollower?: boolean;
 		},
+		hint?: {
+			packedFollowee?: Packed<'UserDetailedNotMe'>,
+			packedFollower?: Packed<'UserDetailedNotMe'>,
+		},
 	): Promise<Packed<'Following'>> {
 		const following = typeof src === 'object' ? src : await this.followingsRepository.findOneByOrFail({ id: src });
 
@@ -88,25 +92,35 @@ export class FollowingEntityService {
 			createdAt: this.idService.parse(following.id).date.toISOString(),
 			followeeId: following.followeeId,
 			followerId: following.followerId,
-			followee: opts.populateFollowee ? this.userEntityService.pack(following.followee ?? following.followeeId, me, {
+			followee: opts.populateFollowee ? hint?.packedFollowee ?? this.userEntityService.pack(following.followee ?? following.followeeId, me, {
 				schema: 'UserDetailedNotMe',
 			}) : undefined,
-			follower: opts.populateFollower ? this.userEntityService.pack(following.follower ?? following.followerId, me, {
+			follower: opts.populateFollower ? hint?.packedFollower ?? this.userEntityService.pack(following.follower ?? following.followerId, me, {
 				schema: 'UserDetailedNotMe',
 			}) : undefined,
 		});
 	}
 
 	@bindThis
-	public packMany(
-		followings: any[],
+	public async packMany(
+		followings: MiFollowing[],
 		me?: { id: MiUser['id'] } | null | undefined,
 		opts?: {
 			populateFollowee?: boolean;
 			populateFollower?: boolean;
 		},
 	) {
-		return Promise.all(followings.map(x => this.pack(x, me, opts)));
+		const _followees = opts?.populateFollowee ? followings.map(({ followee, followeeId }) => followee ?? followeeId) : [];
+		const _followers = opts?.populateFollower ? followings.map(({ follower, followerId }) => follower ?? followerId) : [];
+		const _userMap = await this.userEntityService.packMany([..._followees, ..._followers], me, { schema: 'UserDetailedNotMe' })
+			.then(users => new Map(users.map(u => [u.id, u])));
+		return Promise.all(
+			followings.map(following => {
+				const packedFollowee = opts?.populateFollowee ? _userMap.get(following.followeeId) : undefined;
+				const packedFollower = opts?.populateFollower ? _userMap.get(following.followerId) : undefined;
+				return this.pack(following, me, opts, { packedFollowee, packedFollower });
+			}),
+		);
 	}
 }
 
diff --git a/packages/backend/src/core/entities/GalleryPostEntityService.ts b/packages/backend/src/core/entities/GalleryPostEntityService.ts
index 101182a9e5..9746a4c1af 100644
--- a/packages/backend/src/core/entities/GalleryPostEntityService.ts
+++ b/packages/backend/src/core/entities/GalleryPostEntityService.ts
@@ -35,6 +35,9 @@ export class GalleryPostEntityService {
 	public async pack(
 		src: MiGalleryPost['id'] | MiGalleryPost,
 		me?: { id: MiUser['id'] } | null | undefined,
+		hint?: {
+			packedUser?: Packed<'UserLite'>
+		},
 	): Promise<Packed<'GalleryPost'>> {
 		const meId = me ? me.id : null;
 		const post = typeof src === 'object' ? src : await this.galleryPostsRepository.findOneByOrFail({ id: src });
@@ -44,7 +47,7 @@ export class GalleryPostEntityService {
 			createdAt: this.idService.parse(post.id).date.toISOString(),
 			updatedAt: post.updatedAt.toISOString(),
 			userId: post.userId,
-			user: this.userEntityService.pack(post.user ?? post.userId, me),
+			user: hint?.packedUser ?? this.userEntityService.pack(post.user ?? post.userId, me),
 			title: post.title,
 			description: post.description,
 			fileIds: post.fileIds,
@@ -58,11 +61,14 @@ export class GalleryPostEntityService {
 	}
 
 	@bindThis
-	public packMany(
+	public async packMany(
 		posts: MiGalleryPost[],
 		me?: { id: MiUser['id'] } | null | undefined,
 	) {
-		return Promise.all(posts.map(x => this.pack(x, me)));
+		const _users = posts.map(({ user, userId }) => user ?? userId);
+		const _userMap = await this.userEntityService.packMany(_users, me)
+			.then(users => new Map(users.map(u => [u.id, u])));
+		return Promise.all(posts.map(post => this.pack(post, me, { packedUser: _userMap.get(post.userId) })));
 	}
 }
 
diff --git a/packages/backend/src/core/entities/InviteCodeEntityService.ts b/packages/backend/src/core/entities/InviteCodeEntityService.ts
index 891543bc0f..26f57e1299 100644
--- a/packages/backend/src/core/entities/InviteCodeEntityService.ts
+++ b/packages/backend/src/core/entities/InviteCodeEntityService.ts
@@ -12,6 +12,7 @@ import type { MiUser } from '@/models/User.js';
 import type { MiRegistrationTicket } from '@/models/RegistrationTicket.js';
 import { bindThis } from '@/decorators.js';
 import { IdService } from '@/core/IdService.js';
+import { isNotNull } from '@/misc/is-not-null.js';
 import { UserEntityService } from './UserEntityService.js';
 
 @Injectable()
@@ -29,6 +30,10 @@ export class InviteCodeEntityService {
 	public async pack(
 		src: MiRegistrationTicket['id'] | MiRegistrationTicket,
 		me?: { id: MiUser['id'] } | null | undefined,
+		hints?: {
+			packedCreatedBy?: Packed<'UserLite'>,
+			packedUsedBy?: Packed<'UserLite'>,
+		},
 	): Promise<Packed<'InviteCode'>> {
 		const target = typeof src === 'object' ? src : await this.registrationTicketsRepository.findOneOrFail({
 			where: {
@@ -42,18 +47,28 @@ export class InviteCodeEntityService {
 			code: target.code,
 			expiresAt: target.expiresAt ? target.expiresAt.toISOString() : null,
 			createdAt: this.idService.parse(target.id).date.toISOString(),
-			createdBy: target.createdBy ? await this.userEntityService.pack(target.createdBy, me) : null,
-			usedBy: target.usedBy ? await this.userEntityService.pack(target.usedBy, me) : null,
+			createdBy: target.createdBy ? hints?.packedCreatedBy ?? await this.userEntityService.pack(target.createdBy, me) : null,
+			usedBy: target.usedBy ? hints?.packedUsedBy ?? await this.userEntityService.pack(target.usedBy, me) : null,
 			usedAt: target.usedAt ? target.usedAt.toISOString() : null,
 			used: !!target.usedAt,
 		});
 	}
 
 	@bindThis
-	public packMany(
-		targets: any[],
+	public async packMany(
+		tickets: MiRegistrationTicket[],
 		me: { id: MiUser['id'] },
 	) {
-		return Promise.all(targets.map(x => this.pack(x, me)));
+		const _createdBys = tickets.map(({ createdBy, createdById }) => createdBy ?? createdById).filter(isNotNull);
+		const _usedBys = tickets.map(({ usedBy, usedById }) => usedBy ?? usedById).filter(isNotNull);
+		const _userMap = await this.userEntityService.packMany([..._createdBys, ..._usedBys], me)
+			.then(users => new Map(users.map(u => [u.id, u])));
+		return Promise.all(
+			tickets.map(ticket => {
+				const packedCreatedBy = ticket.createdById != null ? _userMap.get(ticket.createdById) : undefined;
+				const packedUsedBy = ticket.usedById != null ? _userMap.get(ticket.usedById) : undefined;
+				return this.pack(ticket, me, { packedCreatedBy, packedUsedBy });
+			}),
+		);
 	}
 }
diff --git a/packages/backend/src/core/entities/ModerationLogEntityService.ts b/packages/backend/src/core/entities/ModerationLogEntityService.ts
index 205e147bd1..bf1b2a002c 100644
--- a/packages/backend/src/core/entities/ModerationLogEntityService.ts
+++ b/packages/backend/src/core/entities/ModerationLogEntityService.ts
@@ -8,9 +8,10 @@ import { DI } from '@/di-symbols.js';
 import type { ModerationLogsRepository } from '@/models/_.js';
 import { awaitAll } from '@/misc/prelude/await-all.js';
 import type { } from '@/models/Blocking.js';
-import type { MiModerationLog } from '@/models/ModerationLog.js';
+import { MiModerationLog } from '@/models/ModerationLog.js';
 import { bindThis } from '@/decorators.js';
 import { IdService } from '@/core/IdService.js';
+import type { Packed } from '@/misc/json-schema.js';
 import { UserEntityService } from './UserEntityService.js';
 
 @Injectable()
@@ -27,6 +28,9 @@ export class ModerationLogEntityService {
 	@bindThis
 	public async pack(
 		src: MiModerationLog['id'] | MiModerationLog,
+		hint?: {
+			packedUser?: Packed<'UserDetailedNotMe'>,
+		},
 	) {
 		const log = typeof src === 'object' ? src : await this.moderationLogsRepository.findOneByOrFail({ id: src });
 
@@ -36,17 +40,20 @@ export class ModerationLogEntityService {
 			type: log.type,
 			info: log.info,
 			userId: log.userId,
-			user: this.userEntityService.pack(log.user ?? log.userId, null, {
+			user: hint?.packedUser ?? this.userEntityService.pack(log.user ?? log.userId, null, {
 				schema: 'UserDetailedNotMe',
 			}),
 		});
 	}
 
 	@bindThis
-	public packMany(
-		reports: any[],
+	public async packMany(
+		reports: MiModerationLog[],
 	) {
-		return Promise.all(reports.map(x => this.pack(x)));
+		const _users = reports.map(({ user, userId }) => user ?? userId);
+		const _userMap = await this.userEntityService.packMany(_users, null, { schema: 'UserDetailedNotMe' })
+			.then(users => new Map(users.map(u => [u.id, u])));
+		return Promise.all(reports.map(report => this.pack(report, { packedUser: _userMap.get(report.userId) })));
 	}
 }
 
diff --git a/packages/backend/src/core/entities/MutingEntityService.ts b/packages/backend/src/core/entities/MutingEntityService.ts
index 0a52f429a2..d361a20271 100644
--- a/packages/backend/src/core/entities/MutingEntityService.ts
+++ b/packages/backend/src/core/entities/MutingEntityService.ts
@@ -30,6 +30,9 @@ export class MutingEntityService {
 	public async pack(
 		src: MiMuting['id'] | MiMuting,
 		me?: { id: MiUser['id'] } | null | undefined,
+		hints?: {
+			packedMutee?: Packed<'UserDetailedNotMe'>,
+		},
 	): Promise<Packed<'Muting'>> {
 		const muting = typeof src === 'object' ? src : await this.mutingsRepository.findOneByOrFail({ id: src });
 
@@ -38,18 +41,21 @@ export class MutingEntityService {
 			createdAt: this.idService.parse(muting.id).date.toISOString(),
 			expiresAt: muting.expiresAt ? muting.expiresAt.toISOString() : null,
 			muteeId: muting.muteeId,
-			mutee: this.userEntityService.pack(muting.muteeId, me, {
+			mutee: hints?.packedMutee ?? this.userEntityService.pack(muting.muteeId, me, {
 				schema: 'UserDetailedNotMe',
 			}),
 		});
 	}
 
 	@bindThis
-	public packMany(
-		mutings: any[],
+	public async packMany(
+		mutings: MiMuting[],
 		me: { id: MiUser['id'] },
 	) {
-		return Promise.all(mutings.map(x => this.pack(x, me)));
+		const _mutees = mutings.map(({ mutee, muteeId }) => mutee ?? muteeId);
+		const _userMap = await this.userEntityService.packMany(_mutees, me, { schema: 'UserDetailedNotMe' })
+			.then(users => new Map(users.map(u => [u.id, u])));
+		return Promise.all(mutings.map(muting => this.pack(muting, me, { packedMutee: _userMap.get(muting.muteeId) })));
 	}
 }
 
diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts
index 22d01462e7..2ce72c50b8 100644
--- a/packages/backend/src/core/entities/NoteEntityService.ts
+++ b/packages/backend/src/core/entities/NoteEntityService.ts
@@ -290,6 +290,7 @@ export class NoteEntityService implements OnModuleInit {
 			_hint_?: {
 				myReactions: Map<MiNote['id'], string | null>;
 				packedFiles: Map<MiNote['fileIds'][number], Packed<'DriveFile'> | null>;
+				packedUsers: Map<MiUser['id'], Packed<'UserLite'>>
 			};
 		},
 	): Promise<Packed<'Note'>> {
@@ -319,12 +320,13 @@ export class NoteEntityService implements OnModuleInit {
 			.filter(x => x.startsWith(':') && x.includes('@') && !x.includes('@.')) // リモートカスタム絵文字のみ
 			.map(x => this.reactionService.decodeReaction(x).reaction.replaceAll(':', ''));
 		const packedFiles = options?._hint_?.packedFiles;
+		const packedUsers = options?._hint_?.packedUsers;
 
 		const packed: Packed<'Note'> = await awaitAll({
 			id: note.id,
 			createdAt: this.idService.parse(note.id).date.toISOString(),
 			userId: note.userId,
-			user: this.userEntityService.pack(note.user ?? note.userId, me),
+			user: packedUsers?.get(note.userId) ?? this.userEntityService.pack(note.user ?? note.userId, me),
 			text: text,
 			cw: note.cw,
 			visibility: note.visibility,
@@ -449,12 +451,20 @@ export class NoteEntityService implements OnModuleInit {
 		// TODO: 本当は renote とか reply がないのに renoteId とか replyId があったらここで解決しておく
 		const fileIds = notes.map(n => [n.fileIds, n.renote?.fileIds, n.reply?.fileIds]).flat(2).filter(isNotNull);
 		const packedFiles = fileIds.length > 0 ? await this.driveFileEntityService.packManyByIdsMap(fileIds) : new Map();
+		const users = [
+			...notes.map(({ user, userId }) => user ?? userId),
+			...notes.map(({ replyUserId }) => replyUserId).filter(isNotNull),
+			...notes.map(({ renoteUserId }) => renoteUserId).filter(isNotNull),
+		];
+		const packedUsers = await this.userEntityService.packMany(users, me)
+			.then(users => new Map(users.map(u => [u.id, u])));
 
 		return await Promise.all(notes.map(n => this.pack(n, me, {
 			...options,
 			_hint_: {
 				myReactions: myReactionsMap,
 				packedFiles,
+				packedUsers,
 			},
 		})));
 	}
diff --git a/packages/backend/src/core/entities/NoteReactionEntityService.ts b/packages/backend/src/core/entities/NoteReactionEntityService.ts
index 3f4fa3cf96..46ec13704c 100644
--- a/packages/backend/src/core/entities/NoteReactionEntityService.ts
+++ b/packages/backend/src/core/entities/NoteReactionEntityService.ts
@@ -52,6 +52,9 @@ export class NoteReactionEntityService implements OnModuleInit {
 		options?: {
 			withNote: boolean;
 		},
+		hints?: {
+			packedUser?: Packed<'UserLite'>
+		},
 	): Promise<Packed<'NoteReaction'>> {
 		const opts = Object.assign({
 			withNote: false,
@@ -62,7 +65,7 @@ export class NoteReactionEntityService implements OnModuleInit {
 		return {
 			id: reaction.id,
 			createdAt: this.idService.parse(reaction.id).date.toISOString(),
-			user: await this.userEntityService.pack(reaction.user ?? reaction.userId, me),
+			user: hints?.packedUser ?? await this.userEntityService.pack(reaction.user ?? reaction.userId, me),
 			type: this.reactionService.convertLegacyReaction(reaction.reaction),
 			...(opts.withNote ? {
 				note: await this.noteEntityService.pack(reaction.note ?? reaction.noteId, me),
@@ -81,7 +84,9 @@ export class NoteReactionEntityService implements OnModuleInit {
 		const opts = Object.assign({
 			withNote: false,
 		}, options);
-
-		return Promise.all(reactions.map(reaction => this.pack(reaction, me, opts)));
+		const _users = reactions.map(({ user, userId }) => user ?? userId);
+		const _userMap = await this.userEntityService.packMany(_users, me)
+			.then(users => new Map(users.map(u => [u.id, u])));
+		return Promise.all(reactions.map(reaction => this.pack(reaction, me, opts, { packedUser: _userMap.get(reaction.userId) })));
 	}
 }
diff --git a/packages/backend/src/core/entities/PageEntityService.ts b/packages/backend/src/core/entities/PageEntityService.ts
index 65c69a49a7..142d9e81db 100644
--- a/packages/backend/src/core/entities/PageEntityService.ts
+++ b/packages/backend/src/core/entities/PageEntityService.ts
@@ -40,6 +40,9 @@ export class PageEntityService {
 	public async pack(
 		src: MiPage['id'] | MiPage,
 		me?: { id: MiUser['id'] } | null | undefined,
+		hint?: {
+			packedUser?: Packed<'UserLite'>
+		},
 	): Promise<Packed<'Page'>> {
 		const meId = me ? me.id : null;
 		const page = typeof src === 'object' ? src : await this.pagesRepository.findOneByOrFail({ id: src });
@@ -91,7 +94,7 @@ export class PageEntityService {
 			createdAt: this.idService.parse(page.id).date.toISOString(),
 			updatedAt: page.updatedAt.toISOString(),
 			userId: page.userId,
-			user: this.userEntityService.pack(page.user ?? page.userId, me), // { schema: 'UserDetailed' } すると無限ループするので注意
+			user: hint?.packedUser ?? this.userEntityService.pack(page.user ?? page.userId, me), // { schema: 'UserDetailed' } すると無限ループするので注意
 			content: page.content,
 			variables: page.variables,
 			title: page.title,
@@ -110,11 +113,14 @@ export class PageEntityService {
 	}
 
 	@bindThis
-	public packMany(
+	public async packMany(
 		pages: MiPage[],
 		me?: { id: MiUser['id'] } | null | undefined,
 	) {
-		return Promise.all(pages.map(x => this.pack(x, me)));
+		const _users = pages.map(({ user, userId }) => user ?? userId);
+		const _userMap = await this.userEntityService.packMany(_users, me)
+			.then(users => new Map(users.map(u => [u.id, u])));
+		return Promise.all(pages.map(page => this.pack(page, me, { packedUser: _userMap.get(page.userId) })));
 	}
 }
 
diff --git a/packages/backend/src/core/entities/RenoteMutingEntityService.ts b/packages/backend/src/core/entities/RenoteMutingEntityService.ts
index 0b05a5db80..e4e154109a 100644
--- a/packages/backend/src/core/entities/RenoteMutingEntityService.ts
+++ b/packages/backend/src/core/entities/RenoteMutingEntityService.ts
@@ -30,6 +30,9 @@ export class RenoteMutingEntityService {
 	public async pack(
 		src: MiRenoteMuting['id'] | MiRenoteMuting,
 		me?: { id: MiUser['id'] } | null | undefined,
+		hints?: {
+			packedMutee?: Packed<'UserDetailedNotMe'>
+		},
 	): Promise<Packed<'RenoteMuting'>> {
 		const muting = typeof src === 'object' ? src : await this.renoteMutingsRepository.findOneByOrFail({ id: src });
 
@@ -37,18 +40,21 @@ export class RenoteMutingEntityService {
 			id: muting.id,
 			createdAt: this.idService.parse(muting.id).date.toISOString(),
 			muteeId: muting.muteeId,
-			mutee: this.userEntityService.pack(muting.muteeId, me, {
+			mutee: hints?.packedMutee ?? this.userEntityService.pack(muting.muteeId, me, {
 				schema: 'UserDetailedNotMe',
 			}),
 		});
 	}
 
 	@bindThis
-	public packMany(
-		mutings: any[],
+	public async packMany(
+		mutings: MiRenoteMuting[],
 		me: { id: MiUser['id'] },
 	) {
-		return Promise.all(mutings.map(x => this.pack(x, me)));
+		const _users = mutings.map(({ mutee, muteeId }) => mutee ?? muteeId);
+		const _userMap = await this.userEntityService.packMany(_users, me, { schema: 'UserDetailedNotMe' })
+			.then(users => new Map(users.map(u => [u.id, u])));
+		return Promise.all(mutings.map(muting => this.pack(muting, me, { packedMutee: _userMap.get(muting.muteeId) })));
 	}
 }
 
diff --git a/packages/backend/src/core/entities/ReversiGameEntityService.ts b/packages/backend/src/core/entities/ReversiGameEntityService.ts
index 32cbe631e4..df042e75c1 100644
--- a/packages/backend/src/core/entities/ReversiGameEntityService.ts
+++ b/packages/backend/src/core/entities/ReversiGameEntityService.ts
@@ -28,13 +28,15 @@ export class ReversiGameEntityService {
 	@bindThis
 	public async packDetail(
 		src: MiReversiGame['id'] | MiReversiGame,
+		hint?: {
+			packedUser1?: Packed<'UserLite'>,
+			packedUser2?: Packed<'UserLite'>,
+		},
 	): Promise<Packed<'ReversiGameDetailed'>> {
 		const game = typeof src === 'object' ? src : await this.reversiGamesRepository.findOneByOrFail({ id: src });
 
-		const users = await Promise.all([
-			this.userEntityService.pack(game.user1 ?? game.user1Id),
-			this.userEntityService.pack(game.user2 ?? game.user2Id),
-		]);
+		const user1 = hint?.packedUser1 ?? await this.userEntityService.pack(game.user1 ?? game.user1Id);
+		const user2 = hint?.packedUser2 ?? await this.userEntityService.pack(game.user2 ?? game.user2Id);
 
 		return await awaitAll({
 			id: game.id,
@@ -49,10 +51,10 @@ export class ReversiGameEntityService {
 			user2Ready: game.user2Ready,
 			user1Id: game.user1Id,
 			user2Id: game.user2Id,
-			user1: users[0],
-			user2: users[1],
+			user1,
+			user2,
 			winnerId: game.winnerId,
-			winner: game.winnerId ? users.find(u => u.id === game.winnerId)! : null,
+			winner: game.winnerId ? [user1, user2].find(u => u.id === game.winnerId)! : null,
 			surrenderedUserId: game.surrenderedUserId,
 			timeoutUserId: game.timeoutUserId,
 			black: game.black,
@@ -68,22 +70,35 @@ export class ReversiGameEntityService {
 	}
 
 	@bindThis
-	public packDetailMany(
-		xs: MiReversiGame[],
+	public async packDetailMany(
+		games: MiReversiGame[],
 	) {
-		return Promise.all(xs.map(x => this.packDetail(x)));
+		const _user1s = games.map(({ user1, user1Id }) => user1 ?? user1Id);
+		const _user2s = games.map(({ user2, user2Id }) => user2 ?? user2Id);
+		const _userMap = await this.userEntityService.packMany([..._user1s, ..._user2s])
+			.then(users => new Map(users.map(u => [u.id, u])));
+		return Promise.all(
+			games.map(game => {
+				return this.packDetail(game, {
+					packedUser1: _userMap.get(game.user1Id),
+					packedUser2: _userMap.get(game.user2Id),
+				});
+			}),
+		);
 	}
 
 	@bindThis
 	public async packLite(
 		src: MiReversiGame['id'] | MiReversiGame,
+		hint?: {
+			packedUser1?: Packed<'UserLite'>,
+			packedUser2?: Packed<'UserLite'>,
+		},
 	): Promise<Packed<'ReversiGameLite'>> {
 		const game = typeof src === 'object' ? src : await this.reversiGamesRepository.findOneByOrFail({ id: src });
 
-		const users = await Promise.all([
-			this.userEntityService.pack(game.user1 ?? game.user1Id),
-			this.userEntityService.pack(game.user2 ?? game.user2Id),
-		]);
+		const user1 = hint?.packedUser1 ?? await this.userEntityService.pack(game.user1 ?? game.user1Id);
+		const user2 = hint?.packedUser2 ?? await this.userEntityService.pack(game.user2 ?? game.user2Id);
 
 		return await awaitAll({
 			id: game.id,
@@ -94,10 +109,10 @@ export class ReversiGameEntityService {
 			isEnded: game.isEnded,
 			user1Id: game.user1Id,
 			user2Id: game.user2Id,
-			user1: users[0],
-			user2: users[1],
+			user1,
+			user2,
 			winnerId: game.winnerId,
-			winner: game.winnerId ? users.find(u => u.id === game.winnerId)! : null,
+			winner: game.winnerId ? [user1, user2].find(u => u.id === game.winnerId)! : null,
 			surrenderedUserId: game.surrenderedUserId,
 			timeoutUserId: game.timeoutUserId,
 			black: game.black,
@@ -111,10 +126,21 @@ export class ReversiGameEntityService {
 	}
 
 	@bindThis
-	public packLiteMany(
-		xs: MiReversiGame[],
+	public async packLiteMany(
+		games: MiReversiGame[],
 	) {
-		return Promise.all(xs.map(x => this.packLite(x)));
+		const _user1s = games.map(({ user1, user1Id }) => user1 ?? user1Id);
+		const _user2s = games.map(({ user2, user2Id }) => user2 ?? user2Id);
+		const _userMap = await this.userEntityService.packMany([..._user1s, ..._user2s])
+			.then(users => new Map(users.map(u => [u.id, u])));
+		return Promise.all(
+			games.map(game => {
+				return this.packLite(game, {
+					packedUser1: _userMap.get(game.user1Id),
+					packedUser2: _userMap.get(game.user2Id),
+				});
+			}),
+		);
 	}
 }
 
diff --git a/packages/backend/src/core/entities/UserListEntityService.ts b/packages/backend/src/core/entities/UserListEntityService.ts
index 09cab24521..b77249c5cb 100644
--- a/packages/backend/src/core/entities/UserListEntityService.ts
+++ b/packages/backend/src/core/entities/UserListEntityService.ts
@@ -50,11 +50,14 @@ export class UserListEntityService {
 	public async packMembershipsMany(
 		memberships: MiUserListMembership[],
 	) {
+		const _users = memberships.map(({ user, userId }) => user ?? userId);
+		const _userMap = await this.userEntityService.packMany(_users)
+			.then(users => new Map(users.map(u => [u.id, u])));
 		return Promise.all(memberships.map(async x => ({
 			id: x.id,
 			createdAt: this.idService.parse(x.id).date.toISOString(),
 			userId: x.userId,
-			user: await this.userEntityService.pack(x.userId),
+			user: _userMap.get(x.userId) ?? await this.userEntityService.pack(x.userId),
 			withReplies: x.withReplies,
 		})));
 	}
diff --git a/packages/backend/src/server/api/endpoints/admin/roles/users.ts b/packages/backend/src/server/api/endpoints/admin/roles/users.ts
index 45758d4f50..198166bec2 100644
--- a/packages/backend/src/server/api/endpoints/admin/roles/users.ts
+++ b/packages/backend/src/server/api/endpoints/admin/roles/users.ts
@@ -89,10 +89,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				.limit(ps.limit)
 				.getMany();
 
+			const _users = assigns.map(({ user, userId }) => user ?? userId);
+			const _userMap = await this.userEntityService.packMany(_users, me, { schema: 'UserDetailed' })
+				.then(users => new Map(users.map(u => [u.id, u])));
 			return await Promise.all(assigns.map(async assign => ({
 				id: assign.id,
 				createdAt: this.idService.parse(assign.id).date.toISOString(),
-				user: await this.userEntityService.pack(assign.user!, me, { schema: 'UserDetailed' }),
+				user: _userMap.get(assign.userId) ?? await this.userEntityService.pack(assign.user!, me, { schema: 'UserDetailed' }),
 				expiresAt: assign.expiresAt?.toISOString() ?? null,
 			})));
 		});
diff --git a/packages/backend/src/server/api/endpoints/drive/files/find.ts b/packages/backend/src/server/api/endpoints/drive/files/find.ts
index 595a6957b2..502d42f9e0 100644
--- a/packages/backend/src/server/api/endpoints/drive/files/find.ts
+++ b/packages/backend/src/server/api/endpoints/drive/files/find.ts
@@ -54,7 +54,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				folderId: ps.folderId ?? IsNull(),
 			});
 
-			return await Promise.all(files.map(file => this.driveFileEntityService.pack(file, { self: true })));
+			return await this.driveFileEntityService.packMany(files, { self: true });
 		});
 	}
 }
diff --git a/packages/backend/src/server/api/endpoints/following/requests/list.ts b/packages/backend/src/server/api/endpoints/following/requests/list.ts
index 88f559138b..fa59e38976 100644
--- a/packages/backend/src/server/api/endpoints/following/requests/list.ts
+++ b/packages/backend/src/server/api/endpoints/following/requests/list.ts
@@ -71,7 +71,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				.limit(ps.limit)
 				.getMany();
 
-			return await Promise.all(requests.map(req => this.followRequestEntityService.pack(req)));
+			return await this.followRequestEntityService.packMany(requests, me);
 		});
 	}
 }
diff --git a/packages/backend/src/server/api/endpoints/notes/reactions.ts b/packages/backend/src/server/api/endpoints/notes/reactions.ts
index a0a1fd9728..97b12ab7f7 100644
--- a/packages/backend/src/server/api/endpoints/notes/reactions.ts
+++ b/packages/backend/src/server/api/endpoints/notes/reactions.ts
@@ -76,7 +76,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 
 			const reactions = await query.limit(ps.limit).getMany();
 
-			return await Promise.all(reactions.map(reaction => this.noteReactionEntityService.pack(reaction, me)));
+			return await this.noteReactionEntityService.packMany(reactions, me);
 		});
 	}
 }
diff --git a/packages/backend/src/server/api/endpoints/roles/users.ts b/packages/backend/src/server/api/endpoints/roles/users.ts
index 85d100ce1c..48d350af59 100644
--- a/packages/backend/src/server/api/endpoints/roles/users.ts
+++ b/packages/backend/src/server/api/endpoints/roles/users.ts
@@ -92,9 +92,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				.limit(ps.limit)
 				.getMany();
 
+			const _users = assigns.map(({ user, userId }) => user ?? userId);
+			const _userMap = await this.userEntityService.packMany(_users, me, { schema: 'UserDetailed' })
+				.then(users => new Map(users.map(u => [u.id, u])));
 			return await Promise.all(assigns.map(async assign => ({
 				id: assign.id,
-				user: await this.userEntityService.pack(assign.user!, me, { schema: 'UserDetailed' }),
+				user: _userMap.get(assign.userId) ?? await this.userEntityService.pack(assign.user!, me, { schema: 'UserDetailed' }),
 			})));
 		});
 	}
diff --git a/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts b/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts
index 02aa037466..9248a2fa68 100644
--- a/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts
+++ b/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts
@@ -118,12 +118,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 			const repliedUsersSorted = Object.keys(repliedUsers).sort((a, b) => repliedUsers[b] - repliedUsers[a]);
 
 			// Extract top replied users
-			const topRepliedUsers = repliedUsersSorted.slice(0, ps.limit);
+			const topRepliedUserIds = repliedUsersSorted.slice(0, ps.limit);
 
 			// Make replies object (includes weights)
-			const repliesObj = await Promise.all(topRepliedUsers.map(async (user) => ({
-				user: await this.userEntityService.pack(user, me, { schema: 'UserDetailed' }),
-				weight: repliedUsers[user] / peak,
+			const _userMap = await this.userEntityService.packMany(topRepliedUserIds, me, { schema: 'UserDetailed' })
+				.then(users => new Map(users.map(u => [u.id, u])));
+			const repliesObj = await Promise.all(topRepliedUserIds.map(async (userId) => ({
+				user: _userMap.get(userId) ?? await this.userEntityService.pack(userId, me, { schema: 'UserDetailed' }),
+				weight: repliedUsers[userId] / peak,
 			})));
 
 			return repliesObj;
diff --git a/packages/backend/src/server/api/endpoints/users/show.ts b/packages/backend/src/server/api/endpoints/users/show.ts
index 26cfa921c5..062326e28d 100644
--- a/packages/backend/src/server/api/endpoints/users/show.ts
+++ b/packages/backend/src/server/api/endpoints/users/show.ts
@@ -117,9 +117,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 					if (user != null) _users.push(user);
 				}
 
-				return await Promise.all(_users.map(u => this.userEntityService.pack(u, me, {
-					schema: 'UserDetailed',
-				})));
+				const _userMap = await this.userEntityService.packMany(_users, me, { schema: 'UserDetailed' })
+					.then(users => new Map(users.map(u => [u.id, u])));
+				return _users.map(u => _userMap.get(u.id)!);
 			} else {
 				// Lookup user
 				if (typeof ps.host === 'string' && typeof ps.username === 'string') {

From dc55adbaf799de67e933e5207801502f49f9efa9 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Fri, 31 May 2024 07:06:41 +0000
Subject: [PATCH 180/191] Bump version to 2024.5.0-rc.9

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 04942d16bf..26a15b694c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2024.5.0-rc.8",
+	"version": "2024.5.0-rc.9",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index 1a611d8f10..6ec4674c08 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2024.5.0-rc.8",
+	"version": "2024.5.0-rc.9",
 	"description": "Misskey SDK for JavaScript",
 	"license": "MIT",
 	"main": "./built/index.js",

From 030082f7567e6896add3180fbc48f2d6ee4a151e Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Fri, 31 May 2024 19:35:27 +0900
Subject: [PATCH 181/191] :art:

---
 locales/index.d.ts                          |  4 ++++
 locales/ja-JP.yml                           |  1 +
 packages/frontend/src/pages/admin/index.vue | 16 ++++++++--------
 3 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/locales/index.d.ts b/locales/index.d.ts
index 91bbe4ccb6..0b1b86d373 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -3364,6 +3364,10 @@ export interface Locale extends ILocale {
      * 管理者情報が設定されていません。
      */
     "noMaintainerInformationWarning": string;
+    /**
+     * 問い合わせ先URLが設定されていません。
+     */
+    "noInquiryUrlWarning": string;
     /**
      * Botプロテクションが設定されていません。
      */
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index b7083b4942..a89cfbd843 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -837,6 +837,7 @@ administration: "管理"
 accounts: "アカウント"
 switch: "切り替え"
 noMaintainerInformationWarning: "管理者情報が設定されていません。"
+noInquiryUrlWarning: "問い合わせ先URLが設定されていません。"
 noBotProtectionWarning: "Botプロテクションが設定されていません。"
 configure: "設定する"
 postToGallery: "ギャラリーへ投稿"
diff --git a/packages/frontend/src/pages/admin/index.vue b/packages/frontend/src/pages/admin/index.vue
index eef1c8afa9..794feae202 100644
--- a/packages/frontend/src/pages/admin/index.vue
+++ b/packages/frontend/src/pages/admin/index.vue
@@ -12,10 +12,13 @@ SPDX-License-Identifier: AGPL-3.0-only
 					<img :src="instance.iconUrl || '/favicon.ico'" alt="" class="icon"/>
 				</div>
 
-				<MkInfo v-if="thereIsUnresolvedAbuseReport" warn class="info">{{ i18n.ts.thereIsUnresolvedAbuseReportWarning }} <MkA to="/admin/abuses" class="_link">{{ i18n.ts.check }}</MkA></MkInfo>
-				<MkInfo v-if="noMaintainerInformation" warn class="info">{{ i18n.ts.noMaintainerInformationWarning }} <MkA to="/admin/settings" class="_link">{{ i18n.ts.configure }}</MkA></MkInfo>
-				<MkInfo v-if="noBotProtection" warn class="info">{{ i18n.ts.noBotProtectionWarning }} <MkA to="/admin/security" class="_link">{{ i18n.ts.configure }}</MkA></MkInfo>
-				<MkInfo v-if="noEmailServer" warn class="info">{{ i18n.ts.noEmailServerWarning }} <MkA to="/admin/email-settings" class="_link">{{ i18n.ts.configure }}</MkA></MkInfo>
+				<div class="_gaps_s">
+					<MkInfo v-if="thereIsUnresolvedAbuseReport" warn>{{ i18n.ts.thereIsUnresolvedAbuseReportWarning }} <MkA to="/admin/abuses" class="_link">{{ i18n.ts.check }}</MkA></MkInfo>
+					<MkInfo v-if="noMaintainerInformation" warn>{{ i18n.ts.noMaintainerInformationWarning }} <MkA to="/admin/settings" class="_link">{{ i18n.ts.configure }}</MkA></MkInfo>
+					<MkInfo v-if="noInquiryUrl" warn>{{ i18n.ts.noInquiryUrlWarning }} <MkA to="/admin/moderation" class="_link">{{ i18n.ts.configure }}</MkA></MkInfo>
+					<MkInfo v-if="noBotProtection" warn>{{ i18n.ts.noBotProtectionWarning }} <MkA to="/admin/security" class="_link">{{ i18n.ts.configure }}</MkA></MkInfo>
+					<MkInfo v-if="noEmailServer" warn>{{ i18n.ts.noEmailServerWarning }} <MkA to="/admin/email-settings" class="_link">{{ i18n.ts.configure }}</MkA></MkInfo>
+				</div>
 
 				<MkSuperMenu :def="menuDef" :grid="narrow"></MkSuperMenu>
 			</div>
@@ -61,6 +64,7 @@ const pageProps = ref({});
 let noMaintainerInformation = isEmpty(instance.maintainerName) || isEmpty(instance.maintainerEmail);
 let noBotProtection = !instance.disableRegistration && !instance.enableHcaptcha && !instance.enableRecaptcha && !instance.enableTurnstile;
 let noEmailServer = !instance.enableEmail;
+let noInquiryUrl = isEmpty(instance.inquiryUrl);
 const thereIsUnresolvedAbuseReport = ref(false);
 const currentPage = computed(() => router.currentRef.value.child);
 
@@ -348,10 +352,6 @@ defineExpose({
 
 	> .nav {
 		.lxpfedzu {
-			> .info {
-				margin: 16px 0;
-			}
-
 			> .banner {
 				margin: 16px;
 

From 374c8791d72ff55b79b2152726a174261cc997d3 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Fri, 31 May 2024 11:13:42 +0000
Subject: [PATCH 182/191] Bump version to 2024.5.0-rc.10

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 26a15b694c..bc56cc45fb 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2024.5.0-rc.9",
+	"version": "2024.5.0-rc.10",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index 6ec4674c08..ce47ee4093 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2024.5.0-rc.9",
+	"version": "2024.5.0-rc.10",
 	"description": "Misskey SDK for JavaScript",
 	"license": "MIT",
 	"main": "./built/index.js",

From 46164f879b9bd672cd7f5eea34180a196b0967b8 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Fri, 31 May 2024 11:20:13 +0000
Subject: [PATCH 183/191] Bump version to 2024.5.0-rc.11

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index bc56cc45fb..4f5e15014c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2024.5.0-rc.10",
+	"version": "2024.5.0-rc.11",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index ce47ee4093..dfda302960 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2024.5.0-rc.10",
+	"version": "2024.5.0-rc.11",
 	"description": "Misskey SDK for JavaScript",
 	"license": "MIT",
 	"main": "./built/index.js",

From 2eaa3e256ff7310bd63197aafe7e72fa207e347b Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Fri, 31 May 2024 20:42:02 +0900
Subject: [PATCH 184/191] Update README.md for Sentry

---
 README.md | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/README.md b/README.md
index 24013a7bd8..92e8fef639 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,10 @@
 
 ## Thanks
 
+<a href="https://sentry.io/"><img src="https://github.com/misskey-dev/misskey/assets/4439005/98576556-222f-467a-94be-e98dbda1d852" height="30" alt="Sentry" /></a>
+
+Thanks to [Sentry](https://sentry.io/) for providing the error tracking platform that helps us catch unexpected errors.
+
 <a href="https://www.chromatic.com/"><img src="https://user-images.githubusercontent.com/321738/84662277-e3db4f80-af1b-11ea-88f5-91d67a5e59f6.png" height="30" alt="Chromatic" /></a>
 
 Thanks to [Chromatic](https://www.chromatic.com/) for providing the visual testing platform that helps us review UI changes and catch visual regressions.

From 316d192bc0fb6dde1fb18c0cfe0d76a247d62388 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Fri, 31 May 2024 12:05:47 +0000
Subject: [PATCH 185/191] Bump version to 2024.5.0-rc.12

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 4f5e15014c..998d612b5b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2024.5.0-rc.11",
+	"version": "2024.5.0-rc.12",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index dfda302960..1b361c4295 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2024.5.0-rc.11",
+	"version": "2024.5.0-rc.12",
 	"description": "Misskey SDK for JavaScript",
 	"license": "MIT",
 	"main": "./built/index.js",

From 27d1b7e6156699184bed278c9a43d5b94e159d4e Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Fri, 31 May 2024 21:09:19 +0900
Subject: [PATCH 186/191] 2024.5.0

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 998d612b5b..b1786e16f1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2024.5.0-rc.12",
+	"version": "2024.5.0",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index 1b361c4295..4ff1a57309 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2024.5.0-rc.12",
+	"version": "2024.5.0",
 	"description": "Misskey SDK for JavaScript",
 	"license": "MIT",
 	"main": "./built/index.js",

From 61eec93f4e93686c362fd68c8ff1f1ca96e1d790 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Fri, 31 May 2024 21:16:35 +0900
Subject: [PATCH 187/191] Revert "2024.5.0"

This reverts commit 27d1b7e6156699184bed278c9a43d5b94e159d4e.
---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index b1786e16f1..998d612b5b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2024.5.0",
+	"version": "2024.5.0-rc.12",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index 4ff1a57309..1b361c4295 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2024.5.0",
+	"version": "2024.5.0-rc.12",
 	"description": "Misskey SDK for JavaScript",
 	"license": "MIT",
 	"main": "./built/index.js",

From a59aa20be827f23f9d15f7a7368779bcc89ece25 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Fri, 31 May 2024 12:18:52 +0000
Subject: [PATCH 188/191] Bump version to 2024.5.0-rc.13

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 998d612b5b..175561e467 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2024.5.0-rc.12",
+	"version": "2024.5.0-rc.13",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index 1b361c4295..a49bfab941 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2024.5.0-rc.12",
+	"version": "2024.5.0-rc.13",
 	"description": "Misskey SDK for JavaScript",
 	"license": "MIT",
 	"main": "./built/index.js",

From 6078081c336ab42535cbea173c728d2aef08d5d2 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Fri, 31 May 2024 12:24:53 +0000
Subject: [PATCH 189/191] [skip ci] Release: 2024.5.0

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 175561e467..b1786e16f1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2024.5.0-rc.13",
+	"version": "2024.5.0",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index a49bfab941..4ff1a57309 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2024.5.0-rc.13",
+	"version": "2024.5.0",
 	"description": "Misskey SDK for JavaScript",
 	"license": "MIT",
 	"main": "./built/index.js",

From ecf7945fe8e4554c0db248512fbc51a41cfaf2c9 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Fri, 31 May 2024 12:25:00 +0000
Subject: [PATCH 190/191] [skip ci] Update CHANGELOG.md (prepend template)

---
 CHANGELOG.md | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9f78ba677d..9d4ef23d27 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,15 @@
+## Unreleased
+
+### General
+-
+
+### Client
+-
+
+### Server
+-
+
+
 ## 2024.5.0
 
 ### Note

From 2b8056a8525e1b38536aa0406ba9446a88b365b9 Mon Sep 17 00:00:00 2001
From: Acid Chicken <root@acid-chicken.com>
Date: Sat, 1 Jun 2024 11:16:44 +0900
Subject: [PATCH 191/191] fix(backend): use insertOne insteadof
 insert/findOneOrFail combination (#13908)

* fix(backend): use insertOne insteadof insert/findOneOrFail combination

* fix: typo

* fix(backend): inherit mainAlias?

* refactor(backend): use extend

* fix(backend): invalid entityTarget

* fix(backend): fake where

* chore: debug

* chore: debug

* test: log

* fix(backend): column names

* fix(backend): remove dummy from

* revert: log

* fix(backend): position

* fix(backend): automatic aliasing

* chore(backend): alias

* chore(backend): remove from

* fix(backend): type

* fix(backend): avoid pure name

* test(backend): fix type

* chore(backend): use cte

* fix(backend): avoid useless alias

* fix(backend): fix typo

* fix(backend): __disambiguation__

* fix(backend): quote

* chore(backend): t

* chore(backend): accessible

* chore(backend): concrete returning

* fix(backend): quote

* chore: log more

* chore: log metadata

* chore(backend): use raw

* fix(backend): returning column name

* fix(backend): transform

* build(backend): wanna logging

* build(backend): transform empty

* build(backend): build alias

* build(backend): restore name

* chore: return entity

* fix: test case

* test(backend): 204

* chore(backend): log sql

* chore(backend): assert user joined

* fix(backend): typo

* chore(backend): log long sql

* chore(backend): log join

* chore(backend): log join depth null

* chore(backend): joinAttributes

* chore(backend): override createJoinExpression

* chore: join log

* fix(backend): escape

* test(backend): log log

* chore(backend): join gonna success?

* chore(backend): relations

* chore(backend): undefined

* chore(backend): target

* chore(backend): remove log

* chore(backend): log chart update

* chore(backend): log columns

* chore(backend): check hasMetadata

* chore(backend): unshift id when not included

* chore(backend): missing select

* chore(backend): remove debug code
---
 .../backend/src/core/AnnouncementService.ts   |   4 +-
 .../src/core/AvatarDecorationService.ts       |   4 +-
 packages/backend/src/core/ClipService.ts      |   4 +-
 .../backend/src/core/CustomEmojiService.ts    |   4 +-
 packages/backend/src/core/DriveService.ts     |   6 +-
 .../src/core/FederatedInstanceService.ts      |   4 +-
 packages/backend/src/core/RelayService.ts     |   4 +-
 packages/backend/src/core/ReversiService.ts   |   7 +-
 packages/backend/src/core/RoleService.ts      |   8 +-
 .../backend/src/core/UserFollowingService.ts  |   4 +-
 .../core/activitypub/models/ApNoteService.ts  |   4 +-
 packages/backend/src/core/chart/core.ts       |  23 +-
 .../backend/src/models/RepositoryModule.ts    | 136 ++++++------
 packages/backend/src/models/_.ts              | 205 ++++++++++++------
 .../ImportAntennasProcessorService.ts         |   4 +-
 .../ImportUserListsProcessorService.ts        |   4 +-
 .../backend/src/server/api/SigninService.ts   |   4 +-
 .../src/server/api/SignupApiService.ts        |   4 +-
 .../server/api/endpoints/admin/ad/create.ts   |   4 +-
 .../api/endpoints/admin/invite/create.ts      |   4 +-
 .../server/api/endpoints/antennas/create.ts   |   4 +-
 .../src/server/api/endpoints/app/create.ts    |   4 +-
 .../api/endpoints/auth/session/generate.ts    |   4 +-
 .../server/api/endpoints/channels/create.ts   |   4 +-
 .../api/endpoints/drive/folders/create.ts     |   4 +-
 .../src/server/api/endpoints/flash/create.ts  |   4 +-
 .../api/endpoints/gallery/posts/create.ts     |   4 +-
 .../server/api/endpoints/i/webhooks/create.ts |   4 +-
 .../src/server/api/endpoints/invite/create.ts |   4 +-
 .../server/api/endpoints/notes/polls/vote.ts  |   4 +-
 .../src/server/api/endpoints/pages/create.ts  |   4 +-
 .../users/lists/create-from-public.ts         |   4 +-
 .../api/endpoints/users/lists/create.ts       |   4 +-
 .../api/endpoints/users/report-abuse.ts       |   4 +-
 packages/backend/test/e2e/move.ts             |   4 +-
 packages/backend/test/e2e/reversi-game.ts     |  33 +++
 36 files changed, 319 insertions(+), 215 deletions(-)
 create mode 100644 packages/backend/test/e2e/reversi-game.ts

diff --git a/packages/backend/src/core/AnnouncementService.ts b/packages/backend/src/core/AnnouncementService.ts
index 9b60df2cae..40a9db01c0 100644
--- a/packages/backend/src/core/AnnouncementService.ts
+++ b/packages/backend/src/core/AnnouncementService.ts
@@ -67,7 +67,7 @@ export class AnnouncementService {
 
 	@bindThis
 	public async create(values: Partial<MiAnnouncement>, moderator?: MiUser): Promise<{ raw: MiAnnouncement; packed: Packed<'Announcement'> }> {
-		const announcement = await this.announcementsRepository.insert({
+		const announcement = await this.announcementsRepository.insertOne({
 			id: this.idService.gen(),
 			updatedAt: null,
 			title: values.title,
@@ -79,7 +79,7 @@ export class AnnouncementService {
 			silence: values.silence,
 			needConfirmationToRead: values.needConfirmationToRead,
 			userId: values.userId,
-		}).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0]));
+		});
 
 		const packed = await this.announcementEntityService.pack(announcement);
 
diff --git a/packages/backend/src/core/AvatarDecorationService.ts b/packages/backend/src/core/AvatarDecorationService.ts
index 21e31d79a4..8b54bbe012 100644
--- a/packages/backend/src/core/AvatarDecorationService.ts
+++ b/packages/backend/src/core/AvatarDecorationService.ts
@@ -55,10 +55,10 @@ export class AvatarDecorationService implements OnApplicationShutdown {
 
 	@bindThis
 	public async create(options: Partial<MiAvatarDecoration>, moderator?: MiUser): Promise<MiAvatarDecoration> {
-		const created = await this.avatarDecorationsRepository.insert({
+		const created = await this.avatarDecorationsRepository.insertOne({
 			id: this.idService.gen(),
 			...options,
-		}).then(x => this.avatarDecorationsRepository.findOneByOrFail(x.identifiers[0]));
+		});
 
 		this.globalEventService.publishInternalEvent('avatarDecorationCreated', created);
 
diff --git a/packages/backend/src/core/ClipService.ts b/packages/backend/src/core/ClipService.ts
index bb8be26ce6..9fd1ebad87 100644
--- a/packages/backend/src/core/ClipService.ts
+++ b/packages/backend/src/core/ClipService.ts
@@ -45,13 +45,13 @@ export class ClipService {
 			throw new ClipService.TooManyClipsError();
 		}
 
-		const clip = await this.clipsRepository.insert({
+		const clip = await this.clipsRepository.insertOne({
 			id: this.idService.gen(),
 			userId: me.id,
 			name: name,
 			isPublic: isPublic,
 			description: description,
-		}).then(x => this.clipsRepository.findOneByOrFail(x.identifiers[0]));
+		});
 
 		return clip;
 	}
diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts
index b1feca7fb4..7e11b9cdca 100644
--- a/packages/backend/src/core/CustomEmojiService.ts
+++ b/packages/backend/src/core/CustomEmojiService.ts
@@ -68,7 +68,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
 		localOnly: boolean;
 		roleIdsThatCanBeUsedThisEmojiAsReaction: MiRole['id'][];
 	}, moderator?: MiUser): Promise<MiEmoji> {
-		const emoji = await this.emojisRepository.insert({
+		const emoji = await this.emojisRepository.insertOne({
 			id: this.idService.gen(),
 			updatedAt: new Date(),
 			name: data.name,
@@ -82,7 +82,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
 			isSensitive: data.isSensitive,
 			localOnly: data.localOnly,
 			roleIdsThatCanBeUsedThisEmojiAsReaction: data.roleIdsThatCanBeUsedThisEmojiAsReaction,
-		}).then(x => this.emojisRepository.findOneByOrFail(x.identifiers[0]));
+		});
 
 		if (data.host == null) {
 			this.localEmojisCache.refresh();
diff --git a/packages/backend/src/core/DriveService.ts b/packages/backend/src/core/DriveService.ts
index 26cf532c70..37c5d1adf7 100644
--- a/packages/backend/src/core/DriveService.ts
+++ b/packages/backend/src/core/DriveService.ts
@@ -220,7 +220,7 @@ export class DriveService {
 			file.size = size;
 			file.storedInternal = false;
 
-			return await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0]));
+			return await this.driveFilesRepository.insertOne(file);
 		} else { // use internal storage
 			const accessKey = randomUUID();
 			const thumbnailAccessKey = 'thumbnail-' + randomUUID();
@@ -254,7 +254,7 @@ export class DriveService {
 			file.md5 = hash;
 			file.size = size;
 
-			return await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0]));
+			return await this.driveFilesRepository.insertOne(file);
 		}
 	}
 
@@ -615,7 +615,7 @@ export class DriveService {
 				file.type = info.type.mime;
 				file.storedInternal = false;
 
-				file = await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0]));
+				file = await this.driveFilesRepository.insertOne(file);
 			} catch (err) {
 			// duplicate key error (when already registered)
 				if (isDuplicateKeyValueError(err)) {
diff --git a/packages/backend/src/core/FederatedInstanceService.ts b/packages/backend/src/core/FederatedInstanceService.ts
index 66db2067d9..6799f2c5bb 100644
--- a/packages/backend/src/core/FederatedInstanceService.ts
+++ b/packages/backend/src/core/FederatedInstanceService.ts
@@ -55,11 +55,11 @@ export class FederatedInstanceService implements OnApplicationShutdown {
 		const index = await this.instancesRepository.findOneBy({ host });
 
 		if (index == null) {
-			const i = await this.instancesRepository.insert({
+			const i = await this.instancesRepository.insertOne({
 				id: this.idService.gen(),
 				host,
 				firstRetrievedAt: new Date(),
-			}).then(x => this.instancesRepository.findOneByOrFail(x.identifiers[0]));
+			});
 
 			this.federatedInstanceCache.set(host, i);
 			return i;
diff --git a/packages/backend/src/core/RelayService.ts b/packages/backend/src/core/RelayService.ts
index e9dc9b57af..8dd3d64f5b 100644
--- a/packages/backend/src/core/RelayService.ts
+++ b/packages/backend/src/core/RelayService.ts
@@ -53,11 +53,11 @@ export class RelayService {
 
 	@bindThis
 	public async addRelay(inbox: string): Promise<MiRelay> {
-		const relay = await this.relaysRepository.insert({
+		const relay = await this.relaysRepository.insertOne({
 			id: this.idService.gen(),
 			inbox,
 			status: 'requesting',
-		}).then(x => this.relaysRepository.findOneByOrFail(x.identifiers[0]));
+		});
 
 		const relayActor = await this.getRelayActor();
 		const follow = await this.apRendererService.renderFollowRelay(relay, relayActor);
diff --git a/packages/backend/src/core/ReversiService.ts b/packages/backend/src/core/ReversiService.ts
index 439bc08845..7f939b99c7 100644
--- a/packages/backend/src/core/ReversiService.ts
+++ b/packages/backend/src/core/ReversiService.ts
@@ -281,7 +281,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
 
 	@bindThis
 	private async matched(parentId: MiUser['id'], childId: MiUser['id'], options: { noIrregularRules: boolean; }): Promise<MiReversiGame> {
-		const game = await this.reversiGamesRepository.insert({
+		const game = await this.reversiGamesRepository.insertOne({
 			id: this.idService.gen(),
 			user1Id: parentId,
 			user2Id: childId,
@@ -294,10 +294,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
 			bw: 'random',
 			isLlotheo: false,
 			noIrregularRules: options.noIrregularRules,
-		}).then(x => this.reversiGamesRepository.findOneOrFail({
-			where: { id: x.identifiers[0].id },
-			relations: ['user1', 'user2'],
-		}));
+		}, { relations: ['user1', 'user2'] });
 		this.cacheGame(game);
 
 		const packed = await this.reversiGameEntityService.packDetail(game);
diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts
index 70c537f9ab..d6eea70297 100644
--- a/packages/backend/src/core/RoleService.ts
+++ b/packages/backend/src/core/RoleService.ts
@@ -471,12 +471,12 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
 			}
 		}
 
-		const created = await this.roleAssignmentsRepository.insert({
+		const created = await this.roleAssignmentsRepository.insertOne({
 			id: this.idService.gen(now),
 			expiresAt: expiresAt,
 			roleId: roleId,
 			userId: userId,
-		}).then(x => this.roleAssignmentsRepository.findOneByOrFail(x.identifiers[0]));
+		});
 
 		this.rolesRepository.update(roleId, {
 			lastUsedAt: new Date(),
@@ -558,7 +558,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
 	@bindThis
 	public async create(values: Partial<MiRole>, moderator?: MiUser): Promise<MiRole> {
 		const date = new Date();
-		const created = await this.rolesRepository.insert({
+		const created = await this.rolesRepository.insertOne({
 			id: this.idService.gen(date.getTime()),
 			updatedAt: date,
 			lastUsedAt: date,
@@ -576,7 +576,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
 			canEditMembersByModerator: values.canEditMembersByModerator,
 			displayOrder: values.displayOrder,
 			policies: values.policies,
-		}).then(x => this.rolesRepository.findOneByOrFail(x.identifiers[0]));
+		});
 
 		this.globalEventService.publishInternalEvent('roleCreated', created);
 
diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts
index deeecdeb1f..406ea04031 100644
--- a/packages/backend/src/core/UserFollowingService.ts
+++ b/packages/backend/src/core/UserFollowingService.ts
@@ -517,7 +517,7 @@ export class UserFollowingService implements OnModuleInit {
 			followerId: follower.id,
 		});
 
-		const followRequest = await this.followRequestsRepository.insert({
+		const followRequest = await this.followRequestsRepository.insertOne({
 			id: this.idService.gen(),
 			followerId: follower.id,
 			followeeId: followee.id,
@@ -531,7 +531,7 @@ export class UserFollowingService implements OnModuleInit {
 			followeeHost: followee.host,
 			followeeInbox: this.userEntityService.isRemoteUser(followee) ? followee.inbox : undefined,
 			followeeSharedInbox: this.userEntityService.isRemoteUser(followee) ? followee.sharedInbox : undefined,
-		}).then(x => this.followRequestsRepository.findOneByOrFail(x.identifiers[0]));
+		});
 
 		// Publish receiveRequest event
 		if (this.userEntityService.isLocalUser(followee)) {
diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts
index e6dff067f3..c6e6b3a1e8 100644
--- a/packages/backend/src/core/activitypub/models/ApNoteService.ts
+++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts
@@ -407,7 +407,7 @@ export class ApNoteService {
 
 			this.logger.info(`register emoji host=${host}, name=${name}`);
 
-			return await this.emojisRepository.insert({
+			return await this.emojisRepository.insertOne({
 				id: this.idService.gen(),
 				host,
 				name,
@@ -416,7 +416,7 @@ export class ApNoteService {
 				publicUrl: tag.icon.url,
 				updatedAt: new Date(),
 				aliases: [],
-			}).then(x => this.emojisRepository.findOneByOrFail(x.identifiers[0]));
+			});
 		}));
 	}
 }
diff --git a/packages/backend/src/core/chart/core.ts b/packages/backend/src/core/chart/core.ts
index f10e30ef10..af5485a46e 100644
--- a/packages/backend/src/core/chart/core.ts
+++ b/packages/backend/src/core/chart/core.ts
@@ -14,7 +14,8 @@ import { EntitySchema, LessThan, Between } from 'typeorm';
 import { dateUTC, isTimeSame, isTimeBefore, subtractTime, addTime } from '@/misc/prelude/time.js';
 import type Logger from '@/logger.js';
 import { bindThis } from '@/decorators.js';
-import type { Repository, DataSource } from 'typeorm';
+import { MiRepository, miRepository } from '@/models/_.js';
+import type { DataSource, Repository } from 'typeorm';
 
 const COLUMN_PREFIX = '___' as const;
 const UNIQUE_TEMP_COLUMN_PREFIX = 'unique_temp___' as const;
@@ -145,10 +146,10 @@ export default abstract class Chart<T extends Schema> {
 		group: string | null;
 	}[] = [];
 	// ↓にしたいけどfindOneとかで型エラーになる
-	//private repositoryForHour: Repository<RawRecord<T>>;
-	//private repositoryForDay: Repository<RawRecord<T>>;
-	private repositoryForHour: Repository<{ id: number; group?: string | null; date: number; }>;
-	private repositoryForDay: Repository<{ id: number; group?: string | null; date: number; }>;
+	//private repositoryForHour: Repository<RawRecord<T>> & MiRepository<RawRecord<T>>;
+	//private repositoryForDay: Repository<RawRecord<T>> & MiRepository<RawRecord<T>>;
+	private repositoryForHour: Repository<{ id: number; group?: string | null; date: number; }> & MiRepository<{ id: number; group?: string | null; date: number; }>;
+	private repositoryForDay: Repository<{ id: number; group?: string | null; date: number; }> & MiRepository<{ id: number; group?: string | null; date: number; }>;
 
 	/**
 	 * 1日に一回程度実行されれば良いような計算処理を入れる(主にCASCADE削除などアプリケーション側で感知できない変動によるズレの修正用)
@@ -211,6 +212,10 @@ export default abstract class Chart<T extends Schema> {
 	} {
 		const createEntity = (span: 'hour' | 'day'): EntitySchema => new EntitySchema({
 			name:
+				span === 'hour' ? `ChartX${name}` :
+				span === 'day' ? `ChartDayX${name}` :
+				new Error('not happen') as never,
+			tableName:
 				span === 'hour' ? `__chart__${camelToSnake(name)}` :
 				span === 'day' ? `__chart_day__${camelToSnake(name)}` :
 				new Error('not happen') as never,
@@ -271,8 +276,8 @@ export default abstract class Chart<T extends Schema> {
 		this.logger = logger;
 
 		const { hour, day } = Chart.schemaToEntity(name, schema, grouped);
-		this.repositoryForHour = db.getRepository<{ id: number; group?: string | null; date: number; }>(hour);
-		this.repositoryForDay = db.getRepository<{ id: number; group?: string | null; date: number; }>(day);
+		this.repositoryForHour = db.getRepository<{ id: number; group?: string | null; date: number; }>(hour).extend(miRepository as MiRepository<{ id: number; group?: string | null; date: number; }>);
+		this.repositoryForDay = db.getRepository<{ id: number; group?: string | null; date: number; }>(day).extend(miRepository as MiRepository<{ id: number; group?: string | null; date: number; }>);
 	}
 
 	@bindThis
@@ -387,11 +392,11 @@ export default abstract class Chart<T extends Schema> {
 			}
 
 			// 新規ログ挿入
-			log = await repository.insert({
+			log = await repository.insertOne({
 				date: date,
 				...(group ? { group: group } : {}),
 				...columns,
-			}).then(x => repository.findOneByOrFail(x.identifiers[0])) as RawRecord<T>;
+			}) as RawRecord<T>;
 
 			this.logger.info(`${this.name + (group ? `:${group}` : '')}(${span}): New commit created`);
 
diff --git a/packages/backend/src/models/RepositoryModule.ts b/packages/backend/src/models/RepositoryModule.ts
index bd447570dd..d3062d6b36 100644
--- a/packages/backend/src/models/RepositoryModule.ts
+++ b/packages/backend/src/models/RepositoryModule.ts
@@ -5,409 +5,409 @@
 
 import { Module } from '@nestjs/common';
 import { DI } from '@/di-symbols.js';
-import { MiAbuseUserReport, MiAccessToken, MiAd, MiAnnouncement, MiAnnouncementRead, MiAntenna, MiApp, MiAuthSession, MiAvatarDecoration, MiBlocking, MiChannel, MiChannelFavorite, MiChannelFollowing, MiClip, MiClipFavorite, MiClipNote, MiDriveFile, MiDriveFolder, MiEmoji, MiFlash, MiFlashLike, MiFollowRequest, MiFollowing, MiGalleryLike, MiGalleryPost, MiHashtag, MiInstance, MiMeta, MiModerationLog, MiMuting, MiNote, MiNoteFavorite, MiNoteReaction, MiNoteThreadMuting, MiNoteUnread, MiPage, MiPageLike, MiPasswordResetRequest, MiPoll, MiPollVote, MiPromoNote, MiPromoRead, MiRegistrationTicket, MiRegistryItem, MiRelay, MiRenoteMuting, MiRetentionAggregation, MiRole, MiRoleAssignment, MiSignin, MiSwSubscription, MiUsedUsername, MiUser, MiUserIp, MiUserKeypair, MiUserList, MiUserListFavorite, MiUserListMembership, MiUserMemo, MiUserNotePining, MiUserPending, MiUserProfile, MiUserPublickey, MiUserSecurityKey, MiWebhook, MiBubbleGameRecord, MiReversiGame } from './_.js';
+import { MiRepository, MiAbuseUserReport, MiAccessToken, MiAd, MiAnnouncement, MiAnnouncementRead, MiAntenna, MiApp, MiAuthSession, MiAvatarDecoration, MiBlocking, MiChannel, MiChannelFavorite, MiChannelFollowing, MiClip, MiClipFavorite, MiClipNote, MiDriveFile, MiDriveFolder, MiEmoji, MiFlash, MiFlashLike, MiFollowRequest, MiFollowing, MiGalleryLike, MiGalleryPost, MiHashtag, MiInstance, MiMeta, MiModerationLog, MiMuting, MiNote, MiNoteFavorite, MiNoteReaction, MiNoteThreadMuting, MiNoteUnread, MiPage, MiPageLike, MiPasswordResetRequest, MiPoll, MiPollVote, MiPromoNote, MiPromoRead, MiRegistrationTicket, MiRegistryItem, MiRelay, MiRenoteMuting, MiRetentionAggregation, MiRole, MiRoleAssignment, MiSignin, MiSwSubscription, MiUsedUsername, MiUser, MiUserIp, MiUserKeypair, MiUserList, MiUserListFavorite, MiUserListMembership, MiUserMemo, MiUserNotePining, MiUserPending, MiUserProfile, MiUserPublickey, MiUserSecurityKey, MiWebhook, MiBubbleGameRecord, MiReversiGame, miRepository } from './_.js';
 import type { DataSource } from 'typeorm';
 import type { Provider } from '@nestjs/common';
 
 const $usersRepository: Provider = {
 	provide: DI.usersRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiUser),
+	useFactory: (db: DataSource) => db.getRepository(MiUser).extend(miRepository as MiRepository<MiUser>),
 	inject: [DI.db],
 };
 
 const $notesRepository: Provider = {
 	provide: DI.notesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiNote),
+	useFactory: (db: DataSource) => db.getRepository(MiNote).extend(miRepository as MiRepository<MiNote>),
 	inject: [DI.db],
 };
 
 const $announcementsRepository: Provider = {
 	provide: DI.announcementsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiAnnouncement),
+	useFactory: (db: DataSource) => db.getRepository(MiAnnouncement).extend(miRepository as MiRepository<MiAnnouncement>),
 	inject: [DI.db],
 };
 
 const $announcementReadsRepository: Provider = {
 	provide: DI.announcementReadsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiAnnouncementRead),
+	useFactory: (db: DataSource) => db.getRepository(MiAnnouncementRead).extend(miRepository as MiRepository<MiAnnouncementRead>),
 	inject: [DI.db],
 };
 
 const $appsRepository: Provider = {
 	provide: DI.appsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiApp),
+	useFactory: (db: DataSource) => db.getRepository(MiApp).extend(miRepository as MiRepository<MiApp>),
 	inject: [DI.db],
 };
 
 const $avatarDecorationsRepository: Provider = {
 	provide: DI.avatarDecorationsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiAvatarDecoration),
+	useFactory: (db: DataSource) => db.getRepository(MiAvatarDecoration).extend(miRepository as MiRepository<MiAvatarDecoration>),
 	inject: [DI.db],
 };
 
 const $noteFavoritesRepository: Provider = {
 	provide: DI.noteFavoritesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiNoteFavorite),
+	useFactory: (db: DataSource) => db.getRepository(MiNoteFavorite).extend(miRepository as MiRepository<MiNoteFavorite>),
 	inject: [DI.db],
 };
 
 const $noteThreadMutingsRepository: Provider = {
 	provide: DI.noteThreadMutingsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiNoteThreadMuting),
+	useFactory: (db: DataSource) => db.getRepository(MiNoteThreadMuting).extend(miRepository as MiRepository<MiNoteThreadMuting>),
 	inject: [DI.db],
 };
 
 const $noteReactionsRepository: Provider = {
 	provide: DI.noteReactionsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiNoteReaction),
+	useFactory: (db: DataSource) => db.getRepository(MiNoteReaction).extend(miRepository as MiRepository<MiNoteReaction>),
 	inject: [DI.db],
 };
 
 const $noteUnreadsRepository: Provider = {
 	provide: DI.noteUnreadsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiNoteUnread),
+	useFactory: (db: DataSource) => db.getRepository(MiNoteUnread).extend(miRepository as MiRepository<MiNoteUnread>),
 	inject: [DI.db],
 };
 
 const $pollsRepository: Provider = {
 	provide: DI.pollsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiPoll),
+	useFactory: (db: DataSource) => db.getRepository(MiPoll).extend(miRepository as MiRepository<MiPoll>),
 	inject: [DI.db],
 };
 
 const $pollVotesRepository: Provider = {
 	provide: DI.pollVotesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiPollVote),
+	useFactory: (db: DataSource) => db.getRepository(MiPollVote).extend(miRepository as MiRepository<MiPollVote>),
 	inject: [DI.db],
 };
 
 const $userProfilesRepository: Provider = {
 	provide: DI.userProfilesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiUserProfile),
+	useFactory: (db: DataSource) => db.getRepository(MiUserProfile).extend(miRepository as MiRepository<MiUserProfile>),
 	inject: [DI.db],
 };
 
 const $userKeypairsRepository: Provider = {
 	provide: DI.userKeypairsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiUserKeypair),
+	useFactory: (db: DataSource) => db.getRepository(MiUserKeypair).extend(miRepository as MiRepository<MiUserKeypair>),
 	inject: [DI.db],
 };
 
 const $userPendingsRepository: Provider = {
 	provide: DI.userPendingsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiUserPending),
+	useFactory: (db: DataSource) => db.getRepository(MiUserPending).extend(miRepository as MiRepository<MiUserPending>),
 	inject: [DI.db],
 };
 
 const $userSecurityKeysRepository: Provider = {
 	provide: DI.userSecurityKeysRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiUserSecurityKey),
+	useFactory: (db: DataSource) => db.getRepository(MiUserSecurityKey).extend(miRepository as MiRepository<MiUserSecurityKey>),
 	inject: [DI.db],
 };
 
 const $userPublickeysRepository: Provider = {
 	provide: DI.userPublickeysRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiUserPublickey),
+	useFactory: (db: DataSource) => db.getRepository(MiUserPublickey).extend(miRepository as MiRepository<MiUserPublickey>),
 	inject: [DI.db],
 };
 
 const $userListsRepository: Provider = {
 	provide: DI.userListsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiUserList),
+	useFactory: (db: DataSource) => db.getRepository(MiUserList).extend(miRepository as MiRepository<MiUserList>),
 	inject: [DI.db],
 };
 
 const $userListFavoritesRepository: Provider = {
 	provide: DI.userListFavoritesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiUserListFavorite),
+	useFactory: (db: DataSource) => db.getRepository(MiUserListFavorite).extend(miRepository as MiRepository<MiUserListFavorite>),
 	inject: [DI.db],
 };
 
 const $userListMembershipsRepository: Provider = {
 	provide: DI.userListMembershipsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiUserListMembership),
+	useFactory: (db: DataSource) => db.getRepository(MiUserListMembership).extend(miRepository as MiRepository<MiUserListMembership>),
 	inject: [DI.db],
 };
 
 const $userNotePiningsRepository: Provider = {
 	provide: DI.userNotePiningsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiUserNotePining),
+	useFactory: (db: DataSource) => db.getRepository(MiUserNotePining).extend(miRepository as MiRepository<MiUserNotePining>),
 	inject: [DI.db],
 };
 
 const $userIpsRepository: Provider = {
 	provide: DI.userIpsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiUserIp),
+	useFactory: (db: DataSource) => db.getRepository(MiUserIp).extend(miRepository as MiRepository<MiUserIp>),
 	inject: [DI.db],
 };
 
 const $usedUsernamesRepository: Provider = {
 	provide: DI.usedUsernamesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiUsedUsername),
+	useFactory: (db: DataSource) => db.getRepository(MiUsedUsername).extend(miRepository as MiRepository<MiUsedUsername>),
 	inject: [DI.db],
 };
 
 const $followingsRepository: Provider = {
 	provide: DI.followingsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiFollowing),
+	useFactory: (db: DataSource) => db.getRepository(MiFollowing).extend(miRepository as MiRepository<MiFollowing>),
 	inject: [DI.db],
 };
 
 const $followRequestsRepository: Provider = {
 	provide: DI.followRequestsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiFollowRequest),
+	useFactory: (db: DataSource) => db.getRepository(MiFollowRequest).extend(miRepository as MiRepository<MiFollowRequest>),
 	inject: [DI.db],
 };
 
 const $instancesRepository: Provider = {
 	provide: DI.instancesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiInstance),
+	useFactory: (db: DataSource) => db.getRepository(MiInstance).extend(miRepository as MiRepository<MiInstance>),
 	inject: [DI.db],
 };
 
 const $emojisRepository: Provider = {
 	provide: DI.emojisRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiEmoji),
+	useFactory: (db: DataSource) => db.getRepository(MiEmoji).extend(miRepository as MiRepository<MiEmoji>),
 	inject: [DI.db],
 };
 
 const $driveFilesRepository: Provider = {
 	provide: DI.driveFilesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiDriveFile),
+	useFactory: (db: DataSource) => db.getRepository(MiDriveFile).extend(miRepository as MiRepository<MiDriveFile>),
 	inject: [DI.db],
 };
 
 const $driveFoldersRepository: Provider = {
 	provide: DI.driveFoldersRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiDriveFolder),
+	useFactory: (db: DataSource) => db.getRepository(MiDriveFolder).extend(miRepository as MiRepository<MiDriveFolder>),
 	inject: [DI.db],
 };
 
 const $metasRepository: Provider = {
 	provide: DI.metasRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiMeta),
+	useFactory: (db: DataSource) => db.getRepository(MiMeta).extend(miRepository as MiRepository<MiMeta>),
 	inject: [DI.db],
 };
 
 const $mutingsRepository: Provider = {
 	provide: DI.mutingsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiMuting),
+	useFactory: (db: DataSource) => db.getRepository(MiMuting).extend(miRepository as MiRepository<MiMuting>),
 	inject: [DI.db],
 };
 
 const $renoteMutingsRepository: Provider = {
 	provide: DI.renoteMutingsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiRenoteMuting),
+	useFactory: (db: DataSource) => db.getRepository(MiRenoteMuting).extend(miRepository as MiRepository<MiRenoteMuting>),
 	inject: [DI.db],
 };
 
 const $blockingsRepository: Provider = {
 	provide: DI.blockingsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiBlocking),
+	useFactory: (db: DataSource) => db.getRepository(MiBlocking).extend(miRepository as MiRepository<MiBlocking>),
 	inject: [DI.db],
 };
 
 const $swSubscriptionsRepository: Provider = {
 	provide: DI.swSubscriptionsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiSwSubscription),
+	useFactory: (db: DataSource) => db.getRepository(MiSwSubscription).extend(miRepository as MiRepository<MiSwSubscription>),
 	inject: [DI.db],
 };
 
 const $hashtagsRepository: Provider = {
 	provide: DI.hashtagsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiHashtag),
+	useFactory: (db: DataSource) => db.getRepository(MiHashtag).extend(miRepository as MiRepository<MiHashtag>),
 	inject: [DI.db],
 };
 
 const $abuseUserReportsRepository: Provider = {
 	provide: DI.abuseUserReportsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiAbuseUserReport),
+	useFactory: (db: DataSource) => db.getRepository(MiAbuseUserReport).extend(miRepository as MiRepository<MiAbuseUserReport>),
 	inject: [DI.db],
 };
 
 const $registrationTicketsRepository: Provider = {
 	provide: DI.registrationTicketsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiRegistrationTicket),
+	useFactory: (db: DataSource) => db.getRepository(MiRegistrationTicket).extend(miRepository as MiRepository<MiRegistrationTicket>),
 	inject: [DI.db],
 };
 
 const $authSessionsRepository: Provider = {
 	provide: DI.authSessionsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiAuthSession),
+	useFactory: (db: DataSource) => db.getRepository(MiAuthSession).extend(miRepository as MiRepository<MiAuthSession>),
 	inject: [DI.db],
 };
 
 const $accessTokensRepository: Provider = {
 	provide: DI.accessTokensRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiAccessToken),
+	useFactory: (db: DataSource) => db.getRepository(MiAccessToken).extend(miRepository as MiRepository<MiAccessToken>),
 	inject: [DI.db],
 };
 
 const $signinsRepository: Provider = {
 	provide: DI.signinsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiSignin),
+	useFactory: (db: DataSource) => db.getRepository(MiSignin).extend(miRepository as MiRepository<MiSignin>),
 	inject: [DI.db],
 };
 
 const $pagesRepository: Provider = {
 	provide: DI.pagesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiPage),
+	useFactory: (db: DataSource) => db.getRepository(MiPage).extend(miRepository as MiRepository<MiPage>),
 	inject: [DI.db],
 };
 
 const $pageLikesRepository: Provider = {
 	provide: DI.pageLikesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiPageLike),
+	useFactory: (db: DataSource) => db.getRepository(MiPageLike).extend(miRepository as MiRepository<MiPageLike>),
 	inject: [DI.db],
 };
 
 const $galleryPostsRepository: Provider = {
 	provide: DI.galleryPostsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiGalleryPost),
+	useFactory: (db: DataSource) => db.getRepository(MiGalleryPost).extend(miRepository as MiRepository<MiGalleryPost>),
 	inject: [DI.db],
 };
 
 const $galleryLikesRepository: Provider = {
 	provide: DI.galleryLikesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiGalleryLike),
+	useFactory: (db: DataSource) => db.getRepository(MiGalleryLike).extend(miRepository as MiRepository<MiGalleryLike>),
 	inject: [DI.db],
 };
 
 const $moderationLogsRepository: Provider = {
 	provide: DI.moderationLogsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiModerationLog),
+	useFactory: (db: DataSource) => db.getRepository(MiModerationLog).extend(miRepository as MiRepository<MiModerationLog>),
 	inject: [DI.db],
 };
 
 const $clipsRepository: Provider = {
 	provide: DI.clipsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiClip),
+	useFactory: (db: DataSource) => db.getRepository(MiClip).extend(miRepository as MiRepository<MiClip>),
 	inject: [DI.db],
 };
 
 const $clipNotesRepository: Provider = {
 	provide: DI.clipNotesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiClipNote),
+	useFactory: (db: DataSource) => db.getRepository(MiClipNote).extend(miRepository as MiRepository<MiClipNote>),
 	inject: [DI.db],
 };
 
 const $clipFavoritesRepository: Provider = {
 	provide: DI.clipFavoritesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiClipFavorite),
+	useFactory: (db: DataSource) => db.getRepository(MiClipFavorite).extend(miRepository as MiRepository<MiClipFavorite>),
 	inject: [DI.db],
 };
 
 const $antennasRepository: Provider = {
 	provide: DI.antennasRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiAntenna),
+	useFactory: (db: DataSource) => db.getRepository(MiAntenna).extend(miRepository as MiRepository<MiAntenna>),
 	inject: [DI.db],
 };
 
 const $promoNotesRepository: Provider = {
 	provide: DI.promoNotesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiPromoNote),
+	useFactory: (db: DataSource) => db.getRepository(MiPromoNote).extend(miRepository as MiRepository<MiPromoNote>),
 	inject: [DI.db],
 };
 
 const $promoReadsRepository: Provider = {
 	provide: DI.promoReadsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiPromoRead),
+	useFactory: (db: DataSource) => db.getRepository(MiPromoRead).extend(miRepository as MiRepository<MiPromoRead>),
 	inject: [DI.db],
 };
 
 const $relaysRepository: Provider = {
 	provide: DI.relaysRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiRelay),
+	useFactory: (db: DataSource) => db.getRepository(MiRelay).extend(miRepository as MiRepository<MiRelay>),
 	inject: [DI.db],
 };
 
 const $channelsRepository: Provider = {
 	provide: DI.channelsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiChannel),
+	useFactory: (db: DataSource) => db.getRepository(MiChannel).extend(miRepository as MiRepository<MiChannel>),
 	inject: [DI.db],
 };
 
 const $channelFollowingsRepository: Provider = {
 	provide: DI.channelFollowingsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiChannelFollowing),
+	useFactory: (db: DataSource) => db.getRepository(MiChannelFollowing).extend(miRepository as MiRepository<MiChannelFollowing>),
 	inject: [DI.db],
 };
 
 const $channelFavoritesRepository: Provider = {
 	provide: DI.channelFavoritesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiChannelFavorite),
+	useFactory: (db: DataSource) => db.getRepository(MiChannelFavorite).extend(miRepository as MiRepository<MiChannelFavorite>),
 	inject: [DI.db],
 };
 
 const $registryItemsRepository: Provider = {
 	provide: DI.registryItemsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiRegistryItem),
+	useFactory: (db: DataSource) => db.getRepository(MiRegistryItem).extend(miRepository as MiRepository<MiRegistryItem>),
 	inject: [DI.db],
 };
 
 const $webhooksRepository: Provider = {
 	provide: DI.webhooksRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiWebhook),
+	useFactory: (db: DataSource) => db.getRepository(MiWebhook).extend(miRepository as MiRepository<MiWebhook>),
 	inject: [DI.db],
 };
 
 const $adsRepository: Provider = {
 	provide: DI.adsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiAd),
+	useFactory: (db: DataSource) => db.getRepository(MiAd).extend(miRepository as MiRepository<MiAd>),
 	inject: [DI.db],
 };
 
 const $passwordResetRequestsRepository: Provider = {
 	provide: DI.passwordResetRequestsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiPasswordResetRequest),
+	useFactory: (db: DataSource) => db.getRepository(MiPasswordResetRequest).extend(miRepository as MiRepository<MiPasswordResetRequest>),
 	inject: [DI.db],
 };
 
 const $retentionAggregationsRepository: Provider = {
 	provide: DI.retentionAggregationsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiRetentionAggregation),
+	useFactory: (db: DataSource) => db.getRepository(MiRetentionAggregation).extend(miRepository as MiRepository<MiRetentionAggregation>),
 	inject: [DI.db],
 };
 
 const $flashsRepository: Provider = {
 	provide: DI.flashsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiFlash),
+	useFactory: (db: DataSource) => db.getRepository(MiFlash).extend(miRepository as MiRepository<MiFlash>),
 	inject: [DI.db],
 };
 
 const $flashLikesRepository: Provider = {
 	provide: DI.flashLikesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiFlashLike),
+	useFactory: (db: DataSource) => db.getRepository(MiFlashLike).extend(miRepository as MiRepository<MiFlashLike>),
 	inject: [DI.db],
 };
 
 const $rolesRepository: Provider = {
 	provide: DI.rolesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiRole),
+	useFactory: (db: DataSource) => db.getRepository(MiRole).extend(miRepository as MiRepository<MiRole>),
 	inject: [DI.db],
 };
 
 const $roleAssignmentsRepository: Provider = {
 	provide: DI.roleAssignmentsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiRoleAssignment),
+	useFactory: (db: DataSource) => db.getRepository(MiRoleAssignment).extend(miRepository as MiRepository<MiRoleAssignment>),
 	inject: [DI.db],
 };
 
 const $userMemosRepository: Provider = {
 	provide: DI.userMemosRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiUserMemo),
+	useFactory: (db: DataSource) => db.getRepository(MiUserMemo).extend(miRepository as MiRepository<MiUserMemo>),
 	inject: [DI.db],
 };
 
 const $bubbleGameRecordsRepository: Provider = {
 	provide: DI.bubbleGameRecordsRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiBubbleGameRecord),
+	useFactory: (db: DataSource) => db.getRepository(MiBubbleGameRecord).extend(miRepository as MiRepository<MiBubbleGameRecord>),
 	inject: [DI.db],
 };
 
 const $reversiGamesRepository: Provider = {
 	provide: DI.reversiGamesRepository,
-	useFactory: (db: DataSource) => db.getRepository(MiReversiGame),
+	useFactory: (db: DataSource) => db.getRepository(MiReversiGame).extend(miRepository as MiRepository<MiReversiGame>),
 	inject: [DI.db],
 };
 
diff --git a/packages/backend/src/models/_.ts b/packages/backend/src/models/_.ts
index 43d42d80dd..2e6a41586e 100644
--- a/packages/backend/src/models/_.ts
+++ b/packages/backend/src/models/_.ts
@@ -3,6 +3,13 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
+import { FindOneOptions, InsertQueryBuilder, ObjectLiteral, Repository, SelectQueryBuilder, TypeORMError } from 'typeorm';
+import { DriverUtils } from 'typeorm/driver/DriverUtils.js';
+import { RelationCountLoader } from 'typeorm/query-builder/relation-count/RelationCountLoader.js';
+import { RelationIdLoader } from 'typeorm/query-builder/relation-id/RelationIdLoader.js';
+import { RawSqlResultsToEntityTransformer } from 'typeorm/query-builder/transformer/RawSqlResultsToEntityTransformer.js';
+import { ObjectUtils } from 'typeorm/util/ObjectUtils.js';
+import { OrmUtils } from 'typeorm/util/OrmUtils.js';
 import { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
 import { MiAccessToken } from '@/models/AccessToken.js';
 import { MiAd } from '@/models/Ad.js';
@@ -70,8 +77,70 @@ import { MiFlashLike } from '@/models/FlashLike.js';
 import { MiUserListFavorite } from '@/models/UserListFavorite.js';
 import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
 import { MiReversiGame } from '@/models/ReversiGame.js';
+import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
 
-import type { Repository } from 'typeorm';
+export interface MiRepository<T extends ObjectLiteral> {
+	createTableColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>): string[];
+	createTableColumnNamesWithPrimaryKey(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>): string[];
+	insertOne(this: Repository<T> & MiRepository<T>, entity: QueryDeepPartialEntity<T>, findOptions?: Pick<FindOneOptions<T>, 'relations'>): Promise<T>;
+	selectAliasColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>, builder: SelectQueryBuilder<T>): void;
+}
+
+export const miRepository = {
+	createTableColumnNames(queryBuilder) {
+		// @ts-expect-error -- protected
+		const insertedColumns = queryBuilder.getInsertedColumns();
+		if (insertedColumns.length) {
+			return insertedColumns.map(column => column.databaseName);
+		}
+		if (!queryBuilder.expressionMap.mainAlias?.hasMetadata && !queryBuilder.expressionMap.insertColumns.length) {
+			// @ts-expect-error -- protected
+			const valueSets = queryBuilder.getValueSets();
+			if (valueSets.length === 1) {
+				return Object.keys(valueSets[0]);
+			}
+		}
+		return queryBuilder.expressionMap.insertColumns;
+	},
+	createTableColumnNamesWithPrimaryKey(queryBuilder) {
+		const columnNames = this.createTableColumnNames(queryBuilder);
+		if (!columnNames.includes('id')) {
+			columnNames.unshift('id');
+		}
+		return columnNames;
+	},
+	async insertOne(entity, findOptions?) {
+		const queryBuilder = this.createQueryBuilder().insert().values(entity);
+		// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+		const mainAlias = queryBuilder.expressionMap.mainAlias!;
+		const name = mainAlias.name;
+		mainAlias.name = 't';
+		const columnNames = this.createTableColumnNamesWithPrimaryKey(queryBuilder);
+		queryBuilder.returning(columnNames.reduce((a, c) => `${a}, ${queryBuilder.escape(c)}`, '').slice(2));
+		const builder = this.createQueryBuilder().addCommonTableExpression(queryBuilder, 'cte', { columnNames });
+		// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+		builder.expressionMap.mainAlias!.tablePath = 'cte';
+		this.selectAliasColumnNames(queryBuilder, builder);
+		if (findOptions) {
+			builder.setFindOptions(findOptions);
+		}
+		const raw = await builder.execute();
+		mainAlias.name = name;
+		const relationId = await new RelationIdLoader(builder.connection, this.queryRunner, builder.expressionMap.relationIdAttributes).load(raw);
+		const relationCount = await new RelationCountLoader(builder.connection, this.queryRunner, builder.expressionMap.relationCountAttributes).load(raw);
+		const result = new RawSqlResultsToEntityTransformer(builder.expressionMap, builder.connection.driver, relationId, relationCount, this.queryRunner).transform(raw, mainAlias);
+		return result[0];
+	},
+	selectAliasColumnNames(queryBuilder, builder) {
+		let selectOrAddSelect = (selection: string, selectionAliasName?: string) => {
+			selectOrAddSelect = (selection, selectionAliasName) => builder.addSelect(selection, selectionAliasName);
+			return builder.select(selection, selectionAliasName);
+		};
+		for (const columnName of this.createTableColumnNamesWithPrimaryKey(queryBuilder)) {
+			selectOrAddSelect(`${builder.alias}.${columnName}`, `${builder.alias}_${columnName}`);
+		}
+	},
+} satisfies MiRepository<ObjectLiteral>;
 
 export {
 	MiAbuseUserReport,
@@ -143,70 +212,70 @@ export {
 	MiReversiGame,
 };
 
-export type AbuseUserReportsRepository = Repository<MiAbuseUserReport>;
-export type AccessTokensRepository = Repository<MiAccessToken>;
-export type AdsRepository = Repository<MiAd>;
-export type AnnouncementsRepository = Repository<MiAnnouncement>;
-export type AnnouncementReadsRepository = Repository<MiAnnouncementRead>;
-export type AntennasRepository = Repository<MiAntenna>;
-export type AppsRepository = Repository<MiApp>;
-export type AvatarDecorationsRepository = Repository<MiAvatarDecoration>;
-export type AuthSessionsRepository = Repository<MiAuthSession>;
-export type BlockingsRepository = Repository<MiBlocking>;
-export type ChannelFollowingsRepository = Repository<MiChannelFollowing>;
-export type ChannelFavoritesRepository = Repository<MiChannelFavorite>;
-export type ClipsRepository = Repository<MiClip>;
-export type ClipNotesRepository = Repository<MiClipNote>;
-export type ClipFavoritesRepository = Repository<MiClipFavorite>;
-export type DriveFilesRepository = Repository<MiDriveFile>;
-export type DriveFoldersRepository = Repository<MiDriveFolder>;
-export type EmojisRepository = Repository<MiEmoji>;
-export type FollowingsRepository = Repository<MiFollowing>;
-export type FollowRequestsRepository = Repository<MiFollowRequest>;
-export type GalleryLikesRepository = Repository<MiGalleryLike>;
-export type GalleryPostsRepository = Repository<MiGalleryPost>;
-export type HashtagsRepository = Repository<MiHashtag>;
-export type InstancesRepository = Repository<MiInstance>;
-export type MetasRepository = Repository<MiMeta>;
-export type ModerationLogsRepository = Repository<MiModerationLog>;
-export type MutingsRepository = Repository<MiMuting>;
-export type RenoteMutingsRepository = Repository<MiRenoteMuting>;
-export type NotesRepository = Repository<MiNote>;
-export type NoteFavoritesRepository = Repository<MiNoteFavorite>;
-export type NoteReactionsRepository = Repository<MiNoteReaction>;
-export type NoteThreadMutingsRepository = Repository<MiNoteThreadMuting>;
-export type NoteUnreadsRepository = Repository<MiNoteUnread>;
-export type PagesRepository = Repository<MiPage>;
-export type PageLikesRepository = Repository<MiPageLike>;
-export type PasswordResetRequestsRepository = Repository<MiPasswordResetRequest>;
-export type PollsRepository = Repository<MiPoll>;
-export type PollVotesRepository = Repository<MiPollVote>;
-export type PromoNotesRepository = Repository<MiPromoNote>;
-export type PromoReadsRepository = Repository<MiPromoRead>;
-export type RegistrationTicketsRepository = Repository<MiRegistrationTicket>;
-export type RegistryItemsRepository = Repository<MiRegistryItem>;
-export type RelaysRepository = Repository<MiRelay>;
-export type SigninsRepository = Repository<MiSignin>;
-export type SwSubscriptionsRepository = Repository<MiSwSubscription>;
-export type UsedUsernamesRepository = Repository<MiUsedUsername>;
-export type UsersRepository = Repository<MiUser>;
-export type UserIpsRepository = Repository<MiUserIp>;
-export type UserKeypairsRepository = Repository<MiUserKeypair>;
-export type UserListsRepository = Repository<MiUserList>;
-export type UserListFavoritesRepository = Repository<MiUserListFavorite>;
-export type UserListMembershipsRepository = Repository<MiUserListMembership>;
-export type UserNotePiningsRepository = Repository<MiUserNotePining>;
-export type UserPendingsRepository = Repository<MiUserPending>;
-export type UserProfilesRepository = Repository<MiUserProfile>;
-export type UserPublickeysRepository = Repository<MiUserPublickey>;
-export type UserSecurityKeysRepository = Repository<MiUserSecurityKey>;
-export type WebhooksRepository = Repository<MiWebhook>;
-export type ChannelsRepository = Repository<MiChannel>;
-export type RetentionAggregationsRepository = Repository<MiRetentionAggregation>;
-export type RolesRepository = Repository<MiRole>;
-export type RoleAssignmentsRepository = Repository<MiRoleAssignment>;
-export type FlashsRepository = Repository<MiFlash>;
-export type FlashLikesRepository = Repository<MiFlashLike>;
-export type UserMemoRepository = Repository<MiUserMemo>;
-export type BubbleGameRecordsRepository = Repository<MiBubbleGameRecord>;
-export type ReversiGamesRepository = Repository<MiReversiGame>;
+export type AbuseUserReportsRepository = Repository<MiAbuseUserReport> & MiRepository<MiAbuseUserReport>;
+export type AccessTokensRepository = Repository<MiAccessToken> & MiRepository<MiAccessToken>;
+export type AdsRepository = Repository<MiAd> & MiRepository<MiAd>;
+export type AnnouncementsRepository = Repository<MiAnnouncement> & MiRepository<MiAnnouncement>;
+export type AnnouncementReadsRepository = Repository<MiAnnouncementRead> & MiRepository<MiAnnouncementRead>;
+export type AntennasRepository = Repository<MiAntenna> & MiRepository<MiAntenna>;
+export type AppsRepository = Repository<MiApp> & MiRepository<MiApp>;
+export type AvatarDecorationsRepository = Repository<MiAvatarDecoration> & MiRepository<MiAvatarDecoration>;
+export type AuthSessionsRepository = Repository<MiAuthSession> & MiRepository<MiAuthSession>;
+export type BlockingsRepository = Repository<MiBlocking> & MiRepository<MiBlocking>;
+export type ChannelFollowingsRepository = Repository<MiChannelFollowing> & MiRepository<MiChannelFollowing>;
+export type ChannelFavoritesRepository = Repository<MiChannelFavorite> & MiRepository<MiChannelFavorite>;
+export type ClipsRepository = Repository<MiClip> & MiRepository<MiClip>;
+export type ClipNotesRepository = Repository<MiClipNote> & MiRepository<MiClipNote>;
+export type ClipFavoritesRepository = Repository<MiClipFavorite> & MiRepository<MiClipFavorite>;
+export type DriveFilesRepository = Repository<MiDriveFile> & MiRepository<MiDriveFile>;
+export type DriveFoldersRepository = Repository<MiDriveFolder> & MiRepository<MiDriveFolder>;
+export type EmojisRepository = Repository<MiEmoji> & MiRepository<MiEmoji>;
+export type FollowingsRepository = Repository<MiFollowing> & MiRepository<MiFollowing>;
+export type FollowRequestsRepository = Repository<MiFollowRequest> & MiRepository<MiFollowRequest>;
+export type GalleryLikesRepository = Repository<MiGalleryLike> & MiRepository<MiGalleryLike>;
+export type GalleryPostsRepository = Repository<MiGalleryPost> & MiRepository<MiGalleryPost>;
+export type HashtagsRepository = Repository<MiHashtag> & MiRepository<MiHashtag>;
+export type InstancesRepository = Repository<MiInstance> & MiRepository<MiInstance>;
+export type MetasRepository = Repository<MiMeta> & MiRepository<MiMeta>;
+export type ModerationLogsRepository = Repository<MiModerationLog> & MiRepository<MiModerationLog>;
+export type MutingsRepository = Repository<MiMuting> & MiRepository<MiMuting>;
+export type RenoteMutingsRepository = Repository<MiRenoteMuting> & MiRepository<MiRenoteMuting>;
+export type NotesRepository = Repository<MiNote> & MiRepository<MiNote>;
+export type NoteFavoritesRepository = Repository<MiNoteFavorite> & MiRepository<MiNoteFavorite>;
+export type NoteReactionsRepository = Repository<MiNoteReaction> & MiRepository<MiNoteReaction>;
+export type NoteThreadMutingsRepository = Repository<MiNoteThreadMuting> & MiRepository<MiNoteThreadMuting>;
+export type NoteUnreadsRepository = Repository<MiNoteUnread> & MiRepository<MiNoteUnread>;
+export type PagesRepository = Repository<MiPage> & MiRepository<MiPage>;
+export type PageLikesRepository = Repository<MiPageLike> & MiRepository<MiPageLike>;
+export type PasswordResetRequestsRepository = Repository<MiPasswordResetRequest> & MiRepository<MiPasswordResetRequest>;
+export type PollsRepository = Repository<MiPoll> & MiRepository<MiPoll>;
+export type PollVotesRepository = Repository<MiPollVote> & MiRepository<MiPollVote>;
+export type PromoNotesRepository = Repository<MiPromoNote> & MiRepository<MiPromoNote>;
+export type PromoReadsRepository = Repository<MiPromoRead> & MiRepository<MiPromoRead>;
+export type RegistrationTicketsRepository = Repository<MiRegistrationTicket> & MiRepository<MiRegistrationTicket>;
+export type RegistryItemsRepository = Repository<MiRegistryItem> & MiRepository<MiRegistryItem>;
+export type RelaysRepository = Repository<MiRelay> & MiRepository<MiRelay>;
+export type SigninsRepository = Repository<MiSignin> & MiRepository<MiSignin>;
+export type SwSubscriptionsRepository = Repository<MiSwSubscription> & MiRepository<MiSwSubscription>;
+export type UsedUsernamesRepository = Repository<MiUsedUsername> & MiRepository<MiUsedUsername>;
+export type UsersRepository = Repository<MiUser> & MiRepository<MiUser>;
+export type UserIpsRepository = Repository<MiUserIp> & MiRepository<MiUserIp>;
+export type UserKeypairsRepository = Repository<MiUserKeypair> & MiRepository<MiUserKeypair>;
+export type UserListsRepository = Repository<MiUserList> & MiRepository<MiUserList>;
+export type UserListFavoritesRepository = Repository<MiUserListFavorite> & MiRepository<MiUserListFavorite>;
+export type UserListMembershipsRepository = Repository<MiUserListMembership> & MiRepository<MiUserListMembership>;
+export type UserNotePiningsRepository = Repository<MiUserNotePining> & MiRepository<MiUserNotePining>;
+export type UserPendingsRepository = Repository<MiUserPending> & MiRepository<MiUserPending>;
+export type UserProfilesRepository = Repository<MiUserProfile> & MiRepository<MiUserProfile>;
+export type UserPublickeysRepository = Repository<MiUserPublickey> & MiRepository<MiUserPublickey>;
+export type UserSecurityKeysRepository = Repository<MiUserSecurityKey> & MiRepository<MiUserSecurityKey>;
+export type WebhooksRepository = Repository<MiWebhook> & MiRepository<MiWebhook>;
+export type ChannelsRepository = Repository<MiChannel> & MiRepository<MiChannel>;
+export type RetentionAggregationsRepository = Repository<MiRetentionAggregation> & MiRepository<MiRetentionAggregation>;
+export type RolesRepository = Repository<MiRole> & MiRepository<MiRole>;
+export type RoleAssignmentsRepository = Repository<MiRoleAssignment> & MiRepository<MiRoleAssignment>;
+export type FlashsRepository = Repository<MiFlash> & MiRepository<MiFlash>;
+export type FlashLikesRepository = Repository<MiFlashLike> & MiRepository<MiFlashLike>;
+export type UserMemoRepository = Repository<MiUserMemo> & MiRepository<MiUserMemo>;
+export type BubbleGameRecordsRepository = Repository<MiBubbleGameRecord> & MiRepository<MiBubbleGameRecord>;
+export type ReversiGamesRepository = Repository<MiReversiGame> & MiRepository<MiReversiGame>;
diff --git a/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts b/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts
index e5b7c5ac52..9c033b73e2 100644
--- a/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts
+++ b/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts
@@ -76,7 +76,7 @@ export class ImportAntennasProcessorService {
 					this.logger.warn('Validation Failed');
 					continue;
 				}
-				const result = await this.antennasRepository.insert({
+				const result = await this.antennasRepository.insertOne({
 					id: this.idService.gen(now.getTime()),
 					lastUsedAt: now,
 					userId: job.data.user.id,
@@ -91,7 +91,7 @@ export class ImportAntennasProcessorService {
 					excludeBots: antenna.excludeBots,
 					withReplies: antenna.withReplies,
 					withFile: antenna.withFile,
-				}).then(x => this.antennasRepository.findOneByOrFail(x.identifiers[0]));
+				});
 				this.logger.succ('Antenna created: ' + result.id);
 				this.globalEventService.publishInternalEvent('antennaCreated', result);
 			}
diff --git a/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts b/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts
index a5992c28c8..db9255b35d 100644
--- a/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts
+++ b/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts
@@ -79,11 +79,11 @@ export class ImportUserListsProcessorService {
 				});
 
 				if (list == null) {
-					list = await this.userListsRepository.insert({
+					list = await this.userListsRepository.insertOne({
 						id: this.idService.gen(),
 						userId: user.id,
 						name: listName,
-					}).then(x => this.userListsRepository.findOneByOrFail(x.identifiers[0]));
+					});
 				}
 
 				let target = this.utilityService.isSelfHost(host!) ? await this.usersRepository.findOneBy({
diff --git a/packages/backend/src/server/api/SigninService.ts b/packages/backend/src/server/api/SigninService.ts
index 714e56e8c3..70306c3113 100644
--- a/packages/backend/src/server/api/SigninService.ts
+++ b/packages/backend/src/server/api/SigninService.ts
@@ -29,13 +29,13 @@ export class SigninService {
 	public signin(request: FastifyRequest, reply: FastifyReply, user: MiLocalUser) {
 		setImmediate(async () => {
 			// Append signin history
-			const record = await this.signinsRepository.insert({
+			const record = await this.signinsRepository.insertOne({
 				id: this.idService.gen(),
 				userId: user.id,
 				ip: request.ip,
 				headers: request.headers as any,
 				success: true,
-			}).then(x => this.signinsRepository.findOneByOrFail(x.identifiers[0]));
+			});
 
 			// Publish signin event
 			this.globalEventService.publishMainStream(user.id, 'signin', await this.signinEntityService.pack(record));
diff --git a/packages/backend/src/server/api/SignupApiService.ts b/packages/backend/src/server/api/SignupApiService.ts
index 546de48e6b..632b0c62bc 100644
--- a/packages/backend/src/server/api/SignupApiService.ts
+++ b/packages/backend/src/server/api/SignupApiService.ts
@@ -183,13 +183,13 @@ export class SignupApiService {
 			const salt = await bcrypt.genSalt(8);
 			const hash = await bcrypt.hash(password, salt);
 
-			const pendingUser = await this.userPendingsRepository.insert({
+			const pendingUser = await this.userPendingsRepository.insertOne({
 				id: this.idService.gen(),
 				code,
 				email: emailAddress!,
 				username: username,
 				password: hash,
-			}).then(x => this.userPendingsRepository.findOneByOrFail(x.identifiers[0]));
+			});
 
 			const link = `${this.config.url}/signup-complete/${code}`;
 
diff --git a/packages/backend/src/server/api/endpoints/admin/ad/create.ts b/packages/backend/src/server/api/endpoints/admin/ad/create.ts
index 1e7a9fb3ec..955154f4fb 100644
--- a/packages/backend/src/server/api/endpoints/admin/ad/create.ts
+++ b/packages/backend/src/server/api/endpoints/admin/ad/create.ts
@@ -50,7 +50,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 		private moderationLogService: ModerationLogService,
 	) {
 		super(meta, paramDef, async (ps, me) => {
-			const ad = await this.adsRepository.insert({
+			const ad = await this.adsRepository.insertOne({
 				id: this.idService.gen(),
 				expiresAt: new Date(ps.expiresAt),
 				startsAt: new Date(ps.startsAt),
@@ -61,7 +61,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				ratio: ps.ratio,
 				place: ps.place,
 				memo: ps.memo,
-			}).then(r => this.adsRepository.findOneByOrFail({ id: r.identifiers[0].id }));
+			});
 
 			this.moderationLogService.log(me, 'createAd', {
 				adId: ad.id,
diff --git a/packages/backend/src/server/api/endpoints/admin/invite/create.ts b/packages/backend/src/server/api/endpoints/admin/invite/create.ts
index 0f551e1ba2..5ecae3161a 100644
--- a/packages/backend/src/server/api/endpoints/admin/invite/create.ts
+++ b/packages/backend/src/server/api/endpoints/admin/invite/create.ts
@@ -66,11 +66,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 			const ticketsPromises = [];
 
 			for (let i = 0; i < ps.count; i++) {
-				ticketsPromises.push(this.registrationTicketsRepository.insert({
+				ticketsPromises.push(this.registrationTicketsRepository.insertOne({
 					id: this.idService.gen(),
 					expiresAt: ps.expiresAt ? new Date(ps.expiresAt) : null,
 					code: generateInviteCode(),
-				}).then(x => this.registrationTicketsRepository.findOneByOrFail(x.identifiers[0])));
+				}));
 			}
 
 			const tickets = await Promise.all(ticketsPromises);
diff --git a/packages/backend/src/server/api/endpoints/antennas/create.ts b/packages/backend/src/server/api/endpoints/antennas/create.ts
index 6b7bacb054..ec08198514 100644
--- a/packages/backend/src/server/api/endpoints/antennas/create.ts
+++ b/packages/backend/src/server/api/endpoints/antennas/create.ts
@@ -112,7 +112,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 
 			const now = new Date();
 
-			const antenna = await this.antennasRepository.insert({
+			const antenna = await this.antennasRepository.insertOne({
 				id: this.idService.gen(now.getTime()),
 				lastUsedAt: now,
 				userId: me.id,
@@ -127,7 +127,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				excludeBots: ps.excludeBots,
 				withReplies: ps.withReplies,
 				withFile: ps.withFile,
-			}).then(x => this.antennasRepository.findOneByOrFail(x.identifiers[0]));
+			});
 
 			this.globalEventService.publishInternalEvent('antennaCreated', antenna);
 
diff --git a/packages/backend/src/server/api/endpoints/app/create.ts b/packages/backend/src/server/api/endpoints/app/create.ts
index 492705d6f9..ba847fc4f0 100644
--- a/packages/backend/src/server/api/endpoints/app/create.ts
+++ b/packages/backend/src/server/api/endpoints/app/create.ts
@@ -54,7 +54,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 			const permission = unique(ps.permission.map(v => v.replace(/^(.+)(\/|-)(read|write)$/, '$3:$1')));
 
 			// Create account
-			const app = await this.appsRepository.insert({
+			const app = await this.appsRepository.insertOne({
 				id: this.idService.gen(),
 				userId: me ? me.id : null,
 				name: ps.name,
@@ -62,7 +62,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				permission,
 				callbackUrl: ps.callbackUrl,
 				secret: secret,
-			}).then(x => this.appsRepository.findOneByOrFail(x.identifiers[0]));
+			});
 
 			return await this.appEntityService.pack(app, null, {
 				detail: true,
diff --git a/packages/backend/src/server/api/endpoints/auth/session/generate.ts b/packages/backend/src/server/api/endpoints/auth/session/generate.ts
index 26dd893138..f8ddfdb75c 100644
--- a/packages/backend/src/server/api/endpoints/auth/session/generate.ts
+++ b/packages/backend/src/server/api/endpoints/auth/session/generate.ts
@@ -78,11 +78,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 			const token = randomUUID();
 
 			// Create session token document
-			const doc = await this.authSessionsRepository.insert({
+			const doc = await this.authSessionsRepository.insertOne({
 				id: this.idService.gen(),
 				appId: app.id,
 				token: token,
-			}).then(x => this.authSessionsRepository.findOneByOrFail(x.identifiers[0]));
+			});
 
 			return {
 				token: doc.token,
diff --git a/packages/backend/src/server/api/endpoints/channels/create.ts b/packages/backend/src/server/api/endpoints/channels/create.ts
index 2866db5424..e3a6d2d670 100644
--- a/packages/backend/src/server/api/endpoints/channels/create.ts
+++ b/packages/backend/src/server/api/endpoints/channels/create.ts
@@ -80,7 +80,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				}
 			}
 
-			const channel = await this.channelsRepository.insert({
+			const channel = await this.channelsRepository.insertOne({
 				id: this.idService.gen(),
 				userId: me.id,
 				name: ps.name,
@@ -89,7 +89,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				isSensitive: ps.isSensitive ?? false,
 				...(ps.color !== undefined ? { color: ps.color } : {}),
 				allowRenoteToExternal: ps.allowRenoteToExternal ?? true,
-			} as MiChannel).then(x => this.channelsRepository.findOneByOrFail(x.identifiers[0]));
+			} as MiChannel);
 
 			return await this.channelEntityService.pack(channel, me);
 		});
diff --git a/packages/backend/src/server/api/endpoints/drive/folders/create.ts b/packages/backend/src/server/api/endpoints/drive/folders/create.ts
index c94070d9ff..08d9d9cdc3 100644
--- a/packages/backend/src/server/api/endpoints/drive/folders/create.ts
+++ b/packages/backend/src/server/api/endpoints/drive/folders/create.ts
@@ -75,12 +75,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 			}
 
 			// Create folder
-			const folder = await this.driveFoldersRepository.insert({
+			const folder = await this.driveFoldersRepository.insertOne({
 				id: this.idService.gen(),
 				name: ps.name,
 				parentId: parent !== null ? parent.id : null,
 				userId: me.id,
-			}).then(x => this.driveFoldersRepository.findOneByOrFail(x.identifiers[0]));
+			});
 
 			const folderObj = await this.driveFolderEntityService.pack(folder);
 
diff --git a/packages/backend/src/server/api/endpoints/flash/create.ts b/packages/backend/src/server/api/endpoints/flash/create.ts
index 361496e17e..64f13a577e 100644
--- a/packages/backend/src/server/api/endpoints/flash/create.ts
+++ b/packages/backend/src/server/api/endpoints/flash/create.ts
@@ -59,7 +59,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 		private idService: IdService,
 	) {
 		super(meta, paramDef, async (ps, me) => {
-			const flash = await this.flashsRepository.insert({
+			const flash = await this.flashsRepository.insertOne({
 				id: this.idService.gen(),
 				userId: me.id,
 				updatedAt: new Date(),
@@ -68,7 +68,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				script: ps.script,
 				permissions: ps.permissions,
 				visibility: ps.visibility,
-			}).then(x => this.flashsRepository.findOneByOrFail(x.identifiers[0]));
+			});
 
 			return await this.flashEntityService.pack(flash);
 		});
diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts
index b07cdf1ed9..46f8998810 100644
--- a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts
+++ b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts
@@ -76,7 +76,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				throw new Error();
 			}
 
-			const post = await this.galleryPostsRepository.insert(new MiGalleryPost({
+			const post = await this.galleryPostsRepository.insertOne(new MiGalleryPost({
 				id: this.idService.gen(),
 				updatedAt: new Date(),
 				title: ps.title,
@@ -84,7 +84,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				userId: me.id,
 				isSensitive: ps.isSensitive,
 				fileIds: files.map(file => file.id),
-			})).then(x => this.galleryPostsRepository.findOneByOrFail(x.identifiers[0]));
+			}));
 
 			return await this.galleryPostEntityService.pack(post, me);
 		});
diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts
index 535a3ea308..c692380288 100644
--- a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts
+++ b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts
@@ -89,14 +89,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				throw new ApiError(meta.errors.tooManyWebhooks);
 			}
 
-			const webhook = await this.webhooksRepository.insert({
+			const webhook = await this.webhooksRepository.insertOne({
 				id: this.idService.gen(),
 				userId: me.id,
 				name: ps.name,
 				url: ps.url,
 				secret: ps.secret,
 				on: ps.on,
-			}).then(x => this.webhooksRepository.findOneByOrFail(x.identifiers[0]));
+			});
 
 			this.globalEventService.publishInternalEvent('webhookCreated', webhook);
 
diff --git a/packages/backend/src/server/api/endpoints/invite/create.ts b/packages/backend/src/server/api/endpoints/invite/create.ts
index 0ff125ad9c..a70b587da7 100644
--- a/packages/backend/src/server/api/endpoints/invite/create.ts
+++ b/packages/backend/src/server/api/endpoints/invite/create.ts
@@ -66,13 +66,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				}
 			}
 
-			const ticket = await this.registrationTicketsRepository.insert({
+			const ticket = await this.registrationTicketsRepository.insertOne({
 				id: this.idService.gen(),
 				createdBy: me,
 				createdById: me.id,
 				expiresAt: policies.inviteExpirationTime ? new Date(Date.now() + (policies.inviteExpirationTime * 1000 * 60)) : null,
 				code: generateInviteCode(),
-			}).then(x => this.registrationTicketsRepository.findOneByOrFail(x.identifiers[0]));
+			});
 
 			return await this.inviteCodeEntityService.pack(ticket, me);
 		});
diff --git a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts
index a91c506afd..f33f49075b 100644
--- a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts
+++ b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts
@@ -144,12 +144,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 			}
 
 			// Create vote
-			const vote = await this.pollVotesRepository.insert({
+			const vote = await this.pollVotesRepository.insertOne({
 				id: this.idService.gen(createdAt.getTime()),
 				noteId: note.id,
 				userId: me.id,
 				choice: ps.choice,
-			}).then(x => this.pollVotesRepository.findOneByOrFail(x.identifiers[0]));
+			});
 
 			// Increment votes count
 			const index = ps.choice + 1; // In SQL, array index is 1 based
diff --git a/packages/backend/src/server/api/endpoints/pages/create.ts b/packages/backend/src/server/api/endpoints/pages/create.ts
index 3a02d359f8..fa03b0b457 100644
--- a/packages/backend/src/server/api/endpoints/pages/create.ts
+++ b/packages/backend/src/server/api/endpoints/pages/create.ts
@@ -102,7 +102,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				}
 			});
 
-			const page = await this.pagesRepository.insert(new MiPage({
+			const page = await this.pagesRepository.insertOne(new MiPage({
 				id: this.idService.gen(),
 				updatedAt: new Date(),
 				title: ps.title,
@@ -117,7 +117,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				alignCenter: ps.alignCenter,
 				hideTitleWhenPinned: ps.hideTitleWhenPinned,
 				font: ps.font,
-			})).then(x => this.pagesRepository.findOneByOrFail(x.identifiers[0]));
+			}));
 
 			return await this.pageEntityService.pack(page);
 		});
diff --git a/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts b/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts
index e2db71c5c7..8504da0209 100644
--- a/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts
+++ b/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts
@@ -104,11 +104,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				throw new ApiError(meta.errors.tooManyUserLists);
 			}
 
-			const userList = await this.userListsRepository.insert({
+			const userList = await this.userListsRepository.insertOne({
 				id: this.idService.gen(),
 				userId: me.id,
 				name: ps.name,
-			} as MiUserList).then(x => this.userListsRepository.findOneByOrFail(x.identifiers[0]));
+			} as MiUserList);
 
 			const users = (await this.userListMembershipsRepository.findBy({
 				userListId: ps.listId,
diff --git a/packages/backend/src/server/api/endpoints/users/lists/create.ts b/packages/backend/src/server/api/endpoints/users/lists/create.ts
index 952580e639..9378bde5cb 100644
--- a/packages/backend/src/server/api/endpoints/users/lists/create.ts
+++ b/packages/backend/src/server/api/endpoints/users/lists/create.ts
@@ -65,11 +65,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				throw new ApiError(meta.errors.tooManyUserLists);
 			}
 
-			const userList = await this.userListsRepository.insert({
+			const userList = await this.userListsRepository.insertOne({
 				id: this.idService.gen(),
 				userId: me.id,
 				name: ps.name,
-			} as MiUserList).then(x => this.userListsRepository.findOneByOrFail(x.identifiers[0]));
+			} as MiUserList);
 
 			return await this.userListEntityService.pack(userList);
 		});
diff --git a/packages/backend/src/server/api/endpoints/users/report-abuse.ts b/packages/backend/src/server/api/endpoints/users/report-abuse.ts
index 1750dd6206..48e14b68cc 100644
--- a/packages/backend/src/server/api/endpoints/users/report-abuse.ts
+++ b/packages/backend/src/server/api/endpoints/users/report-abuse.ts
@@ -82,14 +82,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				throw new ApiError(meta.errors.cannotReportAdmin);
 			}
 
-			const report = await this.abuseUserReportsRepository.insert({
+			const report = await this.abuseUserReportsRepository.insertOne({
 				id: this.idService.gen(),
 				targetUserId: user.id,
 				targetUserHost: user.host,
 				reporterId: me.id,
 				reporterHost: null,
 				comment: ps.comment,
-			}).then(x => this.abuseUserReportsRepository.findOneByOrFail(x.identifiers[0]));
+			});
 
 			// Publish event to moderators
 			setImmediate(async () => {
diff --git a/packages/backend/test/e2e/move.ts b/packages/backend/test/e2e/move.ts
index 35050130dc..74cf61a785 100644
--- a/packages/backend/test/e2e/move.ts
+++ b/packages/backend/test/e2e/move.ts
@@ -9,7 +9,7 @@ process.env.NODE_ENV = 'test';
 
 import * as assert from 'assert';
 import { loadConfig } from '@/config.js';
-import { MiUser, UsersRepository } from '@/models/_.js';
+import { MiRepository, MiUser, UsersRepository, miRepository } from '@/models/_.js';
 import { secureRndstr } from '@/misc/secure-rndstr.js';
 import { jobQueue } from '@/boot/common.js';
 import { api, initTestDb, signup, sleep, successfulApiCall, uploadFile } from '../utils.js';
@@ -42,7 +42,7 @@ describe('Account Move', () => {
 		dave = await signup({ username: 'dave' });
 		eve = await signup({ username: 'eve' });
 		frank = await signup({ username: 'frank' });
-		Users = connection.getRepository(MiUser);
+		Users = connection.getRepository(MiUser).extend(miRepository as MiRepository<MiUser>);
 	}, 1000 * 60 * 2);
 
 	afterAll(async () => {
diff --git a/packages/backend/test/e2e/reversi-game.ts b/packages/backend/test/e2e/reversi-game.ts
new file mode 100644
index 0000000000..788255beac
--- /dev/null
+++ b/packages/backend/test/e2e/reversi-game.ts
@@ -0,0 +1,33 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+process.env.NODE_ENV = 'test';
+
+import * as assert from 'assert';
+import { ReversiMatchResponse } from 'misskey-js/entities.js';
+import { api, signup } from '../utils.js';
+import type * as misskey from 'misskey-js';
+
+describe('ReversiGame', () => {
+	let alice: misskey.entities.SignupResponse;
+	let bob: misskey.entities.SignupResponse;
+
+	beforeAll(async () => {
+		alice = await signup({ username: 'alice' });
+		bob = await signup({ username: 'bob' });
+	}, 1000 * 60 * 2);
+
+	test('matches when alice invites bob and bob accepts', async () => {
+		const response1 = await api('reversi/match', { userId: bob.id }, alice);
+		assert.strictEqual(response1.status, 204);
+		assert.strictEqual(response1.body, null);
+		const response2 = await api('reversi/match', { userId: alice.id }, bob);
+		assert.strictEqual(response2.status, 200);
+		assert.notStrictEqual(response2.body, null);
+		const body = response2.body as ReversiMatchResponse;
+		assert.strictEqual(body.user1.id, alice.id);
+		assert.strictEqual(body.user2.id, bob.id);
+	});
+});