diff --git a/backend/package-lock.json b/backend/package-lock.json index 5f4b23e8..313aa2d0 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -2962,21 +2962,27 @@ } }, "knub": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/knub/-/knub-29.0.0.tgz", - "integrity": "sha512-jnWG/wuh2PogBDwwrYKGw0rI29quk0NEsC/inoOi0l5YbtzoIpK6Qj9BsZf/vjgtIeTemiJySlQZ7HeailYexQ==", + "version": "30.0.0-beta.2", + "resolved": "https://registry.npmjs.org/knub/-/knub-30.0.0-beta.2.tgz", + "integrity": "sha512-t4zQifhGfzD34ZMfjEzEVwLMD6lxySoKIocnfY9UAYSJrjLZyAMIkFlm0Y537CZjzm67VNy5FZfiQi9u1NMgIQ==", "requires": { - "escape-string-regexp": "^2.0.0", - "knub-command-manager": "^7.0.0", - "lodash.clonedeep": "^4.5.0", + "knub-command-manager": "^8.1.0", "reflect-metadata": "^0.1.13", - "ts-essentials": "^2.0.12" + "ts-essentials": "^6.0.7" }, "dependencies": { "escape-string-regexp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" + }, + "knub-command-manager": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/knub-command-manager/-/knub-command-manager-8.1.0.tgz", + "integrity": "sha512-kIQhEGgMtrCIoc8GrkUUJV4yKmbtC0MDpx/dqXi8cNQ8gTlDlQj8+PkM5NnzDkNvrX7cw2/Te10auD7jne3vsQ==", + "requires": { + "escape-string-regexp": "^2.0.0" + } } } }, @@ -4908,9 +4914,9 @@ "dev": true }, "ts-essentials": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-2.0.12.tgz", - "integrity": "sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==" + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-6.0.7.tgz", + "integrity": "sha512-2E4HIIj4tQJlIHuATRHayv0EfMGK3ris/GRk1E3CFnsZzeNV+hUmelbaTZHLtXaZppM5oLhHRtO04gINC4Jusw==" }, "tsc-watch": { "version": "4.0.0", diff --git a/backend/package.json b/backend/package.json index 17132b74..6328719f 100644 --- a/backend/package.json +++ b/backend/package.json @@ -34,7 +34,7 @@ "humanize-duration": "^3.15.0", "io-ts": "^2.0.0", "js-yaml": "^3.13.1", - "knub": "^29.0.0", + "knub": "^30.0.0-beta.2", "knub-command-manager": "^7.0.0", "last-commit-log": "^2.1.0", "lodash.chunk": "^4.2.0", diff --git a/backend/src/api/docs.ts b/backend/src/api/docs.ts index ab1161e0..40f3cbb8 100644 --- a/backend/src/api/docs.ts +++ b/backend/src/api/docs.ts @@ -1,6 +1,6 @@ import express from "express"; import { availablePlugins } from "../plugins/availablePlugins"; -import { ZeppelinPlugin } from "../plugins/ZeppelinPlugin"; +import { ZeppelinPluginClass } from "../plugins/ZeppelinPluginClass"; import { notFound } from "./responses"; import { dropPropertiesByName, indentLines } from "../utils"; import { IPluginCommandConfig, Plugin, pluginUtils } from "knub"; @@ -75,7 +75,7 @@ export function initDocs(app: express.Express) { }; }); - const defaultOptions = (pluginClass as typeof ZeppelinPlugin).getStaticDefaultOptions(); + const defaultOptions = (pluginClass as typeof ZeppelinPluginClass).getStaticDefaultOptions(); const configSchema = pluginClass.configSchema && formatConfigSchema(pluginClass.configSchema); diff --git a/backend/src/configValidator.ts b/backend/src/configValidator.ts index d83a9b4d..b5b2610c 100644 --- a/backend/src/configValidator.ts +++ b/backend/src/configValidator.ts @@ -4,10 +4,10 @@ import { pipe } from "fp-ts/lib/pipeable"; import { fold } from "fp-ts/lib/Either"; import { PathReporter } from "io-ts/lib/PathReporter"; import { availablePlugins } from "./plugins/availablePlugins"; -import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./plugins/ZeppelinPluginClass"; import { decodeAndValidateStrict, StrictValidationError } from "./validatorUtils"; -const pluginNameToClass = new Map(); +const pluginNameToClass = new Map(); for (const pluginClass of availablePlugins) { // @ts-ignore pluginNameToClass.set(pluginClass.pluginName, pluginClass); diff --git a/backend/src/index.ts b/backend/src/index.ts index 45bba7f7..1794ea69 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -77,10 +77,10 @@ for (const [i, part] of actualVersionParts.entries()) { import moment from "moment-timezone"; moment.tz.setDefault("UTC"); -import { Client, TextableChannel, TextChannel } from "eris"; +import { Client, TextChannel } from "eris"; import { connect } from "./data/db"; import { availablePlugins, availableGlobalPlugins, basePlugins } from "./plugins/availablePlugins"; -import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./plugins/ZeppelinPluginClass"; import { customArgumentTypes } from "./customArgumentTypes"; import { errorMessage, isDiscordHTTPError, isDiscordRESTError, successMessage } from "./utils"; import { startUptimeCounter } from "./uptime"; @@ -91,7 +91,7 @@ import { GuildLogs } from "./data/GuildLogs"; import { LogType } from "./data/LogType"; logger.info("Connecting to database"); -connect().then(async conn => { +connect().then(async () => { const client = new Client(`Bot ${process.env.TOKEN}`, { getAllUsers: false, restMode: true, @@ -108,7 +108,7 @@ connect().then(async conn => { const guildConfigs = new Configs(); const bot = new Knub(client, { - plugins: availablePlugins, + guildPlugins: availablePlugins, globalPlugins: availableGlobalPlugins, options: { @@ -126,9 +126,9 @@ connect().then(async conn => { const configuredPlugins = guildConfig.plugins || {}; const pluginNames: string[] = Array.from(this.plugins.keys()); const plugins: Array = Array.from(this.plugins.values()); - const zeppelinPlugins: Array = plugins.filter( - p => p.prototype instanceof ZeppelinPlugin, - ) as Array; + const zeppelinPlugins: Array = plugins.filter( + p => p.prototype instanceof ZeppelinPluginClass, + ) as Array; const enabledBasePlugins = pluginNames.filter(n => basePlugins.includes(n)); const explicitlyEnabledPlugins = pluginNames.filter(pluginName => { @@ -176,13 +176,13 @@ connect().then(async conn => { sendSuccessMessageFn(channel, body) { const guildId = channel instanceof TextChannel ? channel.guild.id : undefined; - const emoji = guildId ? bot.getGuildData(guildId).config.success_emoji : undefined; + const emoji = guildId ? bot.getLoadedGuild(guildId).config.success_emoji : undefined; channel.createMessage(successMessage(body, emoji)); }, sendErrorMessageFn(channel, body) { const guildId = channel instanceof TextChannel ? channel.guild.id : undefined; - const emoji = guildId ? bot.getGuildData(guildId).config.error_emoji : undefined; + const emoji = guildId ? bot.getLoadedGuild(guildId).config.error_emoji : undefined; channel.createMessage(errorMessage(body, emoji)); }, }, diff --git a/backend/src/plugins/AntiRaid.ts b/backend/src/plugins/AntiRaid.ts index 7413b2e2..999c3c0d 100644 --- a/backend/src/plugins/AntiRaid.ts +++ b/backend/src/plugins/AntiRaid.ts @@ -1,6 +1,6 @@ import { IPluginOptions, logger } from "knub"; import * as t from "io-ts"; -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { SavedMessage } from "../data/entities/SavedMessage"; import { convertDelayStringToMS, MINUTES, sorter, stripObjectToScalars, tDelayString } from "../utils"; @@ -28,7 +28,7 @@ interface IDeletionQueueItem { const MAX_DELAY = 5 * MINUTES; -export class AntiRaid extends ZeppelinPlugin { +export class AntiRaid extends ZeppelinPluginClass { public static pluginName = "auto_delete"; public static showInDocs = true; diff --git a/backend/src/plugins/AutoDelete.ts b/backend/src/plugins/AutoDelete.ts index a83cbe31..608313c2 100644 --- a/backend/src/plugins/AutoDelete.ts +++ b/backend/src/plugins/AutoDelete.ts @@ -1,6 +1,6 @@ import { IPluginOptions, logger } from "knub"; import * as t from "io-ts"; -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { SavedMessage } from "../data/entities/SavedMessage"; import { convertDelayStringToMS, MINUTES, sorter, stripObjectToScalars, tDelayString } from "../utils"; @@ -21,7 +21,7 @@ interface IDeletionQueueItem { const MAX_DELAY = 5 * MINUTES; -export class AutoDeletePlugin extends ZeppelinPlugin { +export class AutoDeletePlugin extends ZeppelinPluginClass { public static pluginName = "auto_delete"; public static showInDocs = true; diff --git a/backend/src/plugins/AutoReactionsPlugin.ts b/backend/src/plugins/AutoReactionsPlugin.ts index 231a7cbc..c46f6386 100644 --- a/backend/src/plugins/AutoReactionsPlugin.ts +++ b/backend/src/plugins/AutoReactionsPlugin.ts @@ -4,7 +4,7 @@ import { SavedMessage } from "../data/entities/SavedMessage"; import { GuildAutoReactions } from "../data/GuildAutoReactions"; import { Message } from "eris"; import { customEmojiRegex, errorMessage, isDiscordRESTError, isEmoji } from "../utils"; -import { CommandInfo, trimPluginDescription, ZeppelinPlugin } from "./ZeppelinPlugin"; +import { CommandInfo, trimPluginDescription, ZeppelinPluginClass } from "./ZeppelinPluginClass"; import * as t from "io-ts"; import { GuildLogs } from "../data/GuildLogs"; import { LogType } from "../data/LogType"; @@ -14,7 +14,7 @@ const ConfigSchema = t.type({ }); type TConfigSchema = t.TypeOf; -export class AutoReactionsPlugin extends ZeppelinPlugin { +export class AutoReactionsPlugin extends ZeppelinPluginClass { public static pluginName = "auto_reactions"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/Automod/Automod.ts b/backend/src/plugins/Automod/Automod.ts index 74cf4ece..d68ad525 100644 --- a/backend/src/plugins/Automod/Automod.ts +++ b/backend/src/plugins/Automod/Automod.ts @@ -1,4 +1,4 @@ -import { trimPluginDescription, ZeppelinPlugin } from "../ZeppelinPlugin"; +import { trimPluginDescription, ZeppelinPluginClass } from "../ZeppelinPluginClass"; import * as t from "io-ts"; import { convertDelayStringToMS, @@ -209,7 +209,7 @@ const RAID_SPAM_IDENTIFIER = "raid"; * call addRecentAction() directly. These are then checked by matchRuleToMessage() and matchOtherSpamInRule() to detect * spam. */ -export class AutomodPlugin extends ZeppelinPlugin { +export class AutomodPlugin extends ZeppelinPluginClass { public static pluginName = "automod"; public static configSchema = ConfigSchema; public static dependencies = ["mod_actions", "mutes", "logs"]; diff --git a/backend/src/plugins/Automod/info.ts b/backend/src/plugins/Automod/info.ts index fde24740..e8bd4b66 100644 --- a/backend/src/plugins/Automod/info.ts +++ b/backend/src/plugins/Automod/info.ts @@ -1,4 +1,4 @@ -import { PluginInfo, trimPluginDescription } from "../ZeppelinPlugin"; +import { PluginInfo, trimPluginDescription } from "../ZeppelinPluginClass"; export const pluginInfo: PluginInfo = { prettyName: "Automod", diff --git a/backend/src/plugins/BotControl.ts b/backend/src/plugins/BotControl.ts index 1cb5f85a..44a82d87 100644 --- a/backend/src/plugins/BotControl.ts +++ b/backend/src/plugins/BotControl.ts @@ -4,7 +4,7 @@ import { GuildChannel, Message, TextChannel } from "eris"; import moment from "moment-timezone"; import { createChunkedMessage, errorMessage, noop, sorter, successMessage, tNullable } from "../utils"; import { ReactionRolesPlugin } from "./ReactionRoles"; -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { GuildArchives } from "../data/GuildArchives"; import { GlobalZeppelinPlugin } from "./GlobalZeppelinPlugin"; import * as t from "io-ts"; @@ -222,7 +222,7 @@ export class BotControlPlugin extends GlobalZeppelinPlugin { return; } - if (!(pluginInstance instanceof ZeppelinPlugin)) { + if (!(pluginInstance instanceof ZeppelinPluginClass)) { msg.channel.createMessage(errorMessage(`Plugin is not a Zeppelin plugin`)); return; } diff --git a/backend/src/plugins/Cases.ts b/backend/src/plugins/Cases.ts index 98e30c7c..2d9851a4 100644 --- a/backend/src/plugins/Cases.ts +++ b/backend/src/plugins/Cases.ts @@ -4,7 +4,7 @@ import { CaseTypes } from "../data/CaseTypes"; import { Case } from "../data/entities/Case"; import moment from "moment-timezone"; import { CaseTypeColors } from "../data/CaseTypeColors"; -import { PluginInfo, trimPluginDescription, ZeppelinPlugin } from "./ZeppelinPlugin"; +import { PluginInfo, trimPluginDescription, ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { GuildArchives } from "../data/GuildArchives"; import { IPluginOptions, logger } from "knub"; import { GuildLogs } from "../data/GuildLogs"; @@ -44,7 +44,7 @@ export type CaseNoteArgs = { noteDetails?: string[]; }; -export class CasesPlugin extends ZeppelinPlugin { +export class CasesPlugin extends ZeppelinPluginClass { public static pluginName = "cases"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/Censor.ts b/backend/src/plugins/Censor.ts index cafd952d..551571cc 100644 --- a/backend/src/plugins/Censor.ts +++ b/backend/src/plugins/Censor.ts @@ -14,7 +14,7 @@ import { import { ZalgoRegex } from "../data/Zalgo"; import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { SavedMessage } from "../data/entities/SavedMessage"; -import { trimPluginDescription, ZeppelinPlugin } from "./ZeppelinPlugin"; +import { trimPluginDescription, ZeppelinPluginClass } from "./ZeppelinPluginClass"; import cloneDeep from "lodash.clonedeep"; import * as t from "io-ts"; import { TSafeRegex } from "../validatorUtils"; @@ -36,7 +36,7 @@ const ConfigSchema = t.type({ }); type TConfigSchema = t.TypeOf; -export class CensorPlugin extends ZeppelinPlugin { +export class CensorPlugin extends ZeppelinPluginClass { public static pluginName = "censor"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/ChannelArchiver.ts b/backend/src/plugins/ChannelArchiver.ts index f909ff37..cf2bc961 100644 --- a/backend/src/plugins/ChannelArchiver.ts +++ b/backend/src/plugins/ChannelArchiver.ts @@ -2,7 +2,7 @@ import { decorators as d, ICommandContext, logger } from "knub"; import { GlobalZeppelinPlugin } from "./GlobalZeppelinPlugin"; import { Attachment, GuildChannel, Message, TextChannel } from "eris"; import { confirm, downloadFile, errorMessage, noop, SECONDS, trimLines } from "../utils"; -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import moment from "moment-timezone"; import https from "https"; import fs from "fs"; @@ -13,7 +13,7 @@ const MAX_MESSAGES_PER_FETCH = 100; const PROGRESS_UPDATE_INTERVAL = 5 * SECONDS; const MAX_ATTACHMENT_REHOST_SIZE = 1024 * 1024 * 8; -export class ChannelArchiverPlugin extends ZeppelinPlugin { +export class ChannelArchiverPlugin extends ZeppelinPluginClass { public static pluginName = "channel_archiver"; public static showInDocs = false; diff --git a/backend/src/plugins/CompanionChannels.ts b/backend/src/plugins/CompanionChannels.ts index fc371d54..d09bcb3e 100644 --- a/backend/src/plugins/CompanionChannels.ts +++ b/backend/src/plugins/CompanionChannels.ts @@ -1,5 +1,5 @@ import { decorators as d, IPluginOptions, logger } from "knub"; -import { trimPluginDescription, ZeppelinPlugin } from "./ZeppelinPlugin"; +import { trimPluginDescription, ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { Member, Channel, GuildChannel, PermissionOverwrite, Permission, Message, TextChannel } from "eris"; import * as t from "io-ts"; import { tNullable } from "../utils"; @@ -26,7 +26,7 @@ const defaultCompanionChannelOpts: Partial = { enabled: true, }; -export class CompanionChannelPlugin extends ZeppelinPlugin { +export class CompanionChannelPlugin extends ZeppelinPluginClass { public static pluginName = "companion_channels"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/CustomEvents.ts b/backend/src/plugins/CustomEvents.ts index 84e82bec..849465cc 100644 --- a/backend/src/plugins/CustomEvents.ts +++ b/backend/src/plugins/CustomEvents.ts @@ -1,4 +1,4 @@ -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { IPluginOptions } from "knub"; import { Message, TextChannel, VoiceChannel } from "eris"; import { renderTemplate } from "../templateFormatter"; @@ -68,7 +68,7 @@ type TConfigSchema = t.TypeOf; class ActionError extends Error {} -export class CustomEventsPlugin extends ZeppelinPlugin { +export class CustomEventsPlugin extends ZeppelinPluginClass { public static pluginName = "custom_events"; public static showInDocs = false; public static dependencies = ["cases"]; diff --git a/backend/src/plugins/GuildConfigReloader.ts b/backend/src/plugins/GuildConfigReloader.ts index ed180910..c18a2604 100644 --- a/backend/src/plugins/GuildConfigReloader.ts +++ b/backend/src/plugins/GuildConfigReloader.ts @@ -1,5 +1,5 @@ import moment from "moment-timezone"; -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { Configs } from "../data/Configs"; import { logger } from "knub"; import { GlobalZeppelinPlugin } from "./GlobalZeppelinPlugin"; diff --git a/backend/src/plugins/GuildInfoSaver.ts b/backend/src/plugins/GuildInfoSaver.ts index 2dfd591b..f09ad317 100644 --- a/backend/src/plugins/GuildInfoSaver.ts +++ b/backend/src/plugins/GuildInfoSaver.ts @@ -1,8 +1,8 @@ -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { AllowedGuilds } from "../data/AllowedGuilds"; import { MINUTES } from "../utils"; -export class GuildInfoSaverPlugin extends ZeppelinPlugin { +export class GuildInfoSaverPlugin extends ZeppelinPluginClass { public static pluginName = "guild_info_saver"; public static showInDocs = false; protected allowedGuilds: AllowedGuilds; diff --git a/backend/src/plugins/LocateUser.ts b/backend/src/plugins/LocateUser.ts index 907e070a..d7b5b167 100644 --- a/backend/src/plugins/LocateUser.ts +++ b/backend/src/plugins/LocateUser.ts @@ -1,5 +1,5 @@ import { decorators as d, IPluginOptions, getInviteLink, logger } from "knub"; -import { trimPluginDescription, ZeppelinPlugin, CommandInfo } from "./ZeppelinPlugin"; +import { trimPluginDescription, ZeppelinPluginClass, CommandInfo } from "./ZeppelinPluginClass"; import humanizeDuration from "humanize-duration"; import { Message, Member, Guild, TextableChannel, VoiceChannel, Channel, User } from "eris"; import { GuildVCAlerts } from "../data/GuildVCAlerts"; @@ -15,7 +15,7 @@ type TConfigSchema = t.TypeOf; const ALERT_LOOP_TIME = 30 * SECONDS; -export class LocatePlugin extends ZeppelinPlugin { +export class LocatePlugin extends ZeppelinPluginClass { public static pluginName = "locate_user"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/Logs.ts b/backend/src/plugins/Logs.ts index a8cc8e1a..1530c09d 100644 --- a/backend/src/plugins/Logs.ts +++ b/backend/src/plugins/Logs.ts @@ -24,7 +24,7 @@ import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { SavedMessage } from "../data/entities/SavedMessage"; import { GuildArchives } from "../data/GuildArchives"; import { GuildCases } from "../data/GuildCases"; -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { renderTemplate, TemplateParseError } from "../templateFormatter"; import cloneDeep from "lodash.clonedeep"; import * as t from "io-ts"; @@ -56,7 +56,7 @@ const ConfigSchema = t.type({ }); type TConfigSchema = t.TypeOf; -export class LogsPlugin extends ZeppelinPlugin { +export class LogsPlugin extends ZeppelinPluginClass { public static pluginName = "logs"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/MessageSaver.ts b/backend/src/plugins/MessageSaver.ts index 759172e7..116bbb9d 100644 --- a/backend/src/plugins/MessageSaver.ts +++ b/backend/src/plugins/MessageSaver.ts @@ -2,7 +2,7 @@ import { Plugin, decorators as d, IPluginOptions } from "knub"; import { GuildChannel, Message, TextChannel } from "eris"; import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { successMessage } from "../utils"; -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import * as t from "io-ts"; const ConfigSchema = t.type({ @@ -10,7 +10,7 @@ const ConfigSchema = t.type({ }); type TConfigSchema = t.TypeOf; -export class MessageSaverPlugin extends ZeppelinPlugin { +export class MessageSaverPlugin extends ZeppelinPluginClass { public static pluginName = "message_saver"; public static showInDocs = false; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/ModActions.ts b/backend/src/plugins/ModActions.ts index 5518c396..2ed34337 100644 --- a/backend/src/plugins/ModActions.ts +++ b/backend/src/plugins/ModActions.ts @@ -25,7 +25,7 @@ import { GuildMutes } from "../data/GuildMutes"; import { CaseTypes } from "../data/CaseTypes"; import { GuildLogs } from "../data/GuildLogs"; import { LogType } from "../data/LogType"; -import { trimPluginDescription, ZeppelinPlugin } from "./ZeppelinPlugin"; +import { trimPluginDescription, ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { Case } from "../data/entities/Case"; import { renderTemplate } from "../templateFormatter"; import { CaseArgs, CasesPlugin } from "./Cases"; @@ -125,7 +125,7 @@ export interface BanOptions { deleteMessageDays?: number; } -export class ModActionsPlugin extends ZeppelinPlugin { +export class ModActionsPlugin extends ZeppelinPluginClass { public static pluginName = "mod_actions"; public static dependencies = ["cases", "mutes"]; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/Mutes.ts b/backend/src/plugins/Mutes.ts index a5df9e09..a27fbf3a 100644 --- a/backend/src/plugins/Mutes.ts +++ b/backend/src/plugins/Mutes.ts @@ -1,7 +1,7 @@ import { Member, Message, TextChannel, User } from "eris"; import { GuildCases } from "../data/GuildCases"; import moment from "moment-timezone"; -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { GuildMutes } from "../data/GuildMutes"; import { chunkMessageLines, @@ -75,7 +75,7 @@ const EXPIRED_MUTE_CHECK_INTERVAL = 60 * 1000; let FIRST_CHECK_TIME = Date.now(); const FIRST_CHECK_INCREMENT = 5 * 1000; -export class MutesPlugin extends ZeppelinPlugin { +export class MutesPlugin extends ZeppelinPluginClass { public static pluginName = "mutes"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/NameHistory.ts b/backend/src/plugins/NameHistory.ts index 19ce73f2..d5de4f98 100644 --- a/backend/src/plugins/NameHistory.ts +++ b/backend/src/plugins/NameHistory.ts @@ -2,7 +2,7 @@ import { decorators as d, IPluginOptions } from "knub"; import { GuildNicknameHistory, MAX_NICKNAME_ENTRIES_PER_USER } from "../data/GuildNicknameHistory"; import { Member, Message } from "eris"; import { createChunkedMessage, disableCodeBlocks } from "../utils"; -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { MAX_USERNAME_ENTRIES_PER_USER, UsernameHistory } from "../data/UsernameHistory"; import * as t from "io-ts"; @@ -11,7 +11,7 @@ const ConfigSchema = t.type({ }); type TConfigSchema = t.TypeOf; -export class NameHistoryPlugin extends ZeppelinPlugin { +export class NameHistoryPlugin extends ZeppelinPluginClass { public static pluginName = "name_history"; public static showInDocs = false; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/Persist.ts b/backend/src/plugins/Persist.ts index ba9250eb..9d110215 100644 --- a/backend/src/plugins/Persist.ts +++ b/backend/src/plugins/Persist.ts @@ -5,7 +5,7 @@ import { Member, MemberOptions } from "eris"; import { GuildLogs } from "../data/GuildLogs"; import { LogType } from "../data/LogType"; import { stripObjectToScalars } from "../utils"; -import { trimPluginDescription, ZeppelinPlugin } from "./ZeppelinPlugin"; +import { trimPluginDescription, ZeppelinPluginClass } from "./ZeppelinPluginClass"; import * as t from "io-ts"; const ConfigSchema = t.type({ @@ -15,7 +15,7 @@ const ConfigSchema = t.type({ }); type TConfigSchema = t.TypeOf; -export class PersistPlugin extends ZeppelinPlugin { +export class PersistPlugin extends ZeppelinPluginClass { public static pluginName = "persist"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/PingableRolesPlugin.ts b/backend/src/plugins/PingableRolesPlugin.ts index a0d3bb85..482b34de 100644 --- a/backend/src/plugins/PingableRolesPlugin.ts +++ b/backend/src/plugins/PingableRolesPlugin.ts @@ -3,7 +3,7 @@ import { Message, Role, TextableChannel } from "eris"; import { GuildPingableRoles } from "../data/GuildPingableRoles"; import { PingableRole } from "../data/entities/PingableRole"; import { errorMessage, successMessage } from "../utils"; -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import * as t from "io-ts"; const ConfigSchema = t.type({ @@ -13,7 +13,7 @@ type TConfigSchema = t.TypeOf; const TIMEOUT = 10 * 1000; -export class PingableRolesPlugin extends ZeppelinPlugin { +export class PingableRolesPlugin extends ZeppelinPluginClass { public static pluginName = "pingable_roles"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/Post.ts b/backend/src/plugins/Post.ts index 5263d450..258867ef 100644 --- a/backend/src/plugins/Post.ts +++ b/backend/src/plugins/Post.ts @@ -19,7 +19,7 @@ import { DAYS, } from "../utils"; import { GuildSavedMessages } from "../data/GuildSavedMessages"; -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import fs from "fs"; import { GuildScheduledPosts } from "../data/GuildScheduledPosts"; @@ -45,7 +45,7 @@ const MIN_REPEAT_TIME = 5 * MINUTES; const MAX_REPEAT_TIME = Math.pow(2, 32); const MAX_REPEAT_UNTIL = moment().add(100, "years"); -export class PostPlugin extends ZeppelinPlugin { +export class PostPlugin extends ZeppelinPluginClass { public static pluginName = "post"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/ReactionRoles.ts b/backend/src/plugins/ReactionRoles.ts index 67baeae3..e1c61749 100644 --- a/backend/src/plugins/ReactionRoles.ts +++ b/backend/src/plugins/ReactionRoles.ts @@ -2,7 +2,7 @@ import { decorators as d, IPluginOptions, logger } from "knub"; import { CustomEmoji, errorMessage, isDiscordRESTError, isSnowflake, noop, sleep } from "../utils"; import { GuildReactionRoles } from "../data/GuildReactionRoles"; import { Message, TextChannel } from "eris"; -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { Queue } from "../Queue"; import { ReactionRole } from "../data/entities/ReactionRole"; @@ -42,7 +42,7 @@ type PendingMemberRoleChanges = { }>; }; -export class ReactionRolesPlugin extends ZeppelinPlugin { +export class ReactionRolesPlugin extends ZeppelinPluginClass { public static pluginName = "reaction_roles"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/Reminders.ts b/backend/src/plugins/Reminders.ts index c6d057b8..44fbd614 100644 --- a/backend/src/plugins/Reminders.ts +++ b/backend/src/plugins/Reminders.ts @@ -1,5 +1,5 @@ import { decorators as d, IPluginOptions } from "knub"; -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { GuildReminders } from "../data/GuildReminders"; import { Message, TextChannel } from "eris"; import moment from "moment-timezone"; @@ -22,7 +22,7 @@ type TConfigSchema = t.TypeOf; const REMINDER_LOOP_TIME = 10 * 1000; const MAX_TRIES = 3; -export class RemindersPlugin extends ZeppelinPlugin { +export class RemindersPlugin extends ZeppelinPluginClass { public static pluginName = "reminders"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/Roles.ts b/backend/src/plugins/Roles.ts index 6fc1d601..81ab9312 100644 --- a/backend/src/plugins/Roles.ts +++ b/backend/src/plugins/Roles.ts @@ -1,4 +1,4 @@ -import { trimPluginDescription, ZeppelinPlugin } from "./ZeppelinPlugin"; +import { trimPluginDescription, ZeppelinPluginClass } from "./ZeppelinPluginClass"; import * as t from "io-ts"; import { resolveMember, stripObjectToScalars, successMessage } from "../utils"; import { decorators as d, IPluginOptions, logger } from "knub"; @@ -13,7 +13,7 @@ const ConfigSchema = t.type({ }); type TConfigSchema = t.TypeOf; -export class RolesPlugin extends ZeppelinPlugin { +export class RolesPlugin extends ZeppelinPluginClass { public static pluginName = "roles"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/SelfGrantableRolesPlugin.ts b/backend/src/plugins/SelfGrantableRolesPlugin.ts index 500c9d82..fc34ef91 100644 --- a/backend/src/plugins/SelfGrantableRolesPlugin.ts +++ b/backend/src/plugins/SelfGrantableRolesPlugin.ts @@ -1,7 +1,7 @@ import { decorators as d, IPluginOptions } from "knub"; import { GuildChannel, Message, Role, TextChannel } from "eris"; import { asSingleLine, chunkArray, errorMessage, sorter, successMessage, tDeepPartial, trimLines } from "../utils"; -import { trimPluginDescription, ZeppelinPlugin } from "./ZeppelinPlugin"; +import { trimPluginDescription, ZeppelinPluginClass } from "./ZeppelinPluginClass"; import * as t from "io-ts"; const RoleMap = t.record(t.string, t.array(t.string)); @@ -29,7 +29,7 @@ const defaultSelfGrantableRoleEntry: t.TypeOf = { max_roles: 0, }; -export class SelfGrantableRolesPlugin extends ZeppelinPlugin { +export class SelfGrantableRolesPlugin extends ZeppelinPluginClass { public static pluginName = "self_grantable_roles"; public static showInDocs = true; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/Slowmode.ts b/backend/src/plugins/Slowmode.ts index 27804049..ae059ea5 100644 --- a/backend/src/plugins/Slowmode.ts +++ b/backend/src/plugins/Slowmode.ts @@ -12,7 +12,7 @@ import { } from "../utils"; import { GuildSlowmodes } from "../data/GuildSlowmodes"; import humanizeDuration from "humanize-duration"; -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { SavedMessage } from "../data/entities/SavedMessage"; import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { GuildLogs } from "../data/GuildLogs"; @@ -31,7 +31,7 @@ const NATIVE_SLOWMODE_LIMIT = 6 * 60 * 60; // 6 hours const MAX_SLOWMODE = 60 * 60 * 24 * 365 * 100; // 100 years const BOT_SLOWMODE_CLEAR_INTERVAL = 60 * 1000; -export class SlowmodePlugin extends ZeppelinPlugin { +export class SlowmodePlugin extends ZeppelinPluginClass { public static pluginName = "slowmode"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/Spam.ts b/backend/src/plugins/Spam.ts index 9ff3d11d..19434387 100644 --- a/backend/src/plugins/Spam.ts +++ b/backend/src/plugins/Spam.ts @@ -19,7 +19,7 @@ import moment from "moment-timezone"; import { SavedMessage } from "../data/entities/SavedMessage"; import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { GuildMutes } from "../data/GuildMutes"; -import { trimPluginDescription, ZeppelinPlugin } from "./ZeppelinPlugin"; +import { trimPluginDescription, ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { MuteResult, MutesPlugin } from "./Mutes"; import { CasesPlugin } from "./Cases"; import * as t from "io-ts"; @@ -72,7 +72,7 @@ const MAX_INTERVAL = 300; const SPAM_ARCHIVE_EXPIRY_DAYS = 90; -export class SpamPlugin extends ZeppelinPlugin { +export class SpamPlugin extends ZeppelinPluginClass { public static pluginName = "spam"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/Starboard.ts b/backend/src/plugins/Starboard.ts index 46868206..4302042a 100644 --- a/backend/src/plugins/Starboard.ts +++ b/backend/src/plugins/Starboard.ts @@ -1,5 +1,5 @@ import { decorators as d, IPluginOptions } from "knub"; -import { ZeppelinPlugin, trimPluginDescription } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass, trimPluginDescription } from "./ZeppelinPluginClass"; import { Embed, EmbedBase, GuildChannel, Message, TextChannel } from "eris"; import { errorMessage, @@ -43,7 +43,7 @@ const defaultStarboardOpts: Partial = { enabled: true, }; -export class StarboardPlugin extends ZeppelinPlugin { +export class StarboardPlugin extends ZeppelinPluginClass { public static pluginName = "starboard"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/Stats.ts b/backend/src/plugins/Stats.ts index e3b2a559..93ba7209 100644 --- a/backend/src/plugins/Stats.ts +++ b/backend/src/plugins/Stats.ts @@ -1,4 +1,4 @@ -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import * as t from "io-ts"; import { convertDelayStringToMS, DAYS, HOURS, tAlphanumeric, tDateTime, tDeepPartial, tDelayString } from "../utils"; import { IPluginOptions } from "knub"; @@ -60,7 +60,7 @@ const DEFAULT_RETENTION_PERIOD = "4w"; //endregion //region PLUGIN -export class StatsPlugin extends ZeppelinPlugin { +export class StatsPlugin extends ZeppelinPluginClass { public static pluginName = "stats"; public static configSchema = tConfigSchema; public static showInDocs = false; diff --git a/backend/src/plugins/Tags.ts b/backend/src/plugins/Tags.ts index 73a0e583..b2284940 100644 --- a/backend/src/plugins/Tags.ts +++ b/backend/src/plugins/Tags.ts @@ -15,7 +15,7 @@ import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { SavedMessage } from "../data/entities/SavedMessage"; import moment from "moment-timezone"; import humanizeDuration from "humanize-duration"; -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { parseTemplate, renderTemplate, TemplateParseError } from "../templateFormatter"; import { GuildArchives } from "../data/GuildArchives"; import * as t from "io-ts"; @@ -58,7 +58,7 @@ const ConfigSchema = t.type({ }); type TConfigSchema = t.TypeOf; -export class TagsPlugin extends ZeppelinPlugin { +export class TagsPlugin extends ZeppelinPluginClass { public static pluginName = "tags"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/Utility.ts b/backend/src/plugins/Utility.ts index b2802682..1cdcad6f 100644 --- a/backend/src/plugins/Utility.ts +++ b/backend/src/plugins/Utility.ts @@ -55,7 +55,7 @@ import { CaseTypes } from "../data/CaseTypes"; import { SavedMessage } from "../data/entities/SavedMessage"; import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { GuildArchives } from "../data/GuildArchives"; -import { CommandInfo, trimPluginDescription, ZeppelinPlugin } from "./ZeppelinPlugin"; +import { CommandInfo, trimPluginDescription, ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { getCurrentUptime } from "../uptime"; import LCL from "last-commit-log"; import * as t from "io-ts"; @@ -125,7 +125,7 @@ type MemberSearchParams = { class SearchError extends Error {} -export class UtilityPlugin extends ZeppelinPlugin { +export class UtilityPlugin extends ZeppelinPluginClass { public static pluginName = "utility"; public static configSchema = ConfigSchema; @@ -1377,13 +1377,13 @@ export class UtilityPlugin extends ZeppelinPlugin { const searchStr = args.command.toLowerCase(); const matchingCommands: Array<{ - plugin: ZeppelinPlugin; + plugin: ZeppelinPluginClass; command: ICommandDefinition; }> = []; const guildData = this.knub.getGuildData(this.guildId); for (const plugin of guildData.loadedPlugins.values()) { - if (!(plugin instanceof ZeppelinPlugin)) continue; + if (!(plugin instanceof ZeppelinPluginClass)) continue; const registeredCommands = plugin.getRegisteredCommands(); for (const registeredCommand of registeredCommands) { diff --git a/backend/src/plugins/WelcomeMessage.ts b/backend/src/plugins/WelcomeMessage.ts index f1f53735..20189a81 100644 --- a/backend/src/plugins/WelcomeMessage.ts +++ b/backend/src/plugins/WelcomeMessage.ts @@ -1,4 +1,4 @@ -import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { ZeppelinPluginClass } from "./ZeppelinPluginClass"; import { decorators as d, IPluginOptions } from "knub"; import { Member, TextChannel } from "eris"; import { renderTemplate } from "../templateFormatter"; @@ -14,7 +14,7 @@ const ConfigSchema = t.type({ }); type TConfigSchema = t.TypeOf; -export class WelcomeMessagePlugin extends ZeppelinPlugin { +export class WelcomeMessagePlugin extends ZeppelinPluginClass { public static pluginName = "welcome_message"; public static configSchema = ConfigSchema; diff --git a/backend/src/plugins/ZeppelinPlugin.ts b/backend/src/plugins/ZeppelinPluginClass.ts similarity index 84% rename from backend/src/plugins/ZeppelinPlugin.ts rename to backend/src/plugins/ZeppelinPluginClass.ts index e2e46e9b..c6447173 100644 --- a/backend/src/plugins/ZeppelinPlugin.ts +++ b/backend/src/plugins/ZeppelinPluginClass.ts @@ -1,4 +1,4 @@ -import { configUtils, IBasePluginConfig, IPluginOptions, logger, Plugin } from "knub"; +import { BasePluginType, configUtils, logger, PluginClass, PluginOptions, BasePluginConfig } from "knub"; import * as t from "io-ts"; import { deepKeyIntersect, @@ -59,10 +59,7 @@ export function trimPluginDescription(str) { const inviteCache = new SimpleCache>(10 * MINUTES, 200); -export class ZeppelinPlugin< - TConfig extends {} = IBasePluginConfig, - TCustomOverrideCriteria extends {} = {} -> extends Plugin { +export class ZeppelinPluginClass extends PluginClass { public static pluginInfo: PluginInfo; public static showInDocs: boolean = true; @@ -76,7 +73,7 @@ export class ZeppelinPlugin< } protected canActOn(member1: Member, member2: Member, allowSameLevel = false) { - if (member2.id === this.bot.user.id) { + if (member2.id === this.client.user.id) { return false; } @@ -98,11 +95,8 @@ export class ZeppelinPlugin< /** * Wrapper to fetch the real default options from getStaticDefaultOptions() */ - protected getDefaultOptions(): IPluginOptions { - return (this.constructor as typeof ZeppelinPlugin).getStaticDefaultOptions() as IPluginOptions< - TConfig, - TCustomOverrideCriteria - >; + protected getDefaultOptions(): PluginOptions { + return (this.constructor as typeof ZeppelinPluginClass).getStaticDefaultOptions() as PluginOptions; } /** @@ -123,7 +117,7 @@ export class ZeppelinPlugin< * Like getStaticDefaultOptions(), we also want to use this function for type checking without creating an instance of * the plugin, which is why this has to be a static function. */ - protected static mergeAndDecodeStaticOptions(options: any): IPluginOptions { + protected static mergeAndDecodeStaticOptions(options: any): PluginOptions { const defaultOptions: any = this.getStaticDefaultOptions(); let mergedConfig = configUtils.mergeConfig({}, defaultOptions.config || {}, options.config || {}); const mergedOverrides = options.replaceDefaultOverrides @@ -168,14 +162,13 @@ export class ZeppelinPlugin< /** * Wrapper that calls mergeAndValidateStaticOptions() */ - protected getMergedOptions(): IPluginOptions { + protected getMergedOptions(): PluginOptions { if (!this.mergedPluginOptions) { - this.mergedPluginOptions = ((this.constructor as unknown) as typeof ZeppelinPlugin).mergeAndDecodeStaticOptions( - this.pluginOptions, - ); + this.mergedPluginOptions = ((this + .constructor as unknown) as typeof ZeppelinPluginClass).mergeAndDecodeStaticOptions(this.pluginOptions); } - return this.mergedPluginOptions as IPluginOptions; + return this.mergedPluginOptions as PluginOptions; } /** @@ -208,7 +201,7 @@ export class ZeppelinPlugin< if (isUnicodeEmoji(snowflake)) { return true; } else if (isSnowflake(snowflake)) { - for (const guild of this.bot.guilds.values()) { + for (const guild of this.client.guilds.values()) { if (guild.emojis.some(e => (e as any).id === snowflake)) { return true; } @@ -226,8 +219,8 @@ export class ZeppelinPlugin< } getUser(userResolvable: string): User | UnknownUser { - const id = resolveUserId(this.bot, userResolvable); - return id ? this.bot.users.get(id) || new UnknownUser({ id }) : new UnknownUser(); + const id = resolveUserId(this.client, userResolvable); + return id ? this.client.users.get(id) || new UnknownUser({ id }) : new UnknownUser(); } /** @@ -238,7 +231,7 @@ export class ZeppelinPlugin< async resolveUser(userResolvable: Not): Promise; async resolveUser(userResolvable) { const start = performance.now(); - const user = await resolveUser(this.bot, userResolvable); + const user = await resolveUser(this.client, userResolvable); const time = performance.now() - start; if (time >= SLOW_RESOLVE_THRESHOLD) { const rounded = Math.round(time); @@ -253,7 +246,7 @@ export class ZeppelinPlugin< * @param roleResolvable */ async resolveRoleId(roleResolvable: string): Promise { - const roleId = await resolveRoleId(this.bot, this.guildId, roleResolvable); + const roleId = await resolveRoleId(this.client, this.guildId, roleResolvable); return roleId; } @@ -266,9 +259,9 @@ export class ZeppelinPlugin< let member; if (forceFresh) { - const userId = await resolveUserId(this.bot, memberResolvable); + const userId = await resolveUserId(this.client, memberResolvable); try { - member = userId && (await this.bot.getRESTGuildMember(this.guild.id, userId)); + member = userId && (await this.client.getRESTGuildMember(this.guild.id, userId)); } catch (e) { if (!isDiscordRESTError(e)) { throw e; @@ -277,7 +270,7 @@ export class ZeppelinPlugin< if (member) member.id = member.user.id; } else { - member = await resolveMember(this.bot, this.guild, memberResolvable); + member = await resolveMember(this.client, this.guild, memberResolvable); } const time = performance.now() - start; @@ -294,7 +287,7 @@ export class ZeppelinPlugin< return inviteCache.get(code); } - const promise = this.bot.getInvite(code).catch(() => null); + const promise = this.client.getInvite(code).catch(() => null); inviteCache.set(code, promise); return promise; diff --git a/backend/src/types.ts b/backend/src/types.ts index bb80dee7..dd156404 100644 --- a/backend/src/types.ts +++ b/backend/src/types.ts @@ -1,11 +1,11 @@ -import { IGlobalConfig, IGuildConfig, Knub } from "knub"; +import { BaseConfig, Knub } from "knub"; -export interface IZeppelinGuildConfig extends IGuildConfig { +export interface IZeppelinGuildConfig extends BaseConfig { success_emoji?: string; error_emoji?: string; } -export interface IZeppelinGlobalConfig extends IGlobalConfig { +export interface IZeppelinGlobalConfig extends BaseConfig { url: string; owners?: string[]; }