From 5c79d8db208da1fd7c5bc4900090c3d7b9512196 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Mon, 21 Oct 2024 12:49:29 +0900
Subject: feat: ノートの閲覧にログイン必須にする設定 (#14799)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* wip

* wip

* wip

* Update packages/frontend/src/pages/note.vue

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

* wip

* Update WebhookTestService.ts

* Update privacy.vue

* wip

* rename

* Update locales/ja-JP.yml

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

* :art:

* wip

---------

Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>
Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
---
 packages/frontend/src/components/MkFollowButton.vue | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'packages/frontend/src/components/MkFollowButton.vue')

diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue
index ccea7cd453..cc07175907 100644
--- a/packages/frontend/src/components/MkFollowButton.vue
+++ b/packages/frontend/src/components/MkFollowButton.vue
@@ -37,13 +37,13 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { onBeforeUnmount, onMounted, ref } from 'vue';
 import * as Misskey from 'misskey-js';
+import { host } from '@@/js/config.js';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { useStream } from '@/stream.js';
 import { i18n } from '@/i18n.js';
 import { claimAchievement } from '@/scripts/achievements.js';
 import { pleaseLogin } from '@/scripts/please-login.js';
-import { host } from '@@/js/config.js';
 import { $i } from '@/account.js';
 import { defaultStore } from '@/store.js';
 
@@ -80,7 +80,7 @@ function onFollowChange(user: Misskey.entities.UserDetailed) {
 }
 
 async function onClick() {
-	pleaseLogin(undefined, { type: 'web', path: `/@${props.user.username}@${props.user.host ?? host}` });
+	pleaseLogin({ openOnRemote: { type: 'web', path: `/@${props.user.username}@${props.user.host ?? host}` } });
 
 	wait.value = true;
 
-- 
cgit v1.2.3-freya


From c0d168260482caa974e3fc9e084b121fc32e8ec4 Mon Sep 17 00:00:00 2001
From: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Fri, 15 Nov 2024 17:30:54 +0900
Subject: feat: 送信したフォローリクエストを確認できるように (#14856)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* FEAT: Allow users to view pending follow requests they sent

This commit implements the `following/requests/sent` interface firstly
implemented on Firefish, and provides a UI interface to view the pending
follow requests users sent.

* ux: should not show follow requests tab when have no pending sent follow req

* fix default followreq tab

* fix default followreq tab

* restore missing hasPendingReceivedFollowRequest in navbar

* refactor

* use tabler icons

* tweak design

* Revert "ux: should not show follow requests tab when have no pending sent follow req"

This reverts commit e580b92c37f27c2849c6d27e22ca4c47086081bb.

* Update Changelog

* Update Changelog

* change tab titles

---------

Co-authored-by: Lhc_fl <lhcfl@outlook.com>
Co-authored-by: Hazelnoot <acomputerdog@gmail.com>
---
 CHANGELOG.md                                       |   2 +
 locales/index.d.ts                                 |  10 ++
 locales/ja-JP.yml                                  |   4 +
 packages/backend/src/server/api/EndpointsModule.ts |   3 +
 packages/backend/src/server/api/endpoints.ts       |   2 +
 .../api/endpoints/following/requests/sent.ts       |  77 +++++++++++++++
 .../frontend/src/components/MkFollowButton.vue     |  10 +-
 packages/frontend/src/navbar.ts                    |   1 -
 packages/frontend/src/pages/follow-requests.vue    | 105 ++++++++++++++-------
 packages/misskey-js/etc/misskey-js.api.md          |   8 ++
 packages/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           |  72 ++++++++++++++
 14 files changed, 272 insertions(+), 38 deletions(-)
 create mode 100644 packages/backend/src/server/api/endpoints/following/requests/sent.ts

(limited to 'packages/frontend/src/components/MkFollowButton.vue')

diff --git a/CHANGELOG.md b/CHANGELOG.md
index fcbfed5900..232d52d7e1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -24,6 +24,8 @@
 - Enhance: カタルーニャ語 (ca-ES) に対応
 - Enhance: 個別お知らせページではMetaタグを出力するように
 - Enhance: ノート詳細画面にロールのバッジを表示
+- Enhance: 過去に送信したフォローリクエストを確認できるように  
+  (Based on https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/663)
 - Fix: 通知の範囲指定の設定項目が必要ない通知設定でも範囲指定の設定がでている問題を修正
 - Fix: Turnstileが失敗・期限切れした際にも成功扱いとなってしまう問題を修正  
   (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/768)
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 440f24ac84..18fbfd15f0 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -10579,6 +10579,16 @@ export interface Locale extends ILocale {
          */
         "description3": ParameterizedString<"link">;
     };
+    "_followRequest": {
+        /**
+         * 受け取った申請
+         */
+        "recieved": string;
+        /**
+         * 送った申請
+         */
+        "sent": string;
+    };
 }
 declare const locales: {
     [lang: string]: Locale;
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 5d8e1a5e72..439ae708c5 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -2819,3 +2819,7 @@ _selfXssPrevention:
   description1: "ここに何かを貼り付けると、悪意のあるユーザーにアカウントを乗っ取られたり、個人情報を盗まれたりする可能性があります。"
   description2: "貼り付けようとしているものが何なのかを正確に理解していない場合は、%c今すぐ作業を中止してこのウィンドウを閉じてください。"
   description3: "詳しくはこちらをご確認ください。 {link}"
+
+_followRequest:
+  recieved: "受け取った申請"
+  sent: "送った申請"
diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts
index 3557fa40a5..5bb194313d 100644
--- a/packages/backend/src/server/api/EndpointsModule.ts
+++ b/packages/backend/src/server/api/EndpointsModule.ts
@@ -187,6 +187,7 @@ import * as ep___following_invalidate from './endpoints/following/invalidate.js'
 import * as ep___following_requests_accept from './endpoints/following/requests/accept.js';
 import * as ep___following_requests_cancel from './endpoints/following/requests/cancel.js';
 import * as ep___following_requests_list from './endpoints/following/requests/list.js';
+import * as ep___following_requests_sent from './endpoints/following/requests/sent.js';
 import * as ep___following_requests_reject from './endpoints/following/requests/reject.js';
 import * as ep___gallery_featured from './endpoints/gallery/featured.js';
 import * as ep___gallery_popular from './endpoints/gallery/popular.js';
@@ -574,6 +575,7 @@ const $following_invalidate: Provider = { provide: 'ep:following/invalidate', us
 const $following_requests_accept: Provider = { provide: 'ep:following/requests/accept', useClass: ep___following_requests_accept.default };
 const $following_requests_cancel: Provider = { provide: 'ep:following/requests/cancel', useClass: ep___following_requests_cancel.default };
 const $following_requests_list: Provider = { provide: 'ep:following/requests/list', useClass: ep___following_requests_list.default };
+const $following_requests_sent: Provider = { provide: 'ep:following/requests/sent', useClass: ep___following_requests_sent.default };
 const $following_requests_reject: Provider = { provide: 'ep:following/requests/reject', useClass: ep___following_requests_reject.default };
 const $gallery_featured: Provider = { provide: 'ep:gallery/featured', useClass: ep___gallery_featured.default };
 const $gallery_popular: Provider = { provide: 'ep:gallery/popular', useClass: ep___gallery_popular.default };
@@ -965,6 +967,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
 		$following_requests_accept,
 		$following_requests_cancel,
 		$following_requests_list,
+		$following_requests_sent,
 		$following_requests_reject,
 		$gallery_featured,
 		$gallery_popular,
diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts
index 49b07d6ced..15809b2678 100644
--- a/packages/backend/src/server/api/endpoints.ts
+++ b/packages/backend/src/server/api/endpoints.ts
@@ -193,6 +193,7 @@ import * as ep___following_invalidate from './endpoints/following/invalidate.js'
 import * as ep___following_requests_accept from './endpoints/following/requests/accept.js';
 import * as ep___following_requests_cancel from './endpoints/following/requests/cancel.js';
 import * as ep___following_requests_list from './endpoints/following/requests/list.js';
+import * as ep___following_requests_sent from './endpoints/following/requests/sent.js';
 import * as ep___following_requests_reject from './endpoints/following/requests/reject.js';
 import * as ep___gallery_featured from './endpoints/gallery/featured.js';
 import * as ep___gallery_popular from './endpoints/gallery/popular.js';
@@ -578,6 +579,7 @@ const eps = [
 	['following/requests/accept', ep___following_requests_accept],
 	['following/requests/cancel', ep___following_requests_cancel],
 	['following/requests/list', ep___following_requests_list],
+	['following/requests/sent', ep___following_requests_sent],
 	['following/requests/reject', ep___following_requests_reject],
 	['gallery/featured', ep___gallery_featured],
 	['gallery/popular', ep___gallery_popular],
diff --git a/packages/backend/src/server/api/endpoints/following/requests/sent.ts b/packages/backend/src/server/api/endpoints/following/requests/sent.ts
new file mode 100644
index 0000000000..6325f01bb8
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/following/requests/sent.ts
@@ -0,0 +1,77 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Inject, Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { QueryService } from '@/core/QueryService.js';
+import type { FollowRequestsRepository } from '@/models/_.js';
+import { FollowRequestEntityService } from '@/core/entities/FollowRequestEntityService.js';
+import { DI } from '@/di-symbols.js';
+
+export const meta = {
+	tags: ['following', 'account'],
+
+	requireCredential: true,
+
+	kind: 'read:following',
+
+	res: {
+		type: 'array',
+		optional: false, nullable: false,
+		items: {
+			type: 'object',
+			optional: false, nullable: false,
+			properties: {
+				id: {
+					type: 'string',
+					optional: false, nullable: false,
+					format: 'id',
+				},
+				follower: {
+					type: 'object',
+					optional: false, nullable: false,
+					ref: 'UserLite',
+				},
+				followee: {
+					type: 'object',
+					optional: false, nullable: false,
+					ref: 'UserLite',
+				},
+			},
+		},
+	},
+} as const;
+
+export const paramDef = {
+	type: 'object',
+	properties: {
+		sinceId: { type: 'string', format: 'misskey:id' },
+		untilId: { type: 'string', format: 'misskey:id' },
+		limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
+	},
+	required: [],
+} as const;
+
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
+	constructor(
+		@Inject(DI.followRequestsRepository)
+		private followRequestsRepository: FollowRequestsRepository,
+
+		private followRequestEntityService: FollowRequestEntityService,
+		private queryService: QueryService,
+	) {
+		super(meta, paramDef, async (ps, me) => {
+			const query = this.queryService.makePaginationQuery(this.followRequestsRepository.createQueryBuilder('request'), ps.sinceId, ps.untilId)
+				.andWhere('request.followerId = :meId', { meId: me.id });
+
+			const requests = await query
+				.limit(ps.limit)
+				.getMany();
+
+			return await this.followRequestEntityService.packMany(requests, me);
+		});
+	}
+}
diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue
index cc07175907..c1dc67f776 100644
--- a/packages/frontend/src/components/MkFollowButton.vue
+++ b/packages/frontend/src/components/MkFollowButton.vue
@@ -91,7 +91,10 @@ async function onClick() {
 				text: i18n.tsx.unfollowConfirm({ name: props.user.name || props.user.username }),
 			});
 
-			if (canceled) return;
+			if (canceled) {
+				wait.value = false;
+				return;
+			}
 
 			await misskeyApi('following/delete', {
 				userId: props.user.id,
@@ -125,7 +128,10 @@ async function onClick() {
 				});
 				hasPendingFollowRequestFromYou.value = true;
 
-				if ($i == null) return;
+				if ($i == null) {
+					wait.value = false;
+					return;
+				}
 
 				claimAchievement('following1');
 
diff --git a/packages/frontend/src/navbar.ts b/packages/frontend/src/navbar.ts
index ac730f8021..096d404a57 100644
--- a/packages/frontend/src/navbar.ts
+++ b/packages/frontend/src/navbar.ts
@@ -40,7 +40,6 @@ export const navbarItemDef = reactive({
 	followRequests: {
 		title: i18n.ts.followRequests,
 		icon: 'ti ti-user-plus',
-		show: computed(() => $i != null && $i.isLocked),
 		indicated: computed(() => $i != null && $i.hasPendingReceivedFollowRequest),
 		to: '/my/follow-requests',
 	},
diff --git a/packages/frontend/src/pages/follow-requests.vue b/packages/frontend/src/pages/follow-requests.vue
index a840d0d0b3..8688863c2c 100644
--- a/packages/frontend/src/pages/follow-requests.vue
+++ b/packages/frontend/src/pages/follow-requests.vue
@@ -5,69 +5,104 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <template>
 <MkStickyContainer>
-	<template #header><MkPageHeader/></template>
+	<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
 	<MkSpacer :contentMax="800">
-		<MkPagination ref="paginationComponent" :pagination="pagination">
-			<template #empty>
-				<div class="_fullinfo">
-					<img :src="infoImageUrl" class="_ghost"/>
-					<div>{{ i18n.ts.noFollowRequests }}</div>
-				</div>
-			</template>
-			<template #default="{items}">
-				<div class="mk-follow-requests">
-					<div v-for="req in items" :key="req.id" class="user _panel">
-						<MkAvatar class="avatar" :user="req.follower" indicator link preview/>
-						<div class="body">
-							<div class="name">
-								<MkA v-user-preview="req.follower.id" class="name" :to="userPage(req.follower)"><MkUserName :user="req.follower"/></MkA>
-								<p class="acct">@{{ acct(req.follower) }}</p>
-							</div>
-							<div class="commands">
-								<MkButton class="command" rounded primary @click="accept(req.follower)"><i class="ti ti-check"/> {{ i18n.ts.accept }}</MkButton>
-								<MkButton class="command" rounded danger @click="reject(req.follower)"><i class="ti ti-x"/> {{ i18n.ts.reject }}</MkButton>
+		<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
+			<div :key="tab" class="_gaps">
+				<MkPagination ref="paginationComponent" :pagination="pagination">
+					<template #empty>
+						<div class="_fullinfo">
+							<img :src="infoImageUrl" class="_ghost"/>
+							<div>{{ i18n.ts.noFollowRequests }}</div>
+						</div>
+					</template>
+					<template #default="{items}">
+						<div class="mk-follow-requests">
+							<div v-for="req in items" :key="req.id" class="user _panel">
+								<MkAvatar class="avatar" :user="displayUser(req)" indicator link preview/>
+								<div class="body">
+									<div class="name">
+										<MkA v-user-preview="displayUser(req).id" class="name" :to="userPage(displayUser(req))"><MkUserName :user="displayUser(req)"/></MkA>
+										<p class="acct">@{{ acct(displayUser(req)) }}</p>
+									</div>
+									<div v-if="tab === 'list'" class="commands">
+										<MkButton class="command" rounded primary @click="accept(displayUser(req))"><i class="ti ti-check"/> {{ i18n.ts.accept }}</MkButton>
+										<MkButton class="command" rounded danger @click="reject(displayUser(req))"><i class="ti ti-x"/> {{ i18n.ts.reject }}</MkButton>
+									</div>
+									<div v-else class="commands">
+										<MkButton class="command" rounded danger @click="cancel(displayUser(req))"><i class="ti ti-x"/> {{ i18n.ts.cancel }}</MkButton>
+									</div>
+								</div>
 							</div>
 						</div>
-					</div>
-				</div>
-			</template>
-		</MkPagination>
+					</template>
+				</MkPagination>
+			</div>
+		</MkHorizontalSwipe>
 	</MkSpacer>
 </MkStickyContainer>
 </template>
 
 <script lang="ts" setup>
-import { shallowRef, computed } from 'vue';
-import MkPagination from '@/components/MkPagination.vue';
+import * as Misskey from 'misskey-js';
+import { shallowRef, computed, ref } from 'vue';
+import MkPagination, { type Paging } from '@/components/MkPagination.vue';
 import MkButton from '@/components/MkButton.vue';
 import { userPage, acct } from '@/filters/user.js';
-import { misskeyApi } from '@/scripts/misskey-api.js';
+import * as os from '@/os.js';
 import { i18n } from '@/i18n.js';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
 import { infoImageUrl } from '@/instance.js';
+import { $i } from '@/account.js';
+import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
 
 const paginationComponent = shallowRef<InstanceType<typeof MkPagination>>();
 
-const pagination = {
-	endpoint: 'following/requests/list' as const,
+const pagination = computed<Paging>(() => tab.value === 'list' ? {
+	endpoint: 'following/requests/list',
+	limit: 10,
+} : {
+	endpoint: 'following/requests/sent',
 	limit: 10,
-};
+});
 
-function accept(user) {
-	misskeyApi('following/requests/accept', { userId: user.id }).then(() => {
+function accept(user: Misskey.entities.UserLite) {
+	os.apiWithDialog('following/requests/accept', { userId: user.id }).then(() => {
 		paginationComponent.value?.reload();
 	});
 }
 
-function reject(user) {
-	misskeyApi('following/requests/reject', { userId: user.id }).then(() => {
+function reject(user: Misskey.entities.UserLite) {
+	os.apiWithDialog('following/requests/reject', { userId: user.id }).then(() => {
 		paginationComponent.value?.reload();
 	});
 }
 
+function cancel(user: Misskey.entities.UserLite) {
+	os.apiWithDialog('following/requests/cancel', { userId: user.id }).then(() => {
+		paginationComponent.value?.reload();
+	});
+}
+
+function displayUser(req) {
+	return tab.value === 'list' ? req.follower : req.followee;
+}
+
 const headerActions = computed(() => []);
 
-const headerTabs = computed(() => []);
+const headerTabs = computed(() => [
+	{
+		key: 'list',
+		title: i18n.ts._followRequest.recieved,
+		icon: 'ti ti-mail',
+	}, {
+		key: 'sent',
+		title: i18n.ts._followRequest.sent,
+		icon: 'ti ti-send',
+	},
+]);
+
+const tab = ref($i?.isLocked ? 'list' : 'sent');
 
 definePageMetadata(() => ({
 	title: i18n.ts.followRequests,
diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md
index 061b533b72..01a3dbbb30 100644
--- a/packages/misskey-js/etc/misskey-js.api.md
+++ b/packages/misskey-js/etc/misskey-js.api.md
@@ -1504,6 +1504,8 @@ declare namespace entities {
         FollowingRequestsCancelResponse,
         FollowingRequestsListRequest,
         FollowingRequestsListResponse,
+        FollowingRequestsSentRequest,
+        FollowingRequestsSentResponse,
         FollowingRequestsRejectRequest,
         GalleryFeaturedRequest,
         GalleryFeaturedResponse,
@@ -2018,6 +2020,12 @@ type FollowingRequestsListResponse = operations['following___requests___list']['
 // @public (undocumented)
 type FollowingRequestsRejectRequest = operations['following___requests___reject']['requestBody']['content']['application/json'];
 
+// @public (undocumented)
+type FollowingRequestsSentRequest = operations['following___requests___sent']['requestBody']['content']['application/json'];
+
+// @public (undocumented)
+type FollowingRequestsSentResponse = operations['following___requests___sent']['responses']['200']['content']['application/json'];
+
 // @public (undocumented)
 type FollowingUpdateAllRequest = operations['following___update-all']['requestBody']['content']['application/json'];
 
diff --git a/packages/misskey-js/src/autogen/apiClientJSDoc.ts b/packages/misskey-js/src/autogen/apiClientJSDoc.ts
index e2c7cbba52..1837f3db4f 100644
--- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts
+++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts
@@ -2008,6 +2008,17 @@ declare module '../api.js' {
       credential?: string | null,
     ): Promise<SwitchCaseResponseType<E, P>>;
 
+    /**
+     * No description provided.
+     * 
+     * **Credential required**: *Yes* / **Permission**: *read:following*
+     */
+    request<E extends 'following/requests/sent', 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 5e6bc0a99c..cb1f4dbe96 100644
--- a/packages/misskey-js/src/autogen/endpoint.ts
+++ b/packages/misskey-js/src/autogen/endpoint.ts
@@ -279,6 +279,8 @@ import type {
 	FollowingRequestsCancelResponse,
 	FollowingRequestsListRequest,
 	FollowingRequestsListResponse,
+	FollowingRequestsSentRequest,
+	FollowingRequestsSentResponse,
 	FollowingRequestsRejectRequest,
 	GalleryFeaturedRequest,
 	GalleryFeaturedResponse,
@@ -761,6 +763,7 @@ export type Endpoints = {
 	'following/requests/accept': { req: FollowingRequestsAcceptRequest; res: EmptyResponse };
 	'following/requests/cancel': { req: FollowingRequestsCancelRequest; res: FollowingRequestsCancelResponse };
 	'following/requests/list': { req: FollowingRequestsListRequest; res: FollowingRequestsListResponse };
+	'following/requests/sent': { req: FollowingRequestsSentRequest; res: FollowingRequestsSentResponse };
 	'following/requests/reject': { req: FollowingRequestsRejectRequest; res: EmptyResponse };
 	'gallery/featured': { req: GalleryFeaturedRequest; res: GalleryFeaturedResponse };
 	'gallery/popular': { req: EmptyRequest; res: GalleryPopularResponse };
diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts
index f3ddf64481..a8f474c25c 100644
--- a/packages/misskey-js/src/autogen/entities.ts
+++ b/packages/misskey-js/src/autogen/entities.ts
@@ -282,6 +282,8 @@ export type FollowingRequestsCancelRequest = operations['following___requests___
 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 FollowingRequestsSentRequest = operations['following___requests___sent']['requestBody']['content']['application/json'];
+export type FollowingRequestsSentResponse = operations['following___requests___sent']['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'];
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index a5333d4f93..280abba727 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -1753,6 +1753,15 @@ export type paths = {
      */
     post: operations['following___requests___list'];
   };
+  '/following/requests/sent': {
+    /**
+     * following/requests/sent
+     * @description No description provided.
+     *
+     * **Credential required**: *Yes* / **Permission**: *read:following*
+     */
+    post: operations['following___requests___sent'];
+  };
   '/following/requests/reject': {
     /**
      * following/requests/reject
@@ -16040,6 +16049,69 @@ export type operations = {
       };
     };
   };
+  /**
+   * following/requests/sent
+   * @description No description provided.
+   *
+   * **Credential required**: *Yes* / **Permission**: *read:following*
+   */
+  following___requests___sent: {
+    requestBody: {
+      content: {
+        'application/json': {
+          /** Format: misskey:id */
+          sinceId?: string;
+          /** Format: misskey:id */
+          untilId?: string;
+          /** @default 10 */
+          limit?: number;
+        };
+      };
+    };
+    responses: {
+      /** @description OK (with results) */
+      200: {
+        content: {
+          'application/json': {
+              /** Format: id */
+              id: string;
+              follower: components['schemas']['UserLite'];
+              followee: components['schemas']['UserLite'];
+            }[];
+        };
+      };
+      /** @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'];
+        };
+      };
+    };
+  };
   /**
    * following/requests/reject
    * @description No description provided.
-- 
cgit v1.2.3-freya

