From 06a0a86d55f0d0f804c81c713b158d501aee2bb3 Mon Sep 17 00:00:00 2001 From: Tharki-God Date: Tue, 11 Jun 2024 00:00:56 +0530 Subject: [PATCH 1/4] okay? --- src/renderer/modules/webpack/filters.ts | 17 +++++++++++++++++ src/renderer/modules/webpack/helpers.ts | 8 ++++++++ 2 files changed, 25 insertions(+) diff --git a/src/renderer/modules/webpack/filters.ts b/src/renderer/modules/webpack/filters.ts index f09f644fb..7e5062fd3 100644 --- a/src/renderer/modules/webpack/filters.ts +++ b/src/renderer/modules/webpack/filters.ts @@ -1,6 +1,7 @@ import { getExportsForProps } from "./get-modules"; import { sourceStrings } from "./patch-load"; import type { RawModule } from "../../../types"; +import { Store } from "../common/flux"; /** * Get a module that has all the given properties on one of its exports @@ -58,3 +59,19 @@ export const byValue = (match: string | RegExp) => { return false; }; }; + +/** + * Get a module that has the store with given name + * @param name Name of Store + */ +export const byStoreName = (name: string) => { + return (m: RawModule) => { + if (!m.exports || typeof m.exports !== "object" || typeof m.exports !== "object") { + return false; + } + return ( + (m.exports as { default?: Store & { constructor: { displayName: string } } }).default + ?.constructor.displayName === name + ); + }; +}; diff --git a/src/renderer/modules/webpack/helpers.ts b/src/renderer/modules/webpack/helpers.ts index 62817c752..031d6f3dc 100644 --- a/src/renderer/modules/webpack/helpers.ts +++ b/src/renderer/modules/webpack/helpers.ts @@ -250,3 +250,11 @@ export function getByStoreName(name: string): T | undefined { const stores = Flux.Store.getAll(); return stores.find((store) => store.getName() === name) as T | undefined; } + +export async function waitForStoreName( + name: string, + options?: { timeout: number }, +): Promise { + const module = await waitForModule<{ default?: T }>(filters.byStoreName(name), options); + return module.default; +} From 3178a0e6d83582a25afa4dce95b8c506dc390c68 Mon Sep 17 00:00:00 2001 From: Tharki-God Date: Fri, 21 Jun 2024 11:26:28 +0530 Subject: [PATCH 2/4] for swc --- src/renderer/modules/webpack/filters.ts | 7 ++++--- src/renderer/modules/webpack/helpers.ts | 7 +++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/renderer/modules/webpack/filters.ts b/src/renderer/modules/webpack/filters.ts index 7e5062fd3..8fc5071fe 100644 --- a/src/renderer/modules/webpack/filters.ts +++ b/src/renderer/modules/webpack/filters.ts @@ -69,9 +69,10 @@ export const byStoreName = (name: string) => { if (!m.exports || typeof m.exports !== "object" || typeof m.exports !== "object") { return false; } - return ( - (m.exports as { default?: Store & { constructor: { displayName: string } } }).default - ?.constructor.displayName === name + return ["default", "Z", "ZP"].some( + (key) => + (m.exports as { [key: string]: Store & { constructor: { displayName: string } } })[key] + ?.constructor.displayName === name, ); }; }; diff --git a/src/renderer/modules/webpack/helpers.ts b/src/renderer/modules/webpack/helpers.ts index 031d6f3dc..a37839580 100644 --- a/src/renderer/modules/webpack/helpers.ts +++ b/src/renderer/modules/webpack/helpers.ts @@ -255,6 +255,9 @@ export async function waitForStoreName( name: string, options?: { timeout: number }, ): Promise { - const module = await waitForModule<{ default?: T }>(filters.byStoreName(name), options); - return module.default; + const module = await waitForModule<{ default?: T; ZP?: T; Z?: T }>( + filters.byStoreName(name), + options, + ); + return module.default ?? module.ZP ?? module.ZP; } From d0d41047c9530f2b77ded0300db391f3cd47d279 Mon Sep 17 00:00:00 2001 From: Tharki-God Date: Fri, 21 Jun 2024 11:34:17 +0530 Subject: [PATCH 3/4] fix --- src/renderer/modules/webpack/helpers.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/modules/webpack/helpers.ts b/src/renderer/modules/webpack/helpers.ts index a37839580..464088d11 100644 --- a/src/renderer/modules/webpack/helpers.ts +++ b/src/renderer/modules/webpack/helpers.ts @@ -255,9 +255,9 @@ export async function waitForStoreName( name: string, options?: { timeout: number }, ): Promise { - const module = await waitForModule<{ default?: T; ZP?: T; Z?: T }>( + const module = await waitForModule<{ default?: T; ZP?: T; Z?: T } & T>( filters.byStoreName(name), options, ); - return module.default ?? module.ZP ?? module.ZP; + return module.default ?? module.ZP ?? module.Z ?? module; } From cbe31d3dd62c2b6952ab072ddca321f9be2d685d Mon Sep 17 00:00:00 2001 From: yofukashino Date: Thu, 14 Nov 2024 23:42:39 +0530 Subject: [PATCH 4/4] better idk? --- src/renderer/modules/webpack/filters.ts | 18 ------ src/renderer/modules/webpack/helpers.ts | 11 ---- src/renderer/modules/webpack/index.ts | 2 +- src/renderer/modules/webpack/lazy.ts | 82 +++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 30 deletions(-) diff --git a/src/renderer/modules/webpack/filters.ts b/src/renderer/modules/webpack/filters.ts index 8fc5071fe..f09f644fb 100644 --- a/src/renderer/modules/webpack/filters.ts +++ b/src/renderer/modules/webpack/filters.ts @@ -1,7 +1,6 @@ import { getExportsForProps } from "./get-modules"; import { sourceStrings } from "./patch-load"; import type { RawModule } from "../../../types"; -import { Store } from "../common/flux"; /** * Get a module that has all the given properties on one of its exports @@ -59,20 +58,3 @@ export const byValue = (match: string | RegExp) => { return false; }; }; - -/** - * Get a module that has the store with given name - * @param name Name of Store - */ -export const byStoreName = (name: string) => { - return (m: RawModule) => { - if (!m.exports || typeof m.exports !== "object" || typeof m.exports !== "object") { - return false; - } - return ["default", "Z", "ZP"].some( - (key) => - (m.exports as { [key: string]: Store & { constructor: { displayName: string } } })[key] - ?.constructor.displayName === name, - ); - }; -}; diff --git a/src/renderer/modules/webpack/helpers.ts b/src/renderer/modules/webpack/helpers.ts index 464088d11..62817c752 100644 --- a/src/renderer/modules/webpack/helpers.ts +++ b/src/renderer/modules/webpack/helpers.ts @@ -250,14 +250,3 @@ export function getByStoreName(name: string): T | undefined { const stores = Flux.Store.getAll(); return stores.find((store) => store.getName() === name) as T | undefined; } - -export async function waitForStoreName( - name: string, - options?: { timeout: number }, -): Promise { - const module = await waitForModule<{ default?: T; ZP?: T; Z?: T } & T>( - filters.byStoreName(name), - options, - ); - return module.default ?? module.ZP ?? module.Z ?? module; -} diff --git a/src/renderer/modules/webpack/index.ts b/src/renderer/modules/webpack/index.ts index 719e010bb..e000bd7c1 100644 --- a/src/renderer/modules/webpack/index.ts +++ b/src/renderer/modules/webpack/index.ts @@ -1,4 +1,4 @@ -export { waitForModule } from "./lazy"; +export { waitForModule, waitForStore } from "./lazy"; export { getFunctionBySource, getFunctionKeyBySource } from "./inner-search"; diff --git a/src/renderer/modules/webpack/lazy.ts b/src/renderer/modules/webpack/lazy.ts index c2427846e..59031a8a8 100644 --- a/src/renderer/modules/webpack/lazy.ts +++ b/src/renderer/modules/webpack/lazy.ts @@ -2,6 +2,8 @@ import type { Filter, LazyCallback, LazyListener, RawModule, WaitForOptions } fr import { getExports, getModule } from "./get-modules"; +import type { Store } from "@common/flux"; + /** * Listeners that will be checked when each module is initialized */ @@ -116,3 +118,83 @@ export async function waitForModule( clearTimeout(timeout); }); } + +export async function waitForStore( + filter: string, + options?: { timeout?: number }, +): Promise; + +/** + * Wait for a module that matches the given filter + * @param filter Store Name + * @param options Options + * @param options.timeout Timeout in milliseconds + * + * @see {@link filters} + * + * @remarks + * Some modules may not be available immediately when Discord starts and will take up to a few seconds. + * This is useful to ensure that the module is available before using it. + */ +export async function waitForStore( + name: string, + options: { timeout?: number } = {}, +): Promise { + const { flux } = await import("@common"); + const existingStores = flux.Store.getAll() as Store[] & { + listeners?: Set void)>>; + onPush?: (name: string, callback: (store: Store) => void) => () => void; + }; + if (!existingStores.listeners) { + existingStores.listeners = new Set<[string, (store: Store) => void]>(); + existingStores.onPush = (name, callback) => { + const store = existingStores.find((store) => store.getName() === name); + if (store) { + callback(store); + } + const listener = [name, callback]; + existingStores.listeners!.add(listener); + return () => existingStores.listeners!.delete(listener); + }; + existingStores.push = (...stores: Store[]) => { + for (const [name, callback] of existingStores.listeners!) { + const store = stores.find((store) => store.getName() === name); + if (store) { + (callback as (store: Store) => void)(store); + } + } + return Array.prototype.push.call(existingStores, ...stores); + }; + } + const existingStore = existingStores.find((store) => store.getName() === name) as T | undefined; + + if (existingStore) { + return existingStore; + } + + // Promise that resolves with the module + const promise = new Promise((resolve) => { + const unregister = existingStores.onPush!(name, (store: Store) => { + unregister(); + resolve(store as T); + }); + }); + + // If no timeout, then wait for as long as it takes + if (!options.timeout) return promise; + + // Different in Node and browser environments--number in browser, NodeJS.Timeout in Node + let timeout: ReturnType; + + // Promise that rejects if the module takes too long to appear + const timeoutPromise = new Promise((_, reject) => { + timeout = setTimeout(() => { + reject(new Error(`waitForStore timed out after ${options.timeout}ms`)); + }, options.timeout); + }); + + // Go with whichever happens first + return Promise.race([promise, timeoutPromise]).finally(() => { + clearTimeout(timeout); + }); +}