diff --git a/debug/patches/patchErrorBoundary.tsx b/debug/patches/patchErrorBoundary.tsx deleted file mode 100644 index 2c30ce0..0000000 --- a/debug/patches/patchErrorBoundary.tsx +++ /dev/null @@ -1,160 +0,0 @@ -import React from "react"; -import ErrorBoundaryScreen from "@core/ui/reporter/components/ErrorBoundaryScreen"; -import { after } from "@lib/api/patcher"; -import { _lazyContextSymbol } from "@metro/lazy"; -import { LazyModuleContext } from "@metro/types"; -import { findByNameLazy } from "@metro/wrappers"; - -/** - * Try to resolve the ErrorBoundary prototype context in a resilient way. - * Some Discord versions / builds may expose modules under slightly different - * names; attempt lookup but fail gracefully if not found. - */ -function getErrorBoundaryContext(): Promise { - try { - const ctxt: LazyModuleContext = - findByNameLazy("ErrorBoundary")[_lazyContextSymbol]; - if (ctxt) { - return new Promise((resolve) => - ctxt.getExports((exp: any) => resolve(exp.prototype)), - ); - } - } catch (e) { - // silent - } - - // Best-effort fallback: resolve to null so callers can handle absence. - return Promise.reject(new Error("ErrorBoundary context not found")); -} - -/** - * Small stable wrapper component used when mounting our UI from the patched render. - * Defining a top-level component ensures that hook order inside ErrorBoundaryScreen - * is always respected (React expects components to be declared at module scope). - * - * We avoid using any hooks here; this wrapper simply forwards props to the real screen. - */ -const ErrorBoundaryMount: React.FC<{ - error: any; - rerender: () => void; -}> = ({ error, rerender }) => { - return React.createElement(ErrorBoundaryScreen, { - error, - rerender, - }); -}; - -/** - * Patch Discord's ErrorBoundary.render to return ShiggyCord's custom screen. - * Add defensive logging and fallback behavior so the patch won't break startup - * if lookup fails. Also register lightweight global handlers to capture - * uncaught errors for debugging. - */ -export default function patchErrorBoundary() { - try { - console.log("[ShiggyCord] patchErrorBoundary: registering"); - } catch {} - - // Attempt to attach after the ErrorBoundary render. If the context lookup - // fails, the promise will reject and the patcher will not install the patch, - // which is preferable to throwing during startup. - const ctxPromise = getErrorBoundaryContext().catch((err) => { - try { - console.warn( - "[ShiggyCord] patchErrorBoundary: context lookup failed", - err, - ); - } catch {} - // Return null so after.await receives a thenable; the patcher wrapper will handle it. - return null; - }); - - const unpatch = after.await("render", ctxPromise, function (this: any) { - try { - // Defensive checks: only render our screen when an error is actually present. - if (!this || !this.state || !this.state.error) return; - - try { - console.log( - "[ShiggyCord] patchErrorBoundary: rendering custom error screen", - this.state.error, - ); - } catch {} - - // Return a stable component element (ErrorBoundaryMount). Using a named, - // module-scoped component helps React ensure hook ordering for nested components. - return React.createElement(ErrorBoundaryMount, { - error: this.state.error, - rerender: () => { - try { - // Attempt to reset common ErrorBoundary state shapes safely. - try { - this.setState?.({ info: null, error: null, hasErr: false }); - } catch { - try { - this.setState?.({ error: null }); - } catch {} - } - } catch {} - }, - }); - } catch (e) { - try { - console.error( - "[ShiggyCord] patchErrorBoundary: error while rendering custom screen", - e, - ); - } catch {} - // Fall back to original behavior by returning undefined - return; - } - }); - - // Best-effort: install global handlers to capture uncaught errors / promise rejections. - // These handlers do not attempt to mount UI directly (that can be fragile), but they - // store the last uncaught error for inspection and log details which helps debugging. - try { - const g: any = global as any; - if (g) { - // Wrap React Native's ErrorUtils if present - try { - const ErrorUtils = g.ErrorUtils; - if (ErrorUtils && typeof ErrorUtils.setGlobalHandler === "function") { - // preserve previous handler - const prev = - ErrorUtils.getGlobalHandler?.() ?? - ErrorUtils._globalHandler ?? - null; - ErrorUtils.setGlobalHandler((err: any, isFatal?: boolean) => { - try { - console.error("[ShiggyCord] global uncaught error:", err, { - isFatal, - }); - (window as any).__SHIGGY_LAST_UNCAUGHT_ERROR = err; - } catch {} - try { - if (typeof prev === "function") prev(err, isFatal); - } catch {} - }); - } - } catch {} - - // Listen for unhandled promise rejections if environment supports it. - try { - if (typeof g.addEventListener === "function") { - g.addEventListener("unhandledrejection", (ev: any) => { - try { - console.error( - "[ShiggyCord] unhandledrejection:", - ev?.reason ?? ev, - ); - (window as any).__SHIGGY_LAST_UNCAUGHT_ERROR = ev?.reason ?? ev; - } catch {} - }); - } - } catch {} - } - } catch {} - - return unpatch; -} diff --git a/debug/safeMode.ts b/debug/safeMode.ts deleted file mode 100644 index f44bf06..0000000 --- a/debug/safeMode.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { getCurrentTheme, writeThemeToNative } from "@lib/addons/themes"; -import { BundleUpdaterManager } from "@lib/api/native/modules"; -import { settings } from "@lib/api/settings"; - -export function isSafeMode() { - return settings.safeMode?.enabled === true; -} - -export async function toggleSafeMode({ - to = !isSafeMode(), - reload = true -} = {}) { - const enabled = (settings.safeMode ??= { enabled: to }).enabled = to; - const currentColor = getCurrentTheme(); - await writeThemeToNative(enabled ? {} : currentColor?.data ?? {}); - if (reload) setTimeout(() => BundleUpdaterManager.reload(), 500); -}