react-native-ai-debugger 1.10.9 → 1.10.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/__tests__/setup.js +11 -5
- package/build/__tests__/setup.js.map +1 -1
- package/build/__tests__/unit/iconSemantics.test.d.ts +2 -0
- package/build/__tests__/unit/iconSemantics.test.d.ts.map +1 -0
- package/build/__tests__/unit/iconSemantics.test.js +80 -0
- package/build/__tests__/unit/iconSemantics.test.js.map +1 -0
- package/build/__tests__/unit/screenState.test.d.ts +2 -0
- package/build/__tests__/unit/screenState.test.d.ts.map +1 -0
- package/build/__tests__/unit/screenState.test.js +186 -0
- package/build/__tests__/unit/screenState.test.js.map +1 -0
- package/build/core/connection.d.ts.map +1 -1
- package/build/core/connection.js +57 -2
- package/build/core/connection.js.map +1 -1
- package/build/core/debugGlobals.d.ts.map +1 -1
- package/build/core/debugGlobals.js +29 -0
- package/build/core/debugGlobals.js.map +1 -1
- package/build/core/executor.d.ts +1 -0
- package/build/core/executor.d.ts.map +1 -1
- package/build/core/executor.js +1 -0
- package/build/core/executor.js.map +1 -1
- package/build/core/guides.js +5 -5
- package/build/core/iconSemantics.d.ts +18 -0
- package/build/core/iconSemantics.d.ts.map +1 -0
- package/build/core/iconSemantics.js +114 -0
- package/build/core/iconSemantics.js.map +1 -0
- package/build/core/index.d.ts +3 -1
- package/build/core/index.d.ts.map +1 -1
- package/build/core/index.js +3 -1
- package/build/core/index.js.map +1 -1
- package/build/core/pressables.d.ts +2 -0
- package/build/core/pressables.d.ts.map +1 -1
- package/build/core/pressables.js +51 -21
- package/build/core/pressables.js.map +1 -1
- package/build/core/screenState.d.ts +98 -0
- package/build/core/screenState.d.ts.map +1 -0
- package/build/core/screenState.js +1120 -0
- package/build/core/screenState.js.map +1 -0
- package/build/core/types.d.ts +1 -0
- package/build/core/types.d.ts.map +1 -1
- package/build/tools/componentTools.d.ts.map +1 -1
- package/build/tools/componentTools.js +48 -5
- package/build/tools/componentTools.js.map +1 -1
- package/build/tools/metaTools.d.ts.map +1 -1
- package/build/tools/metaTools.js +6 -5
- package/build/tools/metaTools.js.map +1 -1
- package/build/tools/screenshotTools.d.ts.map +1 -1
- package/build/tools/screenshotTools.js +105 -40
- package/build/tools/screenshotTools.js.map +1 -1
- package/package.json +1 -1
package/build/__tests__/setup.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { afterEach } from "@jest/globals";
|
|
2
2
|
afterEach(async () => {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
try {
|
|
4
|
+
const { cancelAllReconnectionTimers, clearAllConnectionState } = await import("../core/connectionState.js");
|
|
5
|
+
const { pendingExecutions } = await import("../core/state.js");
|
|
6
|
+
cancelAllReconnectionTimers();
|
|
7
|
+
clearAllConnectionState();
|
|
8
|
+
pendingExecutions.clear();
|
|
9
|
+
}
|
|
10
|
+
catch (e) {
|
|
11
|
+
// Silently ignore import errors in test environment
|
|
12
|
+
// Some core modules use import.meta which may not work in all Jest contexts
|
|
13
|
+
}
|
|
8
14
|
});
|
|
9
15
|
//# sourceMappingURL=setup.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/__tests__/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,SAAS,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,GAAG,MAAM,MAAM,CACzE,4BAA4B,CAC/B,CAAC;
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/__tests__/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,SAAS,CAAC,KAAK,IAAI,EAAE;IACjB,IAAI,CAAC;QACD,MAAM,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,GAAG,MAAM,MAAM,CACzE,4BAA4B,CAC/B,CAAC;QACF,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QAC/D,2BAA2B,EAAE,CAAC;QAC9B,uBAAuB,EAAE,CAAC;QAC1B,iBAAiB,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,oDAAoD;QACpD,4EAA4E;IAChF,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"iconSemantics.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/iconSemantics.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { describe, it, expect } from "@jest/globals";
|
|
2
|
+
import { iconSemanticHint, iconLabel } from "../../core/iconSemantics.js";
|
|
3
|
+
import { applyIconHintToLabel } from "../../core/screenState.js";
|
|
4
|
+
describe("iconSemanticHint", () => {
|
|
5
|
+
it("maps chevron/arrow + direction composites", () => {
|
|
6
|
+
expect(iconSemanticHint("SvgChevronBackward")).toBe("possibly back button");
|
|
7
|
+
expect(iconSemanticHint("ChevronLeft")).toBe("possibly back button");
|
|
8
|
+
expect(iconSemanticHint("ArrowRightIcon")).toBe("possibly forward/next button");
|
|
9
|
+
expect(iconSemanticHint("CaretDown")).toBe("possibly expand/open button");
|
|
10
|
+
expect(iconSemanticHint("chevron-up")).toBe("possibly collapse button");
|
|
11
|
+
});
|
|
12
|
+
it("maps standalone icon keywords", () => {
|
|
13
|
+
expect(iconSemanticHint("SvgClose")).toBe("possibly close button");
|
|
14
|
+
expect(iconSemanticHint("CheckboxOutline")).toBe("possibly checkbox");
|
|
15
|
+
expect(iconSemanticHint("RadioOn")).toBe("possibly radio button");
|
|
16
|
+
expect(iconSemanticHint("BackIcon")).toBe("possibly back button");
|
|
17
|
+
expect(iconSemanticHint("IconTrashCan")).toBe("possibly delete button");
|
|
18
|
+
expect(iconSemanticHint("HamburgerMenu")).toBe("possibly menu button");
|
|
19
|
+
expect(iconSemanticHint("SearchOutline")).toBe("possibly search button");
|
|
20
|
+
expect(iconSemanticHint("PlusCircle")).toBe("possibly add button");
|
|
21
|
+
expect(iconSemanticHint("DotsVertical")).toBe("possibly more-options button");
|
|
22
|
+
});
|
|
23
|
+
it("prefers checkbox over check", () => {
|
|
24
|
+
expect(iconSemanticHint("SvgCheckbox")).toBe("possibly checkbox");
|
|
25
|
+
expect(iconSemanticHint("SvgCheckmark")).toBe("possibly confirm/check button");
|
|
26
|
+
});
|
|
27
|
+
it("matches whole words only — no substring false positives", () => {
|
|
28
|
+
expect(iconSemanticHint("FeedbackForm")).toBeNull();
|
|
29
|
+
expect(iconSemanticHint("BackgroundView")).toBeNull();
|
|
30
|
+
expect(iconSemanticHint("Checkout")).toBeNull();
|
|
31
|
+
expect(iconSemanticHint("StarterKit")).toBeNull();
|
|
32
|
+
});
|
|
33
|
+
it("returns null for non-icon names and empty input", () => {
|
|
34
|
+
expect(iconSemanticHint("FloatingHeader")).toBeNull();
|
|
35
|
+
expect(iconSemanticHint("SneakerCard")).toBeNull();
|
|
36
|
+
expect(iconSemanticHint(null)).toBeNull();
|
|
37
|
+
expect(iconSemanticHint(undefined)).toBeNull();
|
|
38
|
+
expect(iconSemanticHint("")).toBeNull();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
describe("iconLabel", () => {
|
|
42
|
+
it("combines the icon component name with the hint", () => {
|
|
43
|
+
expect(iconLabel("FloatingHeader", "SvgChevronBackward")).toBe("SvgChevronBackward — possibly back button");
|
|
44
|
+
});
|
|
45
|
+
it("falls back to the component name when no icon child is known", () => {
|
|
46
|
+
expect(iconLabel("CloseIcon", null)).toBe("CloseIcon — possibly close button");
|
|
47
|
+
});
|
|
48
|
+
it("returns null when neither name carries icon semantics", () => {
|
|
49
|
+
expect(iconLabel("FloatingHeader", null)).toBeNull();
|
|
50
|
+
expect(iconLabel("FloatingHeader", "FancyDecoration")).toBeNull();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe("applyIconHintToLabel", () => {
|
|
54
|
+
function pressable(overrides = {}) {
|
|
55
|
+
return {
|
|
56
|
+
label: "[FloatingHeader]",
|
|
57
|
+
center: { x: 40, y: 100 },
|
|
58
|
+
bounds: { x: 16, y: 76, width: 48, height: 48 },
|
|
59
|
+
testID: null,
|
|
60
|
+
...overrides,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
it("rewrites a fallback label using the icon hint", () => {
|
|
64
|
+
const p = applyIconHintToLabel(pressable({ icon: "SvgChevronBackward" }));
|
|
65
|
+
expect(p.label).toBe("[SvgChevronBackward — possibly back button]");
|
|
66
|
+
});
|
|
67
|
+
it("keeps the existing label when the icon name has no semantics", () => {
|
|
68
|
+
const p = applyIconHintToLabel(pressable({ icon: "FancyDecoration" }));
|
|
69
|
+
expect(p.label).toBe("[FloatingHeader]");
|
|
70
|
+
});
|
|
71
|
+
it("uses the icon name when there is no label at all", () => {
|
|
72
|
+
const p = applyIconHintToLabel(pressable({ label: null, icon: "FancyDecoration" }));
|
|
73
|
+
expect(p.label).toBe("[FancyDecoration]");
|
|
74
|
+
});
|
|
75
|
+
it("never touches text/a11y labels (icon is null for those)", () => {
|
|
76
|
+
const p = applyIconHintToLabel(pressable({ label: "Submit", icon: null }));
|
|
77
|
+
expect(p.label).toBe("Submit");
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
//# sourceMappingURL=iconSemantics.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"iconSemantics.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/iconSemantics.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenState.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/screenState.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { describe, it, expect } from "@jest/globals";
|
|
2
|
+
import { markPressablesCoveredByOverlay, parseScreenStateResponse, formatScreenStateSummary, describePressHandler, describePropHandlers, } from "../../core/screenState.js";
|
|
3
|
+
function pressable(overrides = {}) {
|
|
4
|
+
return {
|
|
5
|
+
label: "Button",
|
|
6
|
+
center: { x: 100, y: 100 },
|
|
7
|
+
bounds: { x: 80, y: 80, width: 40, height: 40 },
|
|
8
|
+
testID: null,
|
|
9
|
+
...overrides,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
describe("markPressablesCoveredByOverlay", () => {
|
|
13
|
+
const overlay = { x: 0, y: 400, width: 375, height: 300 };
|
|
14
|
+
it("does not flag pressable fully above the overlay", () => {
|
|
15
|
+
const p = pressable({ bounds: { x: 10, y: 50, width: 100, height: 44 } });
|
|
16
|
+
const result = markPressablesCoveredByOverlay([p], overlay);
|
|
17
|
+
expect(result[0].blockedByOverlay).toBeUndefined();
|
|
18
|
+
});
|
|
19
|
+
it("flags pressable fully inside the overlay bounds", () => {
|
|
20
|
+
const p = pressable({ bounds: { x: 50, y: 450, width: 100, height: 44 } });
|
|
21
|
+
const result = markPressablesCoveredByOverlay([p], overlay);
|
|
22
|
+
expect(result[0].blockedByOverlay).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
it("does not flag pressable that partially overlaps (only fully covered ones are blocked)", () => {
|
|
25
|
+
const p = pressable({ bounds: { x: 50, y: 380, width: 100, height: 60 } });
|
|
26
|
+
const result = markPressablesCoveredByOverlay([p], overlay);
|
|
27
|
+
expect(result[0].blockedByOverlay).toBeUndefined();
|
|
28
|
+
});
|
|
29
|
+
it("handles empty pressables list", () => {
|
|
30
|
+
expect(markPressablesCoveredByOverlay([], overlay)).toHaveLength(0);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe("parseScreenStateResponse", () => {
|
|
34
|
+
it("returns null for null input", () => {
|
|
35
|
+
expect(parseScreenStateResponse(null)).toBeNull();
|
|
36
|
+
});
|
|
37
|
+
it("returns null when response has error field", () => {
|
|
38
|
+
expect(parseScreenStateResponse({ error: "No hook found" })).toBeNull();
|
|
39
|
+
});
|
|
40
|
+
it("parses a full response with route, overlays, and pressables", () => {
|
|
41
|
+
const raw = {
|
|
42
|
+
route: { name: "ProductDetails", params: { productId: "123" }, stack: ["Home", "ProductDetails"] },
|
|
43
|
+
overlays: [
|
|
44
|
+
{
|
|
45
|
+
type: "BottomSheet",
|
|
46
|
+
title: "Select Size",
|
|
47
|
+
pressables: [
|
|
48
|
+
{ label: "S", center: { x: 70, y: 582 }, bounds: { x: 40, y: 560, width: 60, height: 44 }, testID: null },
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
pressables: [
|
|
53
|
+
{ label: "Back", center: { x: 38, y: 78 }, bounds: { x: 16, y: 56, width: 44, height: 44 }, testID: null },
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
const result = parseScreenStateResponse(raw);
|
|
57
|
+
expect(result).not.toBeNull();
|
|
58
|
+
expect(result.route.name).toBe("ProductDetails");
|
|
59
|
+
expect(result.route.stack).toEqual(["Home", "ProductDetails"]);
|
|
60
|
+
expect(result.overlays).toHaveLength(1);
|
|
61
|
+
expect(result.overlays[0].type).toBe("BottomSheet");
|
|
62
|
+
expect(result.overlays[0].pressables).toHaveLength(1);
|
|
63
|
+
expect(result.pressables).toHaveLength(1);
|
|
64
|
+
expect(result.pressables[0].label).toBe("Back");
|
|
65
|
+
});
|
|
66
|
+
it("parses a response with null route (no navigation library)", () => {
|
|
67
|
+
const raw = { route: null, overlays: [], pressables: [] };
|
|
68
|
+
const result = parseScreenStateResponse(raw);
|
|
69
|
+
expect(result).not.toBeNull();
|
|
70
|
+
expect(result.route).toBeNull();
|
|
71
|
+
expect(result.overlays).toHaveLength(0);
|
|
72
|
+
});
|
|
73
|
+
it("defaults overlays and pressables to empty arrays when missing", () => {
|
|
74
|
+
const raw = { route: null };
|
|
75
|
+
const result = parseScreenStateResponse(raw);
|
|
76
|
+
expect(result.overlays).toEqual([]);
|
|
77
|
+
expect(result.pressables).toEqual([]);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe("describePressHandler", () => {
|
|
81
|
+
it("returns named handlers as calls", () => {
|
|
82
|
+
expect(describePressHandler({ n: "handleSubmit", s: "" })).toBe("handleSubmit()");
|
|
83
|
+
expect(describePressHandler({ n: "startProcessing", s: "function startProcessing() {…}" })).toBe("startProcessing()");
|
|
84
|
+
});
|
|
85
|
+
it("strips the 'bound ' prefix", () => {
|
|
86
|
+
expect(describePressHandler({ n: "bound goBack", s: "" })).toBe("goBack()");
|
|
87
|
+
});
|
|
88
|
+
it("rejects generic and minified names, falling back to source", () => {
|
|
89
|
+
expect(describePressHandler({ n: "onPress", s: "() => setAccepted(prev => !prev)" })).toBe("{() => setAccepted(prev => !prev)}");
|
|
90
|
+
expect(describePressHandler({ n: "t12", s: "" })).toBeNull();
|
|
91
|
+
expect(describePressHandler({ n: "anonymous", s: "" })).toBeNull();
|
|
92
|
+
expect(describePressHandler({ n: "e", s: "" })).toBeNull();
|
|
93
|
+
});
|
|
94
|
+
it("truncates long source snippets", () => {
|
|
95
|
+
const longSrc = "() => " + "x".repeat(100);
|
|
96
|
+
const out = describePressHandler({ n: "", s: longSrc });
|
|
97
|
+
expect(out).toContain("…");
|
|
98
|
+
expect(out.length).toBeLessThan(80);
|
|
99
|
+
});
|
|
100
|
+
it("returns null for bytecode bundles (source stripped in-app) and bad input", () => {
|
|
101
|
+
expect(describePressHandler({ n: "", s: "" })).toBeNull();
|
|
102
|
+
expect(describePressHandler(null)).toBeNull();
|
|
103
|
+
expect(describePressHandler(undefined)).toBeNull();
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe("describePropHandlers", () => {
|
|
107
|
+
it("prefers the identity-matched prop and shows its named handler", () => {
|
|
108
|
+
const raw = [
|
|
109
|
+
{ p: "onRightPress", n: "", same: false },
|
|
110
|
+
{ p: "onBack", n: "goBack", same: true },
|
|
111
|
+
];
|
|
112
|
+
expect(describePropHandlers(raw)).toBe("onBack=goBack()");
|
|
113
|
+
});
|
|
114
|
+
it("reports the prop route when the matched handler is anonymous", () => {
|
|
115
|
+
expect(describePropHandlers([{ p: "onBack", n: "", same: true }])).toBe("onPress→onBack");
|
|
116
|
+
});
|
|
117
|
+
it("suppresses a nameless plain onPress prop (adds nothing)", () => {
|
|
118
|
+
expect(describePropHandlers([{ p: "onPress", n: "", same: true }])).toBeNull();
|
|
119
|
+
expect(describePropHandlers([{ p: "onPress", n: "onPress", same: true }])).toBeNull();
|
|
120
|
+
});
|
|
121
|
+
it("uses the only candidate when there is no identity match", () => {
|
|
122
|
+
expect(describePropHandlers([{ p: "onSelect", n: "", same: false }])).toBe("onPress→onSelect");
|
|
123
|
+
});
|
|
124
|
+
it("returns null on ambiguity (several candidates, none identity-matched)", () => {
|
|
125
|
+
const raw = [
|
|
126
|
+
{ p: "onBack", n: "", same: false },
|
|
127
|
+
{ p: "onRightPress", n: "", same: false },
|
|
128
|
+
];
|
|
129
|
+
expect(describePropHandlers(raw)).toBeNull();
|
|
130
|
+
});
|
|
131
|
+
it("returns null for empty or malformed input", () => {
|
|
132
|
+
expect(describePropHandlers(null)).toBeNull();
|
|
133
|
+
expect(describePropHandlers([])).toBeNull();
|
|
134
|
+
expect(describePropHandlers("nope")).toBeNull();
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
describe("formatScreenStateSummary", () => {
|
|
138
|
+
const state = {
|
|
139
|
+
route: { name: "Checkout", params: { id: "7" }, stack: ["Tabs", "Cart", "Checkout"] },
|
|
140
|
+
overlays: [],
|
|
141
|
+
pressables: [
|
|
142
|
+
pressable({
|
|
143
|
+
label: "Send",
|
|
144
|
+
component: "Button",
|
|
145
|
+
center: { x: 210, y: 838 },
|
|
146
|
+
bounds: { x: 20, y: 810, width: 380, height: 56 },
|
|
147
|
+
}),
|
|
148
|
+
pressable({
|
|
149
|
+
label: "[CheckBox — possibly confirm/check button]",
|
|
150
|
+
component: "CheckBox",
|
|
151
|
+
nearbyText: "Skip verification.",
|
|
152
|
+
center: { x: 31, y: 719 },
|
|
153
|
+
bounds: { x: 20, y: 708, width: 22, height: 22 },
|
|
154
|
+
}),
|
|
155
|
+
],
|
|
156
|
+
};
|
|
157
|
+
it("renders route, params, component tags, labels, nearby text, and frames", () => {
|
|
158
|
+
const out = formatScreenStateSummary(state);
|
|
159
|
+
expect(out).toContain('📍 Currently focused screen: "Checkout" [navigation stack: Tabs > Cart > Checkout]');
|
|
160
|
+
expect(out).toContain('route params: {"id":"7"}');
|
|
161
|
+
expect(out).toContain('(210, 838) <Button /> "Send" frame:(20,810 380x56)');
|
|
162
|
+
expect(out).toContain('near "Skip verification."');
|
|
163
|
+
});
|
|
164
|
+
it("applies the coordinate converter to centers and frames", () => {
|
|
165
|
+
const out = formatScreenStateSummary(state, (p) => ({
|
|
166
|
+
center: { x: p.center.x * 2, y: p.center.y * 2 },
|
|
167
|
+
frame: { x: p.bounds.x * 2, y: p.bounds.y * 2, width: p.bounds.width * 2, height: p.bounds.height * 2 },
|
|
168
|
+
}));
|
|
169
|
+
expect(out).toContain('(420, 1676) <Button /> "Send" frame:(40,1620 760x112)');
|
|
170
|
+
});
|
|
171
|
+
it("groups overlay pressables and lists blocked root pressables separately", () => {
|
|
172
|
+
const withOverlay = {
|
|
173
|
+
route: null,
|
|
174
|
+
overlays: [{ type: "BottomSheet", title: null, pressables: [pressable({ label: "Submit" })] }],
|
|
175
|
+
pressables: [pressable({ label: "Send", blockedByOverlay: true })],
|
|
176
|
+
};
|
|
177
|
+
const out = formatScreenStateSummary(withOverlay);
|
|
178
|
+
expect(out).toContain("📍 Currently focused screen: unknown");
|
|
179
|
+
expect(out).toContain("🔲 BottomSheet:");
|
|
180
|
+
expect(out).toContain('"Submit"');
|
|
181
|
+
expect(out).toContain("🎯 Root pressables: (none reachable)");
|
|
182
|
+
expect(out).toContain("🚫 Blocked by overlay");
|
|
183
|
+
expect(out).toContain('"Send"');
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
//# sourceMappingURL=screenState.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenState.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/screenState.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/core/connection.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,IAAI,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,YAAY,EAAoB,YAAY,EAAkB,cAAc,EAAsB,sBAAsB,EAAmB,qBAAqB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/core/connection.ts"],"names":[],"mappings":"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"}
|
package/build/core/connection.js
CHANGED
|
@@ -20,6 +20,15 @@ const pendingNetworkEnableIds = new Set();
|
|
|
20
20
|
const pendingSdkProbeIds = new Map(); // msgId -> appKey
|
|
21
21
|
const SDK_PROBE_INITIAL_DELAY_MS = 200;
|
|
22
22
|
const SDK_PROBE_INTERVAL_MS = 3000;
|
|
23
|
+
// Consecutive SDK-absent probes required to flip sdkPresent true→false.
|
|
24
|
+
// Hysteresis against the post-reload window where the JS context exists but
|
|
25
|
+
// the SDK's init() hasn't re-run yet (see ConnectedApp.sdkMissCount).
|
|
26
|
+
const SDK_ABSENCE_CONFIRM_COUNT = 2;
|
|
27
|
+
// Fast re-probe schedule after a context is (re)created, so the SDK is
|
|
28
|
+
// re-detected within a few hundred ms instead of waiting up to a full
|
|
29
|
+
// SDK_PROBE_INTERVAL_MS tick. Covers reloads not driven by reload_app
|
|
30
|
+
// (shake-to-reload, Metro "r").
|
|
31
|
+
const SDK_REPROBE_DELAYS_MS = [200, 500, 1000, 2000];
|
|
23
32
|
function sendSdkProbe(ws, appKey) {
|
|
24
33
|
if (ws.readyState !== WebSocket.OPEN)
|
|
25
34
|
return;
|
|
@@ -59,6 +68,20 @@ function startSdkProbeLoop(ws, appKey) {
|
|
|
59
68
|
clearInterval(interval);
|
|
60
69
|
});
|
|
61
70
|
}
|
|
71
|
+
// Fire a burst of SDK probes on the heels of a (re)created execution context.
|
|
72
|
+
// After a reload the context is recreated but the SDK's init() re-runs slightly
|
|
73
|
+
// later; without this, sdkPresent only recovers on the next 3s interval tick,
|
|
74
|
+
// widening the window where get_network_requests falls off the SDK buffer.
|
|
75
|
+
function scheduleFastSdkReprobe(ws, appKey) {
|
|
76
|
+
for (const delay of SDK_REPROBE_DELAYS_MS) {
|
|
77
|
+
const t = setTimeout(() => {
|
|
78
|
+
if (!connectedApps.has(appKey) || ws.readyState !== WebSocket.OPEN)
|
|
79
|
+
return;
|
|
80
|
+
sendSdkProbe(ws, appKey);
|
|
81
|
+
}, delay);
|
|
82
|
+
ws.once("close", () => clearTimeout(t));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
62
85
|
// Suppress auto-reconnection for intentionally disconnected devices
|
|
63
86
|
const reconnectionSuppressed = new Set();
|
|
64
87
|
/**
|
|
@@ -528,8 +551,25 @@ export function handleCDPMessage(message, device, ws) {
|
|
|
528
551
|
const result = message.result?.result;
|
|
529
552
|
const present = result?.value === true;
|
|
530
553
|
const wasPresent = app.sdkPresent === true;
|
|
531
|
-
|
|
532
|
-
|
|
554
|
+
// Hysteresis on the true→false edge: tolerate transient SDK
|
|
555
|
+
// absence right after a reload (context recreated, init() not
|
|
556
|
+
// re-run yet) so we don't restore duplicate-prone CDP/interceptor
|
|
557
|
+
// writes and bounce get_network_requests off the SDK buffer.
|
|
558
|
+
let nextPresent = present;
|
|
559
|
+
if (!present && wasPresent) {
|
|
560
|
+
app.sdkMissCount = (app.sdkMissCount ?? 0) + 1;
|
|
561
|
+
if (app.sdkMissCount < SDK_ABSENCE_CONFIRM_COUNT) {
|
|
562
|
+
nextPresent = true; // hold "present" until absence is confirmed
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
app.sdkMissCount = 0;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
app.sdkMissCount = 0;
|
|
570
|
+
}
|
|
571
|
+
app.sdkPresent = nextPresent;
|
|
572
|
+
if (nextPresent !== wasPresent) {
|
|
533
573
|
console.error(`[execbro] SDK ${present ? "detected" : "no longer detected"} on ${app.deviceInfo.title}; CDP/JS-interceptor buffer writes ${present ? "suppressed" : "restored"}`);
|
|
534
574
|
// Toggle the in-app interceptor's emit flag so it stops
|
|
535
575
|
// (or resumes) producing console.debug lines and CDP
|
|
@@ -650,6 +690,17 @@ export function handleCDPMessage(message, device, ws) {
|
|
|
650
690
|
if (nApp?.sdkPresent) {
|
|
651
691
|
return;
|
|
652
692
|
}
|
|
693
|
+
// An arriving Network.requestWillBeSent is proof the CDP Network domain
|
|
694
|
+
// is active. Some backends (e.g. RN 0.85 Bridgeless/Hermes) enable the
|
|
695
|
+
// domain but never send a response to Network.enable, so the
|
|
696
|
+
// response-based detection above never fires and cdpNetworkSupported
|
|
697
|
+
// stays undefined — leaving the JS interceptor un-suppressed and every
|
|
698
|
+
// request double-captured (CDP + interceptor). Mark support here so the
|
|
699
|
+
// interceptor dedup guard (see Runtime.consoleAPICalled handler) trips.
|
|
700
|
+
if (nApp && !nApp.cdpNetworkSupported) {
|
|
701
|
+
nApp.cdpNetworkSupported = true;
|
|
702
|
+
console.error(`[execbro] CDP Network domain active (detected via requestWillBeSent on ${nApp.deviceInfo.title})`);
|
|
703
|
+
}
|
|
653
704
|
const params = message.params;
|
|
654
705
|
const request = {
|
|
655
706
|
requestId: params.requestId,
|
|
@@ -717,6 +768,10 @@ export function handleCDPMessage(message, device, ws) {
|
|
|
717
768
|
injectNetworkInterceptor(ctxApp.ws);
|
|
718
769
|
const nEnableId = sendNetworkEnable(ctxApp.ws);
|
|
719
770
|
pendingNetworkEnableIds.add(nEnableId);
|
|
771
|
+
// The context was just recreated (e.g. reload). Re-probe the SDK
|
|
772
|
+
// quickly so sdkPresent re-establishes within a few hundred ms
|
|
773
|
+
// instead of on the next 3s interval tick.
|
|
774
|
+
scheduleFastSdkReprobe(ctxApp.ws, appKey);
|
|
720
775
|
}
|
|
721
776
|
}
|
|
722
777
|
// Handle Runtime.executionContextDestroyed
|