this repo has no description
1import { WebpackModule, WebpackModuleFunc, WebpackRequireType } from "@moonlight-mod/types";
2import { Spacepack } from "@moonlight-mod/types/coreExtensions/spacepack";
3import { processFind, testFind } from "@moonlight-mod/core/util/patch";
4
5const webpackRequire = require as unknown as WebpackRequireType;
6const cache = webpackRequire.c;
7const modules = webpackRequire.m;
8
9const logger = moonlight.getLogger("spacepack");
10
11export const spacepack: Spacepack = {
12 require: webpackRequire,
13 modules,
14 cache,
15
16 inspect: (module: number | string) => {
17 if (typeof module === "number") {
18 module = module.toString();
19 }
20
21 if (module in moonlight.moonmap.modules) {
22 module = moonlight.moonmap.modules[module];
23 }
24
25 if (!(module in modules)) {
26 return null;
27 }
28
29 const func = modules[module];
30 if (func.__moonlight === true) {
31 return func;
32 }
33
34 const funcStr = func.toString();
35
36 return new Function(
37 "module",
38 "exports",
39 "require",
40 `(${funcStr}).apply(this, arguments)\n` + `//# sourceURL=Webpack-Module/${module.slice(0, 3)}/${module}`
41 ) as WebpackModuleFunc;
42 },
43
44 findByCode: (...args: (string | RegExp)[]) => {
45 const ret = Object.entries(modules)
46 .filter(([id, mod]) => !args.some((item) => !testFind(mod.toString(), processFind(item))))
47 .map(([id]) => {
48 //if (!(id in cache)) require(id);
49 //return cache[id];
50
51 let exports;
52 try {
53 exports = require(id);
54 } catch (e) {
55 logger.error(`findByCode: Error requiring module "${id}": `, args, e);
56 }
57
58 return {
59 id,
60 exports
61 };
62 })
63 .filter((item) => item !== null);
64
65 if (ret.length === 0) {
66 logger.warn("findByCode: Got zero results for", args, new Error().stack!.substring(5));
67 }
68
69 return ret;
70 },
71
72 findByExports: (...args: string[]) => {
73 return Object.entries(cache)
74 .filter(
75 ([id, { exports }]) =>
76 !args.some(
77 (item) =>
78 !(
79 exports !== undefined &&
80 exports !== window &&
81 (exports?.[item] || exports?.default?.[item] || exports?.Z?.[item] || exports?.ZP?.[item])
82 )
83 )
84 )
85 .map((item) => item[1])
86 .reduce<WebpackModule[]>((prev, curr) => {
87 if (!prev.includes(curr)) prev.push(curr);
88 return prev;
89 }, []);
90 },
91
92 findObjectFromKey: (exports: Record<string, any>, key: string) => {
93 let ret = null;
94 let subKey;
95 if (key.indexOf(".") > -1) {
96 const splitKey = key.split(".");
97 key = splitKey[0];
98 subKey = splitKey[1];
99 }
100 for (const exportKey in exports) {
101 const obj = exports[exportKey];
102 if (obj && obj[key] !== undefined) {
103 if (subKey) {
104 if (obj[key][subKey]) {
105 ret = obj;
106 break;
107 }
108 } else {
109 ret = obj;
110 break;
111 }
112 }
113 }
114
115 if (ret == null) {
116 logger.warn("Failed to find object by key", key, "in", exports, new Error().stack!.substring(5));
117 }
118
119 return ret;
120 },
121
122 findObjectFromValue: (exports: Record<string, any>, value: any) => {
123 let ret = null;
124 for (const exportKey in exports) {
125 const obj = exports[exportKey];
126 // eslint-disable-next-line eqeqeq
127 if (obj == value) {
128 ret = obj;
129 break;
130 }
131 for (const subKey in obj) {
132 // eslint-disable-next-line eqeqeq
133 if (obj && obj[subKey] == value) {
134 ret = obj;
135 break;
136 }
137 }
138 }
139
140 if (ret == null) {
141 logger.warn("Failed to find object by value", value, "in", exports, new Error().stack!.substring(5));
142 }
143
144 return ret;
145 },
146
147 findObjectFromKeyValuePair: (exports: Record<string, any>, key: string, value: any) => {
148 let ret = null;
149 for (const exportKey in exports) {
150 const obj = exports[exportKey];
151 // eslint-disable-next-line eqeqeq
152 if (obj && obj[key] == value) {
153 ret = obj;
154 break;
155 }
156 }
157
158 if (ret == null) {
159 logger.warn(
160 "Failed to find object by key value pair",
161 key,
162 value,
163 "in",
164 exports,
165 new Error().stack!.substring(5)
166 );
167 }
168
169 return null;
170 },
171
172 findFunctionByStrings: (exports: Record<string, any>, ...strings: (string | RegExp)[]) => {
173 const ret =
174 Object.entries(exports).filter(
175 ([index, func]) =>
176 typeof func === "function" && !strings.some((query) => !testFind(func.toString(), processFind(query)))
177 )?.[0]?.[1] ?? null;
178
179 if (ret == null) {
180 logger.warn("Failed to find function by strings", strings, "in", exports, new Error().stack!.substring(5));
181 }
182
183 return ret;
184 },
185
186 lazyLoad: (find: string | RegExp | (string | RegExp)[], chunk: RegExp, module: RegExp) => {
187 chunk = processFind(chunk);
188 module = processFind(module);
189
190 const mod = Array.isArray(find) ? spacepack.findByCode(...find) : spacepack.findByCode(find);
191 if (mod.length < 1) {
192 logger.warn("lazyLoad: Module find failed", find, chunk, module, new Error().stack!.substring(5));
193 return Promise.reject("Module find failed");
194 }
195
196 const findId = mod[0].id;
197 const findCode = webpackRequire.m[findId].toString().replace(/\n/g, "");
198
199 let chunkIds;
200 if (chunk.flags.includes("g")) {
201 chunkIds = [...findCode.matchAll(chunk)].map(([, id]) => id);
202 } else {
203 const match = findCode.match(chunk);
204 if (match) chunkIds = [...match[0].matchAll(/"(\d+)"/g)].map(([, id]) => id);
205 }
206
207 if (!chunkIds || chunkIds.length === 0) {
208 logger.warn("lazyLoad: Chunk ID match failed", find, chunk, module, new Error().stack!.substring(5));
209 return Promise.reject("Chunk ID match failed");
210 }
211
212 const moduleId = findCode.match(module)?.[1];
213 if (!moduleId) {
214 logger.warn("lazyLoad: Module ID match failed", find, chunk, module, new Error().stack!.substring(5));
215 return Promise.reject("Module ID match failed");
216 }
217
218 return Promise.all(chunkIds.map((c) => webpackRequire.e(c))).then(() => webpackRequire(moduleId));
219 },
220
221 filterReal: (modules: WebpackModule[]) => {
222 return modules.filter((module) => module.id.toString().match(/^\d+$/));
223 }
224};
225
226if (moonlight.getConfigOption<boolean>("spacepack", "addToGlobalScope") === true) {
227 window.spacepack = spacepack;
228}
229
230export default spacepack;