From ed0cc443ea8122d01488f427bcced457d3d65d4f Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 21 Nov 2023 09:55:49 +0900 Subject: [PATCH 1/8] =?UTF-8?q?fix(backend):=20=E3=83=AD=E3=83=BC=E3=83=AB?= =?UTF-8?q?=E3=82=BF=E3=82=A4=E3=83=A0=E3=83=A9=E3=82=A4=E3=83=B3=E3=81=8C?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E3=81=95=E3=82=8C=E3=81=AA=E3=81=84=E5=95=8F?= =?UTF-8?q?=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 +- packages/backend/src/core/RoleService.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2c226aec..aff2ed283 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ - ### Server -- +- Fix: ロールタイムラインが保存されない問題を修正 ## 2023.11.1 diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index d6a414694..432887b3b 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -87,6 +87,9 @@ export class RoleService implements OnApplicationShutdown { @Inject(DI.redis) private redisClient: Redis.Redis, + @Inject(DI.redisForTimelines) + private redisForTimelines: Redis.Redis, + @Inject(DI.redisForSub) private redisForSub: Redis.Redis, @@ -476,7 +479,7 @@ export class RoleService implements OnApplicationShutdown { public async addNoteToRoleTimeline(note: Packed<'Note'>): Promise { const roles = await this.getUserRoles(note.userId); - const redisPipeline = this.redisClient.pipeline(); + const redisPipeline = this.redisForTimelines.pipeline(); for (const role of roles) { this.funoutTimelineService.push(`roleTimeline:${role.id}`, note.id, 1000, redisPipeline); From 2ec3227012eecb4358feed6d16bf2b700b3ac9c7 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Tue, 21 Nov 2023 10:48:01 +0900 Subject: [PATCH 2/8] update api.md (#12379) for API changes in b65fd349812fe3c89b5face6ec5c12823459d7df --- packages/misskey-js/etc/misskey-js.api.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 85907de66..63c3cb71a 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -2685,10 +2685,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"]; @@ -3046,8 +3052,8 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u // Warnings were encountered during analysis: // // src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts -// 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:632:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts +// src/api.types.ts:20:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts +// src/api.types.ts:634:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts // src/entities.ts:116:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts // src/entities.ts:627: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 From 8bd9077f77eaebaa4dff403e072ba49e4cab1326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Tue, 21 Nov 2023 11:13:56 +0900 Subject: [PATCH 3/8] =?UTF-8?q?json-schema=E9=85=8D=E4=B8=8B=E3=81=AE?= =?UTF-8?q?=E6=9C=80=E6=96=B0=E5=8C=96=20(#12312)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * user.ts、page.ts、drive-folder.tsを各EntityServiceの戻り値をもとに最新化 * 再確認 * fix error * note以外の残りのファイルを対応 * fix CHANGELOG.md * fix CHANGELOG.md * fix user.ts * fix user.ts * コメント対応 * fix note.ts --------- Co-authored-by: osamu <46447427+sam-osamu@users.noreply.github.com> --- CHANGELOG.md | 1 + .../entities/NotificationEntityService.ts | 14 +- .../src/models/json-schema/announcement.ts | 8 +- .../backend/src/models/json-schema/channel.ts | 63 ++-- .../backend/src/models/json-schema/clip.ts | 8 +- .../src/models/json-schema/drive-file.ts | 2 +- .../src/models/json-schema/drive-folder.ts | 12 +- .../models/json-schema/federation-instance.ts | 9 +- .../backend/src/models/json-schema/flash.ts | 20 +- .../src/models/json-schema/following.ts | 10 +- .../src/models/json-schema/gallery-post.ts | 24 +- .../backend/src/models/json-schema/note.ts | 28 +- .../src/models/json-schema/notification.ts | 26 +- .../backend/src/models/json-schema/page.ts | 68 +++- .../backend/src/models/json-schema/user.ts | 313 ++++++++++++++++-- 15 files changed, 457 insertions(+), 149 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc3835628..2efa1b230 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ - Feat: 管理者がコントロールパネルからメールアドレスの照会を行えるようになりました - Enhance: ローカリゼーションの更新 - Enhance: 依存関係の更新 +- Enhance: json-schema(OpenAPIの戻り値として使用されるスキーマ定義)を出来る限り最新化 #12311 ### Client - Enhance: MFMでルビを振れるように diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts index f74594ff0..e723ea5a5 100644 --- a/packages/backend/src/core/entities/NotificationEntityService.ts +++ b/packages/backend/src/core/entities/NotificationEntityService.ts @@ -198,12 +198,14 @@ export class NotificationEntityService implements OnModuleInit { }); } 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 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, diff --git a/packages/backend/src/models/json-schema/announcement.ts b/packages/backend/src/models/json-schema/announcement.ts index c7e24c7f2..78a98872b 100644 --- a/packages/backend/src/models/json-schema/announcement.ts +++ b/packages/backend/src/models/json-schema/announcement.ts @@ -42,11 +42,15 @@ export const packedAnnouncementSchema = { type: 'string', optional: false, nullable: false, }, - forYou: { + needConfirmationToRead: { type: 'boolean', optional: false, nullable: false, }, - needConfirmationToRead: { + silence: { + type: 'boolean', + optional: false, nullable: false, + }, + 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 8f9770cdc..5b0fa0f15 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 64f7a2ad9..1ab96c2b3 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 87f134081..79f242a71 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 51107d423..aaad30130 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 442e1076f..341731427 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 9453ba1dc..f08fa7a27 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 3a24ebb61..e92cff20a 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-post.ts b/packages/backend/src/models/json-schema/gallery-post.ts index cf260c0bf..df7038950 100644 --- a/packages/backend/src/models/json-schema/gallery-post.ts +++ b/packages/backend/src/models/json-schema/gallery-post.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,5 +70,13 @@ 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 38c0054b5..9d5d558f5 100644 --- a/packages/backend/src/models/json-schema/note.ts +++ b/packages/backend/src/models/json-schema/note.ts @@ -127,22 +127,18 @@ 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: true, + }, + isSensitive: { + type: 'boolean', + optional: true, nullable: false, }, }, }, diff --git a/packages/backend/src/models/json-schema/notification.ts b/packages/backend/src/models/json-schema/notification.ts index 27db3bb62..c6d6e8431 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 3f20a4b80..9baacd688 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,23 +60,47 @@ 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 37bdcbe28..b0e18db01 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: { @@ -249,6 +291,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, @@ -264,6 +311,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', @@ -297,10 +395,6 @@ export const packedUserDetailedNotMeOnlySchema = { type: 'boolean', nullable: false, optional: true, }, - memo: { - type: 'string', - nullable: false, optional: true, - }, notify: { type: 'string', nullable: false, optional: true, @@ -326,29 +420,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', @@ -387,10 +489,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, @@ -429,12 +544,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', @@ -511,5 +746,13 @@ export const packedUserSchema = { type: 'object', ref: 'UserDetailed', }, + { + type: 'object', + ref: 'UserDetailedNotMe', + }, + { + type: 'object', + ref: 'MeDetailed', + }, ], } as const; From 77ac51a680c352d5bed90a90379fcaf1454612a7 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 21 Nov 2023 11:32:13 +0900 Subject: [PATCH 4/8] update typescript to 5.3 --- package.json | 2 +- packages/backend/package.json | 2 +- packages/frontend/package.json | 2 +- packages/misskey-js/package.json | 2 +- packages/sw/package.json | 2 +- pnpm-lock.yaml | 172 +++++++++++++++---------------- 6 files changed, 91 insertions(+), 91 deletions(-) diff --git a/package.json b/package.json index d0fc867b3..f51861401 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,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/package.json b/packages/backend/package.json index 496c79c9c..3b029a49d 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -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/frontend/package.json b/packages/frontend/package.json index 62192d0da..c7736f7ac 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -69,7 +69,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/misskey-js/package.json b/packages/misskey-js/package.json index 0a4855874..69ce173bf 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/sw/package.json b/packages/sw/package.json index 3259cae87..3c74ee8c7 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 904150b07..7373d5f10 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 @@ -806,8 +806,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 @@ -822,7 +822,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) @@ -862,10 +862,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 @@ -880,7 +880,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) @@ -922,10 +922,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) @@ -961,7 +961,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) @@ -1003,7 +1003,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: @@ -1034,10 +1034,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 @@ -1057,8 +1057,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: @@ -1074,7 +1074,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 @@ -1085,8 +1085,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: @@ -4254,7 +4254,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' @@ -4266,8 +4266,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 @@ -6348,7 +6348,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': '*' @@ -6379,7 +6379,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 @@ -6750,7 +6750,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: @@ -6758,10 +6758,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 @@ -6777,7 +6777,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: @@ -6810,7 +6810,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 @@ -6892,7 +6892,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: @@ -6900,7 +6900,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) @@ -6937,7 +6937,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 @@ -7432,7 +7432,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 @@ -8073,7 +8073,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: @@ -8085,10 +8085,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 @@ -8096,13 +8096,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: @@ -8114,11 +8114,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 @@ -8131,7 +8131,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: @@ -8141,12 +8141,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 @@ -8156,7 +8156,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: @@ -8171,13 +8171,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: @@ -8188,7 +8188,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: @@ -8232,7 +8232,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==} @@ -8327,7 +8327,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 @@ -8344,7 +8344,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 @@ -8415,7 +8415,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: '*' @@ -8430,7 +8430,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 @@ -8468,7 +8468,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==} @@ -8491,7 +8491,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 @@ -11158,7 +11158,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 @@ -11176,7 +11176,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 @@ -14852,10 +14852,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 @@ -14884,7 +14884,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 @@ -16773,12 +16773,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: @@ -18627,13 +18627,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: @@ -18897,8 +18897,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 @@ -19186,7 +19186,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 @@ -19400,7 +19400,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): @@ -19444,7 +19444,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: @@ -19454,19 +19454,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: '*' @@ -19479,7 +19479,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==} @@ -19487,7 +19487,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: From b5be0e5780453653ca37ea809c36757057a21758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Tue, 21 Nov 2023 15:12:05 +0900 Subject: [PATCH 5/8] =?UTF-8?q?note.ts=E3=81=AEchannel=E3=82=92=E6=AD=A3?= =?UTF-8?q?=E3=81=97=E3=81=84=E5=BD=A2=E3=81=AB=E3=81=97=E3=81=9F=E3=81=93?= =?UTF-8?q?=E3=81=A8=E3=81=AB=E3=82=88=E3=82=8A=E8=A1=A8=E5=87=BA=E5=8C=96?= =?UTF-8?q?=E3=81=97=E3=81=9F=E5=9E=8B=E3=83=81=E3=82=A7=E3=83=83=E3=82=AF?= =?UTF-8?q?=E3=82=A8=E3=83=A9=E3=83=BC=E3=82=92=E4=BF=AE=E6=AD=A3=20(#1239?= =?UTF-8?q?5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: osamu <46447427+sam-osamu@users.noreply.github.com> --- packages/backend/src/models/json-schema/note.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/models/json-schema/note.ts b/packages/backend/src/models/json-schema/note.ts index 9d5d558f5..392fa7e1c 100644 --- a/packages/backend/src/models/json-schema/note.ts +++ b/packages/backend/src/models/json-schema/note.ts @@ -134,11 +134,19 @@ export const packedNoteSchema = { }, name: { type: 'string', - optional: false, nullable: true, + optional: false, nullable: false, + }, + color: { + type: 'string', + optional: false, nullable: false, }, isSensitive: { type: 'boolean', - optional: true, nullable: false, + optional: false, nullable: false, + }, + allowRenoteToExternal: { + type: 'boolean', + optional: false, nullable: false, }, }, }, From b3d1cc9525b44e37b983c3a97af4e2aea80ea735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Tue, 21 Nov 2023 15:32:34 +0900 Subject: [PATCH 6/8] =?UTF-8?q?=E3=82=B5=E3=83=BC=E3=83=90=E8=B5=B7?= =?UTF-8?q?=E5=8B=95=E6=99=82=E3=81=AB=E3=82=A2=E3=83=B3=E3=83=86=E3=83=8A?= =?UTF-8?q?=E3=81=8C=E9=9D=9E=E3=82=A2=E3=82=AF=E3=83=86=E3=82=A3=E3=83=96?= =?UTF-8?q?=E3=81=A0=E3=81=A3=E3=81=9F=E5=A0=B4=E5=90=88=E3=80=81=E3=82=A2?= =?UTF-8?q?=E3=82=AF=E3=83=86=E3=82=A3=E3=83=96=E5=8C=96=E3=81=97=E3=81=A6?= =?UTF-8?q?=E3=82=82=E5=86=8D=E8=B5=B7=E5=8B=95=E3=81=99=E3=82=8B=E3=81=BE?= =?UTF-8?q?=E3=81=A7=E5=8F=8D=E6=98=A0=E3=81=95=E3=82=8C=E3=81=AA=E3=81=84?= =?UTF-8?q?=20(#12391)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * サーバ起動時にアンテナが非アクティブだった場合、アクティブ化しても再起動するまで反映されない * Fix CHANGELOG.md * lastUsedAtの更新に不備が出るので修正 --------- Co-authored-by: osamu <46447427+sam-osamu@users.noreply.github.com> --- CHANGELOG.md | 1 + packages/backend/src/core/AntennaService.ts | 20 ++++++++++++++----- .../server/api/endpoints/antennas/notes.ts | 16 +++++++++++---- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2efa1b230..900d042ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - fix: 「設定のバックアップ」で一部の項目がバックアップに含まれていなかった問題を修正 ### Server +- Fix: 時間経過により無効化されたアンテナを再有効化したとき、サーバ再起動までその状況が反映されないのを修正 #12303 - Fix: ロールタイムラインが保存されない問題を修正 ## 2023.11.1 diff --git a/packages/backend/src/core/AntennaService.ts b/packages/backend/src/core/AntennaService.ts index 65be27554..2815d2473 100644 --- a/packages/backend/src/core/AntennaService.ts +++ b/packages/backend/src/core/AntennaService.ts @@ -60,11 +60,21 @@ export class AntennaService implements OnApplicationShutdown { lastUsedAt: new Date(body.lastUsedAt), }); break; - case 'antennaUpdated': - this.antennas[this.antennas.findIndex(a => a.id === body.id)] = { - ...body, - lastUsedAt: new Date(body.lastUsedAt), - }; + case 'antennaUpdated': { + const idx = this.antennas.findIndex(a => a.id === body.id); + if (idx >= 0) { + this.antennas[idx] = { + ...body, + lastUsedAt: new Date(body.lastUsedAt), + }; + } else { + // サーバ起動時にactiveじゃなかった場合、リストに持っていないので追加する必要あり + this.antennas.push({ + ...body, + lastUsedAt: new Date(body.lastUsedAt), + }); + } + } break; case 'antennaDeleted': this.antennas = this.antennas.filter(a => a.id !== body.id); diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts index 9b5911800..29e56b108 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); From 481bca4cf2e8f13a46654770291b7ee31a1c361e Mon Sep 17 00:00:00 2001 From: nenohi Date: Tue, 21 Nov 2023 19:50:06 +0900 Subject: [PATCH 7/8] =?UTF-8?q?=E5=BA=83=E5=91=8A=E6=8E=B2=E8=BC=89?= =?UTF-8?q?=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=AB=E3=81=A6filter=E3=82=92?= =?UTF-8?q?=E3=82=8F=E3=81=8B=E3=82=8A=E3=82=84=E3=81=99=E3=81=8F=20(#1238?= =?UTF-8?q?5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/server/api/endpoints/admin/ad/list.ts | 6 ++- packages/frontend/src/pages/admin/ads.vue | 50 ++++++++++++------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/admin/ad/list.ts b/packages/backend/src/server/api/endpoints/admin/ad/list.ts index 29eff8952..1366fbf76 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/list.ts @@ -22,7 +22,7 @@ export const paramDef = { limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, sinceId: { type: 'string', format: 'misskey:id' }, untilId: { type: 'string', format: 'misskey:id' }, - publishing: { type: 'boolean', default: false }, + publishing: { type: 'boolean', default: null, nullable: true}, }, required: [], } as const; @@ -37,8 +37,10 @@ export default class extends Endpoint { // eslint- ) { super(meta, paramDef, async (ps, me) => { const query = this.queryService.makePaginationQuery(this.adsRepository.createQueryBuilder('ad'), ps.sinceId, ps.untilId); - if (ps.publishing) { + if (ps.publishing === true) { query.andWhere('ad.expiresAt > :now', { now: new Date() }).andWhere('ad.startsAt <= :now', { now: new Date() }); + } else if (ps.publishing === false) { + query.andWhere('ad.expiresAt <= :now', { now: new Date() }).orWhere('ad.startsAt > :now', { now: new Date() }); } const ads = await query.limit(ps.limit).getMany(); diff --git a/packages/frontend/src/pages/admin/ads.vue b/packages/frontend/src/pages/admin/ads.vue index 6e07585fd..1ce99d4ba 100644 --- a/packages/frontend/src/pages/admin/ads.vue +++ b/packages/frontend/src/pages/admin/ads.vue @@ -9,12 +9,15 @@ SPDX-License-Identifier: AGPL-3.0-only - - {{ i18n.ts.publishing }} - + + + + + +
- + @@ -82,14 +85,14 @@ SPDX-License-Identifier: AGPL-3.0-only