this repo has no description

moonbase: show possible causes on crash screen

Changed files
+76 -2
packages
core
src
core-extensions
src
moonbase
webpackModules
types
web-preload
src
+70 -2
packages/core-extensions/src/moonbase/webpackModules/crashScreen.tsx
··· 4 4 import spacepack from "@moonlight-mod/wp/spacepack_spacepack"; 5 5 import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores"; 6 6 import { RepositoryManifest, UpdateState } from "../types"; 7 + import { ConfigExtension, DetectedExtension } from "@moonlight-mod/types"; 7 8 8 9 const { Button, TabBar } = Components; 9 10 const TabBarClasses = spacepack.findByCode(/tabBar:"tabBar_[a-z0-9]+",tabBarItem:"tabBarItem_[a-z0-9]+"/)[0].exports; 11 + 12 + const MODULE_REGEX = /Webpack-Module-(\d+)/g; 10 13 11 14 const logger = moonlight.getLogger("moonbase/crashScreen"); 12 15 ··· 83 86 ); 84 87 } 85 88 89 + function ExtensionDisableCard({ ext }: { ext: DetectedExtension }) { 90 + function disableWithDependents() { 91 + const disable = new Set<string>(); 92 + disable.add(ext.id); 93 + for (const [id, dependencies] of moonlightNode.processedExtensions.dependencyGraph) { 94 + if (dependencies?.has(ext.id)) disable.add(id); 95 + } 96 + 97 + const config = structuredClone(moonlightNode.config); 98 + for (const id in config.extensions) { 99 + if (!disable.has(id)) continue; 100 + if (typeof config.extensions[id] === "boolean") config.extensions[id] = false; 101 + else (config.extensions[id] as ConfigExtension).enabled = false; 102 + } 103 + 104 + let msg = `Are you sure you want to disable "${ext.manifest.meta?.name ?? ext.id}"`; 105 + if (disable.size > 1) { 106 + msg += ` and its ${disable.size - 1} dependent${disable.size - 1 === 1 ? "" : "s"}`; 107 + } 108 + msg += "?"; 109 + 110 + if (confirm(msg)) { 111 + moonlightNode.writeConfig(config); 112 + window.location.reload(); 113 + } 114 + } 115 + 116 + return ( 117 + <div className="moonbase-crash-extensionCard"> 118 + <div className="moonbase-crash-extensionCard-meta"> 119 + <div className="moonbase-crash-extensionCard-title">{ext.manifest.meta?.name ?? ext.id}</div> 120 + <div className="moonbase-crash-extensionCard-version">{`v${ext.manifest.version ?? "???"}`}</div> 121 + </div> 122 + <div className="moonbase-crash-extensionCard-button"> 123 + <Button color={Button.Colors.RED} onClick={disableWithDependents}> 124 + Disable 125 + </Button> 126 + </div> 127 + </div> 128 + ); 129 + } 130 + 86 131 export function wrapAction({ action, state }: WrapperProps) { 87 132 const [tab, setTab] = React.useState("crash"); 88 133 ··· 94 139 }; 95 140 }); 96 141 142 + const causes = React.useMemo(() => { 143 + const causes = new Set<string>(); 144 + if (state.error.stack) { 145 + for (const [, id] of state.error.stack.matchAll(MODULE_REGEX)) 146 + for (const ext of moonlight.patched.get(id) ?? []) causes.add(ext); 147 + } 148 + for (const [, id] of state.info.componentStack.matchAll(MODULE_REGEX)) 149 + for (const ext of moonlight.patched.get(id) ?? []) causes.add(ext); 150 + return [...causes]; 151 + }, []); 152 + 97 153 return ( 98 154 <div className="moonbase-crash-wrapper"> 99 155 {action} ··· 104 160 onItemSelect={(v) => setTab(v)} 105 161 > 106 162 <TabBar.Item className={TabBarClasses.tabBarItem} id="crash"> 107 - Crash Details 163 + Crash details 108 164 </TabBar.Item> 109 165 <TabBar.Item className={TabBarClasses.tabBarItem} id="extensions" disabled={updateCount === 0}> 110 - {`Extension Updates (${updateCount})`} 166 + {`Extension updates (${updateCount})`} 167 + </TabBar.Item> 168 + <TabBar.Item className={TabBarClasses.tabBarItem} id="causes" disabled={causes.length === 0}> 169 + {`Possible causes (${causes.length})`} 111 170 </TabBar.Item> 112 171 </TabBar> 113 172 {tab === "crash" ? ( ··· 126 185 {updates.map(([id, ext]) => ( 127 186 <ExtensionUpdateCard id={Number(id)} ext={ext} /> 128 187 ))} 188 + </div> 189 + ) : null} 190 + {tab === "causes" ? ( 191 + <div className="moonbase-crash-extensions"> 192 + {causes 193 + .map((ext) => moonlightNode.extensions.find((e) => e.id === ext)!) 194 + .map((ext) => ( 195 + <ExtensionDisableCard ext={ext} /> 196 + ))} 129 197 </div> 130 198 ) : null} 131 199 </div>
+4
packages/core/src/patch.ts
··· 111 111 const mappedName = moonlight.moonmap.modules[id]; 112 112 let modified = false; 113 113 114 + const exts = new Set<string>(); 115 + 114 116 for (let i = 0; i < patches.length; i++) { 115 117 const patch = patches[i]; 116 118 if (patch.prerequisite != null && !patch.prerequisite()) { ··· 169 171 if (!hardFailed) { 170 172 moduleString = replaced; 171 173 modified = true; 174 + exts.add(patch.ext); 172 175 } 173 176 174 177 moonlight.unpatched.delete(patch); ··· 179 182 if (modified) { 180 183 patchModule(id, patchedStr.join(", "), moduleString); 181 184 moduleCache[id] = moduleString; 185 + moonlight.patched.set(id, exts); 182 186 } 183 187 184 188 try {
+1
packages/types/src/globals.ts
··· 56 56 }; 57 57 58 58 export type MoonlightWeb = { 59 + patched: Map<string, Set<string>>; 59 60 unpatched: Set<IdentifiedPatch>; 60 61 pendingModules: Set<IdentifiedWebpackModule>; 61 62 enabledExtensions: Set<string>;
+1
packages/web-preload/src/index.ts
··· 15 15 const logger = new Logger("web-preload"); 16 16 17 17 window.moonlight = { 18 + patched: new Map(), 18 19 unpatched: new Set(), 19 20 pendingModules: new Set(), 20 21 enabledExtensions: new Set(),