3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-06-06 23:55:03 +00:00

refactor: move defaults to config schemas

This commit is contained in:
Dragory 2025-05-23 01:12:52 +00:00
parent 09eb8e92f2
commit 83d35052c3
No known key found for this signature in database
91 changed files with 450 additions and 888 deletions

View file

@ -49,7 +49,7 @@
"fp-ts": "^2.0.1",
"humanize-duration": "^3.15.0",
"js-yaml": "^4.1.0",
"knub": "^32.0.0-next.23",
"knub": "^32.0.0-next.25",
"knub-command-manager": "^9.1.0",
"last-commit-log": "^2.1.0",
"lodash-es": "^4.17.21",

View file

@ -131,7 +131,7 @@ export function initDocs(router: express.Router) {
config: cmd.config,
}));
const defaultOptions = pluginInfo.plugin.defaultOptions || {};
const defaultOptions = (pluginInfo.plugin as any /* TODO */).defaultOptions || {};
res.json({
name: pluginInfo.plugin.name,

View file

@ -28,10 +28,13 @@ export async function validateGuildConfig(config: any): Promise<string | null> {
}
const plugin = pluginNameToPlugin.get(pluginName)!;
const configManager = new PluginConfigManager(plugin.defaultOptions || { config: {} }, pluginOptions, {
const configManager = new PluginConfigManager({}, {
configSchema: plugin.configSchema,
defaultOverrides: plugin.defaultOverrides ?? [],
levels: {},
parser: plugin.configParser,
customOverrideCriteriaFunctions: plugin.customOverrideCriteriaFunctions,
});
try {
await configManager.init();
} catch (err) {

View file

@ -73,7 +73,7 @@ function overrides(configSchema: z.ZodType): z.ZodType {
const pluginSchemaMap = availableGuildPlugins.reduce((map, pluginInfo) => {
map[pluginInfo.plugin.name] = z.object({
config: pluginInfo.docs.configSchema.optional(),
overrides: overrides(pluginInfo.docs.configSchema).optional(),
overrides: z.array(overrides(pluginInfo.docs.configSchema)).optional(),
});
return map;
}, {});

View file

@ -27,6 +27,7 @@ import { AnyPluginData, BasePluginData, CommandContext, ExtendedMatchParams, Gui
import { isStaff } from "./staff.js";
import { TZeppelinKnub } from "./types.js";
import { Tail } from "./utils/typeUtils.js";
import z from "zod/v4";
const { getMemberLevel } = helpers;
@ -166,7 +167,7 @@ export async function deleteContextResponse(response: ContextResponse): Promise<
await response.delete();
}
export async function getConfigForContext<TPluginData extends BasePluginData<any>>(config: PluginConfigManager<TPluginData>, context: GenericCommandSource): Promise<TPluginData["_pluginType"]["config"]> {
export async function getConfigForContext<TPluginData extends BasePluginData<any>>(config: PluginConfigManager<TPluginData>, context: GenericCommandSource): Promise<z.output<TPluginData["_pluginType"]["configSchema"]>> {
if (context instanceof ChatInputCommandInteraction) {
// TODO: Support for modal interactions (here and Knub)
return config.getForInteraction(context);

View file

@ -8,19 +8,11 @@ import { onMessageCreate } from "./util/onMessageCreate.js";
import { onMessageDelete } from "./util/onMessageDelete.js";
import { onMessageDeleteBulk } from "./util/onMessageDeleteBulk.js";
const defaultOptions: PluginOptions<AutoDeletePluginType> = {
config: {
enabled: false,
delay: "5s",
},
};
export const AutoDeletePlugin = guildPlugin<AutoDeletePluginType>()({
name: "auto_delete",
dependencies: () => [TimeAndDatePlugin, LogsPlugin],
configParser: (input) => zAutoDeleteConfig.parse(input),
defaultOptions,
configSchema: zAutoDeleteConfig,
beforeLoad(pluginData) {
const { state, guild } = pluginData;

View file

@ -14,12 +14,12 @@ export interface IDeletionQueueItem {
}
export const zAutoDeleteConfig = z.strictObject({
enabled: z.boolean(),
delay: zDelayString,
enabled: z.boolean().default(false),
delay: zDelayString.default("5s"),
});
export interface AutoDeletePluginType extends BasePluginType {
config: z.output<typeof zAutoDeleteConfig>;
configSchema: typeof zAutoDeleteConfig;
state: {
guildSavedMessages: GuildSavedMessages;
guildLogs: GuildLogs;

View file

@ -1,4 +1,4 @@
import { PluginOptions, guildPlugin } from "knub";
import { PluginOverride, guildPlugin } from "knub";
import { GuildAutoReactions } from "../../data/GuildAutoReactions.js";
import { GuildSavedMessages } from "../../data/GuildSavedMessages.js";
import { CommonPlugin } from "../Common/CommonPlugin.js";
@ -8,19 +8,14 @@ import { NewAutoReactionsCmd } from "./commands/NewAutoReactionsCmd.js";
import { AddReactionsEvt } from "./events/AddReactionsEvt.js";
import { AutoReactionsPluginType, zAutoReactionsConfig } from "./types.js";
const defaultOptions: PluginOptions<AutoReactionsPluginType> = {
config: {
can_manage: false,
},
overrides: [
{
level: ">=100",
config: {
can_manage: true,
},
const defaultOverrides: Array<PluginOverride<AutoReactionsPluginType>> = [
{
level: ">=100",
config: {
can_manage: true,
},
],
};
},
];
export const AutoReactionsPlugin = guildPlugin<AutoReactionsPluginType>()({
name: "auto_reactions",
@ -30,8 +25,8 @@ export const AutoReactionsPlugin = guildPlugin<AutoReactionsPluginType>()({
LogsPlugin,
],
configParser: (input) => zAutoReactionsConfig.parse(input),
defaultOptions,
configSchema: zAutoReactionsConfig,
defaultOverrides,
// prettier-ignore
messageCommands: [

View file

@ -7,11 +7,11 @@ import { AutoReaction } from "../../data/entities/AutoReaction.js";
import { CommonPlugin } from "../Common/CommonPlugin.js";
export const zAutoReactionsConfig = z.strictObject({
can_manage: z.boolean(),
can_manage: z.boolean().default(false),
});
export interface AutoReactionsPluginType extends BasePluginType {
config: z.output<typeof zAutoReactionsConfig>;
configSchema: typeof zAutoReactionsConfig;
state: {
logs: GuildLogs;
savedMessages: GuildSavedMessages;

View file

@ -34,29 +34,6 @@ import { clearOldRecentActions } from "./functions/clearOldRecentActions.js";
import { clearOldRecentSpam } from "./functions/clearOldRecentSpam.js";
import { AutomodPluginType, zAutomodConfig } from "./types.js";
const defaultOptions = {
config: {
rules: {},
antiraid_levels: ["low", "medium", "high"],
can_set_antiraid: false,
can_view_antiraid: false,
},
overrides: [
{
level: ">=50",
config: {
can_view_antiraid: true,
},
},
{
level: ">=100",
config: {
can_set_antiraid: true,
},
},
],
};
export const AutomodPlugin = guildPlugin<AutomodPluginType>()({
name: "automod",
@ -71,8 +48,7 @@ export const AutomodPlugin = guildPlugin<AutomodPluginType>()({
RoleManagerPlugin,
],
defaultOptions,
configParser: (input) => zAutomodConfig.parse(input),
configSchema: zAutomodConfig,
customOverrideCriteriaFunctions: {
antiraid_level: (pluginData, matchParams, value) => {

View file

@ -9,24 +9,12 @@ interface MatchResultType {
mode: "blacklist" | "whitelist";
}
const baseConfig = z.strictObject({
filetype_blacklist: z.array(z.string().max(32)).max(255).default([]),
const configSchema = z.strictObject({
whitelist_enabled: z.boolean().default(false),
filetype_whitelist: z.array(z.string().max(32)).max(255).default([]),
blacklist_enabled: z.boolean().default(false),
filetype_blacklist: z.array(z.string().max(32)).max(255).default([]),
});
const configWithWhitelist = baseConfig.merge(
z.strictObject({
whitelist_enabled: z.literal(true),
blacklist_enabled: z.literal(false).default(false),
}),
);
const configWithBlacklist = baseConfig.merge(
z.strictObject({
blacklist_enabled: z.literal(true),
whitelist_enabled: z.literal(false).default(false),
}),
);
const configSchema = z.union([configWithWhitelist, configWithBlacklist]);
export const MatchAttachmentTypeTrigger = automodTrigger<MatchResultType>()({
configSchema,

View file

@ -1,31 +1,19 @@
import { escapeInlineCode } from "discord.js";
import z from "zod/v4";
import { asSingleLine, messageSummary, verboseChannelMention } from "../../../utils.js";
import { automodTrigger } from "../helpers.js";
import z from "zod/v4";
interface MatchResultType {
matchedType: string;
mode: "blacklist" | "whitelist";
}
const baseConfig = z.strictObject({
mime_type_blacklist: z.array(z.string().max(32)).max(255).default([]),
const configSchema = z.strictObject({
whitelist_enabled: z.boolean().default(false),
mime_type_whitelist: z.array(z.string().max(32)).max(255).default([]),
blacklist_enabled: z.boolean().default(false),
mime_type_blacklist: z.array(z.string().max(32)).max(255).default([]),
});
const configWithWhitelist = baseConfig.merge(
z.strictObject({
whitelist_enabled: z.literal(true),
blacklist_enabled: z.literal(false).default(false),
}),
);
const configWithBlacklist = baseConfig.merge(
z.strictObject({
blacklist_enabled: z.literal(true),
whitelist_enabled: z.literal(false).default(false),
}),
);
const configSchema = z.union([configWithWhitelist, configWithBlacklist]);
export const MatchMimeTypeTrigger = automodTrigger<MatchResultType>()({
configSchema,

View file

@ -58,14 +58,14 @@ const zRule = z.strictObject({
export type TRule = z.infer<typeof zRule>;
export const zAutomodConfig = z.strictObject({
rules: zBoundedRecord(z.record(z.string().max(100), zRule), 0, 255),
antiraid_levels: z.array(z.string().max(100)).max(10),
can_set_antiraid: z.boolean(),
can_view_antiraid: z.boolean(),
rules: zBoundedRecord(z.record(z.string().max(100), zRule), 0, 255).default({}),
antiraid_levels: z.array(z.string().max(100)).max(10).default(["low", "medium", "high"]),
can_set_antiraid: z.boolean().default(false),
can_view_antiraid: z.boolean().default(false),
});
export interface AutomodPluginType extends BasePluginType {
config: z.output<typeof zAutomodConfig>;
configSchema: typeof zAutomodConfig;
customOverrideCriteria: {
antiraid_level?: string;

View file

@ -23,21 +23,9 @@ import { RestPerformanceCmd } from "./commands/RestPerformanceCmd.js";
import { ServersCmd } from "./commands/ServersCmd.js";
import { BotControlPluginType, zBotControlConfig } from "./types.js";
const defaultOptions = {
config: {
can_use: false,
can_eligible: false,
can_performance: false,
can_add_server_from_invite: false,
can_list_dashboard_perms: false,
update_cmd: null,
},
};
export const BotControlPlugin = globalPlugin<BotControlPluginType>()({
name: "bot_control",
configParser: (input) => zBotControlConfig.parse(input),
defaultOptions,
configSchema: zBotControlConfig,
// prettier-ignore
messageCommands: [

View file

@ -7,16 +7,16 @@ import { GuildArchives } from "../../data/GuildArchives.js";
import { zBoundedCharacters } from "../../utils.js";
export const zBotControlConfig = z.strictObject({
can_use: z.boolean(),
can_eligible: z.boolean(),
can_performance: z.boolean(),
can_add_server_from_invite: z.boolean(),
can_list_dashboard_perms: z.boolean(),
update_cmd: zBoundedCharacters(0, 2000).nullable(),
can_use: z.boolean().default(false),
can_eligible: z.boolean().default(false),
can_performance: z.boolean().default(false),
can_add_server_from_invite: z.boolean().default(false),
can_list_dashboard_perms: z.boolean().default(false),
update_cmd: zBoundedCharacters(0, 2000).nullable().default(null),
});
export interface BotControlPluginType extends BasePluginType {
config: z.output<typeof zBotControlConfig>;
configSchema: typeof zBotControlConfig;
state: {
archives: GuildArchives;
allowedGuilds: AllowedGuilds;

View file

@ -20,23 +20,11 @@ function getLogsPlugin(): Promise<any> {
return import("../Logs/LogsPlugin.js") as Promise<any>;
}
const defaultOptions = {
config: {
log_automatic_actions: true,
case_log_channel: null,
show_relative_times: true,
relative_time_cutoff: "7d",
case_colors: null,
case_icons: null,
},
};
export const CasesPlugin = guildPlugin<CasesPluginType>()({
name: "cases",
dependencies: async () => [TimeAndDatePlugin, InternalPosterPlugin, (await getLogsPlugin()).LogsPlugin],
configParser: (input) => zCasesConfig.parse(input),
defaultOptions,
configSchema: zCasesConfig,
public(pluginData) {
return {

View file

@ -11,16 +11,16 @@ import { zColor } from "../../utils/zColor.js";
const caseKeys = keys(CaseNameToType) as U.ListOf<keyof typeof CaseNameToType>;
export const zCasesConfig = z.strictObject({
log_automatic_actions: z.boolean(),
case_log_channel: zSnowflake.nullable(),
show_relative_times: z.boolean(),
log_automatic_actions: z.boolean().default(true),
case_log_channel: zSnowflake.nullable().default(null),
show_relative_times: z.boolean().default(true),
relative_time_cutoff: zDelayString.default("1w"),
case_colors: z.record(z.enum(caseKeys), zColor).nullable(),
case_icons: z.record(z.enum(caseKeys), zBoundedCharacters(0, 100)).nullable(),
case_colors: z.record(z.enum(caseKeys), zColor).nullable().default(null),
case_icons: z.record(z.enum(caseKeys), zBoundedCharacters(0, 100)).nullable().default(null),
});
export interface CasesPluginType extends BasePluginType {
config: z.infer<typeof zCasesConfig>;
configSchema: typeof zCasesConfig;
state: {
logs: GuildLogs;
cases: GuildCases;

View file

@ -1,4 +1,4 @@
import { PluginOptions, guildPlugin } from "knub";
import { PluginOptions, PluginOverride, guildPlugin } from "knub";
import { GuildLogs } from "../../data/GuildLogs.js";
import { GuildSavedMessages } from "../../data/GuildSavedMessages.js";
import { discardRegExpRunner, getRegExpRunner } from "../../regExpRunners.js";
@ -7,46 +7,26 @@ import { CensorPluginType, zCensorConfig } from "./types.js";
import { onMessageCreate } from "./util/onMessageCreate.js";
import { onMessageUpdate } from "./util/onMessageUpdate.js";
const defaultOptions: PluginOptions<CensorPluginType> = {
config: {
filter_zalgo: false,
filter_invites: false,
invite_guild_whitelist: null,
invite_guild_blacklist: null,
invite_code_whitelist: null,
invite_code_blacklist: null,
allow_group_dm_invites: false,
filter_domains: false,
domain_whitelist: null,
domain_blacklist: null,
blocked_tokens: null,
blocked_words: null,
blocked_regex: null,
},
overrides: [
{
level: ">=50",
config: {
filter_zalgo: false,
filter_invites: false,
filter_domains: false,
blocked_tokens: null,
blocked_words: null,
blocked_regex: null,
},
const defaultOverrides: Array<PluginOverride<CensorPluginType>> = [
{
level: ">=50",
config: {
filter_zalgo: false,
filter_invites: false,
filter_domains: false,
blocked_tokens: null,
blocked_words: null,
blocked_regex: null,
},
],
};
},
];
export const CensorPlugin = guildPlugin<CensorPluginType>()({
name: "censor",
dependencies: () => [LogsPlugin],
configParser: (input) => zCensorConfig.parse(input),
defaultOptions,
configSchema: zCensorConfig,
defaultOverrides,
beforeLoad(pluginData) {
const { state, guild } = pluginData;

View file

@ -6,23 +6,23 @@ import { GuildSavedMessages } from "../../data/GuildSavedMessages.js";
import { zBoundedCharacters, zRegex, zSnowflake } from "../../utils.js";
export const zCensorConfig = z.strictObject({
filter_zalgo: z.boolean(),
filter_invites: z.boolean(),
invite_guild_whitelist: z.array(zSnowflake).nullable(),
invite_guild_blacklist: z.array(zSnowflake).nullable(),
invite_code_whitelist: z.array(zBoundedCharacters(0, 16)).nullable(),
invite_code_blacklist: z.array(zBoundedCharacters(0, 16)).nullable(),
allow_group_dm_invites: z.boolean(),
filter_domains: z.boolean(),
domain_whitelist: z.array(zBoundedCharacters(0, 255)).nullable(),
domain_blacklist: z.array(zBoundedCharacters(0, 255)).nullable(),
blocked_tokens: z.array(zBoundedCharacters(0, 2000)).nullable(),
blocked_words: z.array(zBoundedCharacters(0, 2000)).nullable(),
blocked_regex: z.array(zRegex(z.string().max(1000))).nullable(),
filter_zalgo: z.boolean().default(false),
filter_invites: z.boolean().default(false),
invite_guild_whitelist: z.array(zSnowflake).nullable().default(null),
invite_guild_blacklist: z.array(zSnowflake).nullable().default(null),
invite_code_whitelist: z.array(zBoundedCharacters(0, 16)).nullable().default(null),
invite_code_blacklist: z.array(zBoundedCharacters(0, 16)).nullable().default(null),
allow_group_dm_invites: z.boolean().default(false),
filter_domains: z.boolean().default(false),
domain_whitelist: z.array(zBoundedCharacters(0, 255)).nullable().default(null),
domain_blacklist: z.array(zBoundedCharacters(0, 255)).nullable().default(null),
blocked_tokens: z.array(zBoundedCharacters(0, 2000)).nullable().default(null),
blocked_words: z.array(zBoundedCharacters(0, 2000)).nullable().default(null),
blocked_regex: z.array(zRegex(z.string().max(1000))).nullable().default(null),
});
export interface CensorPluginType extends BasePluginType {
config: z.infer<typeof zCensorConfig>;
configSchema: typeof zCensorConfig;
state: {
serverLogs: GuildLogs;
savedMessages: GuildSavedMessages;

View file

@ -1,15 +1,14 @@
import { guildPlugin } from "knub";
import z from "zod/v4";
import { CommonPlugin } from "../Common/CommonPlugin.js";
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin.js";
import { ArchiveChannelCmd } from "./commands/ArchiveChannelCmd.js";
import { ChannelArchiverPluginType } from "./types.js";
import { ChannelArchiverPluginType, zChannelArchiverPluginConfig } from "./types.js";
export const ChannelArchiverPlugin = guildPlugin<ChannelArchiverPluginType>()({
name: "channel_archiver",
dependencies: () => [TimeAndDatePlugin],
configParser: (input) => z.strictObject({}).parse(input),
configSchema: zChannelArchiverPluginConfig,
// prettier-ignore
messageCommands: [

View file

@ -1,7 +1,11 @@
import { BasePluginType, guildPluginMessageCommand, pluginUtils } from "knub";
import { CommonPlugin } from "../Common/CommonPlugin.js";
import { z } from "zod/v4";
export const zChannelArchiverPluginConfig = z.strictObject({});
export interface ChannelArchiverPluginType extends BasePluginType {
configSchema: typeof zChannelArchiverPluginConfig;
state: {
common: pluginUtils.PluginPublicInterface<typeof CommonPlugin>;
};

View file

@ -1,35 +1,19 @@
import {
Attachment,
ChatInputCommandInteraction,
InteractionResponse,
Message,
MessageCreateOptions,
MessageMentionOptions,
ModalSubmitInteraction,
SendableChannels,
TextBasedChannel,
User,
TextBasedChannel
} from "discord.js";
import { PluginOptions, guildPlugin } from "knub";
import { logger } from "../../logger.js";
import { GenericCommandSource, isContextInteraction, sendContextResponse } from "../../pluginUtils.js";
import { guildPlugin } from "knub";
import { GenericCommandSource, sendContextResponse } from "../../pluginUtils.js";
import { errorMessage, successMessage } from "../../utils.js";
import { getErrorEmoji, getSuccessEmoji } from "./functions/getEmoji.js";
import { CommonPluginType, zCommonConfig } from "./types.js";
const defaultOptions: PluginOptions<CommonPluginType> = {
config: {
success_emoji: "✅",
error_emoji: "❌",
attachment_storing_channel: null,
},
};
export const CommonPlugin = guildPlugin<CommonPluginType>()({
name: "common",
dependencies: () => [],
configParser: (input) => zCommonConfig.parse(input),
defaultOptions,
configSchema: zCommonConfig,
public(pluginData) {
return {
getSuccessEmoji,

View file

@ -2,11 +2,11 @@ import { BasePluginType } from "knub";
import z from "zod/v4";
export const zCommonConfig = z.strictObject({
success_emoji: z.string(),
error_emoji: z.string(),
attachment_storing_channel: z.nullable(z.string()),
success_emoji: z.string().default("✅"),
error_emoji: z.string().default("❌"),
attachment_storing_channel: z.nullable(z.string()).default(null),
});
export interface CommonPluginType extends BasePluginType {
config: z.output<typeof zCommonConfig>;
configSchema: typeof zCommonConfig;
}

View file

@ -4,18 +4,11 @@ import { LogsPlugin } from "../Logs/LogsPlugin.js";
import { VoiceStateUpdateEvt } from "./events/VoiceStateUpdateEvt.js";
import { CompanionChannelsPluginType, zCompanionChannelsConfig } from "./types.js";
const defaultOptions = {
config: {
entries: {},
},
};
export const CompanionChannelsPlugin = guildPlugin<CompanionChannelsPluginType>()({
name: "companion_channels",
dependencies: () => [LogsPlugin],
configParser: (input) => zCompanionChannelsConfig.parse(input),
defaultOptions,
configSchema: zCompanionChannelsConfig,
events: [VoiceStateUpdateEvt],

View file

@ -13,11 +13,11 @@ export const zCompanionChannelOpts = z.strictObject({
export type TCompanionChannelOpts = z.infer<typeof zCompanionChannelOpts>;
export const zCompanionChannelsConfig = z.strictObject({
entries: z.record(zBoundedCharacters(0, 100), zCompanionChannelOpts),
entries: z.record(zBoundedCharacters(0, 100), zCompanionChannelOpts).default({}),
});
export interface CompanionChannelsPluginType extends BasePluginType {
config: z.infer<typeof zCompanionChannelsConfig>;
configSchema: typeof zCompanionChannelsConfig;
state: {
errorCooldownManager: CooldownManager;
serverLogs: GuildLogs;

View file

@ -1,4 +1,4 @@
import { PluginOptions, guildPlugin } from "knub";
import { PluginOptions, PluginOverride, guildPlugin } from "knub";
import { GuildCases } from "../../data/GuildCases.js";
import { CasesPlugin } from "../Cases/CasesPlugin.js";
import { LogsPlugin } from "../Logs/LogsPlugin.js";
@ -13,30 +13,23 @@ import { NoteCmd } from "./commands/NoteUserCtxCmd.js";
import { WarnCmd } from "./commands/WarnUserCtxCmd.js";
import { ContextMenuPluginType, zContextMenusConfig } from "./types.js";
const defaultOptions: PluginOptions<ContextMenuPluginType> = {
config: {
can_use: false,
const defaultOverrides: Array<PluginOverride<ContextMenuPluginType>> = [
{
level: ">=50",
config: {
can_use: true,
can_open_mod_menu: false,
},
overrides: [
{
level: ">=50",
config: {
can_use: true,
can_open_mod_menu: true,
},
can_open_mod_menu: true,
},
],
};
},
];
export const ContextMenuPlugin = guildPlugin<ContextMenuPluginType>()({
name: "context_menu",
dependencies: () => [CasesPlugin, MutesPlugin, ModActionsPlugin, LogsPlugin, UtilityPlugin],
configParser: (input) => zContextMenusConfig.parse(input),
defaultOptions,
configSchema: zContextMenusConfig,
defaultOverrides,
contextMenuCommands: [ModMenuCmd, NoteCmd, WarnCmd, MuteCmd, BanCmd, CleanCmd],

View file

@ -4,12 +4,12 @@ import z from "zod/v4";
import { GuildCases } from "../../data/GuildCases.js";
export const zContextMenusConfig = z.strictObject({
can_use: z.boolean(),
can_open_mod_menu: z.boolean(),
can_use: z.boolean().default(false),
can_open_mod_menu: z.boolean().default(false),
});
export interface ContextMenuPluginType extends BasePluginType {
config: z.infer<typeof zContextMenusConfig>;
configSchema: typeof zContextMenusConfig;
state: {
cases: GuildCases;
};

View file

@ -1,5 +1,5 @@
import { EventEmitter } from "events";
import { PluginOptions, guildPlugin } from "knub";
import { PluginOptions, PluginOverride, guildPlugin } from "knub";
import { GuildCounters } from "../../data/GuildCounters.js";
import { buildCounterConditionString, CounterTrigger, getReverseCounterComparisonOp, parseCounterConditionString } from "../../data/entities/CounterTrigger.js";
import { makePublicFn } from "../../pluginUtils.js";
@ -23,28 +23,20 @@ import { CountersPluginType, zCountersConfig } from "./types.js";
const DECAY_APPLY_INTERVAL = 5 * MINUTES;
const defaultOptions: PluginOptions<CountersPluginType> = {
config: {
counters: {},
can_view: false,
can_edit: false,
can_reset_all: false,
const defaultOverrides: Array<PluginOverride<CountersPluginType>> = [
{
level: ">=50",
config: {
can_view: true,
},
},
overrides: [
{
level: ">=50",
config: {
can_view: true,
},
{
level: ">=100",
config: {
can_edit: true,
},
{
level: ">=100",
config: {
can_edit: true,
},
},
],
};
},
];
/**
* The Counters plugin keeps track of simple integer values that are tied to a user, channel, both, or neither "counters".
@ -59,9 +51,8 @@ const defaultOptions: PluginOptions<CountersPluginType> = {
export const CountersPlugin = guildPlugin<CountersPluginType>()({
name: "counters",
defaultOptions,
// TODO: Separate input and output types
configParser: (input) => zCountersConfig.parse(input),
configSchema: zCountersConfig,
defaultOverrides,
public(pluginData) {
return {

View file

@ -69,10 +69,10 @@ export const zCounter = z.strictObject({
});
export const zCountersConfig = z.strictObject({
counters: zBoundedRecord(z.record(zBoundedCharacters(0, 100), zCounter), 0, MAX_COUNTERS),
can_view: z.boolean(),
can_edit: z.boolean(),
can_reset_all: z.boolean(),
counters: zBoundedRecord(z.record(zBoundedCharacters(0, 100), zCounter), 0, MAX_COUNTERS).default({}),
can_view: z.boolean().default(false),
can_edit: z.boolean().default(false),
can_reset_all: z.boolean().default(false),
});
export interface CounterEvents {
@ -86,7 +86,7 @@ export interface CounterEventEmitter extends EventEmitter {
}
export interface CountersPluginType extends BasePluginType {
config: z.infer<typeof zCountersConfig>;
configSchema: typeof zCountersConfig;
state: {
counters: GuildCounters;
counterIds: Record<string, number>;

View file

@ -16,18 +16,11 @@ import { LogsPlugin } from "../Logs/LogsPlugin.js";
import { runEvent } from "./functions/runEvent.js";
import { CustomEventsPluginType, zCustomEventsConfig } from "./types.js";
const defaultOptions = {
config: {
events: {},
},
};
export const CustomEventsPlugin = guildPlugin<CustomEventsPluginType>()({
name: "custom_events",
dependencies: () => [LogsPlugin],
configParser: (input) => zCustomEventsConfig.parse(input),
defaultOptions,
configSchema: zCustomEventsConfig,
beforeStart(pluginData) {
pluginData.state.common = pluginData.getPlugin(CommonPlugin);

View file

@ -37,11 +37,11 @@ export const zCustomEvent = z.strictObject({
export type TCustomEvent = z.infer<typeof zCustomEvent>;
export const zCustomEventsConfig = z.strictObject({
events: zBoundedRecord(z.record(zBoundedCharacters(0, 100), zCustomEvent), 0, 100),
events: zBoundedRecord(z.record(zBoundedCharacters(0, 100), zCustomEvent), 0, 100).default({}),
});
export interface CustomEventsPluginType extends BasePluginType {
config: z.infer<typeof zCustomEventsConfig>;
configSchema: typeof zCustomEventsConfig;
state: {
clearTriggers: () => void;
common: pluginUtils.PluginPublicInterface<typeof CommonPlugin>;

View file

@ -3,13 +3,7 @@ import { BasePluginType, GlobalPluginData, globalPlugin, globalPluginEventListen
import { AllowedGuilds } from "../../data/AllowedGuilds.js";
import { Configs } from "../../data/Configs.js";
import { env } from "../../env.js";
import { zGuildAccessMonitorConfig } from "./types.js";
interface GuildAccessMonitorPluginType extends BasePluginType {
state: {
allowedGuilds: AllowedGuilds;
};
}
import { GuildAccessMonitorPluginType, zGuildAccessMonitorConfig } from "./types.js";
async function checkGuild(pluginData: GlobalPluginData<GuildAccessMonitorPluginType>, guild: Guild) {
if (!(await pluginData.state.allowedGuilds.isAllowed(guild.id))) {
@ -24,7 +18,7 @@ async function checkGuild(pluginData: GlobalPluginData<GuildAccessMonitorPluginT
*/
export const GuildAccessMonitorPlugin = globalPlugin<GuildAccessMonitorPluginType>()({
name: "guild_access_monitor",
configParser: (input) => zGuildAccessMonitorConfig.parse(input),
configSchema: zGuildAccessMonitorConfig,
events: [
globalPluginEventListener<GuildAccessMonitorPluginType>()({

View file

@ -1,3 +1,12 @@
import { BasePluginType } from "knub";
import { z } from "zod/v4";
import { AllowedGuilds } from "../../data/AllowedGuilds.js";
export const zGuildAccessMonitorConfig = z.strictObject({});
export interface GuildAccessMonitorPluginType extends BasePluginType {
configSchema: typeof zGuildAccessMonitorConfig;
state: {
allowedGuilds: AllowedGuilds;
};
}

View file

@ -1,13 +1,12 @@
import { globalPlugin } from "knub";
import z from "zod/v4";
import { Configs } from "../../data/Configs.js";
import { reloadChangedGuilds } from "./functions/reloadChangedGuilds.js";
import { GuildConfigReloaderPluginType } from "./types.js";
import { GuildConfigReloaderPluginType, zGuildConfigReloaderPluginConfig } from "./types.js";
export const GuildConfigReloaderPlugin = globalPlugin<GuildConfigReloaderPluginType>()({
name: "guild_config_reloader",
configParser: (input) => z.strictObject({}).parse(input),
configSchema: zGuildConfigReloaderPluginConfig,
async beforeLoad(pluginData) {
const { state } = pluginData;

View file

@ -1,8 +1,8 @@
import { ZeppelinPluginDocs } from "../../types.js";
import { zGuildConfigReloaderPlugin } from "./types.js";
import { zGuildConfigReloaderPluginConfig } from "./types.js";
export const guildConfigReloaderPluginDocs: ZeppelinPluginDocs = {
prettyName: "Guild config reloader",
type: "internal",
configSchema: zGuildConfigReloaderPlugin,
configSchema: zGuildConfigReloaderPluginConfig,
};

View file

@ -3,10 +3,10 @@ import { z } from "zod/v4";
import { Configs } from "../../data/Configs.js";
import Timeout = NodeJS.Timeout;
export const zGuildConfigReloaderPlugin = z.strictObject({});
export const zGuildConfigReloaderPluginConfig = z.strictObject({});
export interface GuildConfigReloaderPluginType extends BasePluginType {
config: z.infer<typeof zGuildConfigReloaderPlugin>;
configSchema: typeof zGuildConfigReloaderPluginConfig;
state: {
guildConfigs: Configs;
unloaded: boolean;

View file

@ -1,15 +1,14 @@
import { Guild } from "discord.js";
import { guildPlugin, guildPluginEventListener } from "knub";
import z from "zod/v4";
import { AllowedGuilds } from "../../data/AllowedGuilds.js";
import { ApiPermissionAssignments } from "../../data/ApiPermissionAssignments.js";
import { MINUTES } from "../../utils.js";
import { GuildInfoSaverPluginType } from "./types.js";
import { GuildInfoSaverPluginType, zGuildInfoSaverConfig } from "./types.js";
export const GuildInfoSaverPlugin = guildPlugin<GuildInfoSaverPluginType>()({
name: "guild_info_saver",
configParser: (input) => z.strictObject({}).parse(input),
configSchema: zGuildInfoSaverConfig,
events: [
guildPluginEventListener({

View file

@ -4,7 +4,7 @@ import { z } from "zod/v4";
export const zGuildInfoSaverConfig = z.strictObject({});
export interface GuildInfoSaverPluginType extends BasePluginType {
config: z.infer<typeof zGuildInfoSaverConfig>;
configSchema: typeof zGuildInfoSaverConfig;
state: {
updateInterval: NodeJS.Timeout;
};

View file

@ -1,5 +1,4 @@
import { guildPlugin } from "knub";
import z from "zod/v4";
import { GuildMemberCache } from "../../data/GuildMemberCache.js";
import { makePublicFn } from "../../pluginUtils.js";
import { SECONDS } from "../../utils.js";
@ -10,14 +9,14 @@ import { updateMemberCacheOnMessage } from "./events/updateMemberCacheOnMessage.
import { updateMemberCacheOnRoleChange } from "./events/updateMemberCacheOnRoleChange.js";
import { updateMemberCacheOnVoiceStateUpdate } from "./events/updateMemberCacheOnVoiceStateUpdate.js";
import { getCachedMemberData } from "./functions/getCachedMemberData.js";
import { GuildMemberCachePluginType } from "./types.js";
import { GuildMemberCachePluginType, zGuildMemberCacheConfig } from "./types.js";
const PENDING_SAVE_INTERVAL = 30 * SECONDS;
export const GuildMemberCachePlugin = guildPlugin<GuildMemberCachePluginType>()({
name: "guild_member_cache",
configParser: (input) => z.strictObject({}).parse(input),
configSchema: zGuildMemberCacheConfig,
events: [
updateMemberCacheOnMemberUpdate,

View file

@ -5,7 +5,7 @@ import { GuildMemberCache } from "../../data/GuildMemberCache.js";
export const zGuildMemberCacheConfig = z.strictObject({});
export interface GuildMemberCachePluginType extends BasePluginType {
config: z.infer<typeof zGuildMemberCacheConfig>;
configSchema: typeof zGuildMemberCacheConfig;
state: {
memberCache: GuildMemberCache;
saveInterval: NodeJS.Timeout;

View file

@ -5,18 +5,12 @@ import { Webhooks } from "../../data/Webhooks.js";
import { makePublicFn } from "../../pluginUtils.js";
import { editMessage } from "./functions/editMessage.js";
import { sendMessage } from "./functions/sendMessage.js";
import { InternalPosterPluginType } from "./types.js";
const defaultOptions: PluginOptions<InternalPosterPluginType> = {
config: {},
overrides: [],
};
import { InternalPosterPluginType, zInternalPosterConfig } from "./types.js";
export const InternalPosterPlugin = guildPlugin<InternalPosterPluginType>()({
name: "internal_poster",
configParser: (input) => z.strictObject({}).parse(input),
defaultOptions,
configSchema: zInternalPosterConfig,
public(pluginData) {
return {

View file

@ -4,10 +4,10 @@ import { z } from "zod/v4";
import { Queue } from "../../Queue.js";
import { Webhooks } from "../../data/Webhooks.js";
export const zInternalPosterConfig = z.strictObject({});
export const zInternalPosterConfig = z.strictObject({}).default({});
export interface InternalPosterPluginType extends BasePluginType {
config: z.infer<typeof zInternalPosterConfig>;
configSchema: typeof zInternalPosterConfig;
state: {
queue: Queue;
webhooks: Webhooks;

View file

@ -11,12 +11,11 @@ import { LocateUserPluginType, zLocateUserConfig } from "./types.js";
import { clearExpiredAlert } from "./utils/clearExpiredAlert.js";
import { fillActiveAlertsList } from "./utils/fillAlertsList.js";
const defaultOptions: PluginOptions<LocateUserPluginType> = {
config: {
can_where: false,
can_alert: false,
},
overrides: [
export const LocateUserPlugin = guildPlugin<LocateUserPluginType>()({
name: "locate_user",
configSchema: zLocateUserConfig,
defaultOverrides: [
{
level: ">=50",
config: {
@ -25,13 +24,6 @@ const defaultOptions: PluginOptions<LocateUserPluginType> = {
},
},
],
};
export const LocateUserPlugin = guildPlugin<LocateUserPluginType>()({
name: "locate_user",
configParser: (input) => zLocateUserConfig.parse(input),
defaultOptions,
// prettier-ignore
messageCommands: [

View file

@ -4,12 +4,12 @@ import { GuildVCAlerts } from "../../data/GuildVCAlerts.js";
import { CommonPlugin } from "../Common/CommonPlugin.js";
export const zLocateUserConfig = z.strictObject({
can_where: z.boolean(),
can_alert: z.boolean(),
can_where: z.boolean().default(false),
can_alert: z.boolean().default(false),
});
export interface LocateUserPluginType extends BasePluginType {
config: z.infer<typeof zLocateUserConfig>;
configSchema: typeof zLocateUserConfig;
state: {
alerts: GuildVCAlerts;
usersWithAlerts: string[];

View file

@ -1,5 +1,4 @@
import { CooldownManager, PluginOptions, guildPlugin } from "knub";
import DefaultLogMessages from "../../data/DefaultLogMessages.json" with { type: "json" };
import { CooldownManager, guildPlugin } from "knub";
import { GuildArchives } from "../../data/GuildArchives.js";
import { GuildCases } from "../../data/GuildCases.js";
import { GuildLogs } from "../../data/GuildLogs.js";
@ -115,17 +114,12 @@ function getCasesPlugin(): Promise<any> {
return import("../Cases/CasesPlugin.js") as Promise<any>;
}
const defaultOptions: PluginOptions<LogsPluginType> = {
config: {
channels: {},
format: DefaultLogMessages,
ping_user: true,
allow_user_mentions: false,
timestamp_format: "[<t:]X[>]",
include_embed_timestamp: true,
},
export const LogsPlugin = guildPlugin<LogsPluginType>()({
name: "logs",
overrides: [
dependencies: async () => [TimeAndDatePlugin, InternalPosterPlugin, (await getCasesPlugin()).CasesPlugin],
configSchema: zLogsConfig,
defaultOverrides: [
{
level: ">=50",
config: {
@ -134,14 +128,6 @@ const defaultOptions: PluginOptions<LogsPluginType> = {
},
},
],
};
export const LogsPlugin = guildPlugin<LogsPluginType>()({
name: "logs",
dependencies: async () => [TimeAndDatePlugin, InternalPosterPlugin, (await getCasesPlugin()).CasesPlugin],
configParser: (input) => zLogsConfig.parse(input),
defaultOptions,
events: [
LogsGuildMemberAddEvt,

View file

@ -21,6 +21,7 @@ import {
TemplateSafeUnknownUser,
TemplateSafeUser,
} from "../../utils/templateSafeObjects.js";
import DefaultLogMessages from "../../data/DefaultLogMessages.json" with { type: "json" };
const DEFAULT_BATCH_TIME = 1000;
const MIN_BATCH_TIME = 250;
@ -53,20 +54,20 @@ const zLogChannelMap = z.record(zSnowflake, zLogChannel);
export type TLogChannelMap = z.infer<typeof zLogChannelMap>;
export const zLogsConfig = z.strictObject({
channels: zLogChannelMap,
format: zLogFormats,
channels: zLogChannelMap.default({}),
format: zLogFormats.default(DefaultLogMessages),
// Legacy/deprecated, if below is false mentions wont actually ping. In case you really want the old behavior, set below to true
ping_user: z.boolean(),
allow_user_mentions: z.boolean(),
timestamp_format: z.string().nullable(),
include_embed_timestamp: z.boolean(),
ping_user: z.boolean().default(true),
allow_user_mentions: z.boolean().default(false),
timestamp_format: z.string().nullable().default("[<t:]X[>]"),
include_embed_timestamp: z.boolean().default(true),
});
// Hacky way of allowing a """null""" default value for config.format.timestamp due to legacy io-ts reasons
export const FORMAT_NO_TIMESTAMP = "__NO_TIMESTAMP__";
export interface LogsPluginType extends BasePluginType {
config: z.infer<typeof zLogsConfig>;
configSchema: typeof zLogsConfig;
state: {
guildLogs: GuildLogs;
savedMessages: GuildSavedMessages;

View file

@ -11,11 +11,11 @@ import {
} from "./events/SaveMessagesEvts.js";
import { MessageSaverPluginType, zMessageSaverConfig } from "./types.js";
const defaultOptions: PluginOptions<MessageSaverPluginType> = {
config: {
can_manage: false,
},
overrides: [
export const MessageSaverPlugin = guildPlugin<MessageSaverPluginType>()({
name: "message_saver",
configSchema: zMessageSaverConfig,
defaultOverrides: [
{
level: ">=100",
config: {
@ -23,13 +23,6 @@ const defaultOptions: PluginOptions<MessageSaverPluginType> = {
},
},
],
};
export const MessageSaverPlugin = guildPlugin<MessageSaverPluginType>()({
name: "message_saver",
configParser: (input) => zMessageSaverConfig.parse(input),
defaultOptions,
// prettier-ignore
messageCommands: [

View file

@ -4,11 +4,11 @@ import { GuildSavedMessages } from "../../data/GuildSavedMessages.js";
import { CommonPlugin } from "../Common/CommonPlugin.js";
export const zMessageSaverConfig = z.strictObject({
can_manage: z.boolean(),
can_manage: z.boolean().default(false),
});
export interface MessageSaverPluginType extends BasePluginType {
config: z.infer<typeof zMessageSaverConfig>;
configSchema: typeof zMessageSaverConfig;
state: {
savedMessages: GuildSavedMessages;
common: pluginUtils.PluginPublicInterface<typeof CommonPlugin>;

View file

@ -72,47 +72,14 @@ import { offModActionsEvent } from "./functions/offModActionsEvent.js";
import { onModActionsEvent } from "./functions/onModActionsEvent.js";
import { updateCase } from "./functions/updateCase.js";
import { warnMember } from "./functions/warnMember.js";
import { AttachmentLinkReactionType, ModActionsPluginType, modActionsSlashGroup, zModActionsConfig } from "./types.js";
import { ModActionsPluginType, modActionsSlashGroup, zModActionsConfig } from "./types.js";
const defaultOptions = {
config: {
dm_on_warn: true,
dm_on_kick: false,
dm_on_ban: false,
message_on_warn: false,
message_on_kick: false,
message_on_ban: false,
message_channel: null,
warn_message: "You have received a warning on the {guildName} server: {reason}",
kick_message: "You have been kicked from the {guildName} server. Reason given: {reason}",
ban_message: "You have been banned from the {guildName} server. Reason given: {reason}",
tempban_message: "You have been banned from the {guildName} server for {banTime}. Reason given: {reason}",
alert_on_rejoin: false,
alert_channel: null,
warn_notify_enabled: false,
warn_notify_threshold: 5,
warn_notify_message:
"The user already has **{priorWarnings}** warnings!\n Please check their prior cases and assess whether or not to warn anyways.\n Proceed with the warning?",
ban_delete_message_days: 1,
attachment_link_reaction: "warn" as AttachmentLinkReactionType,
export const ModActionsPlugin = guildPlugin<ModActionsPluginType>()({
name: "mod_actions",
can_note: false,
can_warn: false,
can_mute: false,
can_kick: false,
can_ban: false,
can_unban: false,
can_view: false,
can_addcase: false,
can_massunban: false,
can_massban: false,
can_massmute: false,
can_hidecase: false,
can_deletecase: false,
can_act_as_other: false,
create_cases_for_manual_actions: true,
},
overrides: [
dependencies: () => [TimeAndDatePlugin, CasesPlugin, MutesPlugin, LogsPlugin],
configSchema: zModActionsConfig,
defaultOverrides: [
{
level: ">=50",
config: {
@ -137,14 +104,6 @@ const defaultOptions = {
},
},
],
};
export const ModActionsPlugin = guildPlugin<ModActionsPluginType>()({
name: "mod_actions",
dependencies: () => [TimeAndDatePlugin, CasesPlugin, MutesPlugin, LogsPlugin],
configParser: (input) => zModActionsConfig.parse(input),
defaultOptions,
events: [CreateBanCaseOnManualBanEvt, CreateUnbanCaseOnManualUnbanEvt, PostAlertOnMemberJoinEvt, AuditLogEvents],

View file

@ -22,39 +22,39 @@ import { CommonPlugin } from "../Common/CommonPlugin.js";
export type AttachmentLinkReactionType = "none" | "warn" | "restrict" | null;
export const zModActionsConfig = z.strictObject({
dm_on_warn: z.boolean(),
dm_on_kick: z.boolean(),
dm_on_ban: z.boolean(),
message_on_warn: z.boolean(),
message_on_kick: z.boolean(),
message_on_ban: z.boolean(),
message_channel: z.nullable(z.string()),
warn_message: z.nullable(z.string()),
kick_message: z.nullable(z.string()),
ban_message: z.nullable(z.string()),
tempban_message: z.nullable(z.string()),
alert_on_rejoin: z.boolean(),
alert_channel: z.nullable(z.string()),
warn_notify_enabled: z.boolean(),
warn_notify_threshold: z.number(),
warn_notify_message: z.string(),
ban_delete_message_days: z.number(),
attachment_link_reaction: z.nullable(z.union([z.literal("none"), z.literal("warn"), z.literal("restrict")])),
can_note: z.boolean(),
can_warn: z.boolean(),
can_mute: z.boolean(),
can_kick: z.boolean(),
can_ban: z.boolean(),
can_unban: z.boolean(),
can_view: z.boolean(),
can_addcase: z.boolean(),
can_massunban: z.boolean(),
can_massban: z.boolean(),
can_massmute: z.boolean(),
can_hidecase: z.boolean(),
can_deletecase: z.boolean(),
can_act_as_other: z.boolean(),
create_cases_for_manual_actions: z.boolean(),
dm_on_warn: z.boolean().default(true),
dm_on_kick: z.boolean().default(false),
dm_on_ban: z.boolean().default(false),
message_on_warn: z.boolean().default(false),
message_on_kick: z.boolean().default(false),
message_on_ban: z.boolean().default(false),
message_channel: z.nullable(z.string()).default(null),
warn_message: z.nullable(z.string()).default("You have received a warning on the {guildName} server: {reason}"),
kick_message: z.nullable(z.string()).default("You have been kicked from the {guildName} server. Reason given: {reason}"),
ban_message: z.nullable(z.string()).default("You have been banned from the {guildName} server. Reason given: {reason}"),
tempban_message: z.nullable(z.string()).default("You have been banned from the {guildName} server for {banTime}. Reason given: {reason}"),
alert_on_rejoin: z.boolean().default(false),
alert_channel: z.nullable(z.string()).default(null),
warn_notify_enabled: z.boolean().default(false),
warn_notify_threshold: z.number().default(5),
warn_notify_message: z.string().default("The user already has **{priorWarnings}** warnings!\n Please check their prior cases and assess whether or not to warn anyways.\n Proceed with the warning?"),
ban_delete_message_days: z.number().default(1),
attachment_link_reaction: z.nullable(z.union([z.literal("none"), z.literal("warn"), z.literal("restrict")])).default("warn"),
can_note: z.boolean().default(false),
can_warn: z.boolean().default(false),
can_mute: z.boolean().default(false),
can_kick: z.boolean().default(false),
can_ban: z.boolean().default(false),
can_unban: z.boolean().default(false),
can_view: z.boolean().default(false),
can_addcase: z.boolean().default(false),
can_massunban: z.boolean().default(false),
can_massban: z.boolean().default(false),
can_massmute: z.boolean().default(false),
can_hidecase: z.boolean().default(false),
can_deletecase: z.boolean().default(false),
can_act_as_other: z.boolean().default(false),
create_cases_for_manual_actions: z.boolean().default(true),
});
export interface ModActionsEvents {
@ -72,7 +72,7 @@ export interface ModActionsEventEmitter extends EventEmitter {
}
export interface ModActionsPluginType extends BasePluginType {
config: z.infer<typeof zModActionsConfig>;
configSchema: typeof zModActionsConfig;
state: {
mutes: GuildMutes;
cases: GuildCases;

View file

@ -26,27 +26,12 @@ import { renewTimeoutMute } from "./functions/renewTimeoutMute.js";
import { unmuteUser } from "./functions/unmuteUser.js";
import { MutesPluginType, zMutesConfig } from "./types.js";
const defaultOptions = {
config: {
mute_role: null,
move_to_voice_channel: null,
kick_from_voice_channel: false,
export const MutesPlugin = guildPlugin<MutesPluginType>()({
name: "mutes",
dm_on_mute: false,
dm_on_update: false,
message_on_mute: false,
message_on_update: false,
message_channel: null,
mute_message: "You have been muted on the {guildName} server. Reason given: {reason}",
timed_mute_message: "You have been muted on the {guildName} server for {time}. Reason given: {reason}",
update_mute_message: "Your mute on the {guildName} server has been updated to {time}.",
remove_roles_on_mute: false,
restore_roles_on_mute: false,
can_view_list: false,
can_cleanup: false,
},
overrides: [
dependencies: () => [CasesPlugin, LogsPlugin, RoleManagerPlugin],
configSchema: zMutesConfig,
defaultOverrides: [
{
level: ">=50",
config: {
@ -60,14 +45,6 @@ const defaultOptions = {
},
},
],
};
export const MutesPlugin = guildPlugin<MutesPluginType>()({
name: "mutes",
dependencies: () => [CasesPlugin, LogsPlugin, RoleManagerPlugin],
configParser: (input) => zMutesConfig.parse(input),
defaultOptions,
// prettier-ignore
messageCommands: [

View file

@ -13,23 +13,23 @@ import { CaseArgs } from "../Cases/types.js";
import { CommonPlugin } from "../Common/CommonPlugin.js";
export const zMutesConfig = z.strictObject({
mute_role: zSnowflake.nullable(),
move_to_voice_channel: zSnowflake.nullable(),
kick_from_voice_channel: z.boolean(),
mute_role: zSnowflake.nullable().default(null),
move_to_voice_channel: zSnowflake.nullable().default(null),
kick_from_voice_channel: z.boolean().default(false),
dm_on_mute: z.boolean(),
dm_on_update: z.boolean(),
message_on_mute: z.boolean(),
message_on_update: z.boolean(),
message_channel: z.string().nullable(),
mute_message: z.string().nullable(),
timed_mute_message: z.string().nullable(),
update_mute_message: z.string().nullable(),
dm_on_mute: z.boolean().default(false),
dm_on_update: z.boolean().default(false),
message_on_mute: z.boolean().default(false),
message_on_update: z.boolean().default(false),
message_channel: z.string().nullable().default(null),
mute_message: z.string().nullable().default("You have been muted on the {guildName} server. Reason given: {reason}"),
timed_mute_message: z.string().nullable().default("You have been muted on the {guildName} server for {time}. Reason given: {reason}"),
update_mute_message: z.string().nullable().default("Your mute on the {guildName} server has been updated to {time}."),
remove_roles_on_mute: z.union([z.boolean(), z.array(zSnowflake)]).default(false),
restore_roles_on_mute: z.union([z.boolean(), z.array(zSnowflake)]).default(false),
can_view_list: z.boolean(),
can_cleanup: z.boolean(),
can_view_list: z.boolean().default(false),
can_cleanup: z.boolean().default(false),
});
export interface MutesEvents {
@ -43,7 +43,7 @@ export interface MutesEventEmitter extends EventEmitter {
}
export interface MutesPluginType extends BasePluginType {
config: z.infer<typeof zMutesConfig>;
configSchema: typeof zMutesConfig;
state: {
mutes: GuildMutes;
cases: GuildCases;

View file

@ -6,11 +6,11 @@ import { CommonPlugin } from "../Common/CommonPlugin.js";
import { NamesCmd } from "./commands/NamesCmd.js";
import { NameHistoryPluginType, zNameHistoryConfig } from "./types.js";
const defaultOptions: PluginOptions<NameHistoryPluginType> = {
config: {
can_view: false,
},
overrides: [
export const NameHistoryPlugin = guildPlugin<NameHistoryPluginType>()({
name: "name_history",
configSchema: zNameHistoryConfig,
defaultOverrides: [
{
level: ">=50",
config: {
@ -18,13 +18,6 @@ const defaultOptions: PluginOptions<NameHistoryPluginType> = {
},
},
],
};
export const NameHistoryPlugin = guildPlugin<NameHistoryPluginType>()({
name: "name_history",
configParser: (input) => zNameHistoryConfig.parse(input),
defaultOptions,
// prettier-ignore
messageCommands: [

View file

@ -6,11 +6,11 @@ import { UsernameHistory } from "../../data/UsernameHistory.js";
import { CommonPlugin } from "../Common/CommonPlugin.js";
export const zNameHistoryConfig = z.strictObject({
can_view: z.boolean(),
can_view: z.boolean().default(false),
});
export interface NameHistoryPluginType extends BasePluginType {
config: z.infer<typeof zNameHistoryConfig>;
configSchema: typeof zNameHistoryConfig;
state: {
nicknameHistory: GuildNicknameHistory;
usernameHistory: UsernameHistory;

View file

@ -7,20 +7,11 @@ import { LoadDataEvt } from "./events/LoadDataEvt.js";
import { StoreDataEvt } from "./events/StoreDataEvt.js";
import { PersistPluginType, zPersistConfig } from "./types.js";
const defaultOptions: PluginOptions<PersistPluginType> = {
config: {
persisted_roles: [],
persist_nicknames: false,
persist_voice_mutes: false,
},
};
export const PersistPlugin = guildPlugin<PersistPluginType>()({
name: "persist",
dependencies: () => [LogsPlugin, RoleManagerPlugin],
configParser: (input) => zPersistConfig.parse(input),
defaultOptions,
configSchema: zPersistConfig,
// prettier-ignore
events: [

View file

@ -5,14 +5,13 @@ import { GuildPersistedData } from "../../data/GuildPersistedData.js";
import { zSnowflake } from "../../utils.js";
export const zPersistConfig = z.strictObject({
persisted_roles: z.array(zSnowflake),
persist_nicknames: z.boolean(),
persist_voice_mutes: z.boolean(),
persisted_roles: z.array(zSnowflake).default([]),
persist_nicknames: z.boolean().default(false),
persist_voice_mutes: z.boolean().default(false),
});
export interface PersistPluginType extends BasePluginType {
config: z.infer<typeof zPersistConfig>;
configSchema: typeof zPersistConfig;
state: {
persistedData: GuildPersistedData;
logs: GuildLogs;

View file

@ -4,18 +4,10 @@ import { makePublicFn } from "../../pluginUtils.js";
import { getDomainInfo } from "./functions/getDomainInfo.js";
import { PhishermanPluginType, zPhishermanConfig } from "./types.js";
const defaultOptions: PluginOptions<PhishermanPluginType> = {
config: {
api_key: null,
},
overrides: [],
};
export const PhishermanPlugin = guildPlugin<PhishermanPluginType>()({
name: "phisherman",
configParser: (input) => zPhishermanConfig.parse(input),
defaultOptions,
configSchema: zPhishermanConfig,
public(pluginData) {
return {

View file

@ -2,12 +2,11 @@ import { BasePluginType } from "knub";
import z from "zod/v4";
export const zPhishermanConfig = z.strictObject({
api_key: z.string().max(255).nullable(),
api_key: z.string().max(255).nullable().default(null),
});
export interface PhishermanPluginType extends BasePluginType {
config: z.infer<typeof zPhishermanConfig>;
configSchema: typeof zPhishermanConfig;
state: {
validApiKey: string | null;
};

View file

@ -1,15 +1,15 @@
import { PluginOptions, guildPlugin } from "knub";
import { guildPlugin } from "knub";
import { GuildPingableRoles } from "../../data/GuildPingableRoles.js";
import { CommonPlugin } from "../Common/CommonPlugin.js";
import { PingableRoleDisableCmd } from "./commands/PingableRoleDisableCmd.js";
import { PingableRoleEnableCmd } from "./commands/PingableRoleEnableCmd.js";
import { PingableRolesPluginType, zPingableRolesConfig } from "./types.js";
const defaultOptions: PluginOptions<PingableRolesPluginType> = {
config: {
can_manage: false,
},
overrides: [
export const PingableRolesPlugin = guildPlugin<PingableRolesPluginType>()({
name: "pingable_roles",
configSchema: zPingableRolesConfig,
defaultOverrides: [
{
level: ">=100",
config: {
@ -17,13 +17,6 @@ const defaultOptions: PluginOptions<PingableRolesPluginType> = {
},
},
],
};
export const PingableRolesPlugin = guildPlugin<PingableRolesPluginType>()({
name: "pingable_roles",
configParser: (input) => zPingableRolesConfig.parse(input),
defaultOptions,
// prettier-ignore
messageCommands: [

View file

@ -5,12 +5,11 @@ import { PingableRole } from "../../data/entities/PingableRole.js";
import { CommonPlugin } from "../Common/CommonPlugin.js";
export const zPingableRolesConfig = z.strictObject({
can_manage: z.boolean(),
can_manage: z.boolean().default(false),
});
export interface PingableRolesPluginType extends BasePluginType {
config: z.infer<typeof zPingableRolesConfig>;
configSchema: typeof zPingableRolesConfig;
state: {
pingableRoles: GuildPingableRoles;
cache: Map<string, PingableRole[]>;

View file

@ -1,4 +1,4 @@
import { PluginOptions, guildPlugin } from "knub";
import { guildPlugin } from "knub";
import { onGuildEvent } from "../../data/GuildEvents.js";
import { GuildLogs } from "../../data/GuildLogs.js";
import { GuildSavedMessages } from "../../data/GuildSavedMessages.js";
@ -16,11 +16,12 @@ import { ScheduledPostsShowCmd } from "./commands/ScheduledPostsShowCmd.js";
import { PostPluginType, zPostConfig } from "./types.js";
import { postScheduledPost } from "./util/postScheduledPost.js";
const defaultOptions: PluginOptions<PostPluginType> = {
config: {
can_post: false,
},
overrides: [
export const PostPlugin = guildPlugin<PostPluginType>()({
name: "post",
dependencies: () => [TimeAndDatePlugin, LogsPlugin],
configSchema: zPostConfig,
defaultOverrides: [
{
level: ">=100",
config: {
@ -28,14 +29,6 @@ const defaultOptions: PluginOptions<PostPluginType> = {
},
},
],
};
export const PostPlugin = guildPlugin<PostPluginType>()({
name: "post",
dependencies: () => [TimeAndDatePlugin, LogsPlugin],
configParser: (input) => zPostConfig.parse(input),
defaultOptions,
// prettier-ignore
messageCommands: [

View file

@ -6,11 +6,11 @@ import { GuildScheduledPosts } from "../../data/GuildScheduledPosts.js";
import { CommonPlugin } from "../Common/CommonPlugin.js";
export const zPostConfig = z.strictObject({
can_post: z.boolean(),
can_post: z.boolean().default(false),
});
export interface PostPluginType extends BasePluginType {
config: z.infer<typeof zPostConfig>;
configSchema: typeof zPostConfig;
state: {
savedMessages: GuildSavedMessages;
scheduledPosts: GuildScheduledPosts;

View file

@ -11,19 +11,12 @@ import { AddReactionRoleEvt } from "./events/AddReactionRoleEvt.js";
import { MessageDeletedEvt } from "./events/MessageDeletedEvt.js";
import { ReactionRolesPluginType, zReactionRolesConfig } from "./types.js";
const MIN_AUTO_REFRESH = 1000 * 60 * 15; // 15min minimum, let's not abuse the API
export const ReactionRolesPlugin = guildPlugin<ReactionRolesPluginType>()({
name: "reaction_roles",
const defaultOptions: PluginOptions<ReactionRolesPluginType> = {
config: {
auto_refresh_interval: MIN_AUTO_REFRESH,
remove_user_reactions: true,
can_manage: false,
button_groups: null,
},
overrides: [
dependencies: () => [LogsPlugin],
configSchema: zReactionRolesConfig,
defaultOverrides: [
{
level: ">=100",
config: {
@ -31,14 +24,6 @@ const defaultOptions: PluginOptions<ReactionRolesPluginType> = {
},
},
],
};
export const ReactionRolesPlugin = guildPlugin<ReactionRolesPluginType>()({
name: "reaction_roles",
dependencies: () => [LogsPlugin],
configParser: (input) => zReactionRolesConfig.parse(input),
defaultOptions,
// prettier-ignore
messageCommands: [

View file

@ -5,11 +5,13 @@ import { GuildReactionRoles } from "../../data/GuildReactionRoles.js";
import { GuildSavedMessages } from "../../data/GuildSavedMessages.js";
import { CommonPlugin } from "../Common/CommonPlugin.js";
const MIN_AUTO_REFRESH = 1000 * 60 * 15; // 15min minimum, let's not abuse the API
export const zReactionRolesConfig = z.strictObject({
auto_refresh_interval: z.number(),
remove_user_reactions: z.boolean(),
can_manage: z.boolean(),
button_groups: z.nullable(z.unknown()),
auto_refresh_interval: z.number().min(MIN_AUTO_REFRESH).default(MIN_AUTO_REFRESH),
remove_user_reactions: z.boolean().default(true),
can_manage: z.boolean().default(false),
button_groups: z.null().default(null),
});
export type RoleChangeMode = "+" | "-";
@ -27,7 +29,7 @@ const zReactionRolePair = z.union([z.tuple([z.string(), z.string(), z.string()])
export type TReactionRolePair = z.infer<typeof zReactionRolePair>;
export interface ReactionRolesPluginType extends BasePluginType {
config: z.infer<typeof zReactionRolesConfig>;
configSchema: typeof zReactionRolesConfig;
state: {
reactionRoles: GuildReactionRoles;
savedMessages: GuildSavedMessages;

View file

@ -9,11 +9,12 @@ import { RemindersDeleteCmd } from "./commands/RemindersDeleteCmd.js";
import { postReminder } from "./functions/postReminder.js";
import { RemindersPluginType, zRemindersConfig } from "./types.js";
const defaultOptions: PluginOptions<RemindersPluginType> = {
config: {
can_use: false,
},
overrides: [
export const RemindersPlugin = guildPlugin<RemindersPluginType>()({
name: "reminders",
dependencies: () => [TimeAndDatePlugin],
configSchema: zRemindersConfig,
defaultOverrides: [
{
level: ">=50",
config: {
@ -21,14 +22,6 @@ const defaultOptions: PluginOptions<RemindersPluginType> = {
},
},
],
};
export const RemindersPlugin = guildPlugin<RemindersPluginType>()({
name: "reminders",
dependencies: () => [TimeAndDatePlugin],
configParser: (input) => zRemindersConfig.parse(input),
defaultOptions,
// prettier-ignore
messageCommands: [

View file

@ -4,12 +4,11 @@ import { GuildReminders } from "../../data/GuildReminders.js";
import { CommonPlugin } from "../Common/CommonPlugin.js";
export const zRemindersConfig = z.strictObject({
can_use: z.boolean(),
can_use: z.boolean().default(false),
});
export interface RemindersPluginType extends BasePluginType {
config: z.infer<typeof zRemindersConfig>;
configSchema: typeof zRemindersConfig;
state: {
reminders: GuildReminders;
tries: Map<number, number>;

View file

@ -11,22 +11,15 @@ import { RoleButtonsPluginType, zRoleButtonsConfig } from "./types.js";
export const RoleButtonsPlugin = guildPlugin<RoleButtonsPluginType>()({
name: "role_buttons",
defaultOptions: {
config: {
buttons: {},
can_reset: false,
},
overrides: [
{
level: ">=100",
config: {
can_reset: true,
},
configSchema: zRoleButtonsConfig,
defaultOverrides: [
{
level: ">=100",
config: {
can_reset: true,
},
],
},
configParser: (input) => zRoleButtonsConfig.parse(input),
},
],
dependencies: () => [LogsPlugin, RoleManagerPlugin],

View file

@ -67,8 +67,8 @@ export type TRoleButtonsConfigItem = z.infer<typeof zRoleButtonsConfigItem>;
export const zRoleButtonsConfig = z
.strictObject({
buttons: zBoundedRecord(z.record(zBoundedCharacters(1, 16), zRoleButtonsConfigItem), 0, 100),
can_reset: z.boolean(),
buttons: zBoundedRecord(z.record(zBoundedCharacters(1, 16), zRoleButtonsConfigItem), 0, 100).default({}),
can_reset: z.boolean().default(false),
})
.refine(
(parsed) => {
@ -91,7 +91,7 @@ export const zRoleButtonsConfig = z
);
export interface RoleButtonsPluginType extends BasePluginType {
config: z.infer<typeof zRoleButtonsConfig>;
configSchema: typeof zRoleButtonsConfig;
state: {
roleButtons: GuildRoleButtons;
common: pluginUtils.PluginPublicInterface<typeof CommonPlugin>;

View file

@ -13,7 +13,7 @@ export const RoleManagerPlugin = guildPlugin<RoleManagerPluginType>()({
name: "role_manager",
dependencies: () => [LogsPlugin],
configParser: (input) => zRoleManagerConfig.parse(input),
configSchema: zRoleManagerConfig,
public(pluginData) {
return {

View file

@ -5,7 +5,7 @@ import { GuildRoleQueue } from "../../data/GuildRoleQueue.js";
export const zRoleManagerConfig = z.strictObject({});
export interface RoleManagerPluginType extends BasePluginType {
config: z.infer<typeof zRoleManagerConfig>;
configSchema: typeof zRoleManagerConfig;
state: {
roleQueue: GuildRoleQueue;
roleAssignmentLoopRunning: boolean;

View file

@ -9,13 +9,12 @@ import { MassRemoveRoleCmd } from "./commands/MassRemoveRoleCmd.js";
import { RemoveRoleCmd } from "./commands/RemoveRoleCmd.js";
import { RolesPluginType, zRolesConfig } from "./types.js";
const defaultOptions: PluginOptions<RolesPluginType> = {
config: {
can_assign: false,
can_mass_assign: false,
assignable_roles: [],
},
overrides: [
export const RolesPlugin = guildPlugin<RolesPluginType>()({
name: "roles",
dependencies: () => [LogsPlugin, RoleManagerPlugin],
configSchema: zRolesConfig,
defaultOverrides: [
{
level: ">=50",
config: {
@ -29,14 +28,6 @@ const defaultOptions: PluginOptions<RolesPluginType> = {
},
},
],
};
export const RolesPlugin = guildPlugin<RolesPluginType>()({
name: "roles",
dependencies: () => [LogsPlugin, RoleManagerPlugin],
configParser: (input) => zRolesConfig.parse(input),
defaultOptions,
// prettier-ignore
messageCommands: [

View file

@ -4,13 +4,13 @@ import { GuildLogs } from "../../data/GuildLogs.js";
import { CommonPlugin } from "../Common/CommonPlugin.js";
export const zRolesConfig = z.strictObject({
can_assign: z.boolean(),
can_mass_assign: z.boolean(),
assignable_roles: z.array(z.string()).max(100),
can_assign: z.boolean().default(false),
can_mass_assign: z.boolean().default(false),
assignable_roles: z.array(z.string()).max(100).default([]),
});
export interface RolesPluginType extends BasePluginType {
config: z.infer<typeof zRolesConfig>;
configSchema: typeof zRolesConfig;
state: {
logs: GuildLogs;
common: pluginUtils.PluginPublicInterface<typeof CommonPlugin>;

View file

@ -5,18 +5,10 @@ import { RoleHelpCmd } from "./commands/RoleHelpCmd.js";
import { RoleRemoveCmd } from "./commands/RoleRemoveCmd.js";
import { SelfGrantableRolesPluginType, zSelfGrantableRolesConfig } from "./types.js";
const defaultOptions: PluginOptions<SelfGrantableRolesPluginType> = {
config: {
entries: {},
mention_roles: false,
},
};
export const SelfGrantableRolesPlugin = guildPlugin<SelfGrantableRolesPluginType>()({
name: "self_grantable_roles",
configParser: (input) => zSelfGrantableRolesConfig.parse(input),
defaultOptions,
configSchema: zSelfGrantableRolesConfig,
// prettier-ignore
messageCommands: [

View file

@ -20,12 +20,12 @@ const zSelfGrantableRoleEntry = z.strictObject({
export type TSelfGrantableRoleEntry = z.infer<typeof zSelfGrantableRoleEntry>;
export const zSelfGrantableRolesConfig = z.strictObject({
entries: zBoundedRecord(z.record(zBoundedCharacters(0, 255), zSelfGrantableRoleEntry), 0, 100),
mention_roles: z.boolean(),
entries: zBoundedRecord(z.record(zBoundedCharacters(0, 255), zSelfGrantableRoleEntry), 0, 100).default({}),
mention_roles: z.boolean().default(false),
});
export interface SelfGrantableRolesPluginType extends BasePluginType {
config: z.infer<typeof zSelfGrantableRolesConfig>;
configSchema: typeof zSelfGrantableRolesConfig;
state: {
cooldowns: CooldownManager;
common: pluginUtils.PluginPublicInterface<typeof CommonPlugin>;

View file

@ -1,4 +1,4 @@
import { PluginOptions, guildPlugin } from "knub";
import { guildPlugin } from "knub";
import { GuildLogs } from "../../data/GuildLogs.js";
import { GuildSavedMessages } from "../../data/GuildSavedMessages.js";
import { GuildSlowmodes } from "../../data/GuildSlowmodes.js";
@ -16,25 +16,6 @@ import { onMessageCreate } from "./util/onMessageCreate.js";
const BOT_SLOWMODE_CLEAR_INTERVAL = 60 * SECONDS;
const defaultOptions: PluginOptions<SlowmodePluginType> = {
config: {
use_native_slowmode: true,
can_manage: false,
is_affected: true,
},
overrides: [
{
level: ">=50",
config: {
can_manage: true,
is_affected: false,
},
},
],
};
export const SlowmodePlugin = guildPlugin<SlowmodePluginType>()({
name: "slowmode",
@ -43,8 +24,16 @@ export const SlowmodePlugin = guildPlugin<SlowmodePluginType>()({
LogsPlugin,
],
configParser: (input) => zSlowmodeConfig.parse(input),
defaultOptions,
configSchema: zSlowmodeConfig,
defaultOverrides: [
{
level: ">=50",
config: {
can_manage: true,
is_affected: false,
},
},
],
// prettier-ignore
messageCommands: [

View file

@ -7,14 +7,14 @@ import { SlowmodeChannel } from "../../data/entities/SlowmodeChannel.js";
import { CommonPlugin } from "../Common/CommonPlugin.js";
export const zSlowmodeConfig = z.strictObject({
use_native_slowmode: z.boolean(),
use_native_slowmode: z.boolean().default(true),
can_manage: z.boolean(),
is_affected: z.boolean(),
can_manage: z.boolean().default(false),
is_affected: z.boolean().default(true),
});
export interface SlowmodePluginType extends BasePluginType {
config: z.infer<typeof zSlowmodeConfig>;
configSchema: typeof zSlowmodeConfig;
state: {
slowmodes: GuildSlowmodes;
savedMessages: GuildSavedMessages;

View file

@ -1,4 +1,4 @@
import { PluginOptions, guildPlugin } from "knub";
import { guildPlugin } from "knub";
import { GuildArchives } from "../../data/GuildArchives.js";
import { GuildLogs } from "../../data/GuildLogs.js";
import { GuildMutes } from "../../data/GuildMutes.js";
@ -9,20 +9,12 @@ import { SpamPluginType, zSpamConfig } from "./types.js";
import { clearOldRecentActions } from "./util/clearOldRecentActions.js";
import { onMessageCreate } from "./util/onMessageCreate.js";
const defaultOptions: PluginOptions<SpamPluginType> = {
config: {
max_censor: null,
max_messages: null,
max_mentions: null,
max_links: null,
max_attachments: null,
max_emojis: null,
max_newlines: null,
max_duplicates: null,
max_characters: null,
max_voice_moves: null,
},
overrides: [
export const SpamPlugin = guildPlugin<SpamPluginType>()({
name: "spam",
dependencies: () => [LogsPlugin],
configSchema: zSpamConfig,
defaultOverrides: [
{
level: ">=50",
config: {
@ -38,14 +30,6 @@ const defaultOptions: PluginOptions<SpamPluginType> = {
},
},
],
};
export const SpamPlugin = guildPlugin<SpamPluginType>()({
name: "spam",
dependencies: () => [LogsPlugin],
configParser: (input) => zSpamConfig.parse(input),
defaultOptions,
// prettier-ignore
events: [

View file

@ -18,16 +18,16 @@ const zBaseSingleSpamConfig = z.strictObject({
export type TBaseSingleSpamConfig = z.infer<typeof zBaseSingleSpamConfig>;
export const zSpamConfig = z.strictObject({
max_censor: zBaseSingleSpamConfig.nullable(),
max_messages: zBaseSingleSpamConfig.nullable(),
max_mentions: zBaseSingleSpamConfig.nullable(),
max_links: zBaseSingleSpamConfig.nullable(),
max_attachments: zBaseSingleSpamConfig.nullable(),
max_emojis: zBaseSingleSpamConfig.nullable(),
max_newlines: zBaseSingleSpamConfig.nullable(),
max_duplicates: zBaseSingleSpamConfig.nullable(),
max_characters: zBaseSingleSpamConfig.nullable(),
max_voice_moves: zBaseSingleSpamConfig.nullable(),
max_censor: zBaseSingleSpamConfig.nullable().default(null),
max_messages: zBaseSingleSpamConfig.nullable().default(null),
max_mentions: zBaseSingleSpamConfig.nullable().default(null),
max_links: zBaseSingleSpamConfig.nullable().default(null),
max_attachments: zBaseSingleSpamConfig.nullable().default(null),
max_emojis: zBaseSingleSpamConfig.nullable().default(null),
max_newlines: zBaseSingleSpamConfig.nullable().default(null),
max_duplicates: zBaseSingleSpamConfig.nullable().default(null),
max_characters: zBaseSingleSpamConfig.nullable().default(null),
max_voice_moves: zBaseSingleSpamConfig.nullable().default(null),
});
export enum RecentActionType {
@ -52,7 +52,7 @@ export interface IRecentAction<T> {
}
export interface SpamPluginType extends BasePluginType {
config: z.infer<typeof zSpamConfig>;
configSchema: typeof zSpamConfig;
state: {
logs: GuildLogs;
archives: GuildArchives;

View file

@ -1,4 +1,4 @@
import { PluginOptions, guildPlugin } from "knub";
import { guildPlugin } from "knub";
import { GuildSavedMessages } from "../../data/GuildSavedMessages.js";
import { GuildStarboardMessages } from "../../data/GuildStarboardMessages.js";
import { GuildStarboardReactions } from "../../data/GuildStarboardReactions.js";
@ -9,13 +9,11 @@ import { StarboardReactionRemoveAllEvt, StarboardReactionRemoveEvt } from "./eve
import { StarboardPluginType, zStarboardConfig } from "./types.js";
import { onMessageDelete } from "./util/onMessageDelete.js";
const defaultOptions: PluginOptions<StarboardPluginType> = {
config: {
can_migrate: false,
boards: {},
},
export const StarboardPlugin = guildPlugin<StarboardPluginType>()({
name: "starboard",
overrides: [
configSchema: zStarboardConfig,
defaultOverrides: [
{
level: ">=100",
config: {
@ -23,13 +21,6 @@ const defaultOptions: PluginOptions<StarboardPluginType> = {
},
},
],
};
export const StarboardPlugin = guildPlugin<StarboardPluginType>()({
name: "starboard",
configParser: (input) => zStarboardConfig.parse(input),
defaultOptions,
// prettier-ignore
messageCommands: [

View file

@ -19,13 +19,12 @@ const zStarboardOpts = z.strictObject({
export type TStarboardOpts = z.infer<typeof zStarboardOpts>;
export const zStarboardConfig = z.strictObject({
boards: zBoundedRecord(z.record(z.string(), zStarboardOpts), 0, 100),
can_migrate: z.boolean(),
boards: zBoundedRecord(z.record(z.string(), zStarboardOpts), 0, 100).default({}),
can_migrate: z.boolean().default(false),
});
export interface StarboardPluginType extends BasePluginType {
config: z.infer<typeof zStarboardConfig>;
configSchema: typeof zStarboardConfig;
state: {
savedMessages: GuildSavedMessages;
starboardMessages: GuildStarboardMessages;

View file

@ -1,5 +1,5 @@
import { Snowflake } from "discord.js";
import { PluginOptions, guildPlugin } from "knub";
import { guildPlugin } from "knub";
import moment from "moment-timezone";
import { GuildArchives } from "../../data/GuildArchives.js";
import { GuildLogs } from "../../data/GuildLogs.js";
@ -22,25 +22,12 @@ import { onMessageCreate } from "./util/onMessageCreate.js";
import { onMessageDelete } from "./util/onMessageDelete.js";
import { renderTagBody } from "./util/renderTagBody.js";
const defaultOptions: PluginOptions<TagsPluginType> = {
config: {
prefix: "!!",
delete_with_command: true,
export const TagsPlugin = guildPlugin<TagsPluginType>()({
name: "tags",
user_tag_cooldown: null,
global_tag_cooldown: null,
user_cooldown: null,
allow_mentions: false,
global_cooldown: null,
auto_delete_command: false,
categories: {},
can_create: false,
can_use: false,
can_list: false,
},
overrides: [
dependencies: () => [LogsPlugin],
configSchema: zTagsConfig,
defaultOverrides: [
{
level: ">=50",
config: {
@ -50,13 +37,6 @@ const defaultOptions: PluginOptions<TagsPluginType> = {
},
},
],
};
export const TagsPlugin = guildPlugin<TagsPluginType>()({
name: "tags",
dependencies: () => [LogsPlugin],
defaultOptions,
// prettier-ignore
messageCommands: [
@ -79,8 +59,6 @@ export const TagsPlugin = guildPlugin<TagsPluginType>()({
};
},
configParser: (input) => zTagsConfig.parse(input),
beforeLoad(pluginData) {
const { state, guild } = pluginData;

View file

@ -33,28 +33,28 @@ export type TTagCategory = z.infer<typeof zTagCategory>;
export const zTagsConfig = z
.strictObject({
prefix: z.string(),
delete_with_command: z.boolean(),
prefix: z.string().default("!!"),
delete_with_command: z.boolean().default(true),
user_tag_cooldown: z.union([z.string(), z.number()]).nullable(), // Per user, per tag
global_tag_cooldown: z.union([z.string(), z.number()]).nullable(), // Any user, per tag
user_cooldown: z.union([z.string(), z.number()]).nullable(), // Per user
allow_mentions: z.boolean(), // Per user
global_cooldown: z.union([z.string(), z.number()]).nullable(), // Any tag use
auto_delete_command: z.boolean(), // Any tag
user_tag_cooldown: z.union([z.string(), z.number()]).nullable().default(null), // Per user, per tag
global_tag_cooldown: z.union([z.string(), z.number()]).nullable().default(null), // Any user, per tag
user_cooldown: z.union([z.string(), z.number()]).nullable().default(null), // Per user
allow_mentions: z.boolean().default(false), // Per user
global_cooldown: z.union([z.string(), z.number()]).nullable().default(null), // Any tag use
auto_delete_command: z.boolean().default(false), // Any tag
categories: z.record(z.string(), zTagCategory),
categories: z.record(z.string(), zTagCategory).default({}),
can_create: z.boolean(),
can_use: z.boolean(),
can_list: z.boolean(),
can_create: z.boolean().default(false),
can_use: z.boolean().default(false),
can_list: z.boolean().default(false),
})
.refine((parsed) => !(parsed.auto_delete_command && parsed.delete_with_command), {
message: "Cannot have both (category specific) delete_with_command and auto_delete_command enabled",
});
export interface TagsPluginType extends BasePluginType {
config: z.infer<typeof zTagsConfig>;
configSchema: typeof zTagsConfig;
state: {
archives: GuildArchives;
tags: GuildTags;

View file

@ -13,14 +13,11 @@ import { inGuildTz } from "./functions/inGuildTz.js";
import { inMemberTz } from "./functions/inMemberTz.js";
import { TimeAndDatePluginType, zTimeAndDateConfig } from "./types.js";
const defaultOptions: PluginOptions<TimeAndDatePluginType> = {
config: {
timezone: "Etc/UTC",
can_set_timezone: false,
date_formats: defaultDateFormats,
},
export const TimeAndDatePlugin = guildPlugin<TimeAndDatePluginType>()({
name: "time_and_date",
overrides: [
configSchema: zTimeAndDateConfig,
defaultOverrides: [
{
level: ">=50",
config: {
@ -28,13 +25,6 @@ const defaultOptions: PluginOptions<TimeAndDatePluginType> = {
},
},
],
};
export const TimeAndDatePlugin = guildPlugin<TimeAndDatePluginType>()({
name: "time_and_date",
configParser: (input) => zTimeAndDateConfig.parse(input),
defaultOptions,
// prettier-ignore
messageCommands: [

View file

@ -10,13 +10,13 @@ import { defaultDateFormats } from "./defaultDateFormats.js";
const zDateFormatKeys = z.enum(keys(defaultDateFormats) as U.ListOf<keyof typeof defaultDateFormats>);
export const zTimeAndDateConfig = z.strictObject({
timezone: zValidTimezone(z.string()),
date_formats: z.record(zDateFormatKeys, z.string()).nullable(),
can_set_timezone: z.boolean(),
timezone: zValidTimezone(z.string()).default("Etc/UTC"),
date_formats: z.record(zDateFormatKeys, z.string()).nullable().default(defaultDateFormats),
can_set_timezone: z.boolean().default(false),
});
export interface TimeAndDatePluginType extends BasePluginType {
config: z.infer<typeof zTimeAndDateConfig>;
configSchema: typeof zTimeAndDateConfig;
state: {
memberTimezones: GuildMemberTimezones;
common: pluginUtils.PluginPublicInterface<typeof CommonPlugin>;

View file

@ -7,7 +7,7 @@ import { UsernameSaverPluginType, zUsernameSaverConfig } from "./types.js";
export const UsernameSaverPlugin = guildPlugin<UsernameSaverPluginType>()({
name: "username_saver",
configParser: (input) => zUsernameSaverConfig.parse(input),
configSchema: zUsernameSaverConfig,
// prettier-ignore
events: [

View file

@ -6,7 +6,7 @@ import { UsernameHistory } from "../../data/UsernameHistory.js";
export const zUsernameSaverConfig = z.strictObject({});
export interface UsernameSaverPluginType extends BasePluginType {
config: z.infer<typeof zUsernameSaverConfig>;
configSchema: typeof zUsernameSaverConfig;
state: {
usernameHistory: UsernameHistory;
updateQueue: Queue;

View file

@ -1,5 +1,5 @@
import { Snowflake } from "discord.js";
import { PluginOptions, guildPlugin } from "knub";
import { guildPlugin } from "knub";
import { GuildArchives } from "../../data/GuildArchives.js";
import { GuildCases } from "../../data/GuildCases.js";
import { GuildLogs } from "../../data/GuildLogs.js";
@ -38,45 +38,21 @@ import { UserInfoCmd } from "./commands/UserInfoCmd.js";
import { VcdisconnectCmd } from "./commands/VcdisconnectCmd.js";
import { VcmoveAllCmd, VcmoveCmd } from "./commands/VcmoveCmd.js";
import { AutoJoinThreadEvt, AutoJoinThreadSyncEvt } from "./events/AutoJoinThreadEvt.js";
import { cleanMessages } from "./functions/cleanMessages.js";
import { fetchChannelMessagesToClean } from "./functions/fetchChannelMessagesToClean.js";
import { getUserInfoEmbed } from "./functions/getUserInfoEmbed.js";
import { hasPermission } from "./functions/hasPermission.js";
import { activeReloads } from "./guildReloads.js";
import { refreshMembersIfNeeded } from "./refreshMembers.js";
import { UtilityPluginType, zUtilityConfig } from "./types.js";
import { cleanMessages } from "./functions/cleanMessages.js";
import { fetchChannelMessagesToClean } from "./functions/fetchChannelMessagesToClean.js";
const defaultOptions: PluginOptions<UtilityPluginType> = {
config: {
can_roles: false,
can_level: false,
can_search: false,
can_clean: false,
can_info: false,
can_server: false,
can_inviteinfo: false,
can_channelinfo: false,
can_messageinfo: false,
can_userinfo: false,
can_roleinfo: false,
can_emojiinfo: false,
can_snowflake: false,
can_reload_guild: false,
can_nickname: false,
can_ping: false,
can_source: false,
can_vcmove: false,
can_vckick: false,
can_help: false,
can_about: false,
can_context: false,
can_jumbo: false,
jumbo_size: 128,
can_avatar: false,
info_on_single_result: true,
autojoin_threads: true,
},
overrides: [
export const UtilityPlugin = guildPlugin<UtilityPluginType>()({
name: "utility",
dependencies: () => [TimeAndDatePlugin, ModActionsPlugin, LogsPlugin],
configSchema: zUtilityConfig,
defaultOverrides: [
{
level: ">=50",
config: {
@ -112,14 +88,6 @@ const defaultOptions: PluginOptions<UtilityPluginType> = {
},
},
],
};
export const UtilityPlugin = guildPlugin<UtilityPluginType>()({
name: "utility",
dependencies: () => [TimeAndDatePlugin, ModActionsPlugin, LogsPlugin],
configParser: (input) => zUtilityConfig.parse(input),
defaultOptions,
// prettier-ignore
messageCommands: [

View file

@ -9,37 +9,37 @@ import { Supporters } from "../../data/Supporters.js";
import { CommonPlugin } from "../Common/CommonPlugin.js";
export const zUtilityConfig = z.strictObject({
can_roles: z.boolean(),
can_level: z.boolean(),
can_search: z.boolean(),
can_clean: z.boolean(),
can_info: z.boolean(),
can_server: z.boolean(),
can_inviteinfo: z.boolean(),
can_channelinfo: z.boolean(),
can_messageinfo: z.boolean(),
can_userinfo: z.boolean(),
can_roleinfo: z.boolean(),
can_emojiinfo: z.boolean(),
can_snowflake: z.boolean(),
can_reload_guild: z.boolean(),
can_nickname: z.boolean(),
can_ping: z.boolean(),
can_source: z.boolean(),
can_vcmove: z.boolean(),
can_vckick: z.boolean(),
can_help: z.boolean(),
can_about: z.boolean(),
can_context: z.boolean(),
can_jumbo: z.boolean(),
jumbo_size: z.number(),
can_avatar: z.boolean(),
info_on_single_result: z.boolean(),
autojoin_threads: z.boolean(),
can_roles: z.boolean().default(false),
can_level: z.boolean().default(false),
can_search: z.boolean().default(false),
can_clean: z.boolean().default(false),
can_info: z.boolean().default(false),
can_server: z.boolean().default(false),
can_inviteinfo: z.boolean().default(false),
can_channelinfo: z.boolean().default(false),
can_messageinfo: z.boolean().default(false),
can_userinfo: z.boolean().default(false),
can_roleinfo: z.boolean().default(false),
can_emojiinfo: z.boolean().default(false),
can_snowflake: z.boolean().default(false),
can_reload_guild: z.boolean().default(false),
can_nickname: z.boolean().default(false),
can_ping: z.boolean().default(false),
can_source: z.boolean().default(false),
can_vcmove: z.boolean().default(false),
can_vckick: z.boolean().default(false),
can_help: z.boolean().default(false),
can_about: z.boolean().default(false),
can_context: z.boolean().default(false),
can_jumbo: z.boolean().default(false),
jumbo_size: z.number().default(128),
can_avatar: z.boolean().default(false),
info_on_single_result: z.boolean().default(true),
autojoin_threads: z.boolean().default(true),
});
export interface UtilityPluginType extends BasePluginType {
config: z.infer<typeof zUtilityConfig>;
configSchema: typeof zUtilityConfig;
state: {
logs: GuildLogs;
cases: GuildCases;

View file

@ -4,20 +4,11 @@ import { LogsPlugin } from "../Logs/LogsPlugin.js";
import { SendWelcomeMessageEvt } from "./events/SendWelcomeMessageEvt.js";
import { WelcomeMessagePluginType, zWelcomeMessageConfig } from "./types.js";
const defaultOptions: PluginOptions<WelcomeMessagePluginType> = {
config: {
send_dm: false,
send_to_channel: null,
message: null,
},
};
export const WelcomeMessagePlugin = guildPlugin<WelcomeMessagePluginType>()({
name: "welcome_message",
dependencies: () => [LogsPlugin],
configParser: (input) => zWelcomeMessageConfig.parse(input),
defaultOptions,
configSchema: zWelcomeMessageConfig,
// prettier-ignore
events: [

View file

@ -3,13 +3,13 @@ import z from "zod/v4";
import { GuildLogs } from "../../data/GuildLogs.js";
export const zWelcomeMessageConfig = z.strictObject({
send_dm: z.boolean(),
send_to_channel: z.string().nullable(),
message: z.string().nullable(),
send_dm: z.boolean().default(false),
send_to_channel: z.string().nullable().default(null),
message: z.string().nullable().default(null),
});
export interface WelcomeMessagePluginType extends BasePluginType {
config: z.infer<typeof zWelcomeMessageConfig>;
configSchema: typeof zWelcomeMessageConfig;
state: {
logs: GuildLogs;
sentWelcomeMessages: Set<string>;

8
package-lock.json generated
View file

@ -43,7 +43,7 @@
"fp-ts": "^2.0.1",
"humanize-duration": "^3.15.0",
"js-yaml": "^4.1.0",
"knub": "^32.0.0-next.23",
"knub": "^32.0.0-next.25",
"knub-command-manager": "^9.1.0",
"last-commit-log": "^2.1.0",
"lodash-es": "^4.17.21",
@ -12806,9 +12806,9 @@
}
},
"node_modules/knub": {
"version": "32.0.0-next.23",
"resolved": "https://registry.npmjs.org/knub/-/knub-32.0.0-next.23.tgz",
"integrity": "sha512-kDv6QhE5ALL9bew0GJtzFh2HpyOECCZ6gGBnZNcKUekxWh3LdKW2nYuo1kfqTycEM/5zn7uiHTGLVxfea9LNxA==",
"version": "32.0.0-next.25",
"resolved": "https://registry.npmjs.org/knub/-/knub-32.0.0-next.25.tgz",
"integrity": "sha512-5ki+0f3PD7v3mRH2ew4RIy1aXMXvUUqPGyikUjCBR8/5EF277/GNwqxC8pA5CDJi8/e29UeGyx/mqHKBvGoTXw==",
"license": "MIT",
"dependencies": {
"discord-api-types": "^0.38.8",