From aa3ea2b57a4f51a98449d6fc901037dcb1c3a23d 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, 25 Jul 2024 16:30:29 +0900 Subject: [PATCH 01/24] =?UTF-8?q?fix(frontend):=20=E5=88=9D=E6=9C=9F?= =?UTF-8?q?=E5=8C=96=E6=99=82=E3=81=A8route=E5=A4=89=E6=9B=B4=E6=99=82?= =?UTF-8?q?=E3=81=A7key=E3=81=AE=E6=B1=BA=E5=AE=9A=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E3=81=8C=E9=81=95=E3=81=86=E3=81=AE=E3=82=92=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=20(#14283)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/components/global/RouterView.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/global/RouterView.vue b/packages/frontend/src/components/global/RouterView.vue index 02a2edee3f..19bd794a5d 100644 --- a/packages/frontend/src/components/global/RouterView.vue +++ b/packages/frontend/src/components/global/RouterView.vue @@ -53,7 +53,7 @@ function resolveNested(current: Resolved, d = 0): Resolved | null { const current = resolveNested(router.current)!; const currentPageComponent = shallowRef('component' in current.route ? current.route.component : MkLoadingPage); const currentPageProps = ref(current.props); -const key = ref(current.route.path + JSON.stringify(Object.fromEntries(current.props))); +const key = ref(router.getCurrentKey() + JSON.stringify(Object.fromEntries(current.props))); function onChange({ resolved, key: newKey }) { const current = resolveNested(resolved); From fc71bcc98e14f9c3c13ba74ade9245d64bd4b633 Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Thu, 25 Jul 2024 16:32:07 +0900 Subject: [PATCH 02/24] fix(backend): avoid notifying to remote users on local (#13774) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(backend): avoid notifying to remote users on local * Update CHANGELOG.md * refactor: check before calling method --------- Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> --- CHANGELOG.md | 1 + packages/backend/src/core/RoleService.ts | 5 +++-- packages/backend/src/core/UserFollowingService.ts | 6 ++++-- .../EndedPollNotificationProcessorService.ts | 11 ++++++++--- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f429033aa0..787784ef3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,7 @@ - Fix: 一般ユーザーから見たユーザーのバッジの一覧に公開されていないものが含まれることがある問題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/652) - Fix: ユーザーのリアクション一覧でミュート/ブロックが機能していなかった問題を修正 +- Fix: 一部の通知がローカル上のリモートユーザーに対して行われていた問題を修正 - Fix: エラーメッセージの誤字を修正 (#14213) - Fix: ソーシャルタイムラインにローカルタイムラインに表示される自分へのリプライが表示されない問題を修正 - Fix: リノートのミュートが適用されるまでに時間がかかることがある問題を修正 diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 94026fd503..7966774673 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -505,14 +505,15 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { this.globalEventService.publishInternalEvent('userRoleAssigned', created); - if (role.isPublic) { + const user = await this.usersRepository.findOneByOrFail({ id: userId }); + + if (role.isPublic && user.host === null) { this.notificationService.createNotification(userId, 'roleAssigned', { roleId: roleId, }); } if (moderator) { - const user = await this.usersRepository.findOneByOrFail({ id: userId }); this.moderationLogService.log(moderator, 'assignRole', { roleId: roleId, roleName: role.name, diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts index 267a6a3f1b..6aab8fde70 100644 --- a/packages/backend/src/core/UserFollowingService.ts +++ b/packages/backend/src/core/UserFollowingService.ts @@ -279,8 +279,10 @@ export class UserFollowingService implements OnModuleInit { }); // 通知を作成 - this.notificationService.createNotification(follower.id, 'followRequestAccepted', { - }, followee.id); + if (follower.host === null) { + this.notificationService.createNotification(follower.id, 'followRequestAccepted', { + }, followee.id); + } } if (alreadyFollowed) return; diff --git a/packages/backend/src/queue/processors/EndedPollNotificationProcessorService.ts b/packages/backend/src/queue/processors/EndedPollNotificationProcessorService.ts index 29c1f27bb1..34180e5f2b 100644 --- a/packages/backend/src/queue/processors/EndedPollNotificationProcessorService.ts +++ b/packages/backend/src/queue/processors/EndedPollNotificationProcessorService.ts @@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; import type { PollVotesRepository, NotesRepository } from '@/models/_.js'; import type Logger from '@/logger.js'; +import { CacheService } from '@/core/CacheService.js'; import { NotificationService } from '@/core/NotificationService.js'; import { bindThis } from '@/decorators.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; @@ -24,6 +25,7 @@ export class EndedPollNotificationProcessorService { @Inject(DI.pollVotesRepository) private pollVotesRepository: PollVotesRepository, + private cacheService: CacheService, private notificationService: NotificationService, private queueLoggerService: QueueLoggerService, ) { @@ -47,9 +49,12 @@ export class EndedPollNotificationProcessorService { const userIds = [...new Set([note.userId, ...votes.map(v => v.userId)])]; for (const userId of userIds) { - this.notificationService.createNotification(userId, 'pollEnded', { - noteId: note.id, - }); + const profile = await this.cacheService.userProfileCache.fetch(userId); + if (profile.userHost === null) { + this.notificationService.createNotification(userId, 'pollEnded', { + noteId: note.id, + }); + } } } } From befa8e4a7f91ee6f13ea6179a8a45dc84764b1f7 Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Thu, 25 Jul 2024 16:37:46 +0900 Subject: [PATCH 03/24] fix(backend): avoid caching remote user's HTL when receiving Note (#13772) * fix(backend): avoid caching remote user's HTL when receiving Note * test(backend): add test for FFT * Update CHANGELOG.md --------- Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> --- CHANGELOG.md | 1 + .../backend/src/core/NoteCreateService.ts | 11 +++-- packages/backend/test/e2e/timelines.ts | 40 ++++++++++++++++++- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 787784ef3c..21d25fe0de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,7 @@ - Fix: 一般ユーザーから見たユーザーのバッジの一覧に公開されていないものが含まれることがある問題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/652) - Fix: ユーザーのリアクション一覧でミュート/ブロックが機能していなかった問題を修正 +- Fix: FTT有効時にリモートユーザーのノートがHTLにキャッシュされる問題を修正 - Fix: 一部の通知がローカル上のリモートユーザーに対して行われていた問題を修正 - Fix: エラーメッセージの誤字を修正 (#14213) - Fix: ソーシャルタイムラインにローカルタイムラインに表示される自分へのリプライが表示されない問題を修正 diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index a2c3aaa701..fd9fac357f 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -933,10 +933,13 @@ export class NoteCreateService implements OnApplicationShutdown { } } - if (note.visibility !== 'specified' || !note.visibleUserIds.some(v => v === user.id)) { // 自分自身のHTL - this.fanoutTimelineService.push(`homeTimeline:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax, r); - if (note.fileIds.length > 0) { - this.fanoutTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); + // 自分自身のHTL + if (note.userHost == null) { + if (note.visibility !== 'specified' || !note.visibleUserIds.some(v => v === user.id)) { + this.fanoutTimelineService.push(`homeTimeline:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax, r); + if (note.fileIds.length > 0) { + this.fanoutTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); + } } } diff --git a/packages/backend/test/e2e/timelines.ts b/packages/backend/test/e2e/timelines.ts index 540b866b28..ab65781f70 100644 --- a/packages/backend/test/e2e/timelines.ts +++ b/packages/backend/test/e2e/timelines.ts @@ -9,8 +9,8 @@ import * as assert from 'assert'; import { setTimeout } from 'node:timers/promises'; import { Redis } from 'ioredis'; -import { loadConfig } from '@/config.js'; import { api, post, randomString, sendEnvUpdateRequest, signup, uploadUrl } from '../utils.js'; +import { loadConfig } from '@/config.js'; function genHost() { return randomString() + '.example.com'; @@ -492,6 +492,44 @@ describe('Timelines', () => { assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); + + test.concurrent('FTT: ローカルユーザーの HTL にはプッシュされる', async () => { + const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); + + await api('following/create', { + userId: alice.id, + }, bob); + + const aliceNote = await post(alice, { text: 'I\'m Alice.' }); + const bobNote = await post(bob, { text: 'I\'m Bob.' }); + const carolNote = await post(carol, { text: 'I\'m Carol.' }); + + await waitForPushToTl(); + + // NOTE: notes/timeline だと DB へのフォールバックが効くので Redis を直接見て確かめる + assert.strictEqual(await redisForTimelines.exists(`list:homeTimeline:${bob.id}`), 1); + + const bobHTL = await redisForTimelines.lrange(`list:homeTimeline:${bob.id}`, 0, -1); + assert.strictEqual(bobHTL.includes(aliceNote.id), true); + assert.strictEqual(bobHTL.includes(bobNote.id), true); + assert.strictEqual(bobHTL.includes(carolNote.id), false); + }); + + test.concurrent('FTT: リモートユーザーの HTL にはプッシュされない', async () => { + const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]); + + await api('following/create', { + userId: alice.id, + }, bob); + + await post(alice, { text: 'I\'m Alice.' }); + await post(bob, { text: 'I\'m Bob.' }); + + await waitForPushToTl(); + + // NOTE: notes/timeline だと DB へのフォールバックが効くので Redis を直接見て確かめる + assert.strictEqual(await redisForTimelines.exists(`list:homeTimeline:${bob.id}`), 0); + }); }); describe('Local TL', () => { From 3d8eda14a299dbf97cd135f7087c1797bd1ebb37 Mon Sep 17 00:00:00 2001 From: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com> Date: Thu, 25 Jul 2024 16:40:14 +0900 Subject: [PATCH 04/24] =?UTF-8?q?[Re]=20refactor(misskey-js):=20=E8=AD=A6?= =?UTF-8?q?=E5=91=8A=E3=82=92=E3=81=99=E3=81=B9=E3=81=A6=E8=A7=A3=E6=B1=BA?= =?UTF-8?q?=20(#14277)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(misskey-js): Unchanged files with check annotationsで紛らわしい部分の警告を抑制 ロジック面は後で直す * dummy change to see if the feature do not report them (to be reverted after the check) * refactor: 型合わせ * refactor: fix warnings from c22dd6358ba4e068c49be033a07d9fbb001f2347 * lint * 型合わせ * キャスト * pnpm build-misskey-js-with-types * Revert "dummy change to see if the feature do not report them (to be reverted after the check)" This reverts commit 67072e3ca6e3e16342ca3b35feadcb41afcbe04f. * eliminate reversiGame any * move reversiGame types * lint * Update packages/misskey-js/src/streaming.ts Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com> * Update acct.ts * run api extractor * re-run api extractor --------- Co-authored-by: Kisaragi Marine Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> --- packages/misskey-js/eslint.config.js | 1 + packages/misskey-js/etc/misskey-js.api.md | 27 +++--- packages/misskey-js/src/acct.ts | 3 +- packages/misskey-js/src/api.ts | 3 + packages/misskey-js/src/api.types.ts | 2 + packages/misskey-js/src/consts.ts | 104 +++++++++++++-------- packages/misskey-js/src/entities.ts | 3 +- packages/misskey-js/src/streaming.ts | 30 +++--- packages/misskey-js/src/streaming.types.ts | 18 ++-- 9 files changed, 118 insertions(+), 73 deletions(-) diff --git a/packages/misskey-js/eslint.config.js b/packages/misskey-js/eslint.config.js index e34e7510b2..d8173f30e9 100644 --- a/packages/misskey-js/eslint.config.js +++ b/packages/misskey-js/eslint.config.js @@ -1,6 +1,7 @@ import tsParser from '@typescript-eslint/parser'; import sharedConfig from '../shared/eslint.config.js'; +// eslint-disable-next-line import/no-default-export export default [ ...sharedConfig, { diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index d11d2a4f06..377dd6f658 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -551,7 +551,7 @@ type Channel = components['schemas']['Channel']; // Warning: (ae-forgotten-export) The symbol "AnyOf" needs to be exported by the entry point index.d.ts // // @public (undocumented) -export abstract class ChannelConnection = any> extends EventEmitter { +export abstract class ChannelConnection = AnyOf> extends EventEmitter { constructor(stream: Stream, channel: string, name?: string); // (undocumented) channel: string; @@ -771,12 +771,12 @@ export type Channels = { user1: boolean; user2: boolean; }) => void; - updateSettings: (payload: { + updateSettings: (payload: { userId: User['id']; - key: string; - value: any; + key: K; + value: ReversiGameDetailed[K]; }) => void; - log: (payload: Record) => void; + log: (payload: Record) => void; }; receives: { putStone: { @@ -785,10 +785,7 @@ export type Channels = { }; ready: boolean; cancel: null | Record; - updateSettings: { - key: string; - value: any; - }; + updateSettings: ReversiUpdateSettings; claimTimeIsUp: null | Record; }; }; @@ -2730,7 +2727,7 @@ type PagesUnlikeRequest = operations['pages___unlike']['requestBody']['content'] type PagesUpdateRequest = operations['pages___update']['requestBody']['content']['application/json']; // @public (undocumented) -function parse(acct: string): Acct; +function parse(_acct: string): Acct; // Warning: (ae-forgotten-export) The symbol "Values" needs to be exported by the entry point index.d.ts // @@ -2969,7 +2966,7 @@ export class Stream extends EventEmitter { constructor(origin: string, user: { token: string; } | null, options?: { - WebSocket?: any; + WebSocket?: WebSocket; }); // (undocumented) close(): void; @@ -2992,9 +2989,9 @@ export class Stream extends EventEmitter { // (undocumented) send(typeOrPayload: string): void; // (undocumented) - send(typeOrPayload: string, payload: any): void; + send(typeOrPayload: string, payload: unknown): void; // (undocumented) - send(typeOrPayload: Record | any[]): void; + send(typeOrPayload: Record | unknown[]): void; // (undocumented) state: 'initializing' | 'reconnecting' | 'connected'; // (undocumented) @@ -3229,7 +3226,9 @@ type UsersUpdateMemoRequest = operations['users___update-memo']['requestBody'][' // Warnings were encountered during analysis: // -// src/entities.ts:34:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts +// src/entities.ts:35:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts +// src/streaming.types.ts:220:4 - (ae-forgotten-export) The symbol "ReversiUpdateKey" needs to be exported by the entry point index.d.ts +// src/streaming.types.ts:230:4 - (ae-forgotten-export) The symbol "ReversiUpdateSettings" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/packages/misskey-js/src/acct.ts b/packages/misskey-js/src/acct.ts index b25bc564ea..aa8658cdbd 100644 --- a/packages/misskey-js/src/acct.ts +++ b/packages/misskey-js/src/acct.ts @@ -3,7 +3,8 @@ export type Acct = { host: string | null; }; -export function parse(acct: string): Acct { +export function parse(_acct: string): Acct { + let acct = _acct; if (acct.startsWith('@')) acct = acct.substring(1); const split = acct.split('@', 2); return { username: split[0], host: split[1] || null }; diff --git a/packages/misskey-js/src/api.ts b/packages/misskey-js/src/api.ts index 76d055cbe4..ea1df57f3d 100644 --- a/packages/misskey-js/src/api.ts +++ b/packages/misskey-js/src/api.ts @@ -14,6 +14,7 @@ export type APIError = { code: string; message: string; kind: 'client' | 'server'; + // eslint-disable-next-line @typescript-eslint/no-explicit-any info: Record; }; @@ -29,6 +30,7 @@ export type FetchLike = (input: string, init?: { headers: { [key in string]: string } }) => Promise<{ status: number; + // eslint-disable-next-line @typescript-eslint/no-explicit-any json(): Promise; }>; @@ -49,6 +51,7 @@ export class APIClient { this.fetch = opts.fetch ?? ((...args) => fetch(...args)); } + // eslint-disable-next-line @typescript-eslint/no-explicit-any private assertIsRecord(obj: T): obj is T & Record { return obj !== null && typeof obj === 'object' && !Array.isArray(obj); } diff --git a/packages/misskey-js/src/api.types.ts b/packages/misskey-js/src/api.types.ts index 8c403639b7..5ee4194db2 100644 --- a/packages/misskey-js/src/api.types.ts +++ b/packages/misskey-js/src/api.types.ts @@ -28,11 +28,13 @@ type StrictExtract = Cond extends Union ? Union : never; type IsCaseMatched = Endpoints[E]['res'] extends SwitchCase + // eslint-disable-next-line @typescript-eslint/no-explicit-any ? IsNeverType> extends false ? true : false : false type GetCaseResult = Endpoints[E]['res'] extends SwitchCase + // eslint-disable-next-line @typescript-eslint/no-explicit-any ? StrictExtract[1] : never diff --git a/packages/misskey-js/src/consts.ts b/packages/misskey-js/src/consts.ts index 03b9069290..b509d3280c 100644 --- a/packages/misskey-js/src/consts.ts +++ b/packages/misskey-js/src/consts.ts @@ -1,3 +1,13 @@ +import type { operations } from './autogen/types.js'; +import type { + AbuseReportNotificationRecipient, Ad, + Announcement, + EmojiDetailed, InviteCode, + MetaDetailed, + Note, + Role, SystemWebhook, UserLite, +} from './autogen/models.js'; + export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'roleAssigned', 'achievementEarned'] as const; export const noteVisibilities = ['public', 'home', 'followers', 'specified'] as const; @@ -135,10 +145,30 @@ export const moderationLogTypes = [ 'unsetUserBanner', ] as const; +// See: packages/backend/src/core/ReversiService.ts@L410 +export const reversiUpdateKeys = [ + 'map', + 'bw', + 'isLlotheo', + 'canPutEverywhere', + 'loopedBoard', + 'timeLimitForEachTurn', +] as const; + +export type ReversiUpdateKey = typeof reversiUpdateKeys[number]; + +type AvatarDecoration = UserLite['avatarDecorations'][number]; + +type ReceivedAbuseReport = { + reportId: AbuseReportNotificationRecipient['id']; + report: operations['admin___abuse-user-reports']['responses'][200]['content']['application/json']; + forwarded: boolean; +}; + export type ModerationLogPayloads = { updateServerSettings: { - before: any | null; - after: any | null; + before: MetaDetailed | null; + after: MetaDetailed | null; }; suspend: { userId: string; @@ -159,16 +189,16 @@ export type ModerationLogPayloads = { }; addCustomEmoji: { emojiId: string; - emoji: any; + emoji: EmojiDetailed; }; updateCustomEmoji: { emojiId: string; - before: any; - after: any; + before: EmojiDetailed; + after: EmojiDetailed; }; deleteCustomEmoji: { emojiId: string; - emoji: any; + emoji: EmojiDetailed; }; assignRole: { userId: string; @@ -187,16 +217,16 @@ export type ModerationLogPayloads = { }; createRole: { roleId: string; - role: any; + role: Role; }; updateRole: { roleId: string; - before: any; - after: any; + before: Role; + after: Role; }; deleteRole: { roleId: string; - role: any; + role: Role; }; clearQueue: Record; promoteQueue: Record; @@ -211,39 +241,39 @@ export type ModerationLogPayloads = { noteUserId: string; noteUserUsername: string; noteUserHost: string | null; - note: any; + note: Note; }; createGlobalAnnouncement: { announcementId: string; - announcement: any; + announcement: Announcement; }; createUserAnnouncement: { announcementId: string; - announcement: any; + announcement: Announcement; userId: string; userUsername: string; userHost: string | null; }; updateGlobalAnnouncement: { announcementId: string; - before: any; - after: any; + before: Announcement; + after: Announcement; }; updateUserAnnouncement: { announcementId: string; - before: any; - after: any; + before: Announcement; + after: Announcement; userId: string; userUsername: string; userHost: string | null; }; deleteGlobalAnnouncement: { announcementId: string; - announcement: any; + announcement: Announcement; }; deleteUserAnnouncement: { announcementId: string; - announcement: any; + announcement: Announcement; userId: string; userUsername: string; userHost: string | null; @@ -281,37 +311,37 @@ export type ModerationLogPayloads = { }; resolveAbuseReport: { reportId: string; - report: any; + report: ReceivedAbuseReport; forwarded: boolean; }; createInvitation: { - invitations: any[]; + invitations: InviteCode[]; }; createAd: { adId: string; - ad: any; + ad: Ad; }; updateAd: { adId: string; - before: any; - after: any; + before: Ad; + after: Ad; }; deleteAd: { adId: string; - ad: any; + ad: Ad; }; createAvatarDecoration: { avatarDecorationId: string; - avatarDecoration: any; + avatarDecoration: AvatarDecoration; }; updateAvatarDecoration: { avatarDecorationId: string; - before: any; - after: any; + before: AvatarDecoration; + after: AvatarDecoration; }; deleteAvatarDecoration: { avatarDecorationId: string; - avatarDecoration: any; + avatarDecoration: AvatarDecoration; }; unsetUserAvatar: { userId: string; @@ -327,28 +357,28 @@ export type ModerationLogPayloads = { }; createSystemWebhook: { systemWebhookId: string; - webhook: any; + webhook: SystemWebhook; }; updateSystemWebhook: { systemWebhookId: string; - before: any; - after: any; + before: SystemWebhook; + after: SystemWebhook; }; deleteSystemWebhook: { systemWebhookId: string; - webhook: any; + webhook: SystemWebhook; }; createAbuseReportNotificationRecipient: { recipientId: string; - recipient: any; + recipient: AbuseReportNotificationRecipient; }; updateAbuseReportNotificationRecipient: { recipientId: string; - before: any; - after: any; + before: AbuseReportNotificationRecipient; + after: AbuseReportNotificationRecipient; }; deleteAbuseReportNotificationRecipient: { recipientId: string; - recipient: any; + recipient: AbuseReportNotificationRecipient; }; }; diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index 7331a55a1c..ce58fb2970 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -7,7 +7,7 @@ import { Role, RolePolicies, User, - UserDetailedNotMe + UserDetailedNotMe, } from './autogen/models.js'; export * from './autogen/entities.js'; @@ -19,6 +19,7 @@ export type DateString = string; export type PageEvent = { pageId: Page['id']; event: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any var: any; userId: User['id']; user: User; diff --git a/packages/misskey-js/src/streaming.ts b/packages/misskey-js/src/streaming.ts index 83930e621c..d1d131cfc1 100644 --- a/packages/misskey-js/src/streaming.ts +++ b/packages/misskey-js/src/streaming.ts @@ -15,7 +15,7 @@ export function urlQuery(obj: Record> = T[keyof T]; +type AnyOf> = T[keyof T]; type StreamEvents = { _connected_: void; @@ -25,6 +25,7 @@ type StreamEvents = { /** * Misskey stream connection */ +// eslint-disable-next-line import/no-default-export export default class Stream extends EventEmitter { private stream: _ReconnectingWebsocket.default; public state: 'initializing' | 'reconnecting' | 'connected' = 'initializing'; @@ -34,7 +35,7 @@ export default class Stream extends EventEmitter { private idCounter = 0; constructor(origin: string, user: { token: string; } | null, options?: { - WebSocket?: any; + WebSocket?: WebSocket; }) { super(); @@ -51,6 +52,7 @@ export default class Stream extends EventEmitter { this.send = this.send.bind(this); this.close = this.close.bind(this); + // eslint-disable-next-line no-param-reassign options = options ?? { }; const query = urlQuery({ @@ -91,8 +93,8 @@ export default class Stream extends EventEmitter { this.sharedConnectionPools.push(pool); } - const connection = new SharedConnection(this, channel, pool, name); - this.sharedConnections.push(connection); + const connection = new SharedConnection(this, channel, pool, name); + this.sharedConnections.push(connection as unknown as SharedConnection); return connection; } @@ -106,7 +108,7 @@ export default class Stream extends EventEmitter { private connectToChannel(channel: C, params: Channels[C]['params']): NonSharedConnection { const connection = new NonSharedConnection(this, channel, this.genId(), params); - this.nonSharedConnections.push(connection); + this.nonSharedConnections.push(connection as unknown as NonSharedConnection); return connection; } @@ -174,9 +176,9 @@ export default class Stream extends EventEmitter { * ! ストリーム上のやり取りはすべてJSONで行われます ! */ public send(typeOrPayload: string): void - public send(typeOrPayload: string, payload: any): void - public send(typeOrPayload: Record | any[]): void - public send(typeOrPayload: string | Record | any[], payload?: any): void { + public send(typeOrPayload: string, payload: unknown): void + public send(typeOrPayload: Record | unknown[]): void + public send(typeOrPayload: string | Record | unknown[], payload?: unknown): void { if (typeof typeOrPayload === 'string') { this.stream.send(JSON.stringify({ type: typeOrPayload, @@ -211,7 +213,7 @@ class Pool { public id: string; protected stream: Stream; public users = 0; - private disposeTimerId: any; + private disposeTimerId: ReturnType | null = null; private isConnected = false; constructor(stream: Stream, channel: string, id: string) { @@ -275,7 +277,7 @@ class Pool { } } -export abstract class Connection = any> extends EventEmitter { +export abstract class Connection = AnyOf> extends EventEmitter { public channel: string; protected stream: Stream; public abstract id: string; @@ -309,7 +311,7 @@ export abstract class Connection = any> extends public abstract dispose(): void; } -class SharedConnection = any> extends Connection { +class SharedConnection = AnyOf> extends Connection { private pool: Pool; public get id(): string { @@ -328,11 +330,11 @@ class SharedConnection = any> extends Connection public dispose(): void { this.pool.dec(); this.removeAllListeners(); - this.stream.removeSharedConnection(this); + this.stream.removeSharedConnection(this as unknown as SharedConnection); } } -class NonSharedConnection = any> extends Connection { +class NonSharedConnection = AnyOf> extends Connection { public id: string; protected params: Channel['params']; @@ -359,6 +361,6 @@ class NonSharedConnection = any> extends Connect public dispose(): void { this.removeAllListeners(); this.stream.send('disconnect', { id: this.id }); - this.stream.disconnectToChannel(this); + this.stream.disconnectToChannel(this as unknown as NonSharedConnection); } } diff --git a/packages/misskey-js/src/streaming.types.ts b/packages/misskey-js/src/streaming.types.ts index 9a86e03d69..4447a2e8fc 100644 --- a/packages/misskey-js/src/streaming.types.ts +++ b/packages/misskey-js/src/streaming.types.ts @@ -21,6 +21,14 @@ import { ServerStatsLog, ReversiGameDetailed, } from './entities.js'; +import { + ReversiUpdateKey, +} from './consts.js'; + +type ReversiUpdateSettings = { + key: K; + value: ReversiGameDetailed[K]; +}; export type Channels = { main: { @@ -51,6 +59,7 @@ export type Channels = { registryUpdated: (payload: { scope?: string[]; key: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any value: any | null; }) => void; driveFileCreated: (payload: DriveFile) => void; @@ -208,8 +217,8 @@ export type Channels = { ended: (payload: { winnerId: User['id'] | null; game: ReversiGameDetailed; }) => void; canceled: (payload: { userId: User['id']; }) => void; changeReadyStates: (payload: { user1: boolean; user2: boolean; }) => void; - updateSettings: (payload: { userId: User['id']; key: string; value: any; }) => void; - log: (payload: Record) => void; + updateSettings: (payload: { userId: User['id']; key: K; value: ReversiGameDetailed[K]; }) => void; + log: (payload: Record) => void; }; receives: { putStone: { @@ -218,10 +227,7 @@ export type Channels = { }; ready: boolean; cancel: null | Record; - updateSettings: { - key: string; - value: any; - }; + updateSettings: ReversiUpdateSettings; claimTimeIsUp: null | Record; } } From 7c67d3a5aae29317902d73ced1fe1ec28a209e32 Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Thu, 25 Jul 2024 16:44:38 +0900 Subject: [PATCH 05/24] fix(frontend): emoji picker not opening on `/share` page (#14295) * fix(frontend): emoji picker not opening on `/share` page * Update CHANGELOG.md --- CHANGELOG.md | 1 + packages/frontend/src/boot/sub-boot.ts | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21d25fe0de..1521e88fcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ - Fix: 子メニューの高さがウィンドウからはみ出ることがある問題を修正 - Fix: 個人宛てのダイアログ形式のお知らせが即時表示されない問題を修正 - Fix: 一部の画像がセンシティブ指定されているときに画面に何も表示されないことがあるのを修正 +- Fix: `/share`ページにおいて絵文字ピッカーを開くことができない問題を修正 ### Server - Feat: レートリミット制限に引っかかったときに`Retry-After`ヘッダーを返すように (#13949) diff --git a/packages/frontend/src/boot/sub-boot.ts b/packages/frontend/src/boot/sub-boot.ts index 017457822b..35c84d5568 100644 --- a/packages/frontend/src/boot/sub-boot.ts +++ b/packages/frontend/src/boot/sub-boot.ts @@ -5,9 +5,12 @@ import { createApp, defineAsyncComponent } from 'vue'; import { common } from './common.js'; +import { emojiPicker } from '@/scripts/emoji-picker.js'; export async function subBoot() { const { isClientUpdated } = await common(() => createApp( defineAsyncComponent(() => import('@/ui/minimum.vue')), )); + + emojiPicker.init(); } From ed6dc84c5f92c00c92bb2fa17b5f5aa81c21429e 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, 25 Jul 2024 17:03:00 +0900 Subject: [PATCH 06/24] =?UTF-8?q?fix(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=97=E3=81=9F=E3=83=A6?= =?UTF-8?q?=E3=83=BC=E3=82=B6=E3=83=BC=E4=B8=80=E8=A6=A7=E3=81=AE=E3=83=A6?= =?UTF-8?q?=E3=83=BC=E3=82=B6=E3=83=BC=E5=90=8D=E3=81=8C=E3=81=AF=E3=81=BF?= =?UTF-8?q?=E5=87=BA=E3=82=8B=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=20(#14294)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * pnpm dev で絵文字が表示されない問題を解決 (cherry picked from commit 22fcafbf55830922efe75d129f48b4d8c11724e6) * リアクションしたユーザー一覧のユーザーネームがはみ出る問題を解決 (cherry picked from commit 46458b190e2b4ccfc8b50b6857ee9a5a6fd09fe9) * Update Changelog --------- Co-authored-by: 6wFh3kVo Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> --- CHANGELOG.md | 2 ++ packages/frontend/src/components/MkReactionsViewer.details.vue | 1 + packages/frontend/vite.config.local-dev.ts | 1 + 3 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1521e88fcb..7d48d14c71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ - Fix: 子メニューの高さがウィンドウからはみ出ることがある問題を修正 - Fix: 個人宛てのダイアログ形式のお知らせが即時表示されない問題を修正 - Fix: 一部の画像がセンシティブ指定されているときに画面に何も表示されないことがあるのを修正 +- Fix: リアクションしたユーザー一覧のユーザー名がはみ出る問題を修正 + (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/672) - Fix: `/share`ページにおいて絵文字ピッカーを開くことができない問題を修正 ### Server diff --git a/packages/frontend/src/components/MkReactionsViewer.details.vue b/packages/frontend/src/components/MkReactionsViewer.details.vue index 8b5e6efdf3..60118fadd2 100644 --- a/packages/frontend/src/components/MkReactionsViewer.details.vue +++ b/packages/frontend/src/components/MkReactionsViewer.details.vue @@ -81,6 +81,7 @@ function getReactionName(reaction: string): string { } .user { + display: flex; line-height: 24px; padding-top: 4px; white-space: nowrap; diff --git a/packages/frontend/vite.config.local-dev.ts b/packages/frontend/vite.config.local-dev.ts index 0a88e489c1..887ab7927e 100644 --- a/packages/frontend/vite.config.local-dev.ts +++ b/packages/frontend/vite.config.local-dev.ts @@ -62,6 +62,7 @@ const devConfig: UserConfig = { '/bios': httpUrl, '/cli': httpUrl, '/inbox': httpUrl, + '/emoji/': httpUrl, '/notes': { target: httpUrl, bypass: varyHandler, From ee2f0f3a21bbe978483ebe28a38806431c972405 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, 25 Jul 2024 17:03:55 +0900 Subject: [PATCH 07/24] =?UTF-8?q?fix(frontend):=20=E3=81=84=E3=81=8F?= =?UTF-8?q?=E3=81=A4=E3=81=8B=E3=81=AE`number`=20input=E3=81=AB=E6=9C=80?= =?UTF-8?q?=E5=B0=8F=E5=80=A4=E3=82=92=E8=A8=AD=E5=AE=9A=20(#14284)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/components/MkPollEditor.vue | 2 +- packages/frontend/src/pages/admin/invites.vue | 2 +- packages/frontend/src/pages/settings/statusbar.statusbar.vue | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/frontend/src/components/MkPollEditor.vue b/packages/frontend/src/components/MkPollEditor.vue index db74354bbb..3726ddf822 100644 --- a/packages/frontend/src/components/MkPollEditor.vue +++ b/packages/frontend/src/components/MkPollEditor.vue @@ -37,7 +37,7 @@ SPDX-License-Identifier: AGPL-3.0-only
- + diff --git a/packages/frontend/src/pages/admin/invites.vue b/packages/frontend/src/pages/admin/invites.vue index 95727fb14c..9cb430b0fe 100644 --- a/packages/frontend/src/pages/admin/invites.vue +++ b/packages/frontend/src/pages/admin/invites.vue @@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only - + {{ i18n.ts.create }} diff --git a/packages/frontend/src/pages/settings/statusbar.statusbar.vue b/packages/frontend/src/pages/settings/statusbar.statusbar.vue index 92e389a288..67943524ef 100644 --- a/packages/frontend/src/pages/settings/statusbar.statusbar.vue +++ b/packages/frontend/src/pages/settings/statusbar.statusbar.vue @@ -36,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only - + @@ -48,7 +48,7 @@ SPDX-License-Identifier: AGPL-3.0-only