mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-19 05:55:34 +09:00
refactor(api): collapse single-impl interfaces and facades (#3382)
This commit is contained in:
1 parent
e7b13fd19f
commit
c16d414d93
426 files changed
+2085
-6445
No files matched your search
@@ -1,24 +1,24 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import type {WorkerDependencies} from '@app/api/worker/WorkerDependencies';
|
||||
import {
|
||||
clearWorkerDependencies as clearWorkerDependenciesBase,
|
||||
getWorkerDependencies as getWorkerDependenciesBase,
|
||||
setWorkerDependencies as setWorkerDependenciesBase,
|
||||
} from '@pkgs/worker/src/context/WorkerContext';
|
||||
|
||||
let workerDependencies: WorkerDependencies | null = null;
|
||||
|
||||
export function setWorkerDependencies(dependencies: WorkerDependencies): void {
|
||||
setWorkerDependenciesBase(dependencies);
|
||||
workerDependencies = dependencies;
|
||||
}
|
||||
|
||||
export function setWorkerDependenciesForTest(dependencies: Partial<WorkerDependencies>): void {
|
||||
setWorkerDependenciesBase(dependencies);
|
||||
workerDependencies = dependencies as WorkerDependencies;
|
||||
}
|
||||
|
||||
export function getWorkerDependencies(): WorkerDependencies {
|
||||
return getWorkerDependenciesBase<WorkerDependencies>();
|
||||
if (!workerDependencies) {
|
||||
throw new Error('Worker dependencies have not been initialized. Call setWorkerDependencies() first.');
|
||||
}
|
||||
return workerDependencies;
|
||||
}
|
||||
|
||||
export function clearWorkerDependencies(): void {
|
||||
clearWorkerDependenciesBase();
|
||||
workerDependencies = null;
|
||||
}
|
||||
@@ -10,7 +10,6 @@ import type {ChannelService} from '@app/api/channel/services/ChannelService';
|
||||
import type {ConnectionRepository} from '@app/api/connection/ConnectionRepository';
|
||||
import {ConnectionService} from '@app/api/connection/ConnectionService';
|
||||
import {DonationRepository} from '@app/api/donation/DonationRepository';
|
||||
import type {IDonationRepository} from '@app/api/donation/IDonationRepository';
|
||||
import type {FavoriteMemeRepository} from '@app/api/favorite_meme/FavoriteMemeRepository';
|
||||
import type {GuildAuditLogService} from '@app/api/guild/GuildAuditLogService';
|
||||
import type {GuildRepository} from '@app/api/guild/repositories/GuildRepository';
|
||||
@@ -165,7 +164,7 @@ export interface WorkerDependencies {
|
||||
channelService: ChannelService;
|
||||
guildAuditLogService: GuildAuditLogService;
|
||||
contactChangeLogService: UserContactChangeLogService;
|
||||
donationRepository: IDonationRepository;
|
||||
donationRepository: DonationRepository;
|
||||
guildService: GuildService;
|
||||
billingRepository: BillingRepository;
|
||||
storeEntitlementService: StoreEntitlementService;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import {createHash, randomUUID} from 'node:crypto';
|
||||
import {ArchiveAttemptSupersededError} from '@app/api/archive/ArchiveAttemptSupersededError';
|
||||
import {ArchiveTaskDeferredError, ArchiveTerminalFailureError, isArchiveTask} from '@app/api/archive/ArchiveTask';
|
||||
import type {IJobLedgerRepository} from '@app/api/jobs/IJobLedgerRepository';
|
||||
import type {JobLedgerRepository} from '@app/api/jobs/JobLedgerRepository';
|
||||
import {Logger} from '@app/api/Logger';
|
||||
import {getWorkerService} from '@app/api/middleware/ServiceRegistry';
|
||||
import {isJsonRecord, parseJsonRecord} from '@app/api/utils/JsonBoundaryUtils';
|
||||
@@ -55,7 +55,7 @@ interface WorkerRunnerOptions {
|
||||
queue: WorkerRunnerQueue;
|
||||
consumerName: string;
|
||||
laneName: string;
|
||||
ledger: IJobLedgerRepository;
|
||||
ledger: JobLedgerRepository;
|
||||
workerId?: string;
|
||||
concurrency?: number;
|
||||
maxDeliver?: number;
|
||||
@@ -74,7 +74,7 @@ export class WorkerRunner {
|
||||
private readonly maxDeliver: number;
|
||||
private readonly ackWaitMs: number;
|
||||
private readonly workerService: IWorkerService;
|
||||
private readonly ledger: IJobLedgerRepository;
|
||||
private readonly ledger: JobLedgerRepository;
|
||||
private readonly heartbeat: WorkerHeartbeat | null;
|
||||
private heartbeatSignal: WorkerHeartbeatSignal | null = null;
|
||||
private heartbeatTimer: NodeJS.Timeout | null = null;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import type {ISnowflakeService} from '@app/api/infrastructure/ISnowflakeService';
|
||||
import type {IJobLedgerRepository} from '@app/api/jobs/IJobLedgerRepository';
|
||||
import type {JobLedgerRepository} from '@app/api/jobs/JobLedgerRepository';
|
||||
import {Logger} from '@app/api/Logger';
|
||||
import type {JetStreamWorkerQueue} from '@app/api/worker/JetStreamWorkerQueue';
|
||||
import {findLaneForTask, type WorkerTaskName} from '@app/api/worker/WorkerLaneConfig';
|
||||
@@ -12,9 +12,9 @@ import type {WorkerJobOptions, WorkerJobPayload} from '@pkgs/worker/src/contract
|
||||
export class WorkerService implements IWorkerService<WorkerTaskName> {
|
||||
private readonly queue: JetStreamWorkerQueue;
|
||||
private readonly snowflake: ISnowflakeService;
|
||||
private readonly ledger: IJobLedgerRepository;
|
||||
private readonly ledger: JobLedgerRepository;
|
||||
|
||||
constructor(queue: JetStreamWorkerQueue, snowflake: ISnowflakeService, ledger: IJobLedgerRepository) {
|
||||
constructor(queue: JetStreamWorkerQueue, snowflake: ISnowflakeService, ledger: JobLedgerRepository) {
|
||||
this.queue = queue;
|
||||
this.snowflake = snowflake;
|
||||
this.ledger = ledger;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import type {ReportID} from '@app/api/BrandedTypes';
|
||||
import {Logger} from '@app/api/Logger';
|
||||
import type {IReportRepository} from '@app/api/report/IReportRepository';
|
||||
import type {ReportRepository} from '@app/api/report/ReportRepository';
|
||||
import {getWorkerDependencies} from '@app/api/worker/WorkerContext';
|
||||
import type {WorkerTaskHandler} from '@pkgs/worker/src/contracts/WorkerTask';
|
||||
|
||||
@@ -16,7 +16,7 @@ export interface ClearAuthenticatedReporterEmailsSummary {
|
||||
}
|
||||
|
||||
export async function clearAuthenticatedReporterEmails(
|
||||
reportRepository: IReportRepository,
|
||||
reportRepository: ReportRepository,
|
||||
pageSize = DEFAULT_SCAN_PAGE_SIZE,
|
||||
): Promise<ClearAuthenticatedReporterEmailsSummary> {
|
||||
const summary: ClearAuthenticatedReporterEmailsSummary = {scanned: 0, cleared: 0, skipped: 0, failed: 0};
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import type {ReportID} from '@app/api/BrandedTypes';
|
||||
import {Config} from '@app/api/Config';
|
||||
import {Logger} from '@app/api/Logger';
|
||||
import {type IARSubmission, ReportStatus} from '@app/api/report/IReportRepository';
|
||||
import {
|
||||
deleteReportWithEvidence,
|
||||
forEachStoredReport,
|
||||
@@ -11,6 +10,7 @@ import {
|
||||
type ReportDeletionDeps,
|
||||
referencedObjectKeys,
|
||||
} from '@app/api/report/ReportDeletion';
|
||||
import {type IARSubmission, ReportStatus} from '@app/api/report/ReportModels';
|
||||
import {getReportSearchService} from '@app/api/SearchFactory';
|
||||
import {getWorkerDependencies} from '@app/api/worker/WorkerContext';
|
||||
import type {WorkerTaskHandler} from '@pkgs/worker/src/contracts/WorkerTask';
|
||||
|
||||
@@ -203,7 +203,7 @@ async function readMessageForExpectedContent(
|
||||
): Promise<Message | null> {
|
||||
let lastMessage: Message | null = null;
|
||||
for (let attempt = 0; attempt < MESSAGE_READ_RETRY_ATTEMPTS; attempt++) {
|
||||
const message = await channelRepository.getMessage(channelId, messageId);
|
||||
const message = await channelRepository.messages.getMessage(channelId, messageId);
|
||||
if (message && messageMatchesExpectedContent(message, expectedContentHash)) {
|
||||
return message;
|
||||
}
|
||||
@@ -383,7 +383,7 @@ async function updateMessageEmbeds(
|
||||
...freshMessage.toRow(),
|
||||
embeds: nextEmbeds.length > 0 ? nextEmbeds : null,
|
||||
});
|
||||
await channelRepository.updateEmbeds(messageWithEmbeds);
|
||||
await channelRepository.messages.updateEmbeds(messageWithEmbeds);
|
||||
return messageWithEmbeds;
|
||||
}
|
||||
|
||||
@@ -438,7 +438,7 @@ const extractEmbeds: WorkerTaskHandler = async (payload, helpers) => {
|
||||
Logger.info({messageId: messageId.toString()}, 'Skipping extractEmbeds: message not found or no content');
|
||||
return;
|
||||
}
|
||||
const channel = await channelRepository.findUnique(channelId);
|
||||
const channel = await channelRepository.channelData.findUnique(channelId);
|
||||
if (!channel) {
|
||||
Logger.info({channelId: channelId.toString()}, 'Skipping extractEmbeds: channel not found');
|
||||
return;
|
||||
@@ -465,7 +465,7 @@ const extractEmbeds: WorkerTaskHandler = async (payload, helpers) => {
|
||||
const orderedEmbeds = buildOrderedEmbeds(urls, unfurledEmbedsByUrl);
|
||||
let propagated: Message | null = null;
|
||||
const handled = await withMessageWriteLock(cacheService, channelId, messageId, async () => {
|
||||
const latestExpectedMessage = await channelRepository.getMessage(channelId, messageId);
|
||||
const latestExpectedMessage = await channelRepository.messages.getMessage(channelId, messageId);
|
||||
if (!latestExpectedMessage) {
|
||||
Logger.debug({messageId: messageId.toString()}, 'Message no longer exists, skipping embed update');
|
||||
return false;
|
||||
@@ -494,7 +494,7 @@ const extractEmbeds: WorkerTaskHandler = async (payload, helpers) => {
|
||||
},
|
||||
'Content moderation blocked embed unfurl, deleting parent message',
|
||||
);
|
||||
await channelRepository.deleteMessage(
|
||||
await channelRepository.messages.deleteMessage(
|
||||
channelId,
|
||||
messageId,
|
||||
latestExpectedMessage.authorId || createUserID(0n),
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
} from '@app/api/BrandedTypes';
|
||||
import {guildActive} from '@app/api/experiment/ChannelThreadsGate';
|
||||
import {Logger} from '@app/api/Logger';
|
||||
import type {ReadStateMarker} from '@app/api/read_state/IReadStateRepository';
|
||||
import type {ReadStateMarker} from '@app/api/read_state/ReadStateRepository';
|
||||
import {mapWithConcurrency} from '@app/api/utils/ConcurrencyUtils';
|
||||
import {getWorkerDependencies} from '@app/api/worker/WorkerContext';
|
||||
import {ReadStateFlags} from '@fluxer/constants/src/ThreadConstants';
|
||||
|
||||
@@ -233,12 +233,12 @@ const handleMentions: WorkerTaskHandler = async (payload, helpers) => {
|
||||
const messageId = createMessageID(BigInt(validated.messageId));
|
||||
const payloadGuildId = validated.guildId ? createGuildID(BigInt(validated.guildId)) : null;
|
||||
const mentionHere = validated.mentionHere ?? false;
|
||||
const message = await channelRepository.getMessage(channelId, messageId);
|
||||
const message = await channelRepository.messages.getMessage(channelId, messageId);
|
||||
if (!message) {
|
||||
Logger.debug({messageId}, 'handleMentions: Message not found, skipping');
|
||||
return;
|
||||
}
|
||||
const channel = await channelRepository.findUnique(channelId);
|
||||
const channel = await channelRepository.channelData.findUnique(channelId);
|
||||
if (!channel) {
|
||||
Logger.debug({channelId}, 'handleMentions: Channel not found, skipping');
|
||||
return;
|
||||
|
||||
@@ -235,7 +235,7 @@ const harvestGuildData: ArchiveTaskHandler = async (payload, helpers, attempt) =
|
||||
let beforeMessageId: MessageID | undefined;
|
||||
let channelDownloads: Array<PendingAttachmentDownload> = [];
|
||||
while (messages.length < MESSAGE_LIMIT_PER_CHANNEL) {
|
||||
const batch = await channelRepository.listMessages(channel.id, beforeMessageId, MESSAGE_BATCH_SIZE);
|
||||
const batch = await channelRepository.messages.listMessages(channel.id, beforeMessageId, MESSAGE_BATCH_SIZE);
|
||||
if (batch.length === 0) break;
|
||||
for (const msg of batch) {
|
||||
if (msg.authorId == null) continue;
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
type UserID,
|
||||
} from '@app/api/BrandedTypes';
|
||||
import {Config} from '@app/api/Config';
|
||||
import type {IThreadRepository} from '@app/api/channel/repositories/IThreadRepository';
|
||||
import type {ThreadRepository} from '@app/api/channel/repositories/ThreadRepository';
|
||||
import {
|
||||
isChannelEligible,
|
||||
isTimestampInWindow,
|
||||
@@ -417,7 +417,7 @@ export async function harvestMessages(
|
||||
}
|
||||
|
||||
export async function collectThreadMemberships(
|
||||
threads: Pick<IThreadRepository, 'listJoinedThreadIds' | 'getMember'>,
|
||||
threads: Pick<ThreadRepository, 'listJoinedThreadIds' | 'getMember'>,
|
||||
userId: UserID,
|
||||
guildIds: ReadonlyArray<GuildID>,
|
||||
): Promise<Array<ThreadMember>> {
|
||||
@@ -848,13 +848,18 @@ const harvestUserData: ArchiveTaskHandler = async (payload, helpers, attempt) =>
|
||||
filterArgs = {
|
||||
filter,
|
||||
context,
|
||||
findChannel: (channelId) => channelRepository.findUnique(channelId),
|
||||
findChannel: (channelId) => channelRepository.channelData.findUnique(channelId),
|
||||
};
|
||||
}
|
||||
Logger.debug({userId, harvestId, elapsed: Date.now() - startTime}, 'Starting user data harvest');
|
||||
await progressReporter.updateProgress(INITIAL_PROGRESS, 'Harvesting messages');
|
||||
Logger.debug({elapsed: Date.now() - startTime}, 'Set progress to INITIAL_PROGRESS');
|
||||
const {channelMessagesMap, totalMessages} = await harvestMessages(channelRepository, userId, startTime, filterArgs);
|
||||
const {channelMessagesMap, totalMessages} = await harvestMessages(
|
||||
channelRepository.messages,
|
||||
userId,
|
||||
startTime,
|
||||
filterArgs,
|
||||
);
|
||||
if (totalMessages > 0) {
|
||||
const progress = Math.min(INITIAL_PROGRESS + Math.floor((totalMessages / 10000) * 50), MESSAGES_PROGRESS_MAX);
|
||||
await progressReporter.updateProgress(progress, `Harvested ${totalMessages} messages`);
|
||||
|
||||
@@ -40,7 +40,7 @@ const indexChannelMessages: WorkerTaskHandler = async (payload) => {
|
||||
let totalIndexed = 0;
|
||||
try {
|
||||
while (true) {
|
||||
const messages = await channelRepository.listMessages(channelId, cursor, BULK_BATCH_SIZE);
|
||||
const messages = await channelRepository.messages.listMessages(channelId, cursor, BULK_BATCH_SIZE);
|
||||
if (messages.length === 0) {
|
||||
break;
|
||||
}
|
||||
@@ -81,11 +81,11 @@ const indexChannelMessages: WorkerTaskHandler = async (payload) => {
|
||||
Logger.info({completionKey: validated.completionKey}, 'All channels indexed');
|
||||
}
|
||||
}
|
||||
const channel = await channelRepository.findUnique(channelId);
|
||||
const channel = await channelRepository.channelData.findUnique(channelId);
|
||||
if (channel?.isThread()) {
|
||||
await channelRepository.channelData.patchIndexedAt(channelId, new Date());
|
||||
} else if (channel) {
|
||||
await channelRepository.upsert({...channel.toRow(), indexed_at: new Date()});
|
||||
await channelRepository.channelData.upsert({...channel.toRow(), indexed_at: new Date()});
|
||||
}
|
||||
Logger.info({channelId: channelId.toString(), totalIndexed}, 'Bulk channel indexing complete');
|
||||
} catch (error) {
|
||||
|
||||
@@ -103,7 +103,7 @@ const messageShredTask: WorkerTaskHandler = async (payload, helpers) => {
|
||||
for (const validationChunk of chunkArray(typedSlice, VALIDATION_CHUNK_SIZE)) {
|
||||
const messageFetches = validationChunk.map(
|
||||
({channelId, messageId}: {channelId: ChannelID; messageId: MessageID}) =>
|
||||
channelRepository.getMessage(channelId, messageId),
|
||||
channelRepository.messages.getMessage(channelId, messageId),
|
||||
);
|
||||
const fetchedMessages = await Promise.all(messageFetches);
|
||||
const deletableChunk: Array<{
|
||||
@@ -130,7 +130,7 @@ const messageShredTask: WorkerTaskHandler = async (payload, helpers) => {
|
||||
deletionChunk.map(
|
||||
async ({channelId, messageId, message}: {channelId: ChannelID; messageId: MessageID; message: Message}) => {
|
||||
await purgeMessageAttachments(message, storageService, purgeQueue);
|
||||
return channelRepository.deleteMessage(channelId, messageId, authorId);
|
||||
return channelRepository.messages.deleteMessage(channelId, messageId, authorId);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import type {StorePurchaseRow} from '@app/api/database/types/StoreBillingTypes';
|
||||
import {mapGuildMemberToResponse} from '@app/api/guild/GuildModel';
|
||||
import type {IGuildRepositoryAggregate} from '@app/api/guild/repositories/IGuildRepositoryAggregate';
|
||||
import type {GuildRepository} from '@app/api/guild/repositories/GuildRepository';
|
||||
import type {IGatewayService} from '@app/api/infrastructure/IGatewayService';
|
||||
import type {PremiumStateReconciliationQueueService} from '@app/api/infrastructure/PremiumStateReconciliationQueueService';
|
||||
import type {UserCacheService} from '@app/api/infrastructure/UserCacheService';
|
||||
@@ -18,7 +18,7 @@ import {resolveStoreAccessEnd} from '@app/api/store_billing/StoreBillingMappers'
|
||||
import {isTerminalStorePurchaseState} from '@app/api/store_billing/StoreBillingTypes';
|
||||
import type {StoreEntitlementService} from '@app/api/store_billing/StoreEntitlementService';
|
||||
import {isPremiumTieringActive} from '@app/api/stripe/BillingConfigCache';
|
||||
import type {IUserRepository} from '@app/api/user/IUserRepository';
|
||||
import type {UserRepository} from '@app/api/user/repositories/UserRepository';
|
||||
import {checkIsPremium, createPremiumClearPatch, shouldStripExpiredPremium} from '@app/api/user/UserHelpers';
|
||||
import {mapUserToPrivateResponse} from '@app/api/user/UserMappers';
|
||||
import {getWorkerDependencies} from '@app/api/worker/WorkerContext';
|
||||
@@ -43,8 +43,8 @@ interface SweepResult {
|
||||
}
|
||||
|
||||
interface SweepDeps {
|
||||
userRepository: IUserRepository;
|
||||
guildRepository: IGuildRepositoryAggregate;
|
||||
userRepository: UserRepository;
|
||||
guildRepository: GuildRepository;
|
||||
userCacheService: UserCacheService;
|
||||
gatewayService: IGatewayService;
|
||||
premiumStateReconciliationQueueService: PremiumStateReconciliationQueueService;
|
||||
|
||||
@@ -205,7 +205,7 @@ const refreshChannelMessages: IndexHandler = async (payload, helpers, kvClient,
|
||||
const {channelRepository} = getWorkerDependencies();
|
||||
const guildId = createGuildID(BigInt(payload.guild_id!));
|
||||
const searchService = requireSearchService<IMessageSearchService>(getMessageSearchService());
|
||||
const guildChannels = await channelRepository.listGuildChannels(guildId, 'complete');
|
||||
const guildChannels = await channelRepository.channelData.listGuildChannels(guildId, 'complete');
|
||||
const threadIds = await channelRepository.threads.listGuildThreadIds(guildId, {parents: guildChannels});
|
||||
const channels = [...guildChannels.map((channel) => ({id: channel.id})), ...threadIds.map((id) => ({id}))];
|
||||
if (channels.length === 0) {
|
||||
|
||||
@@ -16,7 +16,7 @@ const removeChannelFollowers: WorkerTaskHandler = async (payload, helpers) => {
|
||||
const {channelRepository, webhookRepository, gatewayService} = getWorkerDependencies();
|
||||
const sourceChannelId = createChannelID(BigInt(validated.sourceChannelId));
|
||||
if (validated.reason === 'converted') {
|
||||
const channel = await channelRepository.findUnique(sourceChannelId);
|
||||
const channel = await channelRepository.channelData.findUnique(sourceChannelId);
|
||||
if (channel?.type === ChannelTypes.GUILD_ANNOUNCEMENT) {
|
||||
helpers.logger.info(
|
||||
{sourceChannelId: validated.sourceChannelId},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import {createGuildID, type GuildID, guildIdToRoleId} from '@app/api/BrandedTypes';
|
||||
import {mapChannelToResponse} from '@app/api/channel/ChannelMappers';
|
||||
import type {IThreadRepository} from '@app/api/channel/repositories/IThreadRepository';
|
||||
import type {ThreadRepository} from '@app/api/channel/repositories/ThreadRepository';
|
||||
import {withThreadParentFieldsMany} from '@app/api/channel/services/thread/ThreadParentSettings';
|
||||
import {getCompiledChannelThreadsConfig, guildActive} from '@app/api/experiment/ChannelThreadsGate';
|
||||
import {mapGuildRoleToResponse} from '@app/api/guild/GuildModel';
|
||||
@@ -41,7 +41,7 @@ async function enqueueThreadPermissionSeed(guildId: string): Promise<void> {
|
||||
);
|
||||
}
|
||||
|
||||
export async function ensureGuildThreadPermissionsSeeded(threads: IThreadRepository, guildId: GuildID): Promise<void> {
|
||||
export async function ensureGuildThreadPermissionsSeeded(threads: ThreadRepository, guildId: GuildID): Promise<void> {
|
||||
const key = guildId.toString();
|
||||
if (seededGuildIds.has(key)) return;
|
||||
const marker = await threads.getGuildMarker(guildId);
|
||||
@@ -74,7 +74,7 @@ const seedThreadPermissions: WorkerTaskHandler = async (payload) => {
|
||||
const guild = await guildRepository.findUnique(guildId);
|
||||
if (!guild) return;
|
||||
await channelRepository.threads.ensureGuildMarker(guildId);
|
||||
const channels = await channelRepository.listGuildChannels(guildId, 'complete');
|
||||
const channels = await channelRepository.channelData.listGuildChannels(guildId, 'complete');
|
||||
const updatedChannels: Array<Channel> = [];
|
||||
for (const channel of channels) {
|
||||
if (channel.permissionOverwrites.size === 0) continue;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import type {GuildID, MessageID, UserID} from '@app/api/BrandedTypes';
|
||||
import type {IChannelRepository} from '@app/api/channel/IChannelRepository';
|
||||
import type {ChannelRepository} from '@app/api/channel/ChannelRepository';
|
||||
import type {
|
||||
CreateThreadMember,
|
||||
IThreadRepository,
|
||||
ThreadMemberAddResult,
|
||||
} from '@app/api/channel/repositories/IThreadRepository';
|
||||
ThreadRepository,
|
||||
} from '@app/api/channel/repositories/ThreadRepository';
|
||||
import {buildBroadcastMessageData} from '@app/api/channel/services/message/MessageGatewayDispatch';
|
||||
import {dispatchThreadEvents, threadMembersUpdateEvent} from '@app/api/channel/services/thread/ThreadDispatch';
|
||||
import {loadThreadView} from '@app/api/channel/services/thread/ThreadViews';
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
import type {GatewayMentionSourceEntry, IGatewayService} from '@app/api/infrastructure/IGatewayService';
|
||||
import type {Channel} from '@app/api/models/Channel';
|
||||
import type {ThreadState} from '@app/api/models/ThreadState';
|
||||
import type {IUserRepository} from '@app/api/user/IUserRepository';
|
||||
import type {UserRepository} from '@app/api/user/repositories/UserRepository';
|
||||
import {
|
||||
MAX_ROLE_MENTION_THREAD_ADDS,
|
||||
MAX_THREAD_MEMBERS,
|
||||
@@ -30,13 +30,13 @@ import {
|
||||
import {MaxThreadMembersError} from '@fluxer/errors/src/domains/channel/MaxThreadMembersError';
|
||||
|
||||
export interface ThreadMentionScopeDeps {
|
||||
channelRepository: IChannelRepository;
|
||||
channelRepository: ChannelRepository;
|
||||
gatewayService: IGatewayService;
|
||||
userRepository: IUserRepository;
|
||||
userRepository: UserRepository;
|
||||
}
|
||||
|
||||
export async function threadRecipients(
|
||||
userRepository: IUserRepository,
|
||||
userRepository: UserRepository,
|
||||
guildId: GuildID,
|
||||
userIds: Array<UserID>,
|
||||
): Promise<Set<UserID>> {
|
||||
@@ -51,7 +51,7 @@ export async function threadRecipients(
|
||||
}
|
||||
|
||||
export async function addThreadMembersWithinCap(
|
||||
threads: IThreadRepository,
|
||||
threads: ThreadRepository,
|
||||
state: ThreadState,
|
||||
members: Array<CreateThreadMember>,
|
||||
): Promise<ThreadMemberAddResult | null> {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import {type ChannelID, createChannelID, type MessageID} from '@app/api/BrandedTypes';
|
||||
import type {IChannelRepository} from '@app/api/channel/IChannelRepository';
|
||||
import type {ChannelRepository} from '@app/api/channel/ChannelRepository';
|
||||
import {withThreadContext} from '@app/api/channel/services/ChannelGatewayDispatch';
|
||||
import {decrementThreadMessageCount} from '@app/api/channel/services/message/MessageHelpers';
|
||||
import type {IGatewayService} from '@app/api/infrastructure/IGatewayService';
|
||||
|
||||
interface BulkDeleteDispatcherDeps {
|
||||
channelRepository: IChannelRepository;
|
||||
channelRepository: ChannelRepository;
|
||||
gatewayService: IGatewayService;
|
||||
batchSize: number;
|
||||
}
|
||||
@@ -30,7 +30,7 @@ export function createBulkDeleteDispatcher({channelRepository, gatewayService, b
|
||||
continue;
|
||||
}
|
||||
const channelId = createChannelID(BigInt(channelIdStr));
|
||||
const channel = await channelRepository.findUnique(channelId);
|
||||
const channel = await channelRepository.channelData.findUnique(channelId);
|
||||
if (channel) {
|
||||
await decrementThreadMessageCount(channelRepository, channel, messageIdsBatch);
|
||||
const payloadIds = messageIdsBatch.map((id) => id.toString());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import type {AdminAuditLog} from '@app/api/admin/IAdminRepository';
|
||||
import type {AdminAuditLog} from '@app/api/admin/AdminRepository';
|
||||
import {createTestAccount, setUserACLs, type TestAccount} from '@app/api/auth/tests/AuthTestUtils';
|
||||
import {createGuildID, createUserID} from '@app/api/BrandedTypes';
|
||||
import {createApiContext} from '@app/api/CreateApiContext';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import type {AdminAuditLog} from '@app/api/admin/IAdminRepository';
|
||||
import type {AdminAuditLog} from '@app/api/admin/AdminRepository';
|
||||
import {createTestAccount, setUserACLs} from '@app/api/auth/tests/AuthTestUtils';
|
||||
import {BANNED_FILE_SHAS_REFRESH_CHANNEL} from '@app/api/constants/ContentModeration';
|
||||
import {getSnowflakeService, setInjectedWorkerService} from '@app/api/middleware/ServiceRegistry';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import type {AdminAuditLog} from '@app/api/admin/IAdminRepository';
|
||||
import type {AdminAuditLog} from '@app/api/admin/AdminRepository';
|
||||
import {sendChannelMessage, setupTestGuildWithMembers} from '@app/api/channel/tests/ChannelTestUtils';
|
||||
import {getGatewayService, getSnowflakeService} from '@app/api/middleware/ServiceRegistry';
|
||||
import {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import {AdminRepository} from '@app/api/admin/AdminRepository';
|
||||
import type {AdminAuditLog} from '@app/api/admin/IAdminRepository';
|
||||
import {type AdminAuditLog, AdminRepository} from '@app/api/admin/AdminRepository';
|
||||
import {
|
||||
clearTestEmails,
|
||||
createTestAccount,
|
||||
@@ -29,7 +28,7 @@ import {
|
||||
getUserPermissionUtils,
|
||||
getUserRepository,
|
||||
} from '@app/api/middleware/ServiceSingletons';
|
||||
import {ReportStatus} from '@app/api/report/IReportRepository';
|
||||
import {ReportStatus} from '@app/api/report/ReportModels';
|
||||
import {ReportRepository} from '@app/api/report/ReportRepository';
|
||||
import {getReportSearchService} from '@app/api/SearchFactory';
|
||||
import {drainSearchTasks} from '@app/api/search/SearchTaskTracker';
|
||||
|
||||
@@ -9,8 +9,8 @@ import {
|
||||
type IARMessageContextRow,
|
||||
type IARSubmissionRow,
|
||||
} from '@app/api/database/types/ReportTypes';
|
||||
import type {IARSubmission} from '@app/api/report/IReportRepository';
|
||||
import type {ReportDeletionDeps} from '@app/api/report/ReportDeletion';
|
||||
import type {IARSubmission} from '@app/api/report/ReportModels';
|
||||
import {ReportRepository} from '@app/api/report/ReportRepository';
|
||||
import type {IReportSearchService} from '@app/api/search/IReportSearchService';
|
||||
import {MockStorageService} from '@app/api/test/mocks/MockStorageService';
|
||||
|
||||
@@ -12,7 +12,7 @@ import type {ChannelRepository} from '@app/api/channel/ChannelRepository';
|
||||
import {syncChannelThreadsConfig} from '@app/api/experiment/ChannelThreadsGate';
|
||||
import type {GatewayMentionSourceEntry, IGatewayService} from '@app/api/infrastructure/IGatewayService';
|
||||
import {ThreadState} from '@app/api/models/ThreadState';
|
||||
import type {ReadStateMentionUpdate} from '@app/api/read_state/IReadStateRepository';
|
||||
import type {ReadStateMentionUpdate} from '@app/api/read_state/ReadStateRepository';
|
||||
import type {ReadStateService} from '@app/api/read_state/ReadStateService';
|
||||
import {NoopLogger} from '@app/api/test/mocks/NoopLogger';
|
||||
import type {UserRepository} from '@app/api/user/repositories/UserRepository';
|
||||
@@ -118,8 +118,6 @@ function createHarness(params: {
|
||||
type: params.channelType ?? ChannelTypes.PUBLIC_THREAD,
|
||||
};
|
||||
const channelRepository = {
|
||||
getMessage: async () => message,
|
||||
findUnique: async () => channel,
|
||||
threads: {
|
||||
getState: async () => state,
|
||||
getMembers: async (_threadId: ChannelID, userIds: Array<UserID>) =>
|
||||
@@ -135,11 +133,10 @@ function createHarness(params: {
|
||||
getParentConfig: async () => ({availableTags: (params.forumTags?.live ?? []).map((id) => ({id}))}),
|
||||
},
|
||||
channelData: {
|
||||
findUnique: async () => ({
|
||||
id: PARENT,
|
||||
type: parentType,
|
||||
isThreadOnly: () => parentType === ChannelTypes.GUILD_FORUM,
|
||||
}),
|
||||
findUnique: async (channelId: ChannelID) =>
|
||||
channelId === THREAD
|
||||
? channel
|
||||
: {id: PARENT, type: parentType, isThreadOnly: () => parentType === ChannelTypes.GUILD_FORUM},
|
||||
},
|
||||
messages: {
|
||||
getMessage: async () => ({...message, toRow: () => ({flags: message.flags})}),
|
||||
|
||||
@@ -35,8 +35,10 @@ function createHarness(messages: Array<Message> = []): {
|
||||
setWorkerDependenciesForTest({
|
||||
kvClient,
|
||||
channelRepository: {
|
||||
listMessages: async (_channelId: unknown, cursor: unknown) => (cursor === undefined ? messages : []),
|
||||
findUnique: async () => null,
|
||||
messages: {
|
||||
listMessages: async (_channelId: unknown, cursor: unknown) => (cursor === undefined ? messages : []),
|
||||
},
|
||||
channelData: {findUnique: async () => null},
|
||||
} as unknown as ChannelRepository,
|
||||
userRepository: {listUsers: async () => []} as unknown as UserRepository,
|
||||
});
|
||||
|
||||
@@ -94,8 +94,8 @@ describe('seedThreadPermissions', () => {
|
||||
})
|
||||
.execute();
|
||||
const channelRepository = getChannelRepository();
|
||||
const stored = await channelRepository.findUnique(createChannelID(BigInt(channel.id)));
|
||||
await channelRepository.upsert({
|
||||
const stored = await channelRepository.channelData.findUnique(createChannelID(BigInt(channel.id)));
|
||||
await channelRepository.channelData.upsert({
|
||||
...stored!.toRow(),
|
||||
permission_overwrites: new Map([
|
||||
[
|
||||
@@ -118,9 +118,9 @@ describe('seedThreadPermissions', () => {
|
||||
await seedThreadPermissions({guildId: guild.id}, helpers());
|
||||
const everyone = await getGuildRepository().getRole(createRoleID(BigInt(guild.id)), guildId);
|
||||
expect(everyone?.permissions).toBe(DEFAULT_PERMISSIONS | DEFAULT_THREAD_PERMISSIONS);
|
||||
const seeded = (await channelRepository.findUnique(createChannelID(BigInt(channel.id))))!.permissionOverwrites.get(
|
||||
createRoleID(BigInt(guild.id)),
|
||||
);
|
||||
const seeded = (await channelRepository.channelData.findUnique(
|
||||
createChannelID(BigInt(channel.id)),
|
||||
))!.permissionOverwrites.get(createRoleID(BigInt(guild.id)));
|
||||
expect(seeded?.allow).toBe(0n);
|
||||
expect(seeded?.deny).toBe(Permissions.SEND_MESSAGES | DEFAULT_THREAD_PERMISSIONS);
|
||||
expect(dispatchGuild.mock.calls.map(([params]) => params.event)).toEqual([
|
||||
@@ -166,7 +166,7 @@ describe('seedThreadPermissions', () => {
|
||||
setConfig({...ALL_THREADS_ACTIVE, ever_enabled: true, enabled_guild_ids: [guild.id]});
|
||||
await seedThreadPermissions({guildId: guild.id}, helpers());
|
||||
|
||||
const seeded = (await getChannelRepository().findUnique(
|
||||
const seeded = (await getChannelRepository().channelData.findUnique(
|
||||
createChannelID(BigInt(channel.id)),
|
||||
))!.permissionOverwrites.get(createRoleID(BigInt(role.id)));
|
||||
expect(seeded?.allow).toBe(Permissions.SEND_MESSAGES | DEFAULT_THREAD_PERMISSIONS);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import type {ChannelService} from '@app/api/channel/services/ChannelService';
|
||||
import type {IJobLedgerRepository} from '@app/api/jobs/IJobLedgerRepository';
|
||||
import type {JobLedgerRepository} from '@app/api/jobs/JobLedgerRepository';
|
||||
import {setInjectedWorkerService} from '@app/api/middleware/ServiceRegistry';
|
||||
import {NoopWorkerService} from '@app/api/test/NoopWorkerService';
|
||||
import type {UserRepository} from '@app/api/user/repositories/UserRepository';
|
||||
@@ -44,7 +44,7 @@ function createLedgerStub(cancelAfter: number) {
|
||||
cancelChecks.count += 1;
|
||||
return cancelChecks.count > cancelAfter;
|
||||
},
|
||||
} as unknown as IJobLedgerRepository;
|
||||
} as unknown as JobLedgerRepository;
|
||||
return {ledger, markCancelled, markSucceeded};
|
||||
}
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ describe('thread maintenance sweeps', () => {
|
||||
it('includes thread messages in user and guild harvests', async () => {
|
||||
const s = await setup();
|
||||
const harvested = await harvestMessages(
|
||||
getChannelRepository(),
|
||||
getChannelRepository().messages,
|
||||
createUserID(BigInt(s.member.userId)),
|
||||
Date.now(),
|
||||
null,
|
||||
|
||||
@@ -134,7 +134,7 @@ describe('thread maintenance tasks', () => {
|
||||
const thread = await startThread(s.owner.token, s.channelId);
|
||||
await deleteChannelThreads({guildId: s.guildId, parentId: s.channelId}, helpers());
|
||||
expect(await state(thread.id)).toBeNull();
|
||||
expect(await getChannelRepository().findUnique(createChannelID(BigInt(thread.id)))).toBeNull();
|
||||
expect(await getChannelRepository().channelData.findUnique(createChannelID(BigInt(thread.id)))).toBeNull();
|
||||
});
|
||||
|
||||
it('purges thread memberships of a removed guild member and keeps those of a rejoined one', async () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import type {IJobLedgerRepository} from '@app/api/jobs/IJobLedgerRepository';
|
||||
import type {JobLedgerRepository} from '@app/api/jobs/JobLedgerRepository';
|
||||
import {setInjectedWorkerService} from '@app/api/middleware/ServiceRegistry';
|
||||
import {NoopWorkerService} from '@app/api/test/NoopWorkerService';
|
||||
import {WorkerRunner} from '@app/api/worker/WorkerRunner';
|
||||
@@ -32,7 +32,7 @@ function createRunner(task: () => Promise<void>): TestWorkerRunner {
|
||||
queue: queueStub,
|
||||
consumerName: 'workers_batch',
|
||||
laneName: 'batch',
|
||||
ledger: {} as IJobLedgerRepository,
|
||||
ledger: {} as JobLedgerRepository,
|
||||
concurrency: 12,
|
||||
maxDeliver: LANE_MAX_DELIVER,
|
||||
ackWaitMs: LANE_ACK_WAIT_MS,
|
||||
@@ -149,7 +149,7 @@ describe('Worker ack heartbeat', () => {
|
||||
queue: queueStub,
|
||||
consumerName: 'workers_batch',
|
||||
laneName: 'batch',
|
||||
ledger: {} as IJobLedgerRepository,
|
||||
ledger: {} as JobLedgerRepository,
|
||||
concurrency: 12,
|
||||
maxDeliver: LANE_MAX_DELIVER,
|
||||
ackWaitMs: LANE_ACK_WAIT_MS,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import type {IJobLedgerRepository} from '@app/api/jobs/IJobLedgerRepository';
|
||||
import type {JobLedgerRepository} from '@app/api/jobs/JobLedgerRepository';
|
||||
import {setInjectedWorkerService} from '@app/api/middleware/ServiceRegistry';
|
||||
import {NoopWorkerService} from '@app/api/test/NoopWorkerService';
|
||||
import {CronScheduler} from '@app/api/worker/CronScheduler';
|
||||
@@ -73,7 +73,7 @@ function createRunner(messages: FakeConsumerMessages, heartbeat: WorkerHeartbeat
|
||||
},
|
||||
consumerName: 'workers_batch',
|
||||
laneName: 'batch',
|
||||
ledger: {} as IJobLedgerRepository,
|
||||
ledger: {} as JobLedgerRepository,
|
||||
concurrency: 12,
|
||||
maxDeliver: 25,
|
||||
ackWaitMs: 120000,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import type {IJobLedgerRepository} from '@app/api/jobs/IJobLedgerRepository';
|
||||
import type {JobLedgerRepository} from '@app/api/jobs/JobLedgerRepository';
|
||||
import {setInjectedWorkerService} from '@app/api/middleware/ServiceRegistry';
|
||||
import {NoopWorkerService} from '@app/api/test/NoopWorkerService';
|
||||
import {WorkerRunner} from '@app/api/worker/WorkerRunner';
|
||||
@@ -36,7 +36,7 @@ function createRunner(): TestWorkerRunner {
|
||||
queue: queueStub,
|
||||
consumerName: 'workers_lifecycle',
|
||||
laneName: 'lifecycle',
|
||||
ledger: ledgerStub as unknown as IJobLedgerRepository,
|
||||
ledger: ledgerStub as unknown as JobLedgerRepository,
|
||||
concurrency: 8,
|
||||
maxDeliver: 25,
|
||||
ackWaitMs: 60000,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import type {IJobLedgerRepository} from '@app/api/jobs/IJobLedgerRepository';
|
||||
import type {JobLedgerRepository} from '@app/api/jobs/JobLedgerRepository';
|
||||
import {setInjectedWorkerService} from '@app/api/middleware/ServiceRegistry';
|
||||
import {NoopWorkerService} from '@app/api/test/NoopWorkerService';
|
||||
import {WorkerRunner} from '@app/api/worker/WorkerRunner';
|
||||
@@ -93,7 +93,7 @@ function createRunner(streams: Array<FakeConsumerMessages>): {runner: WorkerRunn
|
||||
queue,
|
||||
consumerName: 'workers_batch',
|
||||
laneName: 'batch',
|
||||
ledger: {} as IJobLedgerRepository,
|
||||
ledger: {} as JobLedgerRepository,
|
||||
concurrency: 12,
|
||||
maxDeliver: 25,
|
||||
ackWaitMs: 120000,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import type {IJobLedgerRepository} from '@app/api/jobs/IJobLedgerRepository';
|
||||
import type {JobLedgerRepository} from '@app/api/jobs/JobLedgerRepository';
|
||||
import {setInjectedWorkerService} from '@app/api/middleware/ServiceRegistry';
|
||||
import {NoopWorkerService} from '@app/api/test/NoopWorkerService';
|
||||
import {WorkerRunner} from '@app/api/worker/WorkerRunner';
|
||||
@@ -78,7 +78,7 @@ function createRunner(task: () => Promise<void>, messages: FakeConsumerMessages)
|
||||
queue: createQueueStub(messages),
|
||||
consumerName: 'workers_batch',
|
||||
laneName: 'batch',
|
||||
ledger: {} as IJobLedgerRepository,
|
||||
ledger: {} as JobLedgerRepository,
|
||||
concurrency: 12,
|
||||
maxDeliver: 25,
|
||||
ackWaitMs: 120000,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import type {ISnowflakeService} from '@app/api/infrastructure/ISnowflakeService';
|
||||
import type {CreateJobInput, IJobLedgerRepository} from '@app/api/jobs/IJobLedgerRepository';
|
||||
import type {CreateJobInput, JobLedgerRepository} from '@app/api/jobs/JobLedgerRepository';
|
||||
import type {JetStreamWorkerQueue} from '@app/api/worker/JetStreamWorkerQueue';
|
||||
import {WorkerService} from '@app/api/worker/WorkerService';
|
||||
import {describe, expect, test} from 'vitest';
|
||||
@@ -47,7 +47,7 @@ function createHarness(options?: {
|
||||
if (options?.discardError) throw options.discardError;
|
||||
discarded.push({jobId, createdAt});
|
||||
},
|
||||
} as unknown as IJobLedgerRepository;
|
||||
} as unknown as JobLedgerRepository;
|
||||
const queue = {
|
||||
enqueue: async (taskType: string, payload: Record<string, unknown>) => {
|
||||
calls.push('enqueue');
|
||||
|
||||
Reference in new issue
Block a user