Skip to content

Commit acb85ba

Browse files
authored
fix: Restore original behavior broken for old architecture (#194)
2 parents b745ba1 + ec2809f commit acb85ba

File tree

1 file changed

+47
-19
lines changed

1 file changed

+47
-19
lines changed

src/entry.ts

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Metro } from "@metro/types";
22
import { version } from "bunny-build-info";
3+
const { instead } = require("spitroast");
34

45
// @ts-ignore - window is defined later in the bundle, so we assign it early
56
globalThis.window = globalThis;
@@ -33,29 +34,44 @@ if (typeof window.__r === "undefined") {
3334
// Revenge delays the execution of index.ts(x) because Revenge's initialization is asynchronous
3435
interface DeferredQueue {
3536
object: any;
36-
original: any;
3737
method: string;
38+
resume?: (queue: DeferredQueue) => void;
3839
args: any[];
3940
}
4041

4142
const deferredCalls: Array<DeferredQueue> = [];
42-
43-
const deferMethodExecution = (object: any, method: string, condition?: (...args: any[]) => boolean) => {
44-
const originalMethod = object[method];
45-
object[method] = (...args: any[]) => {
46-
if (condition && !condition(...args)) {
47-
originalMethod(...args);
48-
return;
43+
const unpatches: Array<() => void> = [];
44+
45+
const deferMethodExecution = (
46+
object: any,
47+
method: string,
48+
condition?: (...args: any[]) => boolean,
49+
resume?: (queue: DeferredQueue) => void,
50+
returnWith?: (queue: DeferredQueue) => any
51+
) => {
52+
const restore = instead(method, object, function (this: any, args: any[], original: any) {
53+
if (!condition || condition(...args)) {
54+
const queue: DeferredQueue = { object, method, args, resume };
55+
deferredCalls.push(queue);
56+
return returnWith ? returnWith(queue) : undefined;
4957
}
5058

51-
deferredCalls.push({ object, original: originalMethod, method, args });
52-
};
59+
// If the condition is not met, we execute the original method immediately
60+
return original.apply(this, args);
61+
});
62+
63+
unpatches.push(restore);
5364
}
5465

55-
const resumeDeferredAndRestore = () => {
56-
for (const { object, method, args, original } of deferredCalls) {
57-
object[method] = original;
58-
object[method](...args);
66+
const resumeDeferred = () => {
67+
for (const queue of deferredCalls) {
68+
const { object, method, args, resume } = queue;
69+
70+
if (resume) {
71+
resume(queue);
72+
} else {
73+
object[method](...args);
74+
}
5975
}
6076

6177
deferredCalls.length = 0;
@@ -64,11 +80,20 @@ if (typeof window.__r === "undefined") {
6480
const onceIndexRequired = (originalRequire: Metro.RequireFn) => {
6581
// We hold calls from the native side
6682
if (window.__fbBatchedBridge) {
67-
deferMethodExecution(window.__fbBatchedBridge, "callFunctionReturnFlushedQueue", args => {
83+
const batchedBridge = window.__fbBatchedBridge;
84+
deferMethodExecution(
85+
batchedBridge,
86+
"callFunctionReturnFlushedQueue",
6887
// If the call is to AppRegistry, we want to defer it because it is not yet registered (Revenge delays it)
6988
// Same goes to the non-callable modules, which are not registered yet, so we ensure that only registered ones can get through
70-
return args[0] !== "AppRegistry" && window.__fbBatchedBridge.getCallableModule(args[0]);
71-
});
89+
(...args) => args[0] === "AppRegistry" || !batchedBridge.getCallableModule(args[0]),
90+
({ args }) => {
91+
if (batchedBridge.getCallableModule(args[0])) {
92+
batchedBridge.__callFunction(...args);
93+
}
94+
},
95+
() => batchedBridge.flushedQueue()
96+
);
7297
}
7398

7499
// Introduced since RN New Architecture
@@ -78,9 +103,12 @@ if (typeof window.__r === "undefined") {
78103

79104
const startDiscord = async () => {
80105
await initializeRevenge();
81-
originalRequire(0);
106+
107+
for (const unpatch of unpatches) unpatch();
108+
unpatches.length = 0;
82109

83-
resumeDeferredAndRestore();
110+
originalRequire(0);
111+
resumeDeferred();
84112
};
85113

86114
startDiscord();

0 commit comments

Comments
 (0)