refactor: remove unused anchorRoleId parameter from DiscordRoleRepository and decentralize type definitions

This commit is contained in:
MythEclipse
2026-06-06 03:06:00 +07:00
parent 03e2a28e97
commit 66d3b5e997
7 changed files with 43 additions and 36 deletions
+3
View File
@@ -10,6 +10,7 @@
"drizzle-orm": "latest", "drizzle-orm": "latest",
"postgres": "latest", "postgres": "latest",
"winston": "^3.19.0", "winston": "^3.19.0",
"zod": "^4.4.3",
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "^1.3.14", "@types/bun": "^1.3.14",
@@ -275,6 +276,8 @@
"ws": ["ws@8.20.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w=="], "ws": ["ws@8.20.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w=="],
"zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="],
"@discordjs/rest/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="], "@discordjs/rest/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="],
"@discordjs/rest/@sapphire/snowflake": ["@sapphire/snowflake@3.5.5", "", {}, "sha512-xzvBr1Q1c4lCe7i6sRnrofxeO1QTP/LKQ6A6qy0iB4x5yfiSfARMEQEghojzTNALDTcv8En04qYNIco9/K9eZQ=="], "@discordjs/rest/@sapphire/snowflake": ["@sapphire/snowflake@3.5.5", "", {}, "sha512-xzvBr1Q1c4lCe7i6sRnrofxeO1QTP/LKQ6A6qy0iB4x5yfiSfARMEQEghojzTNALDTcv8En04qYNIco9/K9eZQ=="],
+2 -1
View File
@@ -16,7 +16,8 @@
"discord.js": "latest", "discord.js": "latest",
"drizzle-orm": "latest", "drizzle-orm": "latest",
"postgres": "latest", "postgres": "latest",
"winston": "^3.19.0" "winston": "^3.19.0",
"zod": "^4.4.3"
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "^1.3.14", "@types/bun": "^1.3.14",
+2 -2
View File
@@ -16,7 +16,7 @@ export function attachBotHandlers(client: Client, config: AppConfig): void {
const service = new BoosterRoleService( const service = new BoosterRoleService(
store, store,
new DiscordRoleRepository(interaction.guild, config.boosterRoleAnchorRoleId), new DiscordRoleRepository(interaction.guild),
{ anchorPosition: resolveAnchorPosition(interaction.guild, config.boosterRoleAnchorRoleId) } { anchorPosition: resolveAnchorPosition(interaction.guild, config.boosterRoleAnchorRoleId) }
); );
@@ -28,7 +28,7 @@ export function attachBotHandlers(client: Client, config: AppConfig): void {
client.on("guildMemberUpdate", async (oldMember, newMember) => { client.on("guildMemberUpdate", async (oldMember, newMember) => {
const service = new BoosterRoleService( const service = new BoosterRoleService(
store, store,
new DiscordRoleRepository(newMember.guild, config.boosterRoleAnchorRoleId), new DiscordRoleRepository(newMember.guild),
{ anchorPosition: resolveAnchorPosition(newMember.guild, config.boosterRoleAnchorRoleId) } { anchorPosition: resolveAnchorPosition(newMember.guild, config.boosterRoleAnchorRoleId) }
); );
+1 -1
View File
@@ -27,7 +27,7 @@ client.once("clientReady", () => {
startBoostCleanup( startBoostCleanup(
client, client,
store, store,
(guild) => new DiscordRoleRepository(guild, config.boosterRoleAnchorRoleId), (guild) => new DiscordRoleRepository(guild),
{ {
intervalMs: config.boostCleanupIntervalMs, intervalMs: config.boostCleanupIntervalMs,
boosterEligibilityRoleId: config.boosterEligibilityRoleId, boosterEligibilityRoleId: config.boosterEligibilityRoleId,
+5 -27
View File
@@ -7,38 +7,16 @@ import {
normalizeHexColor, normalizeHexColor,
normalizeOptionalHexColor, normalizeOptionalHexColor,
validateRoleName, validateRoleName,
type ExistingRole,
type ManagedRoleIdentity type ManagedRoleIdentity
} from "../domain/roleGuards"; } from "../domain/roleGuards";
import { ValidationError, NotFoundError } from "../domain/errors"; import { ValidationError, NotFoundError } from "../domain/errors";
export type BoosterRoleRecord = { import type { BoosterRoleRecord, BoosterRoleStore } from "./drizzleBoosterRoleStore";
guildId: string; import type { RoleRepository } from "./discordRoleRepository";
userId: string;
roleId: string;
name: string;
color: string | null;
color2: string | null;
icon: string | null;
createdAt: number;
updatedAt: number;
};
export type BoosterRoleStore = { // Re-export for consumers that import from this module
findByUser(guildId: string, userId: string): Promise<BoosterRoleRecord | null>; export type { BoosterRoleRecord, BoosterRoleStore };
findByGuild(guildId: string): Promise<BoosterRoleRecord[]>; export type { RoleRepository } from "./discordRoleRepository";
create(record: BoosterRoleRecord): Promise<void>;
delete(guildId: string, userId: string): Promise<void>;
};
export type RoleRepository = {
listRoles(): Promise<ExistingRole[]>;
createRole(input: { name: string; color: string | null; colors?: { primaryColor: string; secondaryColor?: string; tertiaryColor?: string } | null; permissions: string[]; position: number }): Promise<{ id: string }>;
updateRole(roleId: string, input: { name?: string; color?: string | null; colors?: { primaryColor: string; secondaryColor?: string; tertiaryColor?: string } | null; icon?: string | null }): Promise<void>;
assignRole(userId: string, roleId: string): Promise<void>;
removeRole(userId: string, roleId: string): Promise<void>;
deleteRole(roleId: string): Promise<void>;
};
export type RoleIcon = { export type RoleIcon = {
contentType: string; contentType: string;
+11 -4
View File
@@ -1,10 +1,17 @@
import type { ColorResolvable, Guild, Role, RoleColorsResolvable } from "discord.js"; import type { ColorResolvable, Guild, Role, RoleColorsResolvable } from "discord.js";
import type { RoleRepository } from "./boosterRoleService"; import type { ExistingRole } from "../domain/roleGuards";
export type RoleRepository = {
listRoles(): Promise<ExistingRole[]>;
createRole(input: { name: string; color: string | null; colors?: { primaryColor: string; secondaryColor?: string; tertiaryColor?: string } | null; permissions: string[]; position: number }): Promise<{ id: string }>;
updateRole(roleId: string, input: { name?: string; color?: string | null; colors?: { primaryColor: string; secondaryColor?: string; tertiaryColor?: string } | null; icon?: string | null }): Promise<void>;
assignRole(userId: string, roleId: string): Promise<void>;
removeRole(userId: string, roleId: string): Promise<void>;
deleteRole(roleId: string): Promise<void>;
};
export class DiscordRoleRepository implements RoleRepository { export class DiscordRoleRepository implements RoleRepository {
constructor(private readonly guild: Guild, anchorRoleId: string | null) { constructor(private readonly guild: Guild) {}
void anchorRoleId;
}
async listRoles() { async listRoles() {
await this.guild.roles.fetch(); await this.guild.roles.fetch();
+19 -1
View File
@@ -1,6 +1,24 @@
import { and, eq } from "drizzle-orm"; import { and, eq } from "drizzle-orm";
import { boosterRoles } from "../db/schema"; import { boosterRoles } from "../db/schema";
import type { BoosterRoleRecord, BoosterRoleStore } from "./boosterRoleService";
export type BoosterRoleRecord = {
guildId: string;
userId: string;
roleId: string;
name: string;
color: string | null;
color2: string | null;
icon: string | null;
createdAt: number;
updatedAt: number;
};
export type BoosterRoleStore = {
findByUser(guildId: string, userId: string): Promise<BoosterRoleRecord | null>;
findByGuild(guildId: string): Promise<BoosterRoleRecord[]>;
create(record: BoosterRoleRecord): Promise<void>;
delete(guildId: string, userId: string): Promise<void>;
};
type SelectQuery = { type SelectQuery = {
where(condition: unknown): QueryWithLimit & Promise<BoosterRoleRecord[]>; where(condition: unknown): QueryWithLimit & Promise<BoosterRoleRecord[]>;