From 2eaa3e256ff7310bd63197aafe7e72fa207e347b Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Fri, 31 May 2024 20:42:02 +0900
Subject: [PATCH 001/210] Update README.md for Sentry
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index 24013a7bd817..92e8fef6396e 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,10 @@
## Thanks
+
+
+Thanks to [Sentry](https://sentry.io/) for providing the error tracking platform that helps us catch unexpected errors.
+
Thanks to [Chromatic](https://www.chromatic.com/) for providing the visual testing platform that helps us review UI changes and catch visual regressions.
From ecf7945fe8e4554c0db248512fbc51a41cfaf2c9 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Fri, 31 May 2024 12:25:00 +0000
Subject: [PATCH 002/210] [skip ci] Update CHANGELOG.md (prepend template)
---
CHANGELOG.md | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9f78ba677d6b..9d4ef23d272d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,15 @@
+## Unreleased
+
+### General
+-
+
+### Client
+-
+
+### Server
+-
+
+
## 2024.5.0
### Note
From 2b8056a8525e1b38536aa0406ba9446a88b365b9 Mon Sep 17 00:00:00 2001
From: Acid Chicken
Date: Sat, 1 Jun 2024 11:16:44 +0900
Subject: [PATCH 003/210] fix(backend): use insertOne insteadof
insert/findOneOrFail combination (#13908)
* fix(backend): use insertOne insteadof insert/findOneOrFail combination
* fix: typo
* fix(backend): inherit mainAlias?
* refactor(backend): use extend
* fix(backend): invalid entityTarget
* fix(backend): fake where
* chore: debug
* chore: debug
* test: log
* fix(backend): column names
* fix(backend): remove dummy from
* revert: log
* fix(backend): position
* fix(backend): automatic aliasing
* chore(backend): alias
* chore(backend): remove from
* fix(backend): type
* fix(backend): avoid pure name
* test(backend): fix type
* chore(backend): use cte
* fix(backend): avoid useless alias
* fix(backend): fix typo
* fix(backend): __disambiguation__
* fix(backend): quote
* chore(backend): t
* chore(backend): accessible
* chore(backend): concrete returning
* fix(backend): quote
* chore: log more
* chore: log metadata
* chore(backend): use raw
* fix(backend): returning column name
* fix(backend): transform
* build(backend): wanna logging
* build(backend): transform empty
* build(backend): build alias
* build(backend): restore name
* chore: return entity
* fix: test case
* test(backend): 204
* chore(backend): log sql
* chore(backend): assert user joined
* fix(backend): typo
* chore(backend): log long sql
* chore(backend): log join
* chore(backend): log join depth null
* chore(backend): joinAttributes
* chore(backend): override createJoinExpression
* chore: join log
* fix(backend): escape
* test(backend): log log
* chore(backend): join gonna success?
* chore(backend): relations
* chore(backend): undefined
* chore(backend): target
* chore(backend): remove log
* chore(backend): log chart update
* chore(backend): log columns
* chore(backend): check hasMetadata
* chore(backend): unshift id when not included
* chore(backend): missing select
* chore(backend): remove debug code
---
.../backend/src/core/AnnouncementService.ts | 4 +-
.../src/core/AvatarDecorationService.ts | 4 +-
packages/backend/src/core/ClipService.ts | 4 +-
.../backend/src/core/CustomEmojiService.ts | 4 +-
packages/backend/src/core/DriveService.ts | 6 +-
.../src/core/FederatedInstanceService.ts | 4 +-
packages/backend/src/core/RelayService.ts | 4 +-
packages/backend/src/core/ReversiService.ts | 7 +-
packages/backend/src/core/RoleService.ts | 8 +-
.../backend/src/core/UserFollowingService.ts | 4 +-
.../core/activitypub/models/ApNoteService.ts | 4 +-
packages/backend/src/core/chart/core.ts | 23 +-
.../backend/src/models/RepositoryModule.ts | 136 ++++++------
packages/backend/src/models/_.ts | 205 ++++++++++++------
.../ImportAntennasProcessorService.ts | 4 +-
.../ImportUserListsProcessorService.ts | 4 +-
.../backend/src/server/api/SigninService.ts | 4 +-
.../src/server/api/SignupApiService.ts | 4 +-
.../server/api/endpoints/admin/ad/create.ts | 4 +-
.../api/endpoints/admin/invite/create.ts | 4 +-
.../server/api/endpoints/antennas/create.ts | 4 +-
.../src/server/api/endpoints/app/create.ts | 4 +-
.../api/endpoints/auth/session/generate.ts | 4 +-
.../server/api/endpoints/channels/create.ts | 4 +-
.../api/endpoints/drive/folders/create.ts | 4 +-
.../src/server/api/endpoints/flash/create.ts | 4 +-
.../api/endpoints/gallery/posts/create.ts | 4 +-
.../server/api/endpoints/i/webhooks/create.ts | 4 +-
.../src/server/api/endpoints/invite/create.ts | 4 +-
.../server/api/endpoints/notes/polls/vote.ts | 4 +-
.../src/server/api/endpoints/pages/create.ts | 4 +-
.../users/lists/create-from-public.ts | 4 +-
.../api/endpoints/users/lists/create.ts | 4 +-
.../api/endpoints/users/report-abuse.ts | 4 +-
packages/backend/test/e2e/move.ts | 4 +-
packages/backend/test/e2e/reversi-game.ts | 33 +++
36 files changed, 319 insertions(+), 215 deletions(-)
create mode 100644 packages/backend/test/e2e/reversi-game.ts
diff --git a/packages/backend/src/core/AnnouncementService.ts b/packages/backend/src/core/AnnouncementService.ts
index 9b60df2cae99..40a9db01c057 100644
--- a/packages/backend/src/core/AnnouncementService.ts
+++ b/packages/backend/src/core/AnnouncementService.ts
@@ -67,7 +67,7 @@ export class AnnouncementService {
@bindThis
public async create(values: Partial, moderator?: MiUser): Promise<{ raw: MiAnnouncement; packed: Packed<'Announcement'> }> {
- const announcement = await this.announcementsRepository.insert({
+ const announcement = await this.announcementsRepository.insertOne({
id: this.idService.gen(),
updatedAt: null,
title: values.title,
@@ -79,7 +79,7 @@ export class AnnouncementService {
silence: values.silence,
needConfirmationToRead: values.needConfirmationToRead,
userId: values.userId,
- }).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0]));
+ });
const packed = await this.announcementEntityService.pack(announcement);
diff --git a/packages/backend/src/core/AvatarDecorationService.ts b/packages/backend/src/core/AvatarDecorationService.ts
index 21e31d79a429..8b54bbe01241 100644
--- a/packages/backend/src/core/AvatarDecorationService.ts
+++ b/packages/backend/src/core/AvatarDecorationService.ts
@@ -55,10 +55,10 @@ export class AvatarDecorationService implements OnApplicationShutdown {
@bindThis
public async create(options: Partial, moderator?: MiUser): Promise {
- const created = await this.avatarDecorationsRepository.insert({
+ const created = await this.avatarDecorationsRepository.insertOne({
id: this.idService.gen(),
...options,
- }).then(x => this.avatarDecorationsRepository.findOneByOrFail(x.identifiers[0]));
+ });
this.globalEventService.publishInternalEvent('avatarDecorationCreated', created);
diff --git a/packages/backend/src/core/ClipService.ts b/packages/backend/src/core/ClipService.ts
index bb8be26ce6c5..9fd1ebad8724 100644
--- a/packages/backend/src/core/ClipService.ts
+++ b/packages/backend/src/core/ClipService.ts
@@ -45,13 +45,13 @@ export class ClipService {
throw new ClipService.TooManyClipsError();
}
- const clip = await this.clipsRepository.insert({
+ const clip = await this.clipsRepository.insertOne({
id: this.idService.gen(),
userId: me.id,
name: name,
isPublic: isPublic,
description: description,
- }).then(x => this.clipsRepository.findOneByOrFail(x.identifiers[0]));
+ });
return clip;
}
diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts
index b1feca7fb4d3..7e11b9cdca15 100644
--- a/packages/backend/src/core/CustomEmojiService.ts
+++ b/packages/backend/src/core/CustomEmojiService.ts
@@ -68,7 +68,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
localOnly: boolean;
roleIdsThatCanBeUsedThisEmojiAsReaction: MiRole['id'][];
}, moderator?: MiUser): Promise {
- const emoji = await this.emojisRepository.insert({
+ const emoji = await this.emojisRepository.insertOne({
id: this.idService.gen(),
updatedAt: new Date(),
name: data.name,
@@ -82,7 +82,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
isSensitive: data.isSensitive,
localOnly: data.localOnly,
roleIdsThatCanBeUsedThisEmojiAsReaction: data.roleIdsThatCanBeUsedThisEmojiAsReaction,
- }).then(x => this.emojisRepository.findOneByOrFail(x.identifiers[0]));
+ });
if (data.host == null) {
this.localEmojisCache.refresh();
diff --git a/packages/backend/src/core/DriveService.ts b/packages/backend/src/core/DriveService.ts
index 26cf532c7016..37c5d1adf7b7 100644
--- a/packages/backend/src/core/DriveService.ts
+++ b/packages/backend/src/core/DriveService.ts
@@ -220,7 +220,7 @@ export class DriveService {
file.size = size;
file.storedInternal = false;
- return await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0]));
+ return await this.driveFilesRepository.insertOne(file);
} else { // use internal storage
const accessKey = randomUUID();
const thumbnailAccessKey = 'thumbnail-' + randomUUID();
@@ -254,7 +254,7 @@ export class DriveService {
file.md5 = hash;
file.size = size;
- return await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0]));
+ return await this.driveFilesRepository.insertOne(file);
}
}
@@ -615,7 +615,7 @@ export class DriveService {
file.type = info.type.mime;
file.storedInternal = false;
- file = await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0]));
+ file = await this.driveFilesRepository.insertOne(file);
} catch (err) {
// duplicate key error (when already registered)
if (isDuplicateKeyValueError(err)) {
diff --git a/packages/backend/src/core/FederatedInstanceService.ts b/packages/backend/src/core/FederatedInstanceService.ts
index 66db2067d9f8..6799f2c5bbdc 100644
--- a/packages/backend/src/core/FederatedInstanceService.ts
+++ b/packages/backend/src/core/FederatedInstanceService.ts
@@ -55,11 +55,11 @@ export class FederatedInstanceService implements OnApplicationShutdown {
const index = await this.instancesRepository.findOneBy({ host });
if (index == null) {
- const i = await this.instancesRepository.insert({
+ const i = await this.instancesRepository.insertOne({
id: this.idService.gen(),
host,
firstRetrievedAt: new Date(),
- }).then(x => this.instancesRepository.findOneByOrFail(x.identifiers[0]));
+ });
this.federatedInstanceCache.set(host, i);
return i;
diff --git a/packages/backend/src/core/RelayService.ts b/packages/backend/src/core/RelayService.ts
index e9dc9b57afef..8dd3d64f5b29 100644
--- a/packages/backend/src/core/RelayService.ts
+++ b/packages/backend/src/core/RelayService.ts
@@ -53,11 +53,11 @@ export class RelayService {
@bindThis
public async addRelay(inbox: string): Promise {
- const relay = await this.relaysRepository.insert({
+ const relay = await this.relaysRepository.insertOne({
id: this.idService.gen(),
inbox,
status: 'requesting',
- }).then(x => this.relaysRepository.findOneByOrFail(x.identifiers[0]));
+ });
const relayActor = await this.getRelayActor();
const follow = await this.apRendererService.renderFollowRelay(relay, relayActor);
diff --git a/packages/backend/src/core/ReversiService.ts b/packages/backend/src/core/ReversiService.ts
index 439bc0884585..7f939b99c7a6 100644
--- a/packages/backend/src/core/ReversiService.ts
+++ b/packages/backend/src/core/ReversiService.ts
@@ -281,7 +281,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
@bindThis
private async matched(parentId: MiUser['id'], childId: MiUser['id'], options: { noIrregularRules: boolean; }): Promise {
- const game = await this.reversiGamesRepository.insert({
+ const game = await this.reversiGamesRepository.insertOne({
id: this.idService.gen(),
user1Id: parentId,
user2Id: childId,
@@ -294,10 +294,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
bw: 'random',
isLlotheo: false,
noIrregularRules: options.noIrregularRules,
- }).then(x => this.reversiGamesRepository.findOneOrFail({
- where: { id: x.identifiers[0].id },
- relations: ['user1', 'user2'],
- }));
+ }, { relations: ['user1', 'user2'] });
this.cacheGame(game);
const packed = await this.reversiGameEntityService.packDetail(game);
diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts
index 70c537f9abdc..d6eea702970b 100644
--- a/packages/backend/src/core/RoleService.ts
+++ b/packages/backend/src/core/RoleService.ts
@@ -471,12 +471,12 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
}
}
- const created = await this.roleAssignmentsRepository.insert({
+ const created = await this.roleAssignmentsRepository.insertOne({
id: this.idService.gen(now),
expiresAt: expiresAt,
roleId: roleId,
userId: userId,
- }).then(x => this.roleAssignmentsRepository.findOneByOrFail(x.identifiers[0]));
+ });
this.rolesRepository.update(roleId, {
lastUsedAt: new Date(),
@@ -558,7 +558,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
@bindThis
public async create(values: Partial, moderator?: MiUser): Promise {
const date = new Date();
- const created = await this.rolesRepository.insert({
+ const created = await this.rolesRepository.insertOne({
id: this.idService.gen(date.getTime()),
updatedAt: date,
lastUsedAt: date,
@@ -576,7 +576,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
canEditMembersByModerator: values.canEditMembersByModerator,
displayOrder: values.displayOrder,
policies: values.policies,
- }).then(x => this.rolesRepository.findOneByOrFail(x.identifiers[0]));
+ });
this.globalEventService.publishInternalEvent('roleCreated', created);
diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts
index deeecdeb1f12..406ea040316a 100644
--- a/packages/backend/src/core/UserFollowingService.ts
+++ b/packages/backend/src/core/UserFollowingService.ts
@@ -517,7 +517,7 @@ export class UserFollowingService implements OnModuleInit {
followerId: follower.id,
});
- const followRequest = await this.followRequestsRepository.insert({
+ const followRequest = await this.followRequestsRepository.insertOne({
id: this.idService.gen(),
followerId: follower.id,
followeeId: followee.id,
@@ -531,7 +531,7 @@ export class UserFollowingService implements OnModuleInit {
followeeHost: followee.host,
followeeInbox: this.userEntityService.isRemoteUser(followee) ? followee.inbox : undefined,
followeeSharedInbox: this.userEntityService.isRemoteUser(followee) ? followee.sharedInbox : undefined,
- }).then(x => this.followRequestsRepository.findOneByOrFail(x.identifiers[0]));
+ });
// Publish receiveRequest event
if (this.userEntityService.isLocalUser(followee)) {
diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts
index e6dff067f31f..c6e6b3a1e8db 100644
--- a/packages/backend/src/core/activitypub/models/ApNoteService.ts
+++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts
@@ -407,7 +407,7 @@ export class ApNoteService {
this.logger.info(`register emoji host=${host}, name=${name}`);
- return await this.emojisRepository.insert({
+ return await this.emojisRepository.insertOne({
id: this.idService.gen(),
host,
name,
@@ -416,7 +416,7 @@ export class ApNoteService {
publicUrl: tag.icon.url,
updatedAt: new Date(),
aliases: [],
- }).then(x => this.emojisRepository.findOneByOrFail(x.identifiers[0]));
+ });
}));
}
}
diff --git a/packages/backend/src/core/chart/core.ts b/packages/backend/src/core/chart/core.ts
index f10e30ef1048..af5485a46ee9 100644
--- a/packages/backend/src/core/chart/core.ts
+++ b/packages/backend/src/core/chart/core.ts
@@ -14,7 +14,8 @@ import { EntitySchema, LessThan, Between } from 'typeorm';
import { dateUTC, isTimeSame, isTimeBefore, subtractTime, addTime } from '@/misc/prelude/time.js';
import type Logger from '@/logger.js';
import { bindThis } from '@/decorators.js';
-import type { Repository, DataSource } from 'typeorm';
+import { MiRepository, miRepository } from '@/models/_.js';
+import type { DataSource, Repository } from 'typeorm';
const COLUMN_PREFIX = '___' as const;
const UNIQUE_TEMP_COLUMN_PREFIX = 'unique_temp___' as const;
@@ -145,10 +146,10 @@ export default abstract class Chart {
group: string | null;
}[] = [];
// ↓にしたいけどfindOneとかで型エラーになる
- //private repositoryForHour: Repository>;
- //private repositoryForDay: Repository>;
- private repositoryForHour: Repository<{ id: number; group?: string | null; date: number; }>;
- private repositoryForDay: Repository<{ id: number; group?: string | null; date: number; }>;
+ //private repositoryForHour: Repository> & MiRepository>;
+ //private repositoryForDay: Repository> & MiRepository>;
+ private repositoryForHour: Repository<{ id: number; group?: string | null; date: number; }> & MiRepository<{ id: number; group?: string | null; date: number; }>;
+ private repositoryForDay: Repository<{ id: number; group?: string | null; date: number; }> & MiRepository<{ id: number; group?: string | null; date: number; }>;
/**
* 1日に一回程度実行されれば良いような計算処理を入れる(主にCASCADE削除などアプリケーション側で感知できない変動によるズレの修正用)
@@ -211,6 +212,10 @@ export default abstract class Chart {
} {
const createEntity = (span: 'hour' | 'day'): EntitySchema => new EntitySchema({
name:
+ span === 'hour' ? `ChartX${name}` :
+ span === 'day' ? `ChartDayX${name}` :
+ new Error('not happen') as never,
+ tableName:
span === 'hour' ? `__chart__${camelToSnake(name)}` :
span === 'day' ? `__chart_day__${camelToSnake(name)}` :
new Error('not happen') as never,
@@ -271,8 +276,8 @@ export default abstract class Chart {
this.logger = logger;
const { hour, day } = Chart.schemaToEntity(name, schema, grouped);
- this.repositoryForHour = db.getRepository<{ id: number; group?: string | null; date: number; }>(hour);
- this.repositoryForDay = db.getRepository<{ id: number; group?: string | null; date: number; }>(day);
+ this.repositoryForHour = db.getRepository<{ id: number; group?: string | null; date: number; }>(hour).extend(miRepository as MiRepository<{ id: number; group?: string | null; date: number; }>);
+ this.repositoryForDay = db.getRepository<{ id: number; group?: string | null; date: number; }>(day).extend(miRepository as MiRepository<{ id: number; group?: string | null; date: number; }>);
}
@bindThis
@@ -387,11 +392,11 @@ export default abstract class Chart {
}
// 新規ログ挿入
- log = await repository.insert({
+ log = await repository.insertOne({
date: date,
...(group ? { group: group } : {}),
...columns,
- }).then(x => repository.findOneByOrFail(x.identifiers[0])) as RawRecord;
+ }) as RawRecord;
this.logger.info(`${this.name + (group ? `:${group}` : '')}(${span}): New commit created`);
diff --git a/packages/backend/src/models/RepositoryModule.ts b/packages/backend/src/models/RepositoryModule.ts
index bd447570ddf0..d3062d6b36f8 100644
--- a/packages/backend/src/models/RepositoryModule.ts
+++ b/packages/backend/src/models/RepositoryModule.ts
@@ -5,409 +5,409 @@
import { Module } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
-import { MiAbuseUserReport, MiAccessToken, MiAd, MiAnnouncement, MiAnnouncementRead, MiAntenna, MiApp, MiAuthSession, MiAvatarDecoration, MiBlocking, MiChannel, MiChannelFavorite, MiChannelFollowing, MiClip, MiClipFavorite, MiClipNote, MiDriveFile, MiDriveFolder, MiEmoji, MiFlash, MiFlashLike, MiFollowRequest, MiFollowing, MiGalleryLike, MiGalleryPost, MiHashtag, MiInstance, MiMeta, MiModerationLog, MiMuting, MiNote, MiNoteFavorite, MiNoteReaction, MiNoteThreadMuting, MiNoteUnread, MiPage, MiPageLike, MiPasswordResetRequest, MiPoll, MiPollVote, MiPromoNote, MiPromoRead, MiRegistrationTicket, MiRegistryItem, MiRelay, MiRenoteMuting, MiRetentionAggregation, MiRole, MiRoleAssignment, MiSignin, MiSwSubscription, MiUsedUsername, MiUser, MiUserIp, MiUserKeypair, MiUserList, MiUserListFavorite, MiUserListMembership, MiUserMemo, MiUserNotePining, MiUserPending, MiUserProfile, MiUserPublickey, MiUserSecurityKey, MiWebhook, MiBubbleGameRecord, MiReversiGame } from './_.js';
+import { MiRepository, MiAbuseUserReport, MiAccessToken, MiAd, MiAnnouncement, MiAnnouncementRead, MiAntenna, MiApp, MiAuthSession, MiAvatarDecoration, MiBlocking, MiChannel, MiChannelFavorite, MiChannelFollowing, MiClip, MiClipFavorite, MiClipNote, MiDriveFile, MiDriveFolder, MiEmoji, MiFlash, MiFlashLike, MiFollowRequest, MiFollowing, MiGalleryLike, MiGalleryPost, MiHashtag, MiInstance, MiMeta, MiModerationLog, MiMuting, MiNote, MiNoteFavorite, MiNoteReaction, MiNoteThreadMuting, MiNoteUnread, MiPage, MiPageLike, MiPasswordResetRequest, MiPoll, MiPollVote, MiPromoNote, MiPromoRead, MiRegistrationTicket, MiRegistryItem, MiRelay, MiRenoteMuting, MiRetentionAggregation, MiRole, MiRoleAssignment, MiSignin, MiSwSubscription, MiUsedUsername, MiUser, MiUserIp, MiUserKeypair, MiUserList, MiUserListFavorite, MiUserListMembership, MiUserMemo, MiUserNotePining, MiUserPending, MiUserProfile, MiUserPublickey, MiUserSecurityKey, MiWebhook, MiBubbleGameRecord, MiReversiGame, miRepository } from './_.js';
import type { DataSource } from 'typeorm';
import type { Provider } from '@nestjs/common';
const $usersRepository: Provider = {
provide: DI.usersRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUser),
+ useFactory: (db: DataSource) => db.getRepository(MiUser).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $notesRepository: Provider = {
provide: DI.notesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiNote),
+ useFactory: (db: DataSource) => db.getRepository(MiNote).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $announcementsRepository: Provider = {
provide: DI.announcementsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAnnouncement),
+ useFactory: (db: DataSource) => db.getRepository(MiAnnouncement).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $announcementReadsRepository: Provider = {
provide: DI.announcementReadsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAnnouncementRead),
+ useFactory: (db: DataSource) => db.getRepository(MiAnnouncementRead).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $appsRepository: Provider = {
provide: DI.appsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiApp),
+ useFactory: (db: DataSource) => db.getRepository(MiApp).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $avatarDecorationsRepository: Provider = {
provide: DI.avatarDecorationsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAvatarDecoration),
+ useFactory: (db: DataSource) => db.getRepository(MiAvatarDecoration).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $noteFavoritesRepository: Provider = {
provide: DI.noteFavoritesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiNoteFavorite),
+ useFactory: (db: DataSource) => db.getRepository(MiNoteFavorite).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $noteThreadMutingsRepository: Provider = {
provide: DI.noteThreadMutingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiNoteThreadMuting),
+ useFactory: (db: DataSource) => db.getRepository(MiNoteThreadMuting).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $noteReactionsRepository: Provider = {
provide: DI.noteReactionsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiNoteReaction),
+ useFactory: (db: DataSource) => db.getRepository(MiNoteReaction).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $noteUnreadsRepository: Provider = {
provide: DI.noteUnreadsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiNoteUnread),
+ useFactory: (db: DataSource) => db.getRepository(MiNoteUnread).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $pollsRepository: Provider = {
provide: DI.pollsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPoll),
+ useFactory: (db: DataSource) => db.getRepository(MiPoll).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $pollVotesRepository: Provider = {
provide: DI.pollVotesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPollVote),
+ useFactory: (db: DataSource) => db.getRepository(MiPollVote).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userProfilesRepository: Provider = {
provide: DI.userProfilesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserProfile),
+ useFactory: (db: DataSource) => db.getRepository(MiUserProfile).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userKeypairsRepository: Provider = {
provide: DI.userKeypairsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserKeypair),
+ useFactory: (db: DataSource) => db.getRepository(MiUserKeypair).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userPendingsRepository: Provider = {
provide: DI.userPendingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserPending),
+ useFactory: (db: DataSource) => db.getRepository(MiUserPending).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userSecurityKeysRepository: Provider = {
provide: DI.userSecurityKeysRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserSecurityKey),
+ useFactory: (db: DataSource) => db.getRepository(MiUserSecurityKey).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userPublickeysRepository: Provider = {
provide: DI.userPublickeysRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserPublickey),
+ useFactory: (db: DataSource) => db.getRepository(MiUserPublickey).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userListsRepository: Provider = {
provide: DI.userListsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserList),
+ useFactory: (db: DataSource) => db.getRepository(MiUserList).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userListFavoritesRepository: Provider = {
provide: DI.userListFavoritesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserListFavorite),
+ useFactory: (db: DataSource) => db.getRepository(MiUserListFavorite).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userListMembershipsRepository: Provider = {
provide: DI.userListMembershipsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserListMembership),
+ useFactory: (db: DataSource) => db.getRepository(MiUserListMembership).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userNotePiningsRepository: Provider = {
provide: DI.userNotePiningsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserNotePining),
+ useFactory: (db: DataSource) => db.getRepository(MiUserNotePining).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userIpsRepository: Provider = {
provide: DI.userIpsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserIp),
+ useFactory: (db: DataSource) => db.getRepository(MiUserIp).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $usedUsernamesRepository: Provider = {
provide: DI.usedUsernamesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUsedUsername),
+ useFactory: (db: DataSource) => db.getRepository(MiUsedUsername).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $followingsRepository: Provider = {
provide: DI.followingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiFollowing),
+ useFactory: (db: DataSource) => db.getRepository(MiFollowing).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $followRequestsRepository: Provider = {
provide: DI.followRequestsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiFollowRequest),
+ useFactory: (db: DataSource) => db.getRepository(MiFollowRequest).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $instancesRepository: Provider = {
provide: DI.instancesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiInstance),
+ useFactory: (db: DataSource) => db.getRepository(MiInstance).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $emojisRepository: Provider = {
provide: DI.emojisRepository,
- useFactory: (db: DataSource) => db.getRepository(MiEmoji),
+ useFactory: (db: DataSource) => db.getRepository(MiEmoji).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $driveFilesRepository: Provider = {
provide: DI.driveFilesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiDriveFile),
+ useFactory: (db: DataSource) => db.getRepository(MiDriveFile).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $driveFoldersRepository: Provider = {
provide: DI.driveFoldersRepository,
- useFactory: (db: DataSource) => db.getRepository(MiDriveFolder),
+ useFactory: (db: DataSource) => db.getRepository(MiDriveFolder).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $metasRepository: Provider = {
provide: DI.metasRepository,
- useFactory: (db: DataSource) => db.getRepository(MiMeta),
+ useFactory: (db: DataSource) => db.getRepository(MiMeta).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $mutingsRepository: Provider = {
provide: DI.mutingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiMuting),
+ useFactory: (db: DataSource) => db.getRepository(MiMuting).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $renoteMutingsRepository: Provider = {
provide: DI.renoteMutingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRenoteMuting),
+ useFactory: (db: DataSource) => db.getRepository(MiRenoteMuting).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $blockingsRepository: Provider = {
provide: DI.blockingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiBlocking),
+ useFactory: (db: DataSource) => db.getRepository(MiBlocking).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $swSubscriptionsRepository: Provider = {
provide: DI.swSubscriptionsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiSwSubscription),
+ useFactory: (db: DataSource) => db.getRepository(MiSwSubscription).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $hashtagsRepository: Provider = {
provide: DI.hashtagsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiHashtag),
+ useFactory: (db: DataSource) => db.getRepository(MiHashtag).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $abuseUserReportsRepository: Provider = {
provide: DI.abuseUserReportsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAbuseUserReport),
+ useFactory: (db: DataSource) => db.getRepository(MiAbuseUserReport).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $registrationTicketsRepository: Provider = {
provide: DI.registrationTicketsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRegistrationTicket),
+ useFactory: (db: DataSource) => db.getRepository(MiRegistrationTicket).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $authSessionsRepository: Provider = {
provide: DI.authSessionsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAuthSession),
+ useFactory: (db: DataSource) => db.getRepository(MiAuthSession).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $accessTokensRepository: Provider = {
provide: DI.accessTokensRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAccessToken),
+ useFactory: (db: DataSource) => db.getRepository(MiAccessToken).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $signinsRepository: Provider = {
provide: DI.signinsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiSignin),
+ useFactory: (db: DataSource) => db.getRepository(MiSignin).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $pagesRepository: Provider = {
provide: DI.pagesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPage),
+ useFactory: (db: DataSource) => db.getRepository(MiPage).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $pageLikesRepository: Provider = {
provide: DI.pageLikesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPageLike),
+ useFactory: (db: DataSource) => db.getRepository(MiPageLike).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $galleryPostsRepository: Provider = {
provide: DI.galleryPostsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiGalleryPost),
+ useFactory: (db: DataSource) => db.getRepository(MiGalleryPost).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $galleryLikesRepository: Provider = {
provide: DI.galleryLikesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiGalleryLike),
+ useFactory: (db: DataSource) => db.getRepository(MiGalleryLike).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $moderationLogsRepository: Provider = {
provide: DI.moderationLogsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiModerationLog),
+ useFactory: (db: DataSource) => db.getRepository(MiModerationLog).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $clipsRepository: Provider = {
provide: DI.clipsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiClip),
+ useFactory: (db: DataSource) => db.getRepository(MiClip).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $clipNotesRepository: Provider = {
provide: DI.clipNotesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiClipNote),
+ useFactory: (db: DataSource) => db.getRepository(MiClipNote).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $clipFavoritesRepository: Provider = {
provide: DI.clipFavoritesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiClipFavorite),
+ useFactory: (db: DataSource) => db.getRepository(MiClipFavorite).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $antennasRepository: Provider = {
provide: DI.antennasRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAntenna),
+ useFactory: (db: DataSource) => db.getRepository(MiAntenna).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $promoNotesRepository: Provider = {
provide: DI.promoNotesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPromoNote),
+ useFactory: (db: DataSource) => db.getRepository(MiPromoNote).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $promoReadsRepository: Provider = {
provide: DI.promoReadsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPromoRead),
+ useFactory: (db: DataSource) => db.getRepository(MiPromoRead).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $relaysRepository: Provider = {
provide: DI.relaysRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRelay),
+ useFactory: (db: DataSource) => db.getRepository(MiRelay).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $channelsRepository: Provider = {
provide: DI.channelsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiChannel),
+ useFactory: (db: DataSource) => db.getRepository(MiChannel).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $channelFollowingsRepository: Provider = {
provide: DI.channelFollowingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiChannelFollowing),
+ useFactory: (db: DataSource) => db.getRepository(MiChannelFollowing).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $channelFavoritesRepository: Provider = {
provide: DI.channelFavoritesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiChannelFavorite),
+ useFactory: (db: DataSource) => db.getRepository(MiChannelFavorite).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $registryItemsRepository: Provider = {
provide: DI.registryItemsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRegistryItem),
+ useFactory: (db: DataSource) => db.getRepository(MiRegistryItem).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $webhooksRepository: Provider = {
provide: DI.webhooksRepository,
- useFactory: (db: DataSource) => db.getRepository(MiWebhook),
+ useFactory: (db: DataSource) => db.getRepository(MiWebhook).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $adsRepository: Provider = {
provide: DI.adsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAd),
+ useFactory: (db: DataSource) => db.getRepository(MiAd).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $passwordResetRequestsRepository: Provider = {
provide: DI.passwordResetRequestsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPasswordResetRequest),
+ useFactory: (db: DataSource) => db.getRepository(MiPasswordResetRequest).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $retentionAggregationsRepository: Provider = {
provide: DI.retentionAggregationsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRetentionAggregation),
+ useFactory: (db: DataSource) => db.getRepository(MiRetentionAggregation).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $flashsRepository: Provider = {
provide: DI.flashsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiFlash),
+ useFactory: (db: DataSource) => db.getRepository(MiFlash).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $flashLikesRepository: Provider = {
provide: DI.flashLikesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiFlashLike),
+ useFactory: (db: DataSource) => db.getRepository(MiFlashLike).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $rolesRepository: Provider = {
provide: DI.rolesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRole),
+ useFactory: (db: DataSource) => db.getRepository(MiRole).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $roleAssignmentsRepository: Provider = {
provide: DI.roleAssignmentsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRoleAssignment),
+ useFactory: (db: DataSource) => db.getRepository(MiRoleAssignment).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userMemosRepository: Provider = {
provide: DI.userMemosRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserMemo),
+ useFactory: (db: DataSource) => db.getRepository(MiUserMemo).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $bubbleGameRecordsRepository: Provider = {
provide: DI.bubbleGameRecordsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiBubbleGameRecord),
+ useFactory: (db: DataSource) => db.getRepository(MiBubbleGameRecord).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $reversiGamesRepository: Provider = {
provide: DI.reversiGamesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiReversiGame),
+ useFactory: (db: DataSource) => db.getRepository(MiReversiGame).extend(miRepository as MiRepository),
inject: [DI.db],
};
diff --git a/packages/backend/src/models/_.ts b/packages/backend/src/models/_.ts
index 43d42d80dd32..2e6a41586e45 100644
--- a/packages/backend/src/models/_.ts
+++ b/packages/backend/src/models/_.ts
@@ -3,6 +3,13 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
+import { FindOneOptions, InsertQueryBuilder, ObjectLiteral, Repository, SelectQueryBuilder, TypeORMError } from 'typeorm';
+import { DriverUtils } from 'typeorm/driver/DriverUtils.js';
+import { RelationCountLoader } from 'typeorm/query-builder/relation-count/RelationCountLoader.js';
+import { RelationIdLoader } from 'typeorm/query-builder/relation-id/RelationIdLoader.js';
+import { RawSqlResultsToEntityTransformer } from 'typeorm/query-builder/transformer/RawSqlResultsToEntityTransformer.js';
+import { ObjectUtils } from 'typeorm/util/ObjectUtils.js';
+import { OrmUtils } from 'typeorm/util/OrmUtils.js';
import { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
import { MiAccessToken } from '@/models/AccessToken.js';
import { MiAd } from '@/models/Ad.js';
@@ -70,8 +77,70 @@ import { MiFlashLike } from '@/models/FlashLike.js';
import { MiUserListFavorite } from '@/models/UserListFavorite.js';
import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
import { MiReversiGame } from '@/models/ReversiGame.js';
+import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
-import type { Repository } from 'typeorm';
+export interface MiRepository {
+ createTableColumnNames(this: Repository & MiRepository, queryBuilder: InsertQueryBuilder): string[];
+ createTableColumnNamesWithPrimaryKey(this: Repository & MiRepository, queryBuilder: InsertQueryBuilder): string[];
+ insertOne(this: Repository & MiRepository, entity: QueryDeepPartialEntity, findOptions?: Pick, 'relations'>): Promise;
+ selectAliasColumnNames(this: Repository & MiRepository, queryBuilder: InsertQueryBuilder, builder: SelectQueryBuilder): void;
+}
+
+export const miRepository = {
+ createTableColumnNames(queryBuilder) {
+ // @ts-expect-error -- protected
+ const insertedColumns = queryBuilder.getInsertedColumns();
+ if (insertedColumns.length) {
+ return insertedColumns.map(column => column.databaseName);
+ }
+ if (!queryBuilder.expressionMap.mainAlias?.hasMetadata && !queryBuilder.expressionMap.insertColumns.length) {
+ // @ts-expect-error -- protected
+ const valueSets = queryBuilder.getValueSets();
+ if (valueSets.length === 1) {
+ return Object.keys(valueSets[0]);
+ }
+ }
+ return queryBuilder.expressionMap.insertColumns;
+ },
+ createTableColumnNamesWithPrimaryKey(queryBuilder) {
+ const columnNames = this.createTableColumnNames(queryBuilder);
+ if (!columnNames.includes('id')) {
+ columnNames.unshift('id');
+ }
+ return columnNames;
+ },
+ async insertOne(entity, findOptions?) {
+ const queryBuilder = this.createQueryBuilder().insert().values(entity);
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ const mainAlias = queryBuilder.expressionMap.mainAlias!;
+ const name = mainAlias.name;
+ mainAlias.name = 't';
+ const columnNames = this.createTableColumnNamesWithPrimaryKey(queryBuilder);
+ queryBuilder.returning(columnNames.reduce((a, c) => `${a}, ${queryBuilder.escape(c)}`, '').slice(2));
+ const builder = this.createQueryBuilder().addCommonTableExpression(queryBuilder, 'cte', { columnNames });
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ builder.expressionMap.mainAlias!.tablePath = 'cte';
+ this.selectAliasColumnNames(queryBuilder, builder);
+ if (findOptions) {
+ builder.setFindOptions(findOptions);
+ }
+ const raw = await builder.execute();
+ mainAlias.name = name;
+ const relationId = await new RelationIdLoader(builder.connection, this.queryRunner, builder.expressionMap.relationIdAttributes).load(raw);
+ const relationCount = await new RelationCountLoader(builder.connection, this.queryRunner, builder.expressionMap.relationCountAttributes).load(raw);
+ const result = new RawSqlResultsToEntityTransformer(builder.expressionMap, builder.connection.driver, relationId, relationCount, this.queryRunner).transform(raw, mainAlias);
+ return result[0];
+ },
+ selectAliasColumnNames(queryBuilder, builder) {
+ let selectOrAddSelect = (selection: string, selectionAliasName?: string) => {
+ selectOrAddSelect = (selection, selectionAliasName) => builder.addSelect(selection, selectionAliasName);
+ return builder.select(selection, selectionAliasName);
+ };
+ for (const columnName of this.createTableColumnNamesWithPrimaryKey(queryBuilder)) {
+ selectOrAddSelect(`${builder.alias}.${columnName}`, `${builder.alias}_${columnName}`);
+ }
+ },
+} satisfies MiRepository;
export {
MiAbuseUserReport,
@@ -143,70 +212,70 @@ export {
MiReversiGame,
};
-export type AbuseUserReportsRepository = Repository;
-export type AccessTokensRepository = Repository;
-export type AdsRepository = Repository;
-export type AnnouncementsRepository = Repository;
-export type AnnouncementReadsRepository = Repository;
-export type AntennasRepository = Repository;
-export type AppsRepository = Repository;
-export type AvatarDecorationsRepository = Repository;
-export type AuthSessionsRepository = Repository;
-export type BlockingsRepository = Repository;
-export type ChannelFollowingsRepository = Repository;
-export type ChannelFavoritesRepository = Repository;
-export type ClipsRepository = Repository;
-export type ClipNotesRepository = Repository;
-export type ClipFavoritesRepository = Repository;
-export type DriveFilesRepository = Repository;
-export type DriveFoldersRepository = Repository;
-export type EmojisRepository = Repository;
-export type FollowingsRepository = Repository;
-export type FollowRequestsRepository = Repository;
-export type GalleryLikesRepository = Repository;
-export type GalleryPostsRepository = Repository;
-export type HashtagsRepository = Repository;
-export type InstancesRepository = Repository;
-export type MetasRepository = Repository;
-export type ModerationLogsRepository = Repository;
-export type MutingsRepository = Repository;
-export type RenoteMutingsRepository = Repository;
-export type NotesRepository = Repository;
-export type NoteFavoritesRepository = Repository;
-export type NoteReactionsRepository = Repository;
-export type NoteThreadMutingsRepository = Repository;
-export type NoteUnreadsRepository = Repository;
-export type PagesRepository = Repository;
-export type PageLikesRepository = Repository;
-export type PasswordResetRequestsRepository = Repository;
-export type PollsRepository = Repository;
-export type PollVotesRepository = Repository;
-export type PromoNotesRepository = Repository;
-export type PromoReadsRepository = Repository;
-export type RegistrationTicketsRepository = Repository;
-export type RegistryItemsRepository = Repository;
-export type RelaysRepository = Repository;
-export type SigninsRepository = Repository;
-export type SwSubscriptionsRepository = Repository;
-export type UsedUsernamesRepository = Repository;
-export type UsersRepository = Repository;
-export type UserIpsRepository = Repository;
-export type UserKeypairsRepository = Repository;
-export type UserListsRepository = Repository;
-export type UserListFavoritesRepository = Repository;
-export type UserListMembershipsRepository = Repository;
-export type UserNotePiningsRepository = Repository;
-export type UserPendingsRepository = Repository;
-export type UserProfilesRepository = Repository;
-export type UserPublickeysRepository = Repository;
-export type UserSecurityKeysRepository = Repository;
-export type WebhooksRepository = Repository;
-export type ChannelsRepository = Repository;
-export type RetentionAggregationsRepository = Repository;
-export type RolesRepository = Repository;
-export type RoleAssignmentsRepository = Repository;
-export type FlashsRepository = Repository;
-export type FlashLikesRepository = Repository;
-export type UserMemoRepository = Repository;
-export type BubbleGameRecordsRepository = Repository;
-export type ReversiGamesRepository = Repository;
+export type AbuseUserReportsRepository = Repository & MiRepository;
+export type AccessTokensRepository = Repository & MiRepository;
+export type AdsRepository = Repository & MiRepository;
+export type AnnouncementsRepository = Repository & MiRepository;
+export type AnnouncementReadsRepository = Repository & MiRepository;
+export type AntennasRepository = Repository & MiRepository;
+export type AppsRepository = Repository & MiRepository;
+export type AvatarDecorationsRepository = Repository & MiRepository;
+export type AuthSessionsRepository = Repository & MiRepository;
+export type BlockingsRepository = Repository & MiRepository;
+export type ChannelFollowingsRepository = Repository & MiRepository;
+export type ChannelFavoritesRepository = Repository & MiRepository;
+export type ClipsRepository = Repository & MiRepository;
+export type ClipNotesRepository = Repository & MiRepository;
+export type ClipFavoritesRepository = Repository & MiRepository;
+export type DriveFilesRepository = Repository & MiRepository;
+export type DriveFoldersRepository = Repository & MiRepository;
+export type EmojisRepository = Repository & MiRepository;
+export type FollowingsRepository = Repository & MiRepository;
+export type FollowRequestsRepository = Repository & MiRepository;
+export type GalleryLikesRepository = Repository & MiRepository;
+export type GalleryPostsRepository = Repository & MiRepository;
+export type HashtagsRepository = Repository & MiRepository;
+export type InstancesRepository = Repository & MiRepository;
+export type MetasRepository = Repository & MiRepository;
+export type ModerationLogsRepository = Repository & MiRepository;
+export type MutingsRepository = Repository & MiRepository;
+export type RenoteMutingsRepository = Repository & MiRepository;
+export type NotesRepository = Repository & MiRepository;
+export type NoteFavoritesRepository = Repository & MiRepository;
+export type NoteReactionsRepository = Repository & MiRepository;
+export type NoteThreadMutingsRepository = Repository & MiRepository;
+export type NoteUnreadsRepository = Repository & MiRepository;
+export type PagesRepository = Repository & MiRepository;
+export type PageLikesRepository = Repository & MiRepository;
+export type PasswordResetRequestsRepository = Repository & MiRepository;
+export type PollsRepository = Repository & MiRepository;
+export type PollVotesRepository = Repository & MiRepository;
+export type PromoNotesRepository = Repository & MiRepository;
+export type PromoReadsRepository = Repository & MiRepository;
+export type RegistrationTicketsRepository = Repository & MiRepository