import { ProfileBadge } from "../api/Badges"; import { ChatBarButtonData } from "../api/ChatButtons"; import { NavContextMenuPatchCallback } from "../api/ContextMenu"; import { MemberListDecoratorFactory } from "../api/MemberListDecorators"; import { MessageAccessoryFactory } from "../api/MessageAccessories"; import { MessageDecorationFactory } from "../api/MessageDecorations"; import { MessageClickListener, MessageEditListener, MessageSendListener } from "../api/MessageEvents"; import { MessagePopoverButtonData } from "../api/MessagePopover"; import { Command, FluxEvents } from "@vencord/discord-types"; import { ReactNode } from "react"; import { LiteralUnion } from "type-fest"; export default function definePlugin

(p: P & Record): typeof p & Plugin; export declare function makeRange(start: number, end: number, step?: number): number[]; export type ReplaceFn = (match: string, ...groups: string[]) => string; export interface PatchReplacement { /** The match for the patch replacement. If you use a string it will be implicitly converted to a RegExp */ match: string | RegExp; /** The replacement string or function which returns the string for the patch replacement */ replace: string | ReplaceFn; /** Do not warn if this replacement did no changes */ noWarn?: boolean; /** * A function which returns whether this patch replacement should be applied. * This is ran before patches are registered, so if this returns false, the patch will never be registered. */ predicate?(): boolean; /** The minimum build number for this patch to be applied */ fromBuild?: number; /** The maximum build number for this patch to be applied */ toBuild?: number; } export interface Patch { plugin: string; /** A string or RegExp which is only include/matched in the module code you wish to patch. Prefer only using a RegExp if a simple string test is not enough */ find: string | RegExp; /** The replacement(s) for the module being patched */ replacement: PatchReplacement | PatchReplacement[]; /** Whether this patch should apply to multiple modules */ all?: boolean; /** Do not warn if this patch did no changes */ noWarn?: boolean; /** Only apply this set of replacements if all of them succeed. Use this if your replacements depend on each other */ group?: boolean; /** * A function which returns whether this patch replacement should be applied. * This is ran before patches are registered, so if this returns false, the patch will never be registered. */ predicate?(): boolean; /** The minimum build number for this patch to be applied */ fromBuild?: number; /** The maximum build number for this patch to be applied */ toBuild?: number; } export interface PluginAuthor { name: string; id: BigInt; } export interface Plugin extends PluginDef { patches?: Patch[]; started: boolean; isDependency?: boolean; } export type IconComponent = (props: IconProps & Record) => ReactNode; export type IconProps = { height?: number | string; width?: number | string; className?: string; }; export interface PluginDef { name: string; description: string; authors: PluginAuthor[]; start?(): void; stop?(): void; patches?: Omit[]; /** * List of commands that your plugin wants to register */ commands?: Command[]; /** * A list of other plugins that your plugin depends on. * These will automatically be enabled and loaded before your plugin * Generally these will be API plugins */ dependencies?: string[]; /** * Whether this plugin is required and forcefully enabled */ required?: boolean; /** * Whether this plugin should be hidden from the user */ hidden?: boolean; /** * Whether this plugin should be enabled by default, but can be disabled */ enabledByDefault?: boolean; /** * Whether enabling or disabling this plugin requires a restart. Defaults to true if the plugin has patches. */ requiresRestart?: boolean; /** * When to call the start() method * @default StartAt.WebpackReady */ startAt?: StartAt; /** * Which parts of the plugin can be tested by the reporter. Defaults to all parts */ reporterTestable?: number; /** * Optionally provide settings that the user can configure in the Plugins tab of settings. * @deprecated Use `settings` instead */ options?: Record; /** * Optionally provide settings that the user can configure in the Plugins tab of settings. */ settings?: DefinedSettings; /** * Allows you to specify a custom Component that will be rendered in your * plugin's settings page */ settingsAboutComponent?: React.ComponentType<{}>; /** * Allows you to subscribe to Flux events */ flux?: Partial<{ [E in LiteralUnion]: (event: any) => void | Promise; }>; /** * Allows you to manipulate context menus */ contextMenus?: Record; /** * Allows you to add custom actions to the Vencord Toolbox. * * Can either be an object mapping labels to action functions or a Function returning Menu components. * Please note that you can only use Menu components. * * @example * toolboxActions: { * "Click Me": () => alert("Hi") * } */ toolboxActions?: Record void> | (() => ReactNode); tags?: string[]; /** * Managed style to automatically enable and disable when the plugin is enabled or disabled */ managedStyle?: string; userProfileBadge?: ProfileBadge; messagePopoverButton?: MessagePopoverButtonData; chatBarButton?: ChatBarButtonData; onMessageClick?: MessageClickListener; onBeforeMessageSend?: MessageSendListener; onBeforeMessageEdit?: MessageEditListener; renderMessageAccessory?: MessageAccessoryFactory; renderMessageDecoration?: MessageDecorationFactory; renderMemberListDecorator?: MemberListDecoratorFactory; /** * @deprecated Use {@link chatBarButton} instead */ renderChatBarButton?: never; /** * @deprecated Use {@link messagePopoverButton} instead */ renderMessagePopoverButton?: never; } export declare const enum StartAt { /** Right away, as soon as Vencord initialised */ Init = "Init", /** On the DOMContentLoaded event, so once the document is ready */ DOMContentLoaded = "DOMContentLoaded", /** Once Discord's core webpack modules have finished loading, so as soon as things like react and flux are available */ WebpackReady = "WebpackReady" } export declare const enum ReporterTestable { None = 2, Start = 4, Patches = 8, FluxEvents = 16 } export declare function defineDefault(value: T): T; export declare const enum OptionType { STRING = 0, NUMBER = 1, BIGINT = 2, BOOLEAN = 3, SELECT = 4, SLIDER = 5, COMPONENT = 6, CUSTOM = 7 } export type SettingsDefinition = Record; export type SettingsChecks = { [K in keyof D]?: D[K] extends PluginSettingComponentDef ? IsDisabled> : (IsDisabled> & IsValid, DefinedSettings>); }; export type PluginSettingDef = (PluginSettingCustomDef & Pick) | (PluginSettingComponentDef & Omit) | ((PluginSettingStringDef | PluginSettingNumberDef | PluginSettingBooleanDef | PluginSettingSelectDef | PluginSettingSliderDef | PluginSettingBigIntDef) & PluginSettingCommon); export interface PluginSettingCommon { description: string; placeholder?: string; onChange?(newValue: any): void; /** * Whether changing this setting requires a restart */ restartNeeded?: boolean; componentProps?: Record; /** * Hide this setting from the settings UI */ hidden?: boolean; /** * Set this if the setting only works on Browser or Desktop, not both */ target?: "WEB" | "DESKTOP" | "BOTH"; } interface IsDisabled { /** * Checks if this setting should be disabled */ disabled?(this: D): boolean; } interface IsValid { /** * Prevents the user from saving settings if this is false or a string */ isValid?(this: D, value: T): boolean | string; } export interface PluginSettingStringDef { type: OptionType.STRING; default?: string; } export interface PluginSettingNumberDef { type: OptionType.NUMBER; default?: number; } export interface PluginSettingBigIntDef { type: OptionType.BIGINT; default?: BigInt; } export interface PluginSettingBooleanDef { type: OptionType.BOOLEAN; default?: boolean; } export interface PluginSettingSelectDef { type: OptionType.SELECT; options: readonly PluginSettingSelectOption[]; } export interface PluginSettingSelectOption { label: string; value: string | number | boolean; default?: boolean; } export interface PluginSettingCustomDef { type: OptionType.CUSTOM; default?: any; } export interface PluginSettingSliderDef { type: OptionType.SLIDER; /** * All the possible values in the slider. Needs at least two values. */ markers: number[]; /** * Default value to use */ default: number; /** * If false, allow users to select values in-between your markers. */ stickToMarkers?: boolean; } export interface IPluginOptionComponentProps { /** * Run this when the value changes. * * NOTE: The user will still need to click save to apply these changes. */ setValue(newValue: any): void; /** * The options object */ option: PluginSettingComponentDef; } export interface PluginSettingComponentDef { type: OptionType.COMPONENT; component: (props: IPluginOptionComponentProps) => ReactNode | Promise; default?: any; } /** Maps a `PluginSettingDef` to its value type */ type PluginSettingType = O extends PluginSettingStringDef ? string : O extends PluginSettingNumberDef ? number : O extends PluginSettingBigIntDef ? BigInt : O extends PluginSettingBooleanDef ? boolean : O extends PluginSettingSelectDef ? O["options"][number]["value"] : O extends PluginSettingSliderDef ? number : O extends PluginSettingComponentDef ? O extends { default: infer Default; } ? Default : any : O extends PluginSettingCustomDef ? O extends { default: infer Default; } ? Default : any : never; type PluginSettingDefaultType = O extends PluginSettingSelectDef ? (O["options"] extends { default?: boolean; }[] ? O["options"][number]["value"] : undefined) : O extends { default: infer T; } ? T : undefined; type SettingsStore = { [K in keyof D]: PluginSettingType | PluginSettingDefaultType; }; /** An instance of defined plugin settings */ export interface DefinedSettings = {}, PrivateSettings extends object = {}> { /** Shorthand for `Vencord.Settings.plugins.PluginName`, but with typings */ store: SettingsStore & PrivateSettings; /** Shorthand for `Vencord.PlainSettings.plugins.PluginName`, but with typings */ plain: SettingsStore & PrivateSettings; /** * React hook for getting the settings for this plugin * @param filter optional filter to avoid rerenders for irrelevent settings */ use>(filter?: F[]): Pick & PrivateSettings, F>; /** Definitions of each setting */ def: Def; /** Setting methods with return values that could rely on other settings */ checks: Checks; /** * Name of the plugin these settings belong to, * will be an empty string until plugin is initialized */ pluginName: string; withPrivateSettings(): DefinedSettings; } export type PartialExcept = Partial & Required>; export type IpcRes = { ok: true; value: V; } | { ok: false; error: any; }; export type PluginOptionBase = PluginSettingCommon & IsDisabled; export type PluginOptionsItem = PluginOptionString | PluginOptionNumber | PluginOptionBoolean | PluginOptionSelect | PluginOptionSlider | PluginOptionComponent | PluginOptionCustom; export type PluginOptionString = PluginSettingStringDef & PluginSettingCommon & IsDisabled & IsValid; export type PluginOptionNumber = (PluginSettingNumberDef | PluginSettingBigIntDef) & PluginSettingCommon & IsDisabled & IsValid; export type PluginOptionBoolean = PluginSettingBooleanDef & PluginSettingCommon & IsDisabled & IsValid; export type PluginOptionSelect = PluginSettingSelectDef & PluginSettingCommon & IsDisabled & IsValid; export type PluginOptionSlider = PluginSettingSliderDef & PluginSettingCommon & IsDisabled & IsValid; export type PluginOptionComponent = PluginSettingComponentDef & Omit; export type PluginOptionCustom = PluginSettingCustomDef & Pick; export type PluginNative any>> = { [key in keyof PluginExports]: PluginExports[key] extends (event: Electron.IpcMainInvokeEvent, ...args: infer Args) => infer Return ? (...args: Args) => Return extends Promise ? Return : Promise : never; }; export type AllOrNothing = T | { [K in keyof T]?: never; }; export {};