diff --git a/CHANGELOG.md b/CHANGELOG.md index a5ee835466..3316e8be07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,19 +5,34 @@ - ### Client -- +- Fix: ページ一覧ページの表示がモバイル環境において崩れているのを修正 ### Server - --> +## 2023.x.x (unreleased) + +### General +- Feat: メールアドレスの認証にverifymail.ioを使えるように (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/971ba07a44550f68d2ba31c62066db2d43a0caed) +- Feat: モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能を追加 (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/e0eb5a752f6e5616d6312bb7c9790302f9dbff83) + +### Client +- fix: 「設定のバックアップ」で一部の項目がバックアップに含まれていなかった問題を修正 +- Fix: ウィジェットのジョブキューにて音声の発音方法変更に追従できていなかったのを修正 #12367 + +### Server +- Fix: 時間経過により無効化されたアンテナを再有効化したとき、サーバ再起動までその状況が反映されないのを修正 #12303 +- Fix: ロールタイムラインが保存されない問題を修正 + ## 2023.11.1 ### General - Feat: 管理者がコントロールパネルからメールアドレスの照会を行えるようになりました - Enhance: ローカリゼーションの更新 - Enhance: 依存関係の更新 +- Enhance: json-schema(OpenAPIの戻り値として使用されるスキーマ定義)を出来る限り最新化 #12311 ### Client - Enhance: MFMでルビを振れるように diff --git a/locales/en-US.yml b/locales/en-US.yml index 854bd854f0..65714e92e2 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -566,10 +566,10 @@ output: "Output" script: "Script" disablePagesScript: "Disable AiScript on Pages" updateRemoteUser: "Update remote user information" -deleteUserAvatar: "Delete user icon" -deleteUserAvatarConfirm: "Are you sure that you want to delete this user's icon?" -deleteUserBanner: "Delete user banner" -deleteUserBannerConfirm: "Are you sure that you want to delete this user's banner?" +unsetUserAvatar: "Unset user icon" +unsetUserAvatarConfirm: "Are you sure that you want to unset this user's icon?" +unsetUserBanner: "Unset user banner" +unsetUserBannerConfirm: "Are you sure that you want to unset this user's banner?" deleteAllFiles: "Delete all files" deleteAllFilesConfirm: "Are you sure that you want to delete all files?" removeAllFollowing: "Unfollow all followed users" diff --git a/locales/index.d.ts b/locales/index.d.ts index ace1ad80f4..8ac9937716 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -569,10 +569,10 @@ export interface Locale { "script": string; "disablePagesScript": string; "updateRemoteUser": string; - "deleteUserAvatar": string; - "deleteUserAvatarConfirm": string; - "deleteUserBanner": string; - "deleteUserBannerConfirm": string; + "unsetUserAvatar": string; + "unsetUserAvatarConfirm": string; + "unsetUserBanner": string; + "unsetUserBannerConfirm": string; "deleteAllFiles": string; "deleteAllFilesConfirm": string; "removeAllFollowing": string; @@ -2447,6 +2447,8 @@ export interface Locale { "createAvatarDecoration": string; "updateAvatarDecoration": string; "deleteAvatarDecoration": string; + "unsetUserAvatar": string; + "unsetUserBanner": string; }; "_fileViewer": { "title": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 4d9be1ef33..fab7e25b84 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -566,10 +566,10 @@ output: "出力" script: "スクリプト" disablePagesScript: "Pagesのスクリプトを無効にする" updateRemoteUser: "リモートユーザー情報の更新" -deleteUserAvatar: "アイコンを削除" -deleteUserAvatarConfirm: "アイコンを削除しますか?" -deleteUserBanner: "バナーを削除" -deleteUserBannerConfirm: "バナーを削除しますか?" +unsetUserAvatar: "アイコンを解除" +unsetUserAvatarConfirm: "アイコンを解除しますか?" +unsetUserBanner: "バナーを解除" +unsetUserBannerConfirm: "バナーを解除しますか?" deleteAllFiles: "すべてのファイルを削除" deleteAllFilesConfirm: "すべてのファイルを削除しますか?" removeAllFollowing: "フォローを全解除" @@ -2347,6 +2347,8 @@ _moderationLogTypes: createAvatarDecoration: "アイコンデコレーションを作成" updateAvatarDecoration: "アイコンデコレーションを更新" deleteAvatarDecoration: "アイコンデコレーションを削除" + unsetUserAvatar: "ユーザーのアイコンを解除" + unsetUserBanner: "ユーザーのバナーを解除" _fileViewer: title: "ファイルの詳細" diff --git a/package.json b/package.json index 67aefc45d2..60a3d10fd3 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "js-yaml": "4.1.0", "postcss": "8.4.31", "terser": "5.24.0", - "typescript": "5.2.2" + "typescript": "5.3.2" }, "devDependencies": { "@typescript-eslint/eslint-plugin": "6.11.0", diff --git a/packages/backend/migration/1700303245007-supportVerifyMailApi.js b/packages/backend/migration/1700303245007-supportVerifyMailApi.js new file mode 100644 index 0000000000..3ac59ec37a --- /dev/null +++ b/packages/backend/migration/1700303245007-supportVerifyMailApi.js @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class SupportVerifyMailApi1700303245007 { + name = 'SupportVerifyMailApi1700303245007' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "verifymailAuthKey" character varying(1024)`); + await queryRunner.query(`ALTER TABLE "meta" ADD "enableVerifymailApi" boolean NOT NULL DEFAULT false`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableVerifymailApi"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "verifymailAuthKey"`); + } +} diff --git a/packages/backend/package.json b/packages/backend/package.json index a4856709c3..3b029a49d2 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -7,8 +7,8 @@ "node": ">=18.16.0" }, "scripts": { - "start": "node ./built/index.js", - "start:test": "NODE_ENV=test node ./built/index.js", + "start": "node ./built/boot/entry.js", + "start:test": "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", @@ -165,7 +165,7 @@ "tsconfig-paths": "4.2.0", "twemoji-parser": "14.0.0", "typeorm": "0.3.17", - "typescript": "5.2.2", + "typescript": "5.3.2", "ulid": "2.3.0", "vary": "1.1.2", "web-push": "3.6.6", diff --git a/packages/backend/src/core/AntennaService.ts b/packages/backend/src/core/AntennaService.ts index cd1f32cc00..a6c9345032 100644 --- a/packages/backend/src/core/AntennaService.ts +++ b/packages/backend/src/core/AntennaService.ts @@ -61,12 +61,23 @@ export class AntennaService implements OnApplicationShutdown { lastUsedAt: new Date(body.lastUsedAt), }); break; - case 'antennaUpdated': - this.antennas[this.antennas.findIndex(a => a.id === body.id)] = { - ...body, - createdAt: new Date(body.createdAt), - lastUsedAt: new Date(body.lastUsedAt), - }; + case 'antennaUpdated': { + const idx = this.antennas.findIndex(a => a.id === body.id); + if (idx >= 0) { + this.antennas[idx] = { + ...body, + createdAt: new Date(body.createdAt), + lastUsedAt: new Date(body.lastUsedAt), + }; + } else { + // サーバ起動時にactiveじゃなかった場合、リストに持っていないので追加する必要あり + this.antennas.push({ + ...body, + createdAt: new Date(body.createdAt), + lastUsedAt: new Date(body.lastUsedAt), + }); + } + } break; case 'antennaDeleted': this.antennas = this.antennas.filter(a => a.id !== body.id); diff --git a/packages/backend/src/core/EmailService.ts b/packages/backend/src/core/EmailService.ts index c9da3f77c0..f31cec2b3a 100644 --- a/packages/backend/src/core/EmailService.ts +++ b/packages/backend/src/core/EmailService.ts @@ -3,9 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +import { URLSearchParams } from 'node:url'; import * as nodemailer from 'nodemailer'; import { Inject, Injectable } from '@nestjs/common'; import { validate as validateEmail } from 'deep-email-validator'; +import { SubOutputFormat } from 'deep-email-validator/dist/output/output.js'; import { MetaService } from '@/core/MetaService.js'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; @@ -13,6 +15,7 @@ import type Logger from '@/logger.js'; import type { UserProfilesRepository } from '@/models/_.js'; import { LoggerService } from '@/core/LoggerService.js'; import { bindThis } from '@/decorators.js'; +import { HttpRequestService } from '@/core/HttpRequestService.js'; @Injectable() export class EmailService { @@ -27,6 +30,7 @@ export class EmailService { private metaService: MetaService, private loggerService: LoggerService, + private httpRequestService: HttpRequestService, ) { this.logger = this.loggerService.getLogger('email'); } @@ -160,14 +164,25 @@ export class EmailService { email: emailAddress, }); - const validated = meta.enableActiveEmailValidation ? await validateEmail({ - email: emailAddress, - validateRegex: true, - validateMx: true, - validateTypo: false, // TLDを見ているみたいだけどclubとか弾かれるので - validateDisposable: true, // 捨てアドかどうかチェック - validateSMTP: false, // 日本だと25ポートが殆どのプロバイダーで塞がれていてタイムアウトになるので - }) : { valid: true, reason: null }; + const verifymailApi = meta.enableVerifymailApi && meta.verifymailAuthKey != null; + let validated; + + if (meta.enableActiveEmailValidation && meta.verifymailAuthKey) { + if (verifymailApi) { + validated = await this.verifyMail(emailAddress, meta.verifymailAuthKey); + } else { + validated = meta.enableActiveEmailValidation ? await validateEmail({ + email: emailAddress, + validateRegex: true, + validateMx: true, + validateTypo: false, // TLDを見ているみたいだけどclubとか弾かれるので + validateDisposable: true, // 捨てアドかどうかチェック + validateSMTP: false, // 日本だと25ポートが殆どのプロバイダーで塞がれていてタイムアウトになるので + }) : { valid: true, reason: null }; + } + } else { + validated = { valid: true, reason: null }; + } const available = exist === 0 && validated.valid; @@ -182,4 +197,65 @@ export class EmailService { null, }; } + + private async verifyMail(emailAddress: string, verifymailAuthKey: string): Promise<{ + valid: boolean; + reason: 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | null; + }> { + const endpoint = 'https://verifymail.io/api/' + emailAddress + '?key=' + verifymailAuthKey; + const res = await this.httpRequestService.send(endpoint, { + method: 'GET', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Accept: 'application/json, */*', + }, + }); + + const json = (await res.json()) as { + block: boolean; + catch_all: boolean; + deliverable_email: boolean; + disposable: boolean; + domain: string; + email_address: string; + email_provider: string; + mx: boolean; + mx_fallback: boolean; + mx_host: string[]; + mx_ip: string[]; + mx_priority: { [key: string]: number }; + privacy: boolean; + related_domains: string[]; + }; + + if (json.email_address === undefined) { + return { + valid: false, + reason: 'format', + }; + } + if (json.deliverable_email !== undefined && !json.deliverable_email) { + return { + valid: false, + reason: 'smtp', + }; + } + if (json.disposable) { + return { + valid: false, + reason: 'disposable', + }; + } + if (json.mx !== undefined && !json.mx) { + return { + valid: false, + reason: 'mx', + }; + } + + return { + valid: true, + reason: null, + }; + } } diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts index b9e5e28297..86c9bd156b 100644 --- a/packages/backend/src/core/entities/NotificationEntityService.ts +++ b/packages/backend/src/core/entities/NotificationEntityService.ts @@ -177,7 +177,7 @@ export class NotificationEntityService implements OnModuleInit { ) : undefined; if (notification.type === 'reaction:grouped') { - const reactions = await Promise.all(notification.reactions.map(async reaction => { + const reactions = await Promise.allSettled(notification.reactions.map(async reaction => { const user = hint?.packedUsers != null ? hint.packedUsers.get(reaction.userId)! : await this.userEntityService.pack(reaction.userId, { id: meId }, { @@ -193,23 +193,27 @@ export class NotificationEntityService implements OnModuleInit { createdAt: new Date(notification.createdAt).toISOString(), type: notification.type, note: noteIfNeed, - reactions, + reactions: reactions.filter(result => result.status === 'fulfilled') + .map(result => (result as PromiseFulfilledResult<{ user: Packed<'User'>; reaction: string; }>).value), }); } else if (notification.type === 'renote:grouped') { - const users = await Promise.all(notification.userIds.map(userId => { - const user = hint?.packedUsers != null - ? hint.packedUsers.get(userId) - : this.userEntityService.pack(userId!, { id: meId }, { - detail: false, - }); - return user; + const users = await Promise.allSettled(notification.userIds.map(userId => { + const packedUser = hint?.packedUsers != null ? hint.packedUsers.get(userId) : null; + if (packedUser) { + return packedUser; + } + + return this.userEntityService.pack(userId, { id: meId }, { + detail: false, + }); })); return await awaitAll({ id: notification.id, createdAt: new Date(notification.createdAt).toISOString(), type: notification.type, note: noteIfNeed, - users, + users: users.filter(result => result.status === 'fulfilled') + .map(result => (result as PromiseFulfilledResult>).value), }); } @@ -278,9 +282,11 @@ export class NotificationEntityService implements OnModuleInit { validNotifications = validNotifications.filter(x => (x.type !== 'receiveFollowRequest') || reqs.some(r => r.followerId === x.notifierId)); } - return await Promise.all(validNotifications.map(x => this.packGrouped(x, meId, {}, { + return (await Promise.allSettled(validNotifications.map(x => this.packGrouped(x, meId, {}, { packedNotes, packedUsers, - }))); + })))) + .filter(result => result.status === 'fulfilled') + .map(result => (result as PromiseFulfilledResult>).value); } } diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index d0ed87e7e5..7496251575 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -446,6 +446,17 @@ export class MiMeta { }) public enableActiveEmailValidation: boolean; + @Column('boolean', { + default: false, + }) + public enableVerifymailApi: boolean; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public verifymailAuthKey: string | null; + @Column('boolean', { default: true, }) diff --git a/packages/backend/src/models/json-schema/announcement.ts b/packages/backend/src/models/json-schema/announcement.ts index fdeea862ef..4ef738cbab 100644 --- a/packages/backend/src/models/json-schema/announcement.ts +++ b/packages/backend/src/models/json-schema/announcement.ts @@ -42,11 +42,11 @@ export const packedAnnouncementSchema = { type: 'string', optional: false, nullable: false, }, - forYou: { + needConfirmationToRead: { type: 'boolean', optional: false, nullable: false, }, - needConfirmationToRead: { + forYou: { type: 'boolean', optional: false, nullable: false, }, diff --git a/packages/backend/src/models/json-schema/channel.ts b/packages/backend/src/models/json-schema/channel.ts index 8f9770cdc5..5b0fa0f15d 100644 --- a/packages/backend/src/models/json-schema/channel.ts +++ b/packages/backend/src/models/json-schema/channel.ts @@ -19,7 +19,7 @@ export const packedChannelSchema = { }, lastNotedAt: { type: 'string', - optional: false, nullable: true, + nullable: true, optional: false, format: 'date-time', }, name: { @@ -28,38 +28,18 @@ export const packedChannelSchema = { }, description: { type: 'string', - nullable: true, optional: false, - }, - bannerUrl: { - type: 'string', - format: 'url', - nullable: true, optional: false, - }, - isArchived: { - type: 'boolean', - optional: false, nullable: false, - }, - notesCount: { - type: 'number', - nullable: false, optional: false, - }, - usersCount: { - type: 'number', - nullable: false, optional: false, - }, - isFollowing: { - type: 'boolean', - optional: true, nullable: false, - }, - isFavorited: { - type: 'boolean', - optional: true, nullable: false, + optional: false, nullable: true, }, userId: { type: 'string', nullable: true, optional: false, format: 'id', }, + bannerUrl: { + type: 'string', + format: 'url', + nullable: true, optional: false, + }, pinnedNoteIds: { type: 'array', nullable: false, optional: false, @@ -72,6 +52,18 @@ export const packedChannelSchema = { type: 'string', optional: false, nullable: false, }, + isArchived: { + type: 'boolean', + optional: false, nullable: false, + }, + usersCount: { + type: 'number', + nullable: false, optional: false, + }, + notesCount: { + type: 'number', + nullable: false, optional: false, + }, isSensitive: { type: 'boolean', optional: false, nullable: false, @@ -80,5 +72,22 @@ export const packedChannelSchema = { type: 'boolean', optional: false, nullable: false, }, + isFollowing: { + type: 'boolean', + optional: true, nullable: false, + }, + isFavorited: { + type: 'boolean', + optional: true, nullable: false, + }, + pinnedNotes: { + type: 'array', + optional: true, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + ref: 'Note', + }, + }, }, } as const; diff --git a/packages/backend/src/models/json-schema/clip.ts b/packages/backend/src/models/json-schema/clip.ts index 64f7a2ad9c..1ab96c2b3b 100644 --- a/packages/backend/src/models/json-schema/clip.ts +++ b/packages/backend/src/models/json-schema/clip.ts @@ -44,13 +44,13 @@ export const packedClipSchema = { type: 'boolean', optional: false, nullable: false, }, - isFavorited: { - type: 'boolean', - optional: true, nullable: false, - }, favoritedCount: { type: 'number', optional: false, nullable: false, }, + isFavorited: { + type: 'boolean', + optional: true, nullable: false, + }, }, } as const; diff --git a/packages/backend/src/models/json-schema/drive-file.ts b/packages/backend/src/models/json-schema/drive-file.ts index 87f1340812..79f242a711 100644 --- a/packages/backend/src/models/json-schema/drive-file.ts +++ b/packages/backend/src/models/json-schema/drive-file.ts @@ -74,7 +74,7 @@ export const packedDriveFileSchema = { }, url: { type: 'string', - optional: false, nullable: true, + optional: false, nullable: false, format: 'url', }, thumbnailUrl: { diff --git a/packages/backend/src/models/json-schema/drive-folder.ts b/packages/backend/src/models/json-schema/drive-folder.ts index 51107d423f..aaad301303 100644 --- a/packages/backend/src/models/json-schema/drive-folder.ts +++ b/packages/backend/src/models/json-schema/drive-folder.ts @@ -21,6 +21,12 @@ export const packedDriveFolderSchema = { type: 'string', optional: false, nullable: false, }, + parentId: { + type: 'string', + optional: false, nullable: true, + format: 'id', + example: 'xxxxxxxxxx', + }, foldersCount: { type: 'number', optional: true, nullable: false, @@ -29,12 +35,6 @@ export const packedDriveFolderSchema = { type: 'number', optional: true, nullable: false, }, - parentId: { - type: 'string', - optional: false, nullable: true, - format: 'id', - example: 'xxxxxxxxxx', - }, parent: { type: 'object', optional: true, 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 442e1076f2..3417314272 100644 --- a/packages/backend/src/models/json-schema/federation-instance.ts +++ b/packages/backend/src/models/json-schema/federation-instance.ts @@ -79,6 +79,10 @@ export const packedFederationInstanceSchema = { type: 'string', optional: false, nullable: true, }, + isSilenced: { + type: 'boolean', + optional: false, nullable: false, + }, iconUrl: { type: 'string', optional: false, nullable: true, @@ -93,11 +97,6 @@ export const packedFederationInstanceSchema = { type: 'string', optional: false, nullable: true, }, - isSilenced: { - type: "boolean", - optional: false, - nullable: false, - }, infoUpdatedAt: { type: 'string', optional: false, nullable: true, diff --git a/packages/backend/src/models/json-schema/flash.ts b/packages/backend/src/models/json-schema/flash.ts index 64b6f59811..3ad3a11c9e 100644 --- a/packages/backend/src/models/json-schema/flash.ts +++ b/packages/backend/src/models/json-schema/flash.ts @@ -22,6 +22,16 @@ export const packedFlashSchema = { optional: false, nullable: false, format: 'date-time', }, + userId: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + user: { + type: 'object', + ref: 'UserLite', + optional: false, nullable: false, + }, title: { type: 'string', optional: false, nullable: false, @@ -34,16 +44,6 @@ export const packedFlashSchema = { type: 'string', optional: false, nullable: false, }, - userId: { - type: 'string', - optional: false, nullable: false, - format: 'id', - }, - user: { - type: 'object', - ref: 'UserLite', - optional: false, nullable: false, - }, likedCount: { type: 'number', optional: false, nullable: true, diff --git a/packages/backend/src/models/json-schema/following.ts b/packages/backend/src/models/json-schema/following.ts index 93f1de4123..a948a24b6a 100644 --- a/packages/backend/src/models/json-schema/following.ts +++ b/packages/backend/src/models/json-schema/following.ts @@ -22,16 +22,16 @@ export const packedFollowingSchema = { optional: false, nullable: false, format: 'id', }, - followee: { - type: 'object', - optional: true, nullable: false, - ref: 'UserDetailed', - }, followerId: { type: 'string', optional: false, nullable: false, format: 'id', }, + followee: { + type: 'object', + optional: true, nullable: false, + ref: 'UserDetailed', + }, follower: { type: 'object', optional: true, nullable: false, diff --git a/packages/backend/src/models/json-schema/gallery.ts b/packages/backend/src/models/json-schema/gallery.ts index 679261d76f..3e71a1fcb1 100644 --- a/packages/backend/src/models/json-schema/gallery.ts +++ b/packages/backend/src/models/json-schema/gallery.ts @@ -22,14 +22,6 @@ export const packedGalleryPostSchema = { optional: false, nullable: false, format: 'date-time', }, - title: { - type: 'string', - optional: false, nullable: false, - }, - description: { - type: 'string', - optional: false, nullable: true, - }, userId: { type: 'string', optional: false, nullable: false, @@ -40,6 +32,14 @@ export const packedGalleryPostSchema = { ref: 'UserLite', optional: false, nullable: false, }, + title: { + type: 'string', + optional: false, nullable: false, + }, + description: { + type: 'string', + optional: false, nullable: true, + }, fileIds: { type: 'array', optional: true, nullable: false, @@ -70,6 +70,14 @@ export const packedGalleryPostSchema = { type: 'boolean', optional: false, nullable: false, }, + likedCount: { + type: 'number', + optional: false, nullable: false, + }, + isLiked: { + type: 'boolean', + optional: true, nullable: false, + }, }, } as const; diff --git a/packages/backend/src/models/json-schema/note.ts b/packages/backend/src/models/json-schema/note.ts index 38c0054b55..392fa7e1cb 100644 --- a/packages/backend/src/models/json-schema/note.ts +++ b/packages/backend/src/models/json-schema/note.ts @@ -127,22 +127,26 @@ export const packedNoteSchema = { channel: { type: 'object', optional: true, nullable: true, - items: { - type: 'object', - optional: false, nullable: false, - properties: { - id: { - type: 'string', - optional: false, nullable: false, - }, - name: { - type: 'string', - optional: false, nullable: true, - }, - isSensitive: { - type: 'boolean', - optional: true, nullable: false, - }, + properties: { + id: { + type: 'string', + optional: false, nullable: false, + }, + name: { + type: 'string', + optional: false, nullable: false, + }, + color: { + type: 'string', + optional: false, nullable: false, + }, + isSensitive: { + type: 'boolean', + optional: false, nullable: false, + }, + allowRenoteToExternal: { + type: 'boolean', + optional: false, nullable: false, }, }, }, diff --git a/packages/backend/src/models/json-schema/notification.ts b/packages/backend/src/models/json-schema/notification.ts index 27db3bb62c..c6d6e84317 100644 --- a/packages/backend/src/models/json-schema/notification.ts +++ b/packages/backend/src/models/json-schema/notification.ts @@ -42,13 +42,9 @@ export const packedNotificationSchema = { type: 'string', optional: true, nullable: true, }, - choice: { - type: 'number', - optional: true, nullable: true, - }, - invitation: { - type: 'object', - optional: true, nullable: true, + achievement: { + type: 'string', + optional: true, nullable: false, }, body: { type: 'string', @@ -81,14 +77,14 @@ export const packedNotificationSchema = { required: ['user', 'reaction'], }, }, - }, - users: { - type: 'array', - optional: true, nullable: true, - items: { - type: 'object', - ref: 'UserLite', - optional: false, nullable: false, + users: { + type: 'array', + optional: true, nullable: true, + items: { + type: 'object', + ref: 'UserLite', + optional: false, nullable: false, + }, }, }, } as const; diff --git a/packages/backend/src/models/json-schema/page.ts b/packages/backend/src/models/json-schema/page.ts index 98ec53065d..b022f9651e 100644 --- a/packages/backend/src/models/json-schema/page.ts +++ b/packages/backend/src/models/json-schema/page.ts @@ -22,6 +22,32 @@ export const packedPageSchema = { optional: false, nullable: false, format: 'date-time', }, + userId: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + user: { + type: 'object', + ref: 'UserLite', + optional: false, nullable: false, + }, + content: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + }, + }, + variables: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + }, + }, title: { type: 'string', optional: false, nullable: false, @@ -34,24 +60,48 @@ export const packedPageSchema = { type: 'string', optional: false, nullable: true, }, - content: { - type: 'array', + hideTitleWhenPinned: { + type: 'boolean', optional: false, nullable: false, }, - variables: { - type: 'array', + alignCenter: { + type: 'boolean', optional: false, nullable: false, }, - userId: { + font: { type: 'string', optional: false, nullable: false, - format: 'id', }, - user: { - type: 'object', - ref: 'UserLite', + script: { + type: 'string', optional: false, nullable: false, }, + eyeCatchingImageId: { + type: 'string', + optional: false, nullable: true, + }, + eyeCatchingImage: { + type: 'object', + optional: false, nullable: true, + ref: 'DriveFile', + }, + attachedFiles: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + ref: 'DriveFile', + }, + }, + likedCount: { + type: 'number', + optional: false, nullable: false, + }, + isLiked: { + type: 'boolean', + optional: true, nullable: false, + }, }, } as const; diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index ac6968120b..c63fac54bf 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -49,11 +49,6 @@ export const packedUserLiteSchema = { nullable: false, optional: false, format: 'id', }, - url: { - type: 'string', - format: 'url', - nullable: false, optional: false, - }, angle: { type: 'number', nullable: false, optional: true, @@ -62,19 +57,14 @@ export const packedUserLiteSchema = { type: 'boolean', nullable: false, optional: true, }, + url: { + type: 'string', + format: 'url', + nullable: false, optional: false, + }, }, }, }, - isAdmin: { - type: 'boolean', - nullable: false, optional: true, - default: false, - }, - isModerator: { - type: 'boolean', - nullable: false, optional: true, - default: false, - }, isBot: { type: 'boolean', nullable: false, optional: true, @@ -83,12 +73,67 @@ export const packedUserLiteSchema = { type: 'boolean', nullable: false, optional: true, }, + instance: { + type: 'object', + nullable: false, optional: true, + properties: { + name: { + type: 'string', + nullable: true, optional: false, + }, + softwareName: { + type: 'string', + nullable: true, optional: false, + }, + softwareVersion: { + type: 'string', + nullable: true, optional: false, + }, + iconUrl: { + type: 'string', + nullable: true, optional: false, + }, + faviconUrl: { + type: 'string', + nullable: true, optional: false, + }, + themeColor: { + type: 'string', + nullable: true, optional: false, + }, + }, + }, + emojis: { + type: 'object', + nullable: false, optional: false, + }, onlineStatus: { type: 'string', - format: 'url', - nullable: true, optional: false, + nullable: false, optional: false, enum: ['unknown', 'online', 'active', 'offline'], }, + badgeRoles: { + type: 'array', + nullable: false, optional: true, + items: { + type: 'object', + nullable: false, optional: false, + properties: { + name: { + type: 'string', + nullable: false, optional: false, + }, + iconUrl: { + type: 'string', + nullable: true, optional: false, + }, + displayOrder: { + type: 'number', + nullable: false, optional: false, + }, + }, + }, + }, }, } as const; @@ -105,21 +150,18 @@ export const packedUserDetailedNotMeOnlySchema = { format: 'uri', nullable: true, optional: false, }, - movedToUri: { + movedTo: { type: 'string', format: 'uri', - nullable: true, - optional: false, + nullable: true, optional: false, }, alsoKnownAs: { type: 'array', - nullable: true, - optional: false, + nullable: true, optional: false, items: { type: 'string', format: 'id', - nullable: false, - optional: false, + nullable: false, optional: false, }, }, createdAt: { @@ -253,6 +295,11 @@ export const packedUserDetailedNotMeOnlySchema = { type: 'boolean', nullable: false, optional: false, }, + ffVisibility: { + type: 'string', + nullable: false, optional: false, + enum: ['public', 'followers', 'private'], + }, twoFactorEnabled: { type: 'boolean', nullable: false, optional: false, @@ -268,6 +315,57 @@ export const packedUserDetailedNotMeOnlySchema = { nullable: false, optional: false, default: false, }, + roles: { + type: 'array', + nullable: false, optional: false, + items: { + type: 'object', + nullable: false, optional: false, + properties: { + id: { + type: 'string', + nullable: false, optional: false, + format: 'id', + }, + name: { + type: 'string', + nullable: false, optional: false, + }, + color: { + type: 'string', + nullable: true, optional: false, + }, + iconUrl: { + type: 'string', + nullable: true, optional: false, + }, + description: { + type: 'string', + nullable: false, optional: false, + }, + isModerator: { + type: 'boolean', + nullable: false, optional: false, + }, + isAdministrator: { + type: 'boolean', + nullable: false, optional: false, + }, + displayOrder: { + type: 'number', + nullable: false, optional: false, + }, + }, + }, + }, + memo: { + type: 'string', + nullable: true, optional: false, + }, + moderationNote: { + type: 'string', + nullable: false, optional: true, + }, //#region relations isFollowing: { type: 'boolean', @@ -301,10 +399,6 @@ export const packedUserDetailedNotMeOnlySchema = { type: 'boolean', nullable: false, optional: true, }, - memo: { - type: 'string', - nullable: false, optional: true, - }, notify: { type: 'string', nullable: false, optional: true, @@ -330,29 +424,37 @@ export const packedMeDetailedOnlySchema = { nullable: true, optional: false, format: 'id', }, - injectFeaturedNote: { + isModerator: { type: 'boolean', nullable: true, optional: false, }, + isAdmin: { + type: 'boolean', + nullable: true, optional: false, + }, + injectFeaturedNote: { + type: 'boolean', + nullable: false, optional: false, + }, receiveAnnouncementEmail: { type: 'boolean', - nullable: true, optional: false, + nullable: false, optional: false, }, alwaysMarkNsfw: { type: 'boolean', - nullable: true, optional: false, + nullable: false, optional: false, }, autoSensitive: { type: 'boolean', - nullable: true, optional: false, + nullable: false, optional: false, }, carefulBot: { type: 'boolean', - nullable: true, optional: false, + nullable: false, optional: false, }, autoAcceptFollowed: { type: 'boolean', - nullable: true, optional: false, + nullable: false, optional: false, }, noCrawle: { type: 'boolean', @@ -391,10 +493,23 @@ export const packedMeDetailedOnlySchema = { type: 'boolean', nullable: false, optional: false, }, + unreadAnnouncements: { + type: 'array', + nullable: false, optional: false, + items: { + type: 'object', + nullable: false, optional: false, + ref: 'Announcement', + }, + }, hasUnreadAntenna: { type: 'boolean', nullable: false, optional: false, }, + hasUnreadChannel: { + type: 'boolean', + nullable: false, optional: false, + }, hasUnreadNotification: { type: 'boolean', nullable: false, optional: false, @@ -433,12 +548,132 @@ export const packedMeDetailedOnlySchema = { }, emailNotificationTypes: { type: 'array', - nullable: true, optional: false, + nullable: false, optional: false, items: { type: 'string', nullable: false, optional: false, }, }, + achievements: { + type: 'array', + nullable: false, optional: false, + items: { + type: 'object', + nullable: false, optional: false, + properties: { + name: { + type: 'string', + nullable: false, optional: false, + }, + unlockedAt: { + type: 'number', + nullable: false, optional: false, + }, + }, + }, + }, + loggedInDays: { + type: 'number', + nullable: false, optional: false, + }, + policies: { + type: 'object', + nullable: false, optional: false, + properties: { + gtlAvailable: { + type: 'boolean', + nullable: false, optional: false, + }, + ltlAvailable: { + type: 'boolean', + nullable: false, optional: false, + }, + canPublicNote: { + type: 'boolean', + nullable: false, optional: false, + }, + canInvite: { + type: 'boolean', + nullable: false, optional: false, + }, + inviteLimit: { + type: 'number', + nullable: false, optional: false, + }, + inviteLimitCycle: { + type: 'number', + nullable: false, optional: false, + }, + inviteExpirationTime: { + type: 'number', + nullable: false, optional: false, + }, + canManageCustomEmojis: { + type: 'boolean', + nullable: false, optional: false, + }, + canManageAvatarDecorations: { + type: 'boolean', + nullable: false, optional: false, + }, + canSearchNotes: { + type: 'boolean', + nullable: false, optional: false, + }, + canUseTranslator: { + type: 'boolean', + nullable: false, optional: false, + }, + canHideAds: { + type: 'boolean', + nullable: false, optional: false, + }, + driveCapacityMb: { + type: 'number', + nullable: false, optional: false, + }, + alwaysMarkNsfw: { + type: 'boolean', + nullable: false, optional: false, + }, + pinLimit: { + type: 'number', + nullable: false, optional: false, + }, + antennaLimit: { + type: 'number', + nullable: false, optional: false, + }, + wordMuteLimit: { + type: 'number', + nullable: false, optional: false, + }, + webhookLimit: { + type: 'number', + nullable: false, optional: false, + }, + clipLimit: { + type: 'number', + nullable: false, optional: false, + }, + noteEachClipsLimit: { + type: 'number', + nullable: false, optional: false, + }, + userListLimit: { + type: 'number', + nullable: false, optional: false, + }, + userEachUserListsLimit: { + type: 'number', + nullable: false, optional: false, + }, + rateLimitFactor: { + type: 'number', + nullable: false, optional: false, + }, + }, + }, //#region secrets email: { type: 'string', @@ -515,5 +750,13 @@ export const packedUserSchema = { type: 'object', ref: 'UserDetailed', }, + { + type: 'object', + ref: 'UserDetailedNotMe', + }, + { + type: 'object', + ref: 'MeDetailed', + }, ], } as const; diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index 89ee3ebaac..c96fd9de30 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -28,8 +28,8 @@ import * as ep___admin_avatarDecorations_delete from './endpoints/admin/avatar-d import * as ep___admin_avatarDecorations_list from './endpoints/admin/avatar-decorations/list.js'; import * as ep___admin_avatarDecorations_update from './endpoints/admin/avatar-decorations/update.js'; import * as ep___admin_deleteAllFilesOfAUser from './endpoints/admin/delete-all-files-of-a-user.js'; -import * as ep___admin_deleteUserAvatar from './endpoints/admin/delete-user-avatar.js'; -import * as ep___admin_deleteUserBanner from './endpoints/admin/delete-user-banner.js'; +import * as ep___admin_unsetUserAvatar from './endpoints/admin/unset-user-avatar.js'; +import * as ep___admin_unsetUserBanner from './endpoints/admin/unset-user-banner.js'; import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js'; import * as ep___admin_drive_cleanup from './endpoints/admin/drive/cleanup.js'; import * as ep___admin_drive_files from './endpoints/admin/drive/files.js'; @@ -393,8 +393,8 @@ const $admin_avatarDecorations_delete: Provider = { provide: 'ep:admin/avatar-de const $admin_avatarDecorations_list: Provider = { provide: 'ep:admin/avatar-decorations/list', useClass: ep___admin_avatarDecorations_list.default }; const $admin_avatarDecorations_update: Provider = { provide: 'ep:admin/avatar-decorations/update', useClass: ep___admin_avatarDecorations_update.default }; const $admin_deleteAllFilesOfAUser: Provider = { provide: 'ep:admin/delete-all-files-of-a-user', useClass: ep___admin_deleteAllFilesOfAUser.default }; -const $admin_deleteUserAvatar: Provider = { provide: 'ep:admin/delete-user-avatar', useClass: ep___admin_deleteUserAvatar.default }; -const $admin_deleteUserBanner: Provider = { provide: 'ep:admin/delete-user-banner', useClass: ep___admin_deleteUserBanner.default }; +const $admin_unsetUserAvatar: Provider = { provide: 'ep:admin/unset-user-avatar', useClass: ep___admin_unsetUserAvatar.default }; +const $admin_unsetUserBanner: Provider = { provide: 'ep:admin/unset-user-banner', useClass: ep___admin_unsetUserBanner.default }; const $admin_drive_cleanRemoteFiles: Provider = { provide: 'ep:admin/drive/clean-remote-files', useClass: ep___admin_drive_cleanRemoteFiles.default }; const $admin_drive_cleanup: Provider = { provide: 'ep:admin/drive/cleanup', useClass: ep___admin_drive_cleanup.default }; const $admin_drive_files: Provider = { provide: 'ep:admin/drive/files', useClass: ep___admin_drive_files.default }; @@ -762,8 +762,8 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $admin_avatarDecorations_list, $admin_avatarDecorations_update, $admin_deleteAllFilesOfAUser, - $admin_deleteUserAvatar, - $admin_deleteUserBanner, + $admin_unsetUserAvatar, + $admin_unsetUserBanner, $admin_drive_cleanRemoteFiles, $admin_drive_cleanup, $admin_drive_files, @@ -1125,8 +1125,8 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $admin_avatarDecorations_list, $admin_avatarDecorations_update, $admin_deleteAllFilesOfAUser, - $admin_deleteUserAvatar, - $admin_deleteUserBanner, + $admin_unsetUserAvatar, + $admin_unsetUserBanner, $admin_drive_cleanRemoteFiles, $admin_drive_cleanup, $admin_drive_files, diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 45d051b5b6..2fa53f0e57 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -28,8 +28,8 @@ import * as ep___admin_avatarDecorations_delete from './endpoints/admin/avatar-d import * as ep___admin_avatarDecorations_list from './endpoints/admin/avatar-decorations/list.js'; import * as ep___admin_avatarDecorations_update from './endpoints/admin/avatar-decorations/update.js'; import * as ep___admin_deleteAllFilesOfAUser from './endpoints/admin/delete-all-files-of-a-user.js'; -import * as ep___admin_deleteUserAvatar from './endpoints/admin/delete-user-avatar.js'; -import * as ep___admin_deleteUserBanner from './endpoints/admin/delete-user-banner.js'; +import * as ep___admin_unsetUserAvatar from './endpoints/admin/unset-user-avatar.js'; +import * as ep___admin_unsetUserBanner from './endpoints/admin/unset-user-banner.js'; import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js'; import * as ep___admin_drive_cleanup from './endpoints/admin/drive/cleanup.js'; import * as ep___admin_drive_files from './endpoints/admin/drive/files.js'; @@ -391,8 +391,8 @@ const eps = [ ['admin/avatar-decorations/list', ep___admin_avatarDecorations_list], ['admin/avatar-decorations/update', ep___admin_avatarDecorations_update], ['admin/delete-all-files-of-a-user', ep___admin_deleteAllFilesOfAUser], - ['admin/delete-user-avatar', ep___admin_deleteUserAvatar], - ['admin/delete-user-banner', ep___admin_deleteUserBanner], + ['admin/unset-user-avatar', ep___admin_unsetUserAvatar], + ['admin/unset-user-banner', ep___admin_unsetUserBanner], ['admin/drive/clean-remote-files', ep___admin_drive_cleanRemoteFiles], ['admin/drive/cleanup', ep___admin_drive_cleanup], ['admin/drive/files', ep___admin_drive_files], diff --git a/packages/backend/src/server/api/endpoints/admin/delete-user-avatar.ts b/packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts similarity index 77% rename from packages/backend/src/server/api/endpoints/admin/delete-user-avatar.ts rename to packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts index d3c78d7fb6..79715d43b8 100644 --- a/packages/backend/src/server/api/endpoints/admin/delete-user-avatar.ts +++ b/packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts @@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common'; import type { UsersRepository } from '@/models/_.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { DI } from '@/di-symbols.js'; +import { ModerationLogService } from '@/core/ModerationLogService.js'; export const meta = { tags: ['admin'], @@ -29,6 +30,8 @@ export default class extends Endpoint { constructor( @Inject(DI.usersRepository) private usersRepository: UsersRepository, + + private moderationLogService: ModerationLogService, ) { super(meta, paramDef, async (ps, me) => { const user = await this.usersRepository.findOneBy({ id: ps.userId }); @@ -37,12 +40,21 @@ export default class extends Endpoint { throw new Error('user not found'); } + if (user.avatarId == null) return; + await this.usersRepository.update(user.id, { avatar: null, avatarId: null, avatarUrl: null, avatarBlurhash: null, }); + + this.moderationLogService.log(me, 'unsetUserAvatar', { + userId: user.id, + userUsername: user.username, + userHost: user.host, + fileId: user.avatarId, + }); }); } } diff --git a/packages/backend/src/server/api/endpoints/admin/delete-user-banner.ts b/packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts similarity index 77% rename from packages/backend/src/server/api/endpoints/admin/delete-user-banner.ts rename to packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts index e076cdcfc1..66acd367df 100644 --- a/packages/backend/src/server/api/endpoints/admin/delete-user-banner.ts +++ b/packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts @@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common'; import type { UsersRepository } from '@/models/_.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { DI } from '@/di-symbols.js'; +import { ModerationLogService } from '@/core/ModerationLogService.js'; export const meta = { tags: ['admin'], @@ -29,6 +30,8 @@ export default class extends Endpoint { constructor( @Inject(DI.usersRepository) private usersRepository: UsersRepository, + + private moderationLogService: ModerationLogService, ) { super(meta, paramDef, async (ps, me) => { const user = await this.usersRepository.findOneBy({ id: ps.userId }); @@ -37,12 +40,21 @@ export default class extends Endpoint { throw new Error('user not found'); } + if (user.bannerId == null) return; + await this.usersRepository.update(user.id, { banner: null, bannerId: null, bannerUrl: null, bannerBlurhash: null, }); + + this.moderationLogService.log(me, 'unsetUserBanner', { + userId: user.id, + userUsername: user.username, + userHost: user.host, + fileId: user.bannerId, + }); }); } } 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 17cae430a9..485ea2839e 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -113,6 +113,8 @@ export const paramDef = { objectStorageS3ForcePathStyle: { type: 'boolean' }, enableIpLogging: { type: 'boolean' }, enableActiveEmailValidation: { type: 'boolean' }, + enableVerifymailApi: { type: 'boolean' }, + verifymailAuthKey: { type: 'string', nullable: true }, enableChartsForRemoteUser: { type: 'boolean' }, enableChartsForFederatedInstances: { type: 'boolean' }, enableServerMachineStats: { type: 'boolean' }, @@ -462,6 +464,18 @@ export default class extends Endpoint { // eslint- set.enableActiveEmailValidation = ps.enableActiveEmailValidation; } + if (ps.enableVerifymailApi !== undefined) { + set.enableVerifymailApi = ps.enableVerifymailApi; + } + + if (ps.verifymailAuthKey !== undefined) { + if (ps.verifymailAuthKey === '') { + set.verifymailAuthKey = null; + } else { + set.verifymailAuthKey = ps.verifymailAuthKey; + } + } + if (ps.enableChartsForRemoteUser !== undefined) { set.enableChartsForRemoteUser = ps.enableChartsForRemoteUser; } diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts index 9b5911800c..29e56b1085 100644 --- a/packages/backend/src/server/api/endpoints/antennas/notes.ts +++ b/packages/backend/src/server/api/endpoints/antennas/notes.ts @@ -13,6 +13,7 @@ import { DI } from '@/di-symbols.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { IdService } from '@/core/IdService.js'; import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -71,6 +72,7 @@ export default class extends Endpoint { // eslint- private queryService: QueryService, private noteReadService: NoteReadService, private funoutTimelineService: FunoutTimelineService, + private globalEventService: GlobalEventService, ) { super(meta, paramDef, async (ps, me) => { const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null); @@ -85,10 +87,16 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.noSuchAntenna); } - this.antennasRepository.update(antenna.id, { - isActive: true, - lastUsedAt: new Date(), - }); + // falseだった場合はアンテナの配信先が増えたことを通知したい + const needPublishEvent = !antenna.isActive; + + antenna.isActive = true; + antenna.lastUsedAt = new Date(); + this.antennasRepository.update(antenna.id, antenna); + + if (needPublishEvent) { + this.globalEventService.publishInternalEvent('antennaUpdated', antenna); + } let noteIds = await this.funoutTimelineService.get(`antennaTimeline:${antenna.id}`, untilId, sinceId); noteIds = noteIds.slice(0, ps.limit); diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index e6dfeb6f8c..1fb3d6a6ce 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -63,6 +63,8 @@ export const moderationLogTypes = [ 'createAvatarDecoration', 'updateAvatarDecoration', 'deleteAvatarDecoration', + 'unsetUserAvatar', + 'unsetUserBanner', ] as const; export type ModerationLogPayloads = { @@ -237,6 +239,18 @@ export type ModerationLogPayloads = { avatarDecorationId: string; avatarDecoration: any; }; + unsetUserAvatar: { + userId: string; + userUsername: string; + userHost: string | null; + fileId: string; + }; + unsetUserBanner: { + userId: string; + userUsername: string; + userHost: string | null; + fileId: string; + }; }; export type Serialized = { diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 52a12ca039..7fcc562494 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -70,7 +70,7 @@ "tsc-alias": "1.8.8", "tsconfig-paths": "4.2.0", "twemoji-parser": "14.0.0", - "typescript": "5.2.2", + "typescript": "5.3.2", "uuid": "9.0.1", "v-code-diff": "1.7.2", "vanilla-tilt": "1.8.1", diff --git a/packages/frontend/src/components/MkPagePreview.vue b/packages/frontend/src/components/MkPagePreview.vue index 05b577c49c..6c8a0e56a6 100644 --- a/packages/frontend/src/components/MkPagePreview.vue +++ b/packages/frontend/src/components/MkPagePreview.vue @@ -114,7 +114,6 @@ const props = defineProps<{ & + article { left: 0; - width: 100%; } } } @@ -124,6 +123,7 @@ const props = defineProps<{ > .thumbnail { height: 80px; + overflow: clip; } > article { diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue index 0e428734ab..254dde5a96 100644 --- a/packages/frontend/src/pages/admin-user.vue +++ b/packages/frontend/src/pages/admin-user.vue @@ -123,12 +123,11 @@ SPDX-License-Identifier: AGPL-3.0-only - {{ i18n.ts.deleteAccount }} -
- {{ i18n.ts.deleteUserAvatar }} - {{ i18n.ts.deleteUserBanner }} + {{ i18n.ts.unsetUserAvatar }} + {{ i18n.ts.unsetUserBanner }}
+ {{ i18n.ts.deleteAccount }} @@ -330,14 +329,14 @@ async function toggleSuspend(v) { } } -async function deleteUserAvatar() { +async function unsetUserAvatar() { const confirm = await os.confirm({ type: 'warning', - text: i18n.ts.deleteUserAvatarConfirm, + text: i18n.ts.unsetUserAvatarConfirm, }); if (confirm.canceled) return; const process = async () => { - await os.api('admin/delete-user-avatar', { userId: user.id }); + await os.api('admin/unset-user-avatar', { userId: user.id }); os.success(); }; await process().catch(err => { @@ -349,14 +348,14 @@ async function deleteUserAvatar() { refreshUser(); } -async function deleteUserBanner() { +async function unsetUserBanner() { const confirm = await os.confirm({ type: 'warning', - text: i18n.ts.deleteUserBannerConfirm, + text: i18n.ts.unsetUserBannerConfirm, }); if (confirm.canceled) return; const process = async () => { - await os.api('admin/delete-user-banner', { userId: user.id }); + await os.api('admin/unset-user-banner', { userId: user.id }); os.success(); }; await process().catch(err => { diff --git a/packages/frontend/src/pages/admin/external-services.vue b/packages/frontend/src/pages/admin/external-services.vue index e88860166c..e614bfeb1b 100644 --- a/packages/frontend/src/pages/admin/external-services.vue +++ b/packages/frontend/src/pages/admin/external-services.vue @@ -38,6 +38,7 @@ import { } from 'vue'; import XHeader from './_header_.vue'; import MkInput from '@/components/MkInput.vue'; import MkButton from '@/components/MkButton.vue'; +import MkSwitch from '@/components/MkSwitch.vue'; import FormSuspense from '@/components/form/suspense.vue'; import FormSection from '@/components/form/section.vue'; import * as os from '@/os.js'; diff --git a/packages/frontend/src/pages/admin/security.vue b/packages/frontend/src/pages/admin/security.vue index a2594ee6c5..f7f76d910a 100644 --- a/packages/frontend/src/pages/admin/security.vue +++ b/packages/frontend/src/pages/admin/security.vue @@ -73,6 +73,13 @@ SPDX-License-Identifier: AGPL-3.0-only + + + + + + + @@ -132,6 +139,8 @@ let setSensitiveFlagAutomatically: boolean = $ref(false); let enableSensitiveMediaDetectionForVideos: boolean = $ref(false); let enableIpLogging: boolean = $ref(false); let enableActiveEmailValidation: boolean = $ref(false); +let enableVerifymailApi: boolean = $ref(false); +let verifymailAuthKey: string | null = $ref(null); async function init() { const meta = await os.api('admin/meta'); @@ -150,6 +159,8 @@ async function init() { enableSensitiveMediaDetectionForVideos = meta.enableSensitiveMediaDetectionForVideos; enableIpLogging = meta.enableIpLogging; enableActiveEmailValidation = meta.enableActiveEmailValidation; + enableVerifymailApi = meta.enableVerifymailApi; + verifymailAuthKey = meta.verifymailAuthKey; } function save() { @@ -167,6 +178,8 @@ function save() { enableSensitiveMediaDetectionForVideos, enableIpLogging, enableActiveEmailValidation, + enableVerifymailApi, + verifymailAuthKey, }).then(() => { fetchInstance(); }); diff --git a/packages/frontend/src/pages/settings/preferences-backups.vue b/packages/frontend/src/pages/settings/preferences-backups.vue index 3b3a6bd07d..35435238fc 100644 --- a/packages/frontend/src/pages/settings/preferences-backups.vue +++ b/packages/frontend/src/pages/settings/preferences-backups.vue @@ -54,22 +54,24 @@ import { miLocalStorage } from '@/local-storage.js'; const { t, ts } = i18n; const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [ + 'collapseRenotes', 'menu', 'visibility', 'localOnly', 'statusbars', 'widgets', 'tl', + 'pinnedUserLists', 'overridedDeviceKind', 'serverDisconnectedBehavior', - 'collapseRenotes', - 'showNoteActionsOnlyHover', 'nsfw', + 'highlightSensitiveMedia', 'animation', 'animatedMfm', 'advancedMfm', 'loadRawImages', 'imageNewTab', + 'enableDataSaverMode', 'disableShowingAnimatedImages', 'emojiStyle', 'disableDrawer', @@ -89,9 +91,28 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [ 'menuDisplay', 'reportError', 'squareAvatars', + 'showAvatarDecorations', 'numberOfPageCache', + 'showNoteActionsOnlyHover', + 'showClipButtonInNoteFooter', + 'reactionsDisplaySize', + 'forceShowAds', 'aiChanMode', + 'devMode', 'mediaListWithOneImageAppearance', + 'notificationPosition', + 'notificationStackAxis', + 'enableCondensedLineForAcct', + 'keepScreenOn', + 'defaultWithReplies', + 'disableStreamingTimeline', + 'useGroupedNotifications', + 'sound_masterVolume', + 'sound_note', + 'sound_noteMy', + 'sound_notification', + 'sound_antenna', + 'sound_channel', ]; const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [ 'lightTheme', diff --git a/packages/frontend/src/scripts/sound.ts b/packages/frontend/src/scripts/sound.ts index 9dd0e192d1..27e9b3e4dd 100644 --- a/packages/frontend/src/scripts/sound.ts +++ b/packages/frontend/src/scripts/sound.ts @@ -122,7 +122,7 @@ export const soundsTypes = [ 'Copyright_Misskey.io/ThinaticSystem/yonderuzo3', ] as const; -export async function getAudio(file: string, useCache = true) { +export async function loadAudio(file: string, useCache = true) { if (useCache && cache.has(file)) { return cache.get(file)!; } @@ -138,12 +138,6 @@ export async function getAudio(file: string, useCache = true) { return audioBuffer; } -export function setVolume(audio: HTMLAudioElement, volume: number): HTMLAudioElement { - const masterVolume = defaultStore.state.sound_masterVolume; - audio.volume = masterVolume - ((1 - volume) * masterVolume); - return audio; -} - export function play(type: 'noteMy' | 'note' | 'antenna' | 'channel' | 'notification') { const sound = defaultStore.state[`sound_${type}`]; if (_DEV_) console.log('play', type, sound); @@ -152,16 +146,22 @@ export function play(type: 'noteMy' | 'note' | 'antenna' | 'channel' | 'notifica } export async function playFile(file: string, volume: number) { + const buffer = await loadAudio(file); + createSourceNode(buffer, volume)?.start(); +} + +export function createSourceNode(buffer: AudioBuffer, volume: number) : AudioBufferSourceNode | null { const masterVolume = defaultStore.state.sound_masterVolume; if (masterVolume === 0 || volume === 0) { - return; + return null; } const gainNode = ctx.createGain(); gainNode.gain.value = masterVolume * volume; const soundSource = ctx.createBufferSource(); - soundSource.buffer = await getAudio(file); + soundSource.buffer = buffer; soundSource.connect(gainNode).connect(ctx.destination); - soundSource.start(); + + return soundSource; } diff --git a/packages/frontend/src/widgets/WidgetJobQueue.vue b/packages/frontend/src/widgets/WidgetJobQueue.vue index 89770b2216..fa82997570 100644 --- a/packages/frontend/src/widgets/WidgetJobQueue.vue +++ b/packages/frontend/src/widgets/WidgetJobQueue.vue @@ -99,7 +99,10 @@ const current = reactive({ }, }); const prev = reactive({} as typeof current); -const jammedSound = sound.setVolume(sound.getAudio('syuilo/queue-jammed'), 1); +let jammedAudioBuffer: AudioBuffer | null = $ref(null); +let jammedSoundNodePlaying: boolean = $ref(false); + +sound.loadAudio('syuilo/queue-jammed').then(buf => jammedAudioBuffer = buf); for (const domain of ['inbox', 'deliver']) { prev[domain] = deepClone(current[domain]); @@ -113,8 +116,13 @@ const onStats = (stats) => { current[domain].waiting = stats[domain].waiting; current[domain].delayed = stats[domain].delayed; - if (current[domain].waiting > 0 && widgetProps.sound && jammedSound.paused) { - jammedSound.play(); + if (current[domain].waiting > 0 && widgetProps.sound && jammedAudioBuffer && !jammedSoundNodePlaying) { + const soundNode = sound.createSourceNode(jammedAudioBuffer, 1); + if (soundNode) { + jammedSoundNodePlaying = true; + soundNode.onended = () => jammedSoundNodePlaying = false; + soundNode.start(); + } } } }; diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index b22e1d0c4b..b7549a896c 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -352,13 +352,13 @@ export type Endpoints = { }; res: null; }; - 'admin/delete-user-avatar': { + 'admin/unset-user-avatar': { req: { userId: User['id']; }; res: null; }; - 'admin/delete-user-banner': { + 'admin/unset-user-banner': { req: { userId: User['id']; }; @@ -2708,10 +2708,16 @@ type ModerationLog = { } | { type: 'resolveAbuseReport'; info: ModerationLogPayloads['resolveAbuseReport']; +} | { + type: 'unsetUserAvatar'; + info: ModerationLogPayloads['unsetUserAvatar']; +} | { + type: 'unsetUserBanner'; + info: ModerationLogPayloads['unsetUserBanner']; }); // @public (undocumented) -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", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration"]; +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", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner"]; // @public (undocumented) export const mutedNoteReasons: readonly ["word", "manual", "spam", "other"]; diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index 0a4855874f..69ce173bf4 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -32,7 +32,7 @@ "jest-websocket-mock": "2.5.0", "mock-socket": "9.3.1", "tsd": "0.29.0", - "typescript": "5.2.2" + "typescript": "5.3.2" }, "files": [ "built" diff --git a/packages/misskey-js/src/api.types.ts b/packages/misskey-js/src/api.types.ts index e964ce8060..4d5fbd19cb 100644 --- a/packages/misskey-js/src/api.types.ts +++ b/packages/misskey-js/src/api.types.ts @@ -15,8 +15,8 @@ export type Endpoints = { // admin 'admin/abuse-user-reports': { req: TODO; res: TODO; }; 'admin/delete-all-files-of-a-user': { req: { userId: User['id']; }; res: null; }; - 'admin/delete-user-avatar': { req: { userId: User['id']; }; res: null; }; - 'admin/delete-user-banner': { req: { userId: User['id']; }; res: null; }; + 'admin/unset-user-avatar': { req: { userId: User['id']; }; res: null; }; + 'admin/unset-user-banner': { req: { userId: User['id']; }; res: null; }; 'admin/delete-logs': { req: NoParams; res: null; }; 'admin/get-index-stats': { req: TODO; res: TODO; }; 'admin/get-table-stats': { req: TODO; res: TODO; }; diff --git a/packages/misskey-js/src/consts.ts b/packages/misskey-js/src/consts.ts index 48a36a31d6..a8f0b96d5d 100644 --- a/packages/misskey-js/src/consts.ts +++ b/packages/misskey-js/src/consts.ts @@ -81,6 +81,8 @@ export const moderationLogTypes = [ 'createAvatarDecoration', 'updateAvatarDecoration', 'deleteAvatarDecoration', + 'unsetUserAvatar', + 'unsetUserBanner', ] as const; export type ModerationLogPayloads = { @@ -255,4 +257,16 @@ export type ModerationLogPayloads = { avatarDecorationId: string; avatarDecoration: any; }; + unsetUserAvatar: { + userId: string; + userUsername: string; + userHost: string | null; + fileId: string; + }; + unsetUserBanner: { + userId: string; + userUsername: string; + userHost: string | null; + fileId: string; + }; }; diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index cc512989ba..86d064c914 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -737,4 +737,10 @@ export type ModerationLog = { } | { type: 'resolveAbuseReport'; info: ModerationLogPayloads['resolveAbuseReport']; +} | { + type: 'unsetUserAvatar'; + info: ModerationLogPayloads['unsetUserAvatar']; +} | { + type: 'unsetUserBanner'; + info: ModerationLogPayloads['unsetUserBanner']; }); diff --git a/packages/sw/package.json b/packages/sw/package.json index 3259cae879..3c74ee8c78 100644 --- a/packages/sw/package.json +++ b/packages/sw/package.json @@ -18,7 +18,7 @@ "@typescript/lib-webworker": "npm:@types/serviceworker@0.0.67", "eslint": "8.53.0", "eslint-plugin-import": "2.29.0", - "typescript": "5.2.2" + "typescript": "5.3.2" }, "type": "module" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5c3e6ef18c..5e9dab7e00 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,8 +28,8 @@ importers: specifier: 5.24.0 version: 5.24.0 typescript: - specifier: 5.2.2 - version: 5.2.2 + specifier: 5.3.2 + version: 5.3.2 optionalDependencies: '@tensorflow/tfjs-core': specifier: 4.4.0 @@ -37,10 +37,10 @@ importers: devDependencies: '@typescript-eslint/eslint-plugin': specifier: 6.11.0 - version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2) + version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.2) '@typescript-eslint/parser': specifier: 6.11.0 - version: 6.11.0(eslint@8.53.0)(typescript@5.2.2) + version: 6.11.0(eslint@8.53.0)(typescript@5.3.2) cross-env: specifier: 7.0.3 version: 7.0.3 @@ -381,8 +381,8 @@ importers: specifier: 0.3.17 version: 0.3.17(ioredis@5.3.2)(pg@8.11.3) typescript: - specifier: 5.2.2 - version: 5.2.2 + specifier: 5.3.2 + version: 5.3.2 ulid: specifier: 2.3.0 version: 2.3.0 @@ -615,10 +615,10 @@ importers: version: 8.5.9 '@typescript-eslint/eslint-plugin': specifier: 6.11.0 - version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2) + version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.2) '@typescript-eslint/parser': specifier: 6.11.0 - version: 6.11.0(eslint@8.53.0)(typescript@5.2.2) + version: 6.11.0(eslint@8.53.0)(typescript@5.3.2) aws-sdk-client-mock: specifier: 3.0.0 version: 3.0.0 @@ -663,7 +663,7 @@ importers: version: 5.0.5(rollup@4.4.1) '@rollup/plugin-typescript': specifier: 11.1.5 - version: 11.1.5(rollup@4.4.1)(typescript@5.2.2) + version: 11.1.5(rollup@4.4.1)(typescript@5.3.2) '@rollup/pluginutils': specifier: 5.0.5 version: 5.0.5(rollup@4.4.1) @@ -809,8 +809,8 @@ importers: specifier: 14.0.0 version: 14.0.0 typescript: - specifier: 5.2.2 - version: 5.2.2 + specifier: 5.3.2 + version: 5.3.2 uuid: specifier: 9.0.1 version: 9.0.1 @@ -825,7 +825,7 @@ importers: version: 4.5.0(@types/node@20.9.1)(sass@1.69.5)(terser@5.24.0) vue: specifier: 3.3.8 - version: 3.3.8(typescript@5.2.2) + version: 3.3.8(typescript@5.3.2) vuedraggable: specifier: next version: 4.1.0(vue@3.3.8) @@ -865,10 +865,10 @@ importers: version: 7.5.3 '@storybook/react': specifier: 7.5.3 - version: 7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2) + version: 7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.2) '@storybook/react-vite': specifier: 7.5.3 - version: 7.5.3(react-dom@18.2.0)(react@18.2.0)(rollup@4.4.1)(typescript@5.2.2)(vite@4.5.0) + version: 7.5.3(react-dom@18.2.0)(react@18.2.0)(rollup@4.4.1)(typescript@5.3.2)(vite@4.5.0) '@storybook/testing-library': specifier: 0.2.2 version: 0.2.2 @@ -883,7 +883,7 @@ importers: version: 7.5.3(@vue/compiler-core@3.3.8)(vue@3.3.8) '@storybook/vue3-vite': specifier: 7.5.3 - version: 7.5.3(@vue/compiler-core@3.3.8)(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2)(vite@4.5.0)(vue@3.3.8) + version: 7.5.3(@vue/compiler-core@3.3.8)(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.2)(vite@4.5.0)(vue@3.3.8) '@testing-library/vue': specifier: 8.0.0 version: 8.0.0(@vue/compiler-sfc@3.3.8)(vue@3.3.8) @@ -925,10 +925,10 @@ importers: version: 8.5.9 '@typescript-eslint/eslint-plugin': specifier: 6.11.0 - version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2) + version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.2) '@typescript-eslint/parser': specifier: 6.11.0 - version: 6.11.0(eslint@8.53.0)(typescript@5.2.2) + version: 6.11.0(eslint@8.53.0)(typescript@5.3.2) '@vitest/coverage-v8': specifier: 0.34.6 version: 0.34.6(vitest@0.34.6) @@ -964,7 +964,7 @@ importers: version: 4.0.5 msw: specifier: 1.3.2 - version: 1.3.2(typescript@5.2.2) + version: 1.3.2(typescript@5.3.2) msw-storybook-addon: specifier: 1.10.0 version: 1.10.0(msw@1.3.2) @@ -1006,7 +1006,7 @@ importers: version: 9.3.2(eslint@8.53.0) vue-tsc: specifier: 1.8.22 - version: 1.8.22(typescript@5.2.2) + version: 1.8.22(typescript@5.3.2) packages/misskey-js: dependencies: @@ -1037,10 +1037,10 @@ 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.2.2) + version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.2) '@typescript-eslint/parser': specifier: 6.11.0 - version: 6.11.0(eslint@8.53.0)(typescript@5.2.2) + version: 6.11.0(eslint@8.53.0)(typescript@5.3.2) eslint: specifier: 8.53.0 version: 8.53.0 @@ -1060,8 +1060,8 @@ importers: specifier: 0.29.0 version: 0.29.0 typescript: - specifier: 5.2.2 - version: 5.2.2 + specifier: 5.3.2 + version: 5.3.2 packages/sw: dependencies: @@ -1077,7 +1077,7 @@ importers: devDependencies: '@typescript-eslint/parser': specifier: 6.11.0 - version: 6.11.0(eslint@8.53.0)(typescript@5.2.2) + version: 6.11.0(eslint@8.53.0)(typescript@5.3.2) '@typescript/lib-webworker': specifier: npm:@types/serviceworker@0.0.67 version: /@types/serviceworker@0.0.67 @@ -1088,8 +1088,8 @@ importers: specifier: 2.29.0 version: 2.29.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0) typescript: - specifier: 5.2.2 - version: 5.2.2 + specifier: 5.3.2 + version: 5.3.2 packages: @@ -4257,7 +4257,7 @@ packages: chalk: 4.1.2 dev: true - /@joshwooding/vite-plugin-react-docgen-typescript@0.3.0(typescript@5.2.2)(vite@4.5.0): + /@joshwooding/vite-plugin-react-docgen-typescript@0.3.0(typescript@5.3.2)(vite@4.5.0): resolution: {integrity: sha512-2D6y7fNvFmsLmRt6UCOFJPvFoPMJGT0Uh1Wg0RaigUp7kdQPs6yYn8Dmx6GZkOH/NW0yMTwRz/p0SRMMRo50vA==} peerDependencies: typescript: '>= 4.3.x' @@ -4269,8 +4269,8 @@ packages: 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.2.2) - typescript: 5.2.2 + react-docgen-typescript: 2.2.2(typescript@5.3.2) + typescript: 5.3.2 vite: 4.5.0(@types/node@20.9.1)(sass@1.69.5)(terser@5.24.0) dev: true @@ -5261,7 +5261,7 @@ packages: rollup: 4.4.1 dev: false - /@rollup/plugin-typescript@11.1.5(rollup@4.4.1)(typescript@5.2.2): + /@rollup/plugin-typescript@11.1.5(rollup@4.4.1)(typescript@5.3.2): resolution: {integrity: sha512-rnMHrGBB0IUEv69Q8/JGRD/n4/n6b3nfpufUu26axhUcboUzv/twfZU8fIBbTOphRAe0v8EyxzeDpKXqGHfyDA==} engines: {node: '>=14.0.0'} peerDependencies: @@ -5277,7 +5277,7 @@ packages: '@rollup/pluginutils': 5.0.5(rollup@4.4.1) resolve: 1.22.3 rollup: 4.4.1 - typescript: 5.2.2 + typescript: 5.3.2 dev: false /@rollup/pluginutils@5.0.5(rollup@4.4.1): @@ -6370,7 +6370,7 @@ packages: - supports-color dev: true - /@storybook/builder-vite@7.5.3(typescript@5.2.2)(vite@4.5.0): + /@storybook/builder-vite@7.5.3(typescript@5.3.2)(vite@4.5.0): resolution: {integrity: sha512-c104V3O75OCVnfZj0Jr70V09g0KSbPGvQK2Zh31omXGvakG8XrhWolYxkmjOcForJmAqsXnKs/nw3F75Gp853g==} peerDependencies: '@preact/preset-vite': '*' @@ -6401,7 +6401,7 @@ packages: fs-extra: 11.1.1 magic-string: 0.30.5 rollup: 3.29.4 - typescript: 5.2.2 + typescript: 5.3.2 vite: 4.5.0(@types/node@20.9.1)(sass@1.69.5)(terser@5.24.0) transitivePeerDependencies: - encoding @@ -6772,7 +6772,7 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/react-vite@7.5.3(react-dom@18.2.0)(react@18.2.0)(rollup@4.4.1)(typescript@5.2.2)(vite@4.5.0): + /@storybook/react-vite@7.5.3(react-dom@18.2.0)(react@18.2.0)(rollup@4.4.1)(typescript@5.3.2)(vite@4.5.0): resolution: {integrity: sha512-ArPyHgiPbT5YvcyK4xK/DfqBOpn4R4/EP3kfIGhx8QKJyOtxPEYFdkLIZ5xu3KnPX7/z7GT+4a6Rb+8sk9gliA==} engines: {node: '>=16'} peerDependencies: @@ -6780,10 +6780,10 @@ packages: react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 vite: ^3.0.0 || ^4.0.0 || ^5.0.0 dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.2.2)(vite@4.5.0) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.3.2)(vite@4.5.0) '@rollup/pluginutils': 5.0.5(rollup@4.4.1) - '@storybook/builder-vite': 7.5.3(typescript@5.2.2)(vite@4.5.0) - '@storybook/react': 7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2) + '@storybook/builder-vite': 7.5.3(typescript@5.3.2)(vite@4.5.0) + '@storybook/react': 7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.2) '@vitejs/plugin-react': 3.1.0(vite@4.5.0) magic-string: 0.30.5 react: 18.2.0 @@ -6799,7 +6799,7 @@ packages: - vite-plugin-glimmerx dev: true - /@storybook/react@7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2): + /@storybook/react@7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.2): resolution: {integrity: sha512-dZILdM36xMFDjdmmy421G5X+sOIncB2qF3IPTooniG1i1Z6v/dVNo57ovdID9lDTNa+AWr2fLB9hANiISMqmjQ==} engines: {node: '>=16.0.0'} peerDependencies: @@ -6832,7 +6832,7 @@ packages: react-element-to-jsx-string: 15.0.0(react-dom@18.2.0)(react@18.2.0) ts-dedent: 2.2.0 type-fest: 2.19.0 - typescript: 5.2.2 + typescript: 5.3.2 util-deprecate: 1.0.2 transitivePeerDependencies: - encoding @@ -6914,7 +6914,7 @@ packages: file-system-cache: 2.3.0 dev: true - /@storybook/vue3-vite@7.5.3(@vue/compiler-core@3.3.8)(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2)(vite@4.5.0)(vue@3.3.8): + /@storybook/vue3-vite@7.5.3(@vue/compiler-core@3.3.8)(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.2)(vite@4.5.0)(vue@3.3.8): resolution: {integrity: sha512-gkNwDDn2AKthAtaoPrHb0+2gi33UluxpfSq/M5COoMEVFphj6y/jyDa+OEYlceXgnD8g2xvX4/yv2TbTNDzmcQ==} engines: {node: ^14.18 || >=16} peerDependencies: @@ -6922,7 +6922,7 @@ packages: react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 vite: ^3.0.0 || ^4.0.0 || ^5.0.0 dependencies: - '@storybook/builder-vite': 7.5.3(typescript@5.2.2)(vite@4.5.0) + '@storybook/builder-vite': 7.5.3(typescript@5.3.2)(vite@4.5.0) '@storybook/core-server': 7.5.3 '@storybook/vue3': 7.5.3(@vue/compiler-core@3.3.8)(vue@3.3.8) '@vitejs/plugin-vue': 4.5.0(vite@4.5.0)(vue@3.3.8) @@ -6959,7 +6959,7 @@ packages: lodash: 4.17.21 ts-dedent: 2.2.0 type-fest: 2.19.0 - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) vue-component-type-helpers: 1.8.22 transitivePeerDependencies: - encoding @@ -7454,7 +7454,7 @@ packages: '@testing-library/dom': 9.3.3 '@vue/compiler-sfc': 3.3.8 '@vue/test-utils': 2.4.1(vue@3.3.8) - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) transitivePeerDependencies: - '@vue/server-renderer' dev: true @@ -8095,7 +8095,7 @@ packages: dev: true optional: true - /@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2): + /@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.2): resolution: {integrity: sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8107,10 +8107,10 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.6.2 - '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.2) '@typescript-eslint/scope-manager': 6.11.0 - '@typescript-eslint/type-utils': 6.11.0(eslint@8.53.0)(typescript@5.2.2) - '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/type-utils': 6.11.0(eslint@8.53.0)(typescript@5.3.2) + '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.2) '@typescript-eslint/visitor-keys': 6.11.0 debug: 4.3.4(supports-color@8.1.1) eslint: 8.53.0 @@ -8118,13 +8118,13 @@ packages: ignore: 5.2.4 natural-compare: 1.4.0 semver: 7.5.4 - ts-api-utils: 1.0.1(typescript@5.2.2) - typescript: 5.2.2 + ts-api-utils: 1.0.1(typescript@5.3.2) + typescript: 5.3.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.2.2): + /@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.2): resolution: {integrity: sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8136,11 +8136,11 @@ packages: dependencies: '@typescript-eslint/scope-manager': 6.11.0 '@typescript-eslint/types': 6.11.0 - '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.2) '@typescript-eslint/visitor-keys': 6.11.0 debug: 4.3.4(supports-color@8.1.1) eslint: 8.53.0 - typescript: 5.2.2 + typescript: 5.3.2 transitivePeerDependencies: - supports-color dev: true @@ -8153,7 +8153,7 @@ packages: '@typescript-eslint/visitor-keys': 6.11.0 dev: true - /@typescript-eslint/type-utils@6.11.0(eslint@8.53.0)(typescript@5.2.2): + /@typescript-eslint/type-utils@6.11.0(eslint@8.53.0)(typescript@5.3.2): resolution: {integrity: sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8163,12 +8163,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.2.2) - '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.2) + '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.2) debug: 4.3.4(supports-color@8.1.1) eslint: 8.53.0 - ts-api-utils: 1.0.1(typescript@5.2.2) - typescript: 5.2.2 + ts-api-utils: 1.0.1(typescript@5.3.2) + typescript: 5.3.2 transitivePeerDependencies: - supports-color dev: true @@ -8178,7 +8178,7 @@ packages: engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/typescript-estree@6.11.0(typescript@5.2.2): + /@typescript-eslint/typescript-estree@6.11.0(typescript@5.3.2): resolution: {integrity: sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8193,13 +8193,13 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 - ts-api-utils: 1.0.1(typescript@5.2.2) - typescript: 5.2.2 + ts-api-utils: 1.0.1(typescript@5.3.2) + typescript: 5.3.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@6.11.0(eslint@8.53.0)(typescript@5.2.2): + /@typescript-eslint/utils@6.11.0(eslint@8.53.0)(typescript@5.3.2): resolution: {integrity: sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8210,7 +8210,7 @@ packages: '@types/semver': 7.5.5 '@typescript-eslint/scope-manager': 6.11.0 '@typescript-eslint/types': 6.11.0 - '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.2) eslint: 8.53.0 semver: 7.5.4 transitivePeerDependencies: @@ -8254,7 +8254,7 @@ packages: vue: ^3.2.25 dependencies: vite: 4.5.0(@types/node@20.9.1)(sass@1.69.5)(terser@5.24.0) - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) /@vitest/coverage-v8@0.34.6(vitest@0.34.6): resolution: {integrity: sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw==} @@ -8349,7 +8349,7 @@ packages: ast-kit: 0.11.2(rollup@4.4.1) local-pkg: 0.5.0 magic-string-ast: 0.3.0 - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) transitivePeerDependencies: - rollup dev: false @@ -8366,7 +8366,7 @@ packages: '@vue/shared': 3.3.8 magic-string: 0.30.5 unplugin: 1.5.1 - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) transitivePeerDependencies: - rollup dev: false @@ -8437,7 +8437,7 @@ packages: '@vue/compiler-dom': 3.3.8 '@vue/shared': 3.3.8 - /@vue/language-core@1.8.22(typescript@5.2.2): + /@vue/language-core@1.8.22(typescript@5.3.2): resolution: {integrity: sha512-bsMoJzCrXZqGsxawtUea1cLjUT9dZnDsy5TuZ+l1fxRMzUGQUG9+Ypq4w//CqpWmrx7nIAJpw2JVF/t258miRw==} peerDependencies: typescript: '*' @@ -8452,7 +8452,7 @@ packages: computeds: 0.0.1 minimatch: 9.0.3 muggle-string: 0.3.1 - typescript: 5.2.2 + typescript: 5.3.2 vue-template-compiler: 2.7.14 dev: true @@ -8490,7 +8490,7 @@ packages: dependencies: '@vue/compiler-ssr': 3.3.8 '@vue/shared': 3.3.8 - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) /@vue/shared@3.3.6: resolution: {integrity: sha512-Xno5pEqg8SVhomD0kTSmfh30ZEmV/+jZtyh39q6QflrjdJCXah5lrnOLi9KB6a5k5aAHXMXjoMnxlzUkCNfWLQ==} @@ -8513,7 +8513,7 @@ packages: optional: true dependencies: js-beautify: 1.14.9 - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) vue-component-type-helpers: 1.8.4 dev: true @@ -11180,7 +11180,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.2) debug: 3.2.7(supports-color@5.5.0) eslint: 8.53.0 eslint-import-resolver-node: 0.3.9 @@ -11198,7 +11198,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.2) array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 @@ -14862,10 +14862,10 @@ packages: msw: '>=0.35.0 <2.0.0' dependencies: is-node-process: 1.2.0 - msw: 1.3.2(typescript@5.2.2) + msw: 1.3.2(typescript@5.3.2) dev: true - /msw@1.3.2(typescript@5.2.2): + /msw@1.3.2(typescript@5.3.2): resolution: {integrity: sha512-wKLhFPR+NitYTkQl5047pia0reNGgf0P6a1eTnA5aNlripmiz0sabMvvHcicE8kQ3/gZcI0YiPFWmYfowfm3lA==} engines: {node: '>=14'} hasBin: true @@ -14894,7 +14894,7 @@ packages: path-to-regexp: 6.2.1 strict-event-emitter: 0.4.6 type-fest: 2.19.0 - typescript: 5.2.2 + typescript: 5.3.2 yargs: 17.6.2 transitivePeerDependencies: - encoding @@ -16783,12 +16783,12 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /react-docgen-typescript@2.2.2(typescript@5.2.2): + /react-docgen-typescript@2.2.2(typescript@5.3.2): resolution: {integrity: sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==} peerDependencies: typescript: '>= 4.3.x' dependencies: - typescript: 5.2.2 + typescript: 5.3.2 dev: true /react-docgen@6.0.4: @@ -18636,13 +18636,13 @@ packages: escape-string-regexp: 5.0.0 dev: false - /ts-api-utils@1.0.1(typescript@5.2.2): + /ts-api-utils@1.0.1(typescript@5.3.2): resolution: {integrity: sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==} engines: {node: '>=16.13.0'} peerDependencies: typescript: '>=4.2.0' dependencies: - typescript: 5.2.2 + typescript: 5.3.2 dev: true /ts-dedent@2.2.0: @@ -18906,8 +18906,8 @@ packages: hasBin: true dev: true - /typescript@5.2.2: - resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + /typescript@5.3.2: + resolution: {integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==} engines: {node: '>=14.17'} hasBin: true @@ -19195,7 +19195,7 @@ packages: diff: 5.1.0 diff-match-patch: 1.0.5 highlight.js: 11.8.0 - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) vue-demi: 0.13.11(vue@3.3.8) dev: false @@ -19409,7 +19409,7 @@ packages: '@vue/composition-api': optional: true dependencies: - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) dev: false /vue-docgen-api@4.64.1(vue@3.3.8): @@ -19453,7 +19453,7 @@ packages: peerDependencies: vue: '>=2' dependencies: - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) dev: true /vue-template-compiler@2.7.14: @@ -19463,19 +19463,19 @@ packages: he: 1.2.0 dev: true - /vue-tsc@1.8.22(typescript@5.2.2): + /vue-tsc@1.8.22(typescript@5.3.2): resolution: {integrity: sha512-j9P4kHtW6eEE08aS5McFZE/ivmipXy0JzrnTgbomfABMaVKx37kNBw//irL3+LlE3kOo63XpnRigyPC3w7+z+A==} hasBin: true peerDependencies: typescript: '*' dependencies: '@volar/typescript': 1.10.7 - '@vue/language-core': 1.8.22(typescript@5.2.2) + '@vue/language-core': 1.8.22(typescript@5.3.2) semver: 7.5.4 - typescript: 5.2.2 + typescript: 5.3.2 dev: true - /vue@3.3.8(typescript@5.2.2): + /vue@3.3.8(typescript@5.3.2): resolution: {integrity: sha512-5VSX/3DabBikOXMsxzlW8JyfeLKlG9mzqnWgLQLty88vdZL7ZJgrdgBOmrArwxiLtmS+lNNpPcBYqrhE6TQW5w==} peerDependencies: typescript: '*' @@ -19488,7 +19488,7 @@ packages: '@vue/runtime-dom': 3.3.8 '@vue/server-renderer': 3.3.8(vue@3.3.8) '@vue/shared': 3.3.8 - typescript: 5.2.2 + typescript: 5.3.2 /vuedraggable@4.1.0(vue@3.3.8): resolution: {integrity: sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==} @@ -19496,7 +19496,7 @@ packages: vue: ^3.0.1 dependencies: sortablejs: 1.14.0 - vue: 3.3.8(typescript@5.2.2) + vue: 3.3.8(typescript@5.3.2) dev: false /w3c-xmlserializer@4.0.0: