From 4f20c871860d0f62aef77bc716c3cc2677d4a592 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Mon, 9 Oct 2023 13:32:41 +0900
Subject: [PATCH] lint fixes

---
 packages/backend/src/core/QueryService.ts     | 101 ++++++++++--------
 .../src/core/entities/RoleEntityService.ts    |   7 +-
 .../src/server/ActivityPubServerService.ts    |   7 +-
 .../server/api/endpoints/admin/roles/users.ts |   7 +-
 .../server/api/endpoints/channels/search.ts   |   7 +-
 .../server/api/endpoints/notes/children.ts    |  21 ++--
 .../server/api/endpoints/notes/mentions.ts    |   7 +-
 .../endpoints/notes/polls/recommendation.ts   |   7 +-
 .../src/server/api/endpoints/roles/users.ts   |   7 +-
 .../users/search-by-username-and-host.ts      |   7 +-
 .../src/server/api/endpoints/users/search.ts  |  21 ++--
 packages/misskey-js/etc/misskey-js.api.md     |   7 +-
 packages/misskey-js/src/api.ts                |   3 +-
 packages/misskey-js/src/consts.ts             |   2 +-
 packages/misskey-js/src/entities.ts           |   3 +
 packages/sw/src/scripts/operations.ts         |   2 +-
 16 files changed, 124 insertions(+), 92 deletions(-)

diff --git a/packages/backend/src/core/QueryService.ts b/packages/backend/src/core/QueryService.ts
index 18bd49286e..4575917bf6 100644
--- a/packages/backend/src/core/QueryService.ts
+++ b/packages/backend/src/core/QueryService.ts
@@ -76,13 +76,15 @@ export class QueryService {
 		// 投稿の引用元の作者にブロックされていない
 		q
 			.andWhere(`note.userId NOT IN (${ blockingQuery.getQuery() })`)
-			.andWhere(new Brackets(qb => { qb
-				.where('note.replyUserId IS NULL')
-				.orWhere(`note.replyUserId NOT IN (${ blockingQuery.getQuery() })`);
+			.andWhere(new Brackets(qb => {
+				qb
+					.where('note.replyUserId IS NULL')
+					.orWhere(`note.replyUserId NOT IN (${ blockingQuery.getQuery() })`);
 			}))
-			.andWhere(new Brackets(qb => { qb
-				.where('note.renoteUserId IS NULL')
-				.orWhere(`note.renoteUserId NOT IN (${ blockingQuery.getQuery() })`);
+			.andWhere(new Brackets(qb => {
+				qb
+					.where('note.renoteUserId IS NULL')
+					.orWhere(`note.renoteUserId NOT IN (${ blockingQuery.getQuery() })`);
 			}));
 
 		q.setParameters(blockingQuery.getParameters());
@@ -112,9 +114,10 @@ export class QueryService {
 			.where('threadMuted.userId = :userId', { userId: me.id });
 
 		q.andWhere(`note.id NOT IN (${ mutedQuery.getQuery() })`);
-		q.andWhere(new Brackets(qb => { qb
-			.where('note.threadId IS NULL')
-			.orWhere(`note.threadId NOT IN (${ mutedQuery.getQuery() })`);
+		q.andWhere(new Brackets(qb => {
+			qb
+				.where('note.threadId IS NULL')
+				.orWhere(`note.threadId NOT IN (${ mutedQuery.getQuery() })`);
 		}));
 
 		q.setParameters(mutedQuery.getParameters());
@@ -139,26 +142,31 @@ export class QueryService {
 		// 投稿の引用元の作者をミュートしていない
 		q
 			.andWhere(`note.userId NOT IN (${ mutingQuery.getQuery() })`)
-			.andWhere(new Brackets(qb => { qb
-				.where('note.replyUserId IS NULL')
-				.orWhere(`note.replyUserId NOT IN (${ mutingQuery.getQuery() })`);
+			.andWhere(new Brackets(qb => {
+				qb
+					.where('note.replyUserId IS NULL')
+					.orWhere(`note.replyUserId NOT IN (${ mutingQuery.getQuery() })`);
 			}))
-			.andWhere(new Brackets(qb => { qb
-				.where('note.renoteUserId IS NULL')
-				.orWhere(`note.renoteUserId NOT IN (${ mutingQuery.getQuery() })`);
+			.andWhere(new Brackets(qb => {
+				qb
+					.where('note.renoteUserId IS NULL')
+					.orWhere(`note.renoteUserId NOT IN (${ mutingQuery.getQuery() })`);
 			}))
 			// mute instances
-			.andWhere(new Brackets(qb => { qb
-				.andWhere('note.userHost IS NULL')
-				.orWhere(`NOT ((${ mutingInstanceQuery.getQuery() })::jsonb ? note.userHost)`);
+			.andWhere(new Brackets(qb => {
+				qb
+					.andWhere('note.userHost IS NULL')
+					.orWhere(`NOT ((${ mutingInstanceQuery.getQuery() })::jsonb ? note.userHost)`);
 			}))
-			.andWhere(new Brackets(qb => { qb
-				.where('note.replyUserHost IS NULL')
-				.orWhere(`NOT ((${ mutingInstanceQuery.getQuery() })::jsonb ? note.replyUserHost)`);
+			.andWhere(new Brackets(qb => {
+				qb
+					.where('note.replyUserHost IS NULL')
+					.orWhere(`NOT ((${ mutingInstanceQuery.getQuery() })::jsonb ? note.replyUserHost)`);
 			}))
-			.andWhere(new Brackets(qb => { qb
-				.where('note.renoteUserHost IS NULL')
-				.orWhere(`NOT ((${ mutingInstanceQuery.getQuery() })::jsonb ? note.renoteUserHost)`);
+			.andWhere(new Brackets(qb => {
+				qb
+					.where('note.renoteUserHost IS NULL')
+					.orWhere(`NOT ((${ mutingInstanceQuery.getQuery() })::jsonb ? note.renoteUserHost)`);
 			}));
 
 		q.setParameters(mutingQuery.getParameters());
@@ -180,36 +188,41 @@ export class QueryService {
 	public generateVisibilityQuery(q: SelectQueryBuilder<any>, me?: { id: MiUser['id'] } | null): void {
 		// This code must always be synchronized with the checks in Notes.isVisibleForMe.
 		if (me == null) {
-			q.andWhere(new Brackets(qb => { qb
-				.where('note.visibility = \'public\'')
-				.orWhere('note.visibility = \'home\'');
+			q.andWhere(new Brackets(qb => {
+				qb
+					.where('note.visibility = \'public\'')
+					.orWhere('note.visibility = \'home\'');
 			}));
 		} else {
 			const followingQuery = this.followingsRepository.createQueryBuilder('following')
 				.select('following.followeeId')
 				.where('following.followerId = :meId');
 
-			q.andWhere(new Brackets(qb => { qb
+			q.andWhere(new Brackets(qb => {
+				qb
 				// 公開投稿である
-				.where(new Brackets(qb => { qb
-					.where('note.visibility = \'public\'')
-					.orWhere('note.visibility = \'home\'');
-				}))
+					.where(new Brackets(qb => {
+						qb
+							.where('note.visibility = \'public\'')
+							.orWhere('note.visibility = \'home\'');
+					}))
 				// または 自分自身
-				.orWhere('note.userId = :meId')
+					.orWhere('note.userId = :meId')
 				// または 自分宛て
-				.orWhere(':meId = ANY(note.visibleUserIds)')
-				.orWhere(':meId = ANY(note.mentions)')
-				.orWhere(new Brackets(qb => { qb
-					// または フォロワー宛ての投稿であり、
-					.where('note.visibility = \'followers\'')
-					.andWhere(new Brackets(qb => { qb
-						// 自分がフォロワーである
-						.where(`note.userId IN (${ followingQuery.getQuery() })`)
-						// または 自分の投稿へのリプライ
-						.orWhere('note.replyUserId = :meId');
+					.orWhere(':meId = ANY(note.visibleUserIds)')
+					.orWhere(':meId = ANY(note.mentions)')
+					.orWhere(new Brackets(qb => {
+						qb
+						// または フォロワー宛ての投稿であり、
+							.where('note.visibility = \'followers\'')
+							.andWhere(new Brackets(qb => {
+								qb
+								// 自分がフォロワーである
+									.where(`note.userId IN (${ followingQuery.getQuery() })`)
+								// または 自分の投稿へのリプライ
+									.orWhere('note.replyUserId = :meId');
+							}));
 					}));
-				}));
 			}));
 
 			q.setParameters({ meId: me.id });
diff --git a/packages/backend/src/core/entities/RoleEntityService.ts b/packages/backend/src/core/entities/RoleEntityService.ts
index 23e82561d6..79375a7008 100644
--- a/packages/backend/src/core/entities/RoleEntityService.ts
+++ b/packages/backend/src/core/entities/RoleEntityService.ts
@@ -33,9 +33,10 @@ export class RoleEntityService {
 
 		const assignedCount = await this.roleAssignmentsRepository.createQueryBuilder('assign')
 			.where('assign.roleId = :roleId', { roleId: role.id })
-			.andWhere(new Brackets(qb => { qb
-				.where('assign.expiresAt IS NULL')
-				.orWhere('assign.expiresAt > :now', { now: new Date() });
+			.andWhere(new Brackets(qb => {
+				qb
+					.where('assign.expiresAt IS NULL')
+					.orWhere('assign.expiresAt > :now', { now: new Date() });
 			}))
 			.getCount();
 
diff --git a/packages/backend/src/server/ActivityPubServerService.ts b/packages/backend/src/server/ActivityPubServerService.ts
index 2428fa2792..a7f6f82daf 100644
--- a/packages/backend/src/server/ActivityPubServerService.ts
+++ b/packages/backend/src/server/ActivityPubServerService.ts
@@ -379,9 +379,10 @@ export class ActivityPubServerService {
 		if (page) {
 			const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), sinceId, untilId)
 				.andWhere('note.userId = :userId', { userId: user.id })
-				.andWhere(new Brackets(qb => { qb
-					.where('note.visibility = \'public\'')
-					.orWhere('note.visibility = \'home\'');
+				.andWhere(new Brackets(qb => {
+					qb
+						.where('note.visibility = \'public\'')
+						.orWhere('note.visibility = \'home\'');
 				}))
 				.andWhere('note.localOnly = FALSE');
 
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 b1772be777..ef5627bc9a 100644
--- a/packages/backend/src/server/api/endpoints/admin/roles/users.ts
+++ b/packages/backend/src/server/api/endpoints/admin/roles/users.ts
@@ -61,9 +61,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 
 			const query = this.queryService.makePaginationQuery(this.roleAssignmentsRepository.createQueryBuilder('assign'), ps.sinceId, ps.untilId)
 				.andWhere('assign.roleId = :roleId', { roleId: role.id })
-				.andWhere(new Brackets(qb => { qb
-					.where('assign.expiresAt IS NULL')
-					.orWhere('assign.expiresAt > :now', { now: new Date() });
+				.andWhere(new Brackets(qb => {
+					qb
+						.where('assign.expiresAt IS NULL')
+						.orWhere('assign.expiresAt > :now', { now: new Date() });
 				}))
 				.innerJoinAndSelect('assign.user', 'user');
 
diff --git a/packages/backend/src/server/api/endpoints/channels/search.ts b/packages/backend/src/server/api/endpoints/channels/search.ts
index 65df45706b..9c78a94844 100644
--- a/packages/backend/src/server/api/endpoints/channels/search.ts
+++ b/packages/backend/src/server/api/endpoints/channels/search.ts
@@ -55,9 +55,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 
 			if (ps.query !== '') {
 				if (ps.type === 'nameAndDescription') {
-					query.andWhere(new Brackets(qb => { qb
-						.where('channel.name ILIKE :q', { q: `%${ sqlLikeEscape(ps.query) }%` })
-						.orWhere('channel.description ILIKE :q', { q: `%${ sqlLikeEscape(ps.query) }%` });
+					query.andWhere(new Brackets(qb => {
+						qb
+							.where('channel.name ILIKE :q', { q: `%${ sqlLikeEscape(ps.query) }%` })
+							.orWhere('channel.description ILIKE :q', { q: `%${ sqlLikeEscape(ps.query) }%` });
 					}));
 				} else {
 					query.andWhere('channel.name ILIKE :q', { q: `%${ sqlLikeEscape(ps.query) }%` });
diff --git a/packages/backend/src/server/api/endpoints/notes/children.ts b/packages/backend/src/server/api/endpoints/notes/children.ts
index 1a82a4b5d7..1e569d9806 100644
--- a/packages/backend/src/server/api/endpoints/notes/children.ts
+++ b/packages/backend/src/server/api/endpoints/notes/children.ts
@@ -49,16 +49,19 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 	) {
 		super(meta, paramDef, async (ps, me) => {
 			const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
-				.andWhere(new Brackets(qb => { qb
-					.where('note.replyId = :noteId', { noteId: ps.noteId })
-					.orWhere(new Brackets(qb => { qb
-						.where('note.renoteId = :noteId', { noteId: ps.noteId })
-						.andWhere(new Brackets(qb => { qb
-							.where('note.text IS NOT NULL')
-							.orWhere('note.fileIds != \'{}\'')
-							.orWhere('note.hasPoll = TRUE');
+				.andWhere(new Brackets(qb => {
+					qb
+						.where('note.replyId = :noteId', { noteId: ps.noteId })
+						.orWhere(new Brackets(qb => {
+							qb
+								.where('note.renoteId = :noteId', { noteId: ps.noteId })
+								.andWhere(new Brackets(qb => {
+									qb
+										.where('note.text IS NOT NULL')
+										.orWhere('note.fileIds != \'{}\'')
+										.orWhere('note.hasPoll = TRUE');
+								}));
 						}));
-					}));
 				}))
 				.innerJoinAndSelect('note.user', 'user')
 				.leftJoinAndSelect('note.reply', 'reply')
diff --git a/packages/backend/src/server/api/endpoints/notes/mentions.ts b/packages/backend/src/server/api/endpoints/notes/mentions.ts
index 65e7bd8cd5..6fab024d17 100644
--- a/packages/backend/src/server/api/endpoints/notes/mentions.ts
+++ b/packages/backend/src/server/api/endpoints/notes/mentions.ts
@@ -59,9 +59,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				.where('following.followerId = :followerId', { followerId: me.id });
 
 			const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
-				.andWhere(new Brackets(qb => { qb
-					.where(`'{"${me.id}"}' <@ note.mentions`)
-					.orWhere(`'{"${me.id}"}' <@ note.visibleUserIds`);
+				.andWhere(new Brackets(qb => {
+					qb
+						.where(`'{"${me.id}"}' <@ note.mentions`)
+						.orWhere(`'{"${me.id}"}' <@ note.visibleUserIds`);
 				}))
 				// Avoid scanning primary key index
 				.orderBy('CONCAT(note.id)', 'DESC')
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 29190af62a..986201e950 100644
--- a/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts
+++ b/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts
@@ -57,9 +57,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				.where('poll.userHost IS NULL')
 				.andWhere('poll.userId != :meId', { meId: me.id })
 				.andWhere('poll.noteVisibility = \'public\'')
-				.andWhere(new Brackets(qb => { qb
-					.where('poll.expiresAt IS NULL')
-					.orWhere('poll.expiresAt > :now', { now: new Date() });
+				.andWhere(new Brackets(qb => {
+					qb
+						.where('poll.expiresAt IS NULL')
+						.orWhere('poll.expiresAt > :now', { now: new Date() });
 				}));
 
 			//#region exclude arleady voted polls
diff --git a/packages/backend/src/server/api/endpoints/roles/users.ts b/packages/backend/src/server/api/endpoints/roles/users.ts
index 37aac908b5..caaa3735e9 100644
--- a/packages/backend/src/server/api/endpoints/roles/users.ts
+++ b/packages/backend/src/server/api/endpoints/roles/users.ts
@@ -62,9 +62,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 
 			const query = this.queryService.makePaginationQuery(this.roleAssignmentsRepository.createQueryBuilder('assign'), ps.sinceId, ps.untilId)
 				.andWhere('assign.roleId = :roleId', { roleId: role.id })
-				.andWhere(new Brackets(qb => { qb
-					.where('assign.expiresAt IS NULL')
-					.orWhere('assign.expiresAt > :now', { now: new Date() });
+				.andWhere(new Brackets(qb => {
+					qb
+						.where('assign.expiresAt IS NULL')
+						.orWhere('assign.expiresAt > :now', { now: new Date() });
 				}))
 				.innerJoinAndSelect('assign.user', 'user');
 
diff --git a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts
index 74408cc64a..4bf25d9fbb 100644
--- a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts
+++ b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts
@@ -92,9 +92,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 					.andWhere(`user.id IN (${ followingQuery.getQuery() })`)
 					.andWhere('user.id != :meId', { meId: me.id })
 					.andWhere('user.isSuspended = FALSE')
-					.andWhere(new Brackets(qb => { qb
-						.where('user.updatedAt IS NULL')
-						.orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold });
+					.andWhere(new Brackets(qb => {
+						qb
+							.where('user.updatedAt IS NULL')
+							.orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold });
 					}));
 
 				query.setParameters(followingQuery.getParameters());
diff --git a/packages/backend/src/server/api/endpoints/users/search.ts b/packages/backend/src/server/api/endpoints/users/search.ts
index aff5b98779..32b5c12372 100644
--- a/packages/backend/src/server/api/endpoints/users/search.ts
+++ b/packages/backend/src/server/api/endpoints/users/search.ts
@@ -64,9 +64,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 			if (isUsername) {
 				const usernameQuery = this.usersRepository.createQueryBuilder('user')
 					.where('user.usernameLower LIKE :username', { username: sqlLikeEscape(ps.query.replace('@', '').toLowerCase()) + '%' })
-					.andWhere(new Brackets(qb => { qb
-						.where('user.updatedAt IS NULL')
-						.orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold });
+					.andWhere(new Brackets(qb => {
+						qb
+							.where('user.updatedAt IS NULL')
+							.orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold });
 					}))
 					.andWhere('user.isSuspended = FALSE');
 
@@ -91,9 +92,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 							qb.orWhere('user.usernameLower LIKE :username', { username: '%' + sqlLikeEscape(ps.query.toLowerCase()) + '%' });
 						}
 					}))
-					.andWhere(new Brackets(qb => { qb
-						.where('user.updatedAt IS NULL')
-						.orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold });
+					.andWhere(new Brackets(qb => {
+						qb
+							.where('user.updatedAt IS NULL')
+							.orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold });
 					}))
 					.andWhere('user.isSuspended = FALSE');
 
@@ -122,9 +124,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 
 					const query = this.usersRepository.createQueryBuilder('user')
 						.where(`user.id IN (${ profQuery.getQuery() })`)
-						.andWhere(new Brackets(qb => { qb
-							.where('user.updatedAt IS NULL')
-							.orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold });
+						.andWhere(new Brackets(qb => {
+							qb
+								.where('user.updatedAt IS NULL')
+								.orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold });
 						}))
 						.andWhere('user.isSuspended = FALSE')
 						.setParameters(profQuery.getParameters());
diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md
index 09662073ed..1a0bbeac78 100644
--- a/packages/misskey-js/etc/misskey-js.api.md
+++ b/packages/misskey-js/etc/misskey-js.api.md
@@ -2755,6 +2755,9 @@ type Notification_2 = {
     invitation: UserGroup;
     user: User;
     userId: User['id'];
+} | {
+    type: 'achievementEarned';
+    achievement: string;
 } | {
     type: 'app';
     header?: string | null;
@@ -2765,7 +2768,7 @@ type Notification_2 = {
 });
 
 // @public (undocumented)
-export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "pollVote", "pollEnded", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app"];
+export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "pollVote", "pollEnded", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app", "achievementEarned"];
 
 // @public (undocumented)
 type OriginType = 'combined' | 'local' | 'remote';
@@ -2981,7 +2984,7 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u
 // src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts
 // src/api.types.ts:630:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts
 // src/entities.ts:107:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts
-// src/entities.ts:597:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts
+// src/entities.ts:600:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts
 // src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts
 
 // (No @packageDocumentation comment for this package)
diff --git a/packages/misskey-js/src/api.ts b/packages/misskey-js/src/api.ts
index 974cb35ace..9415e692e3 100644
--- a/packages/misskey-js/src/api.ts
+++ b/packages/misskey-js/src/api.ts
@@ -67,8 +67,7 @@ export class APIClient {
 			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']>
-	{
+		: Endpoints[E]['res']> {
 		const promise = new Promise((resolve, reject) => {
 			this.fetch(`${this.origin}/api/${endpoint}`, {
 				method: 'POST',
diff --git a/packages/misskey-js/src/consts.ts b/packages/misskey-js/src/consts.ts
index ccc55537d2..c4ddead823 100644
--- a/packages/misskey-js/src/consts.ts
+++ b/packages/misskey-js/src/consts.ts
@@ -1,4 +1,4 @@
-export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app'] as const;
+export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'achievementEarned'] as const;
 
 export const noteVisibilities = ['public', 'home', 'followers', 'specified'] as const;
 
diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts
index b02f3e1f9b..aed242d8aa 100644
--- a/packages/misskey-js/src/entities.ts
+++ b/packages/misskey-js/src/entities.ts
@@ -277,6 +277,9 @@ export type Notification = {
 	invitation: UserGroup;
 	user: User;
 	userId: User['id'];
+} | {
+	type: 'achievementEarned';
+	achievement: string;
 } | {
 	type: 'app';
 	header?: string | null;
diff --git a/packages/sw/src/scripts/operations.ts b/packages/sw/src/scripts/operations.ts
index be4f066b5f..0cbf4c7953 100644
--- a/packages/sw/src/scripts/operations.ts
+++ b/packages/sw/src/scripts/operations.ts
@@ -15,7 +15,7 @@ import { getUrlWithLoginId } from '@/scripts/login-id.js';
 export const cli = new Misskey.api.APIClient({ origin, fetch: (...args): Promise<Response> => fetch(...args) });
 
 export async function api<E extends keyof Misskey.Endpoints, O extends Misskey.Endpoints[E]['req']>(endpoint: E, userId?: string, options?: O): Promise<void | ReturnType<typeof cli.request<E, O>>> {
-	let account: { token: string; id: string } | void;
+	let account: { token: string; id: string } | void = undefined;
 
 	if (userId) {
 		account = await getAccountFromId(userId);