···11-## Moonbase
22-33-- Overhauled restart notifications
44- - Moonbase now waits for the user to save their changes before prompting to restart the client
55- - Restarting the client in Moonbase now *fully* restarts the client when needed
66- - Allowed extensions to specify "restart advice" for settings
77-- Improved update systems
88- - Fixed the update banner having an invisible close button
99- - Made updates clearer in Moonbase by adding a divider + filter
1010- - Extension settings now update immediately after updating, without having to restart
1111- - Added extension changelogs (`meta.changelog` in the manifest)
1212- - Added a refresh button to Moonbase
1313- - Added the ability to update moonlight from the system tray
1414-- Moonbase now warns the user when enabling a dangerous extension
1515-- Moonbase now checks the extension author when using the search filter
1616-- Added a tooltip for conflicting extensions in Moonbase
1717-- Added basic crash cause detection
1818-191## Core
2022121-- Reworked core loading to properly be asynchronous, fixing race conditions
2222- - **A full client restart is required when updating to this version!**
2323- - If you have any issues starting your client, or moonlight does not load, let us know!
2424- - Special thanks to @gBasil for helping us find this issue.
2525-- Added better support for `\i` in patching and Spacepack
2626-- Added better error handling in entrypoint Webpack modules to prevent crashes
2727-- Added hard fail/"grouping" to patches
2828-- Added being able to patch mapped modules by referencing their name in the patch find
2929-- Fixed a bug with extensions patching the same Webpack module
3030- - Special thanks to @karashiiro for helping us find this issue.
3131-- Added API parity to all moonlight global variables
3232-- Updated all core extension manifests
3333-- Added an optional config to the injector for special installation setups
3434-3535-## Documentation
3636-3737-- Updated the GitHub README and project website
3838-- Added "Why moonlight?" section to the project website
3939-- Updated Starlight
4040-- Added better documentation for all core extensions
4141-- Documented the new moonlight features
4242-- Added documentation for writing mappings
4343-- Added note about auto-detected Linux installs and running as root
4444-- Added clearer download buttons for the moonlight installer
4545-- Documented installing moonlight through Nix
4646-- Added contribution guidelines
4747-- Added reminder to restart fully when adding React DevTools
4848-- Mention all files when editing the sample extension
4949-- Documented extension manifests
5050-- Documented adding types for Webpack module import statements
5151-- Clarified how moonlight environments and globals behave
5252-- Fixed an invalid suggestion for matching yourself with Spacepack
5353-- Performed a general cleanup pass on grammar
5454-5555-## Misc
5656-5757-- Fixed Nix support by updating pnpm2nix (thank you @sersorrel!)
5858-- Cleaned up the installer (thank you @pauliesnug!)
5959-- Updated deprecated GitHub Actions to the latest version
6060-- Updated & cleaned up sample extension
6161-- Fixed auth requirement for RoboJules
6262-- Merged 9 new extensions (thank you @Cynosphere, @redstonekasi!)
6363-- Cleaned up GitHub organization permissions by moving to teams
33+- Updated mappings
44+- Fixed using remapped paths as patch finds not working
+1-1
README.md
···23232424moonlight is heavily inspired by hh3 (a private client mod) and the projects before it that it is inspired by, namely EndPwn. All core code is original or used with permission from their respective authors where not copyleft.
25252626-**_This is an experimental passion project._** Anything and everything is subject to change, but it is stable enough for tinkerers and developers to experiment with.
2626+moonlight is a **_passion project_** - things may break from time to time, but we try our best to keep things working in a timely manner.
27272828moonlight is licensed under the [GNU Lesser General Public License](https://www.gnu.org/licenses/lgpl-3.0.html) (`LGPL-3.0-or-later`). See [the documentation](https://moonlight-mod.github.io/) for more information.
···11import React from "@moonlight-mod/wp/react";
22-import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
32import Flex from "@moonlight-mod/wp/discord/uikit/Flex";
43import { Text } from "@moonlight-mod/wp/discord/components/common/index";
55-66-const Margins = spacepack.require("discord/styles/shared/Margins.css");
77-const HelpMessageClasses = spacepack.findByExports("positive", "iconDiv")[0].exports;
44+import HelpMessageClasses from "@moonlight-mod/wp/discord/components/common/HelpMessage.css";
55+import Margins from "@moonlight-mod/wp/discord/styles/shared/Margins.css";
8697// reimpl of HelpMessage but with a custom icon
108export default function HelpMessage({
···77 "name": "Rocketship",
88 "tagline": "Adds new features when using rocketship",
99 "description": "**This extension only works on Linux when using rocketship:**\nhttps://github.com/moonlight-mod/rocketship\n\nAdds new features to the Discord Linux client with rocketship, such as a better screensharing experience.",
1010- "authors": ["NotNite", "Cynosphere", "adryd"]
1010+ "authors": ["NotNite", "Cynosphere", "adryd"],
1111+ "deprecated": true
1112 }
1213}
···3333 };
34343535export type BooleanSettingType = {
3636+ /**
3737+ * Displays as a simple switch.
3838+ */
3639 type: ExtensionSettingType.Boolean;
3740 default?: boolean;
3841};
39424043export type NumberSettingType = {
4444+ /**
4545+ * Displays as a simple slider.
4646+ */
4147 type: ExtensionSettingType.Number;
4248 default?: number;
4349 min?: number;
···4551};
46524753export type StringSettingType = {
5454+ /**
5555+ * Displays as a single line string input.
5656+ */
4857 type: ExtensionSettingType.String;
4958 default?: string;
5059};
51605261export type MultilineTextInputSettingType = {
6262+ /**
6363+ * Displays as a multiple line string input.
6464+ */
5365 type: ExtensionSettingType.MultilineString;
5466 default?: string;
5567};
56685769export type SelectSettingType = {
7070+ /**
7171+ * A dropdown to pick between one of many values.
7272+ */
5873 type: ExtensionSettingType.Select;
5974 options: SelectOption[];
6075 default?: string;
6176};
62776378export type MultiSelectSettingType = {
7979+ /**
8080+ * A dropdown to pick multiple values.
8181+ */
6482 type: ExtensionSettingType.MultiSelect;
6583 options: string[];
6684 default?: string[];
6785};
68866987export type ListSettingType = {
8888+ /**
8989+ * A list of strings that the user can add or remove from.
9090+ */
7091 type: ExtensionSettingType.List;
7192 default?: string[];
7293};
73947495export type DictionarySettingType = {
9696+ /**
9797+ * A dictionary (key-value pair) that the user can add or remove from.
9898+ */
7599 type: ExtensionSettingType.Dictionary;
76100 default?: Record<string, string>;
77101};
7810279103export type CustomSettingType = {
104104+ /**
105105+ * A custom component.
106106+ * You can use the registerConfigComponent function in the Moonbase API to register a React component to render here.
107107+ */
80108 type: ExtensionSettingType.Custom;
81109 default?: any;
82110};
···88116}
8911790118export type ExtensionSettingsManifest = {
119119+ /**
120120+ * A human friendly name for the setting.
121121+ */
91122 displayName?: string;
123123+124124+ /**
125125+ * A longer description for the setting.
126126+ * Markdown is not supported.
127127+ */
92128 description?: string;
129129+130130+ /**
131131+ * The "advice" to give upon changing this setting.
132132+ * Can be configured to reload the client, restart the client, or do nothing.
133133+ */
93134 advice?: ExtensionSettingsAdvice;
94135} & (
95136 | BooleanSettingType
···1414 * Registers a new context menu item for a given context menu type.
1515 * @param navId The navigation ID for the target context menu (e.g. "user-context", "message")
1616 * @param item A React component
1717- * @param anchorId An existing item's ID to anchor the new item to
1717+ * @param anchor An existing item's ID to anchor the new item to
1818 * @param before Whether to insert the new item before the anchor item
1919 */
2020- addItem: (navId: string, item: React.FC<any>, anchorId: string, before?: boolean) => void;
2020+ addItem: (navId: string, item: React.FC<any>, anchor: string | RegExp, before?: boolean) => void;
21212222 MenuCheckboxItem: MenuCheckboxItem;
2323 MenuControlItem: MenuControlItem;
+1-1
packages/types/src/coreExtensions/notices.ts
···11-import type { Store } from "@moonlight-mod/mappings/discord/packages/flux";
11+import type { Store } from "@moonlight-mod/mappings/discord/packages/flux/Store";
2233export type NoticeButton = {
44 name: string;
+11-8
packages/types/src/coreExtensions/settings.ts
···11import React, { ReactElement } from "react";
22-import type { Store } from "@moonlight-mod/mappings/discord/packages/flux";
22+import type { Store } from "@moonlight-mod/mappings/discord/packages/flux/Store";
3344export type NoticeProps = {
55 stores: Store<any>[];
···77};
8899export type SettingsSection =
1010- | { section: "DIVIDER"; pos: number }
1111- | { section: "HEADER"; label: string; pos: number }
1010+ | { section: "DIVIDER"; pos: number | ((sections: SettingsSection[]) => number) }
1111+ | { section: "HEADER"; label: string; pos: number | ((sections: SettingsSection[]) => number) }
1212 | {
1313 section: string;
1414 label: string;
1515 color: string | null;
1616 element: React.FunctionComponent;
1717- pos: number;
1717+ pos: number | ((sections: SettingsSection[]) => number);
1818 notice?: NoticeProps;
1919+ onClick?: () => void;
1920 _moonlight_submenu?: () => ReactElement | ReactElement[];
2021 };
2122···3233 * @param color A color to use for the section
3334 * @param pos The position in the settings menu to place the section
3435 * @param notice A notice to display when in the section
3636+ * @param onClick A custom action to execute when clicked from the context menu
3537 */
3638 addSection: (
3739 section: string,
3840 label: string,
3941 element: React.FunctionComponent,
4042 color?: string | null,
4141- pos?: number,
4242- notice?: NoticeProps
4343+ pos?: number | ((sections: SettingsSection[]) => number),
4444+ notice?: NoticeProps,
4545+ onClick?: () => void
4346 ) => void;
44474548 /**
···5356 * Places a divider in the settings menu.
5457 * @param pos The position in the settings menu to place the divider
5558 */
5656- addDivider: (pos: number | null) => void;
5959+ addDivider: (pos: number | ((sections: SettingsSection[]) => number) | null) => void;
57605861 /**
5962 * Places a header in the settings menu.
6063 * @param pos The position in the settings menu to place the header
6164 */
6262- addHeader: (label: string, pos: number | null) => void;
6565+ addHeader: (label: string, pos: number | ((sections: SettingsSection[]) => number) | null) => void;
63666467 /**
6568 * @private
+1
packages/types/src/coreExtensions/spacepack.ts
···18181919 /**
2020 * Find Webpack modules based on their exports.
2121+ * @deprecated This has race conditions. Consider using findByCode instead.
2122 * @param args A list of finds to match exports against
2223 * @returns The Webpack modules, if found
2324 */
+3
packages/types/src/coreExtensions.ts
···55export * as Notices from "./coreExtensions/notices";
66export * as Moonbase from "./coreExtensions/moonbase";
77export * as AppPanels from "./coreExtensions/appPanels";
88+export * as Commands from "./coreExtensions/commands";
99+export * as ComponentEditor from "./coreExtensions/componentEditor";
1010+export * as Common from "./coreExtensions/common";
+12
packages/types/src/discord/require.ts
···11import { AppPanels } from "../coreExtensions/appPanels";
22+import { Commands } from "../coreExtensions/commands";
33+import { ErrorBoundary, Icons } from "../coreExtensions/common";
44+import { DMList, MemberList, Messages } from "../coreExtensions/componentEditor";
25import { ContextMenu, EvilItemParser } from "../coreExtensions/contextMenu";
36import { Markdown } from "../coreExtensions/markdown";
47import { Moonbase } from "../coreExtensions/moonbase";
···912declare function WebpackRequire(id: string): any;
10131114declare function WebpackRequire(id: "appPanels_appPanels"): AppPanels;
1515+1616+declare function WebpackRequire(id: "commands_commands"): Commands;
1717+1818+declare function WebpackRequire(id: "common_ErrorBoundary"): ErrorBoundary;
1919+declare function WebpackRequire(id: "common_icons"): Icons;
2020+2121+declare function WebpackRequire(id: "componentEditor_dmList"): DMList;
2222+declare function WebpackRequire(id: "componentEditor_memberList"): MemberList;
2323+declare function WebpackRequire(id: "componentEditor_messages"): Messages;
12241325declare function WebpackRequire(id: "contextMenu_evilMenu"): EvilItemParser;
1426declare function WebpackRequire(id: "contextMenu_contextMenu"): ContextMenu;
+101-1
packages/types/src/extension.ts
···2828 };
29293030export type ExtensionManifest = {
3131+ $schema?: string;
3232+3333+ /**
3434+ * A unique identifier for your extension.
3535+ */
3136 id: string;
3737+3838+ /**
3939+ * A version string for your extension - doesn't need to follow a specific format. Required for publishing.
4040+ */
3241 version?: string;
4242+4343+ /**
4444+ * The API level this extension targets. If it does not match the current version, the extension will not be loaded.
4545+ */
3346 apiLevel?: number;
4747+4848+ /**
4949+ * Which environment this extension is capable of running in.
5050+ */
3451 environment?: ExtensionEnvironment;
35525353+ /**
5454+ * Metadata about your extension for use in Moonbase.
5555+ */
3656 meta?: {
5757+ /**
5858+ * A human friendly name for your extension as a proper noun.
5959+ */
3760 name?: string;
6161+6262+ /**
6363+ * A short tagline that appears below the name.
6464+ */
3865 tagline?: string;
6666+6767+ /**
6868+ * A longer description that can use Markdown.
6969+ */
3970 description?: string;
7171+7272+ /**
7373+ * List of authors that worked on this extension - accepts string or object with ID.
7474+ */
4075 authors?: ExtensionAuthor[];
4141- deprecated?: boolean;
7676+7777+ /**
7878+ * A list of tags that are relevant to the extension.
7979+ */
4280 tags?: ExtensionTag[];
8181+8282+ /**
8383+ * The URL to the source repository.
8484+ */
4385 source?: string;
8686+8787+ /**
8888+ * A donation link (or other method of support). If you don't want financial contributions, consider putting your favorite charity here!
8989+ */
9090+ donate?: string;
9191+9292+ /**
9393+ * A changelog to show in Moonbase.
9494+ * Moonbase will show the changelog for the latest version, even if it is not installed.
9595+ */
4496 changelog?: string;
9797+9898+ /**
9999+ * Whether the extension is deprecated and no longer receiving updates.
100100+ */
101101+ deprecated?: boolean;
45102 };
46103104104+ /**
105105+ * A list of extension IDs that are required for the extension to load.
106106+ */
47107 dependencies?: string[];
108108+109109+ /**
110110+ * A list of extension IDs that the user may want to install.
111111+ */
48112 suggested?: string[];
113113+114114+ /**
115115+ * A list of extension IDs that the extension is incompatible with.
116116+ * If two incompatible extensions are enabled, one of them will not load.
117117+ */
49118 incompatible?: string[];
50119120120+ /**
121121+ * A list of settings for your extension, where the key is the settings ID.
122122+ */
51123 settings?: Record<string, ExtensionSettingsManifest>;
52124125125+ /**
126126+ * A list of URLs to bypass CORS for.
127127+ * This is implemented by checking if the start of the URL matches.
128128+ * @example https://moonlight-mod.github.io/
129129+ */
53130 cors?: string[];
131131+132132+ /**
133133+ * A list of URLs to block all requests to.
134134+ * This is implemented by checking if the start of the URL matches.
135135+ * @example https://moonlight-mod.github.io/
136136+ */
54137 blocked?: string[];
138138+139139+ /**
140140+ * A mapping from CSP directives to URLs to allow.
141141+ * @example { "script-src": ["https://example.com"] }
142142+ */
143143+ csp?: Record<string, string[]>;
55144};
5614557146export enum ExtensionEnvironment {
147147+ /**
148148+ * The extension will run on both platforms, the host/native modules MAY be loaded
149149+ */
58150 Both = "both",
151151+152152+ /**
153153+ * Extension will run on desktop only, the host/native modules are guaranteed to load
154154+ */
59155 Desktop = "desktop",
156156+157157+ /**
158158+ * Currently equivalent to Both
159159+ */
60160 Web = "web"
61161}
62162