From 6bf3b40cc7577e2b5de232e236569bc1217fb1cf Mon Sep 17 00:00:00 2001 From: asepharyana Date: Thu, 24 Sep 2026 14:58:19 +0700 Subject: [PATCH] refactor(gateway): drop shared barrel, migrate to granular imports + shared error helpers - delete src/shared/index.ts fat barrel; point 10 importers at the exact module they use (redis-channels, moderation-types, utils/pagination) - message-capture/types.ts re-exports from shared/moderation-types directly - shared/errors: add errorMessage() + isTransientStreamError() helpers, replacing the repeated err-message and transient-code checks - drop unused imports flagged by biome No behavior change. typecheck + lint + 138 tests green. --- services/discord-gateway/src/app/retention.ts | 5 +--- .../modules/command-handler/commandHandler.ts | 4 +-- .../modules/command-handler/guild.handler.ts | 5 +++- .../command-handler/handler-registry.ts | 2 +- .../command-handler/moderation.handler.ts | 5 +++- .../event-broadcaster/eventBroadcaster.ts | 5 +++- .../modules/event-broadcaster/eventTypes.ts | 2 +- .../message-capture/messagesPagination.ts | 5 +++- .../message-capture/moderationActionsDb.ts | 5 +++- .../src/modules/message-capture/reviewsDb.ts | 5 +++- .../src/modules/message-capture/types.ts | 5 ++-- .../src/shared/errors/index.ts | 29 +++++++++++++++++++ services/discord-gateway/src/shared/index.ts | 9 ------ 13 files changed, 60 insertions(+), 26 deletions(-) delete mode 100644 services/discord-gateway/src/shared/index.ts diff --git a/services/discord-gateway/src/app/retention.ts b/services/discord-gateway/src/app/retention.ts index d7b83e1b..a7314bd4 100644 --- a/services/discord-gateway/src/app/retention.ts +++ b/services/discord-gateway/src/app/retention.ts @@ -1,8 +1,5 @@ import { inArray, lt } from "drizzle-orm"; -import type { - NodePgDatabase, - NodePgQueryResultHKT, -} from "drizzle-orm/node-postgres"; +import type { NodePgDatabase } from "drizzle-orm/node-postgres"; import { createChildLogger } from "@/shared/logger/index"; import { config } from "../shared/config/index.js"; import { getDatabase } from "../shared/database/drizzle.js"; diff --git a/services/discord-gateway/src/modules/command-handler/commandHandler.ts b/services/discord-gateway/src/modules/command-handler/commandHandler.ts index ea7e377f..a6254849 100644 --- a/services/discord-gateway/src/modules/command-handler/commandHandler.ts +++ b/services/discord-gateway/src/modules/command-handler/commandHandler.ts @@ -1,12 +1,12 @@ import type { Client } from "discord.js-selfbot-v13"; import Redis from "ioredis"; import { config } from "../../shared/config/index.js"; +import { createChildLogger } from "../../shared/logger/index.js"; import { BACKEND_COMMAND, type CommandMessage, type CommandReply, -} from "../../shared/index.js"; -import { createChildLogger } from "../../shared/logger/index.js"; +} from "../../shared/redis-channels.js"; import { GuildHandler } from "./guild.handler.js"; import { type CommandHandlerFn, diff --git a/services/discord-gateway/src/modules/command-handler/guild.handler.ts b/services/discord-gateway/src/modules/command-handler/guild.handler.ts index 1adaf687..b7ceb72b 100644 --- a/services/discord-gateway/src/modules/command-handler/guild.handler.ts +++ b/services/discord-gateway/src/modules/command-handler/guild.handler.ts @@ -1,6 +1,9 @@ import type { Client } from "discord.js-selfbot-v13"; -import type { CommandMessage, CommandReply } from "../../shared/index.js"; import { createChildLogger } from "../../shared/logger/index.js"; +import type { + CommandMessage, + CommandReply, +} from "../../shared/redis-channels.js"; // --------------------------------------------------------------------------- // GuildHandler diff --git a/services/discord-gateway/src/modules/command-handler/handler-registry.ts b/services/discord-gateway/src/modules/command-handler/handler-registry.ts index 6bf8fb95..cc6df2ab 100644 --- a/services/discord-gateway/src/modules/command-handler/handler-registry.ts +++ b/services/discord-gateway/src/modules/command-handler/handler-registry.ts @@ -4,7 +4,7 @@ import { COMMAND_MODERATION_ACTION, type CommandMessage, type CommandReply, -} from "../../shared/index.js"; +} from "../../shared/redis-channels.js"; import type { GuildHandler } from "./guild.handler.js"; import type { ModerationHandler } from "./moderation.handler.js"; diff --git a/services/discord-gateway/src/modules/command-handler/moderation.handler.ts b/services/discord-gateway/src/modules/command-handler/moderation.handler.ts index 2496a16c..b44041e2 100644 --- a/services/discord-gateway/src/modules/command-handler/moderation.handler.ts +++ b/services/discord-gateway/src/modules/command-handler/moderation.handler.ts @@ -1,6 +1,9 @@ import type { Client } from "discord.js-selfbot-v13"; -import type { CommandMessage, CommandReply } from "../../shared/index.js"; import { createChildLogger } from "../../shared/logger/index.js"; +import type { + CommandMessage, + CommandReply, +} from "../../shared/redis-channels.js"; import { messageStore } from "../message-capture/messageStore.js"; // --------------------------------------------------------------------------- diff --git a/services/discord-gateway/src/modules/event-broadcaster/eventBroadcaster.ts b/services/discord-gateway/src/modules/event-broadcaster/eventBroadcaster.ts index 83834279..0ada3f7a 100644 --- a/services/discord-gateway/src/modules/event-broadcaster/eventBroadcaster.ts +++ b/services/discord-gateway/src/modules/event-broadcaster/eventBroadcaster.ts @@ -1,9 +1,12 @@ import Redis from "ioredis"; -import type { AttachmentRecord, MessageRecord } from "../../shared/index.js"; import { type CustomLogger, createChildLogger, } from "../../shared/logger/index.js"; +import type { + AttachmentRecord, + MessageRecord, +} from "../../shared/moderation-types.js"; import { type DiscordGatewayEvent, EventChannels } from "./eventTypes.js"; export class RedisEventPublisher { diff --git a/services/discord-gateway/src/modules/event-broadcaster/eventTypes.ts b/services/discord-gateway/src/modules/event-broadcaster/eventTypes.ts index d7a30a92..68113ee3 100644 --- a/services/discord-gateway/src/modules/event-broadcaster/eventTypes.ts +++ b/services/discord-gateway/src/modules/event-broadcaster/eventTypes.ts @@ -17,7 +17,7 @@ import { DISCORD_THREAD_DELETED, DISCORD_THREAD_UPDATED, type DiscordGatewayEvent, -} from "../../shared/index.js"; +} from "../../shared/redis-channels.js"; export type { DiscordGatewayEvent }; diff --git a/services/discord-gateway/src/modules/message-capture/messagesPagination.ts b/services/discord-gateway/src/modules/message-capture/messagesPagination.ts index 7baa0fae..c75ca92d 100644 --- a/services/discord-gateway/src/modules/message-capture/messagesPagination.ts +++ b/services/discord-gateway/src/modules/message-capture/messagesPagination.ts @@ -2,8 +2,11 @@ import { and, desc, eq, inArray, type SQL, sql } from "drizzle-orm"; import type { NodePgDatabase } from "drizzle-orm/node-postgres"; import type * as schema from "../../shared/database/schema.js"; import { messagesTable } from "../../shared/database/schema.js"; -import { buildCursorCondition, pageResult } from "../../shared/index.js"; import { createChildLogger, type Logger } from "../../shared/logger/index.js"; +import { + buildCursorCondition, + pageResult, +} from "../../shared/utils/pagination.js"; import type { MessageQuery, MessageRecord, diff --git a/services/discord-gateway/src/modules/message-capture/moderationActionsDb.ts b/services/discord-gateway/src/modules/message-capture/moderationActionsDb.ts index 26080708..7bddce4b 100644 --- a/services/discord-gateway/src/modules/message-capture/moderationActionsDb.ts +++ b/services/discord-gateway/src/modules/message-capture/moderationActionsDb.ts @@ -2,8 +2,11 @@ import { and, desc, eq, inArray, type SQL } from "drizzle-orm"; import type { NodePgDatabase } from "drizzle-orm/node-postgres"; import type * as schema from "../../shared/database/schema.js"; import { moderationActionsTable } from "../../shared/database/schema.js"; -import { buildCursorCondition, pageResult } from "../../shared/index.js"; import { createChildLogger, type Logger } from "../../shared/logger/index.js"; +import { + buildCursorCondition, + pageResult, +} from "../../shared/utils/pagination.js"; import type { EventBroadcaster } from "../event-broadcaster/eventBroadcaster.js"; import type { ModerationAction, PageResult } from "../message-capture/types.js"; diff --git a/services/discord-gateway/src/modules/message-capture/reviewsDb.ts b/services/discord-gateway/src/modules/message-capture/reviewsDb.ts index 3e085dfd..4aa3d4ce 100644 --- a/services/discord-gateway/src/modules/message-capture/reviewsDb.ts +++ b/services/discord-gateway/src/modules/message-capture/reviewsDb.ts @@ -2,8 +2,11 @@ import { and, desc, eq, inArray, type SQL } from "drizzle-orm"; import type { NodePgDatabase } from "drizzle-orm/node-postgres"; import type * as schema from "../../shared/database/schema.js"; import { messageReviewsTable } from "../../shared/database/schema.js"; -import { buildCursorCondition, pageResult } from "../../shared/index.js"; import { createChildLogger, type Logger } from "../../shared/logger/index.js"; +import { + buildCursorCondition, + pageResult, +} from "../../shared/utils/pagination.js"; import type { MessageReview, PageResult } from "../message-capture/types.js"; // ─── ReviewsDb Class ──────────────────────────────────────────────────────── diff --git a/services/discord-gateway/src/modules/message-capture/types.ts b/services/discord-gateway/src/modules/message-capture/types.ts index c760b555..f2b5a36f 100644 --- a/services/discord-gateway/src/modules/message-capture/types.ts +++ b/services/discord-gateway/src/modules/message-capture/types.ts @@ -2,8 +2,7 @@ import type { AnalysisQueueStatus, AttachmentRecord, MessageRecord, - UserMetadata, -} from "../../shared/index.js"; +} from "../../shared/moderation-types.js"; // Re-export all shared types for backward compatibility export type { @@ -26,7 +25,7 @@ export type { ReviewStatus, RoleMetadata, UserMetadata, -} from "../../shared/index.js"; +} from "../../shared/moderation-types.js"; // Local-only types (not shared across services) export type ModerationWsEvent = diff --git a/services/discord-gateway/src/shared/errors/index.ts b/services/discord-gateway/src/shared/errors/index.ts index 0ddb7ee5..e9dbf32d 100644 --- a/services/discord-gateway/src/shared/errors/index.ts +++ b/services/discord-gateway/src/shared/errors/index.ts @@ -46,3 +46,32 @@ export class ConfigError extends AppError { this.name = "ConfigError"; } } + +// --------------------------------------------------------------------------- +// Generic error helpers (shared by every module — avoids the repeated +// `err instanceof Error ? err.message : String(err)` pattern, 18+ sites) +// --------------------------------------------------------------------------- + +/** Normalize an unknown thrown value to a readable message. */ +export function errorMessage(err: unknown): string { + return err instanceof Error ? err.message : String(err); +} + +/** + * True when an error code is a transient stream-teardown failure + * (EPIPE / stream destroyed / write-after-end / socket reset). + * + * These are NOT fatal: crashing the gateway on them (e.g. voice stop races, + * ffmpeg stdin closed while we still write) takes the whole bot offline + * mid-operation. Callers that install process-level handlers use this to + * log-and-continue instead of shutting down. + */ +export function isTransientStreamError(err: unknown): boolean { + const code = (err as NodeJS.ErrnoException)?.code ?? ""; + return ( + code === "EPIPE" || + code === "ERR_STREAM_DESTROYED" || + code === "ERR_STREAM_WRITE_AFTER_END" || + code === "ECONNRESET" + ); +} diff --git a/services/discord-gateway/src/shared/index.ts b/services/discord-gateway/src/shared/index.ts deleted file mode 100644 index c5d5d990..00000000 --- a/services/discord-gateway/src/shared/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export * from "./config/index.js"; -export * from "./database/init.js"; -export * from "./database/pool.js"; -export * from "./database/schema.js"; -export * from "./errors/index.js"; -export * from "./logger/index.js"; -export * from "./moderation-types.js"; -export * from "./redis-channels.js"; -export * from "./utils/index.js";