This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
export type DiscordGame = 't5' | 't6';
|
||||
|
||||
export interface DiscordSettings {
|
||||
enabled: boolean;
|
||||
guildId: string;
|
||||
channels: Record<DiscordGame, string>;
|
||||
publishedServers: string[];
|
||||
showPlayers: boolean;
|
||||
showAddresses: boolean;
|
||||
leaderboardEnabled: boolean;
|
||||
}
|
||||
|
||||
export const defaultDiscordSettings: DiscordSettings = {
|
||||
enabled: false,
|
||||
guildId: '',
|
||||
channels: { t5: '', t6: '' },
|
||||
publishedServers: [],
|
||||
showPlayers: false,
|
||||
showAddresses: false,
|
||||
leaderboardEnabled: false
|
||||
};
|
||||
|
||||
export const discordSnowflake = (value: unknown): value is string =>
|
||||
typeof value === 'string' && /^[1-9][0-9]{16,19}$/.test(value);
|
||||
|
||||
export function validateDiscordSettings(value: unknown): DiscordSettings {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value))
|
||||
throw new Error('Provide Discord settings.');
|
||||
const input = value as Record<string, unknown>;
|
||||
for (const key of ['enabled', 'showPlayers', 'showAddresses', 'leaderboardEnabled']) {
|
||||
if (typeof input[key] !== 'boolean') throw new Error(`Invalid ${key} setting.`);
|
||||
}
|
||||
if (typeof input.guildId !== 'string' || (input.guildId && !discordSnowflake(input.guildId)))
|
||||
throw new Error('Provide a valid Discord server ID.');
|
||||
if (!input.channels || typeof input.channels !== 'object' || Array.isArray(input.channels))
|
||||
throw new Error('Provide Discord channels for each game.');
|
||||
const channels = input.channels as Record<string, unknown>;
|
||||
for (const game of ['t5', 't6'] as const) {
|
||||
if (
|
||||
typeof channels[game] !== 'string' ||
|
||||
(channels[game] && !discordSnowflake(channels[game]))
|
||||
)
|
||||
throw new Error('Channel IDs must be valid Discord IDs or empty.');
|
||||
}
|
||||
if (
|
||||
!Array.isArray(input.publishedServers) ||
|
||||
input.publishedServers.length > 100 ||
|
||||
input.publishedServers.some(
|
||||
(name) => typeof name !== 'string' || !/^[A-Za-z0-9_.-]{1,128}$/.test(name)
|
||||
)
|
||||
)
|
||||
throw new Error('Choose up to 100 published servers.');
|
||||
if (input.enabled && (!input.guildId || (!channels.t5 && !channels.t6)))
|
||||
throw new Error('Choose a Discord server and at least one board channel before enabling.');
|
||||
return {
|
||||
enabled: input.enabled as boolean,
|
||||
guildId: input.guildId,
|
||||
channels: { t5: channels.t5 as string, t6: channels.t6 as string },
|
||||
publishedServers: [...new Set(input.publishedServers as string[])].sort(),
|
||||
showPlayers: input.showPlayers as boolean,
|
||||
showAddresses: input.showAddresses as boolean,
|
||||
leaderboardEnabled: input.leaderboardEnabled as boolean
|
||||
};
|
||||
}
|
||||
|
||||
export interface DiscordPublicServer {
|
||||
name: string;
|
||||
game: DiscordGame;
|
||||
label: string;
|
||||
map: string;
|
||||
mapKey: string;
|
||||
state: 'empty' | 'in-progress' | 'full' | 'starting' | 'offline' | 'stale' | 'unknown';
|
||||
players: number | null;
|
||||
capacity: number | null;
|
||||
round: number | null;
|
||||
observedAt: string | null;
|
||||
playerNames: string[];
|
||||
connection: string | null;
|
||||
}
|
||||
|
||||
export interface DiscordMessage {
|
||||
content?: string;
|
||||
flags?: number;
|
||||
components?: Record<string, unknown>[];
|
||||
allowed_mentions: { parse: string[] };
|
||||
}
|
||||
|
||||
export interface DiscordDeliveryStatus {
|
||||
lastAttemptAt: string | null;
|
||||
lastSuccessAt: string | null;
|
||||
lastError: string | null;
|
||||
boards: { game: DiscordGame; channelId: string; messageCount: number }[];
|
||||
activeSubscriptions: number;
|
||||
pendingNotifications: number;
|
||||
}
|
||||
|
||||
export interface DiscordAdminState {
|
||||
settings: DiscordSettings;
|
||||
credentials: {
|
||||
applicationId: string;
|
||||
publicKeyConfigured: boolean;
|
||||
botTokenConfigured: boolean;
|
||||
};
|
||||
status: DiscordDeliveryStatus;
|
||||
servers: { name: string; game: DiscordGame; label: string; map: string }[];
|
||||
preview: Record<DiscordGame, DiscordPublicServer[]>;
|
||||
}
|
||||
Reference in New Issue
Block a user