@appilots/sdk 0.8.0 → 0.10.0
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/README.md +5 -4
- package/dist/.build-meta.json +5 -0
- package/dist/{chunk-H7BMQTXH.js → chunk-2GCWCPSD.js} +19 -16
- package/dist/{chunk-C2KVVJ5K.mjs → chunk-AHHDOUVX.mjs} +1968 -386
- package/dist/{chunk-ZSEACJKU.mjs → chunk-IHPLS5FE.mjs} +16 -13
- package/dist/{chunk-N7EAOLBP.js → chunk-VX7AL4SA.js} +956 -1134
- package/dist/{chunk-MHWVRZYF.mjs → chunk-XHR65V2W.mjs} +736 -919
- package/dist/{chunk-AYWMBMSN.js → chunk-YB77RYCC.js} +1992 -384
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.js +11 -11
- package/dist/hooks/index.mjs +2 -2
- package/dist/{index-BdYY-dvG.d.mts → index-BPZ0j71S.d.mts} +254 -6
- package/dist/{index-BdYY-dvG.d.ts → index-BPZ0j71S.d.ts} +254 -6
- package/dist/index.d.mts +306 -21
- package/dist/index.d.ts +306 -21
- package/dist/index.js +337 -229
- package/dist/index.mjs +269 -173
- package/dist/navigation/index.d.mts +171 -3
- package/dist/navigation/index.d.ts +171 -3
- package/dist/navigation/index.js +13 -13
- package/dist/navigation/index.mjs +2 -2
- package/metro.d.ts +16 -1
- package/metro.js +104 -10
- package/package.json +4 -2
- package/dist/registerScreen-D1oGm28T.d.mts +0 -159
- package/dist/registerScreen-D1oGm28T.d.ts +0 -159
|
@@ -1,660 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkYB77RYCC_js = require('./chunk-YB77RYCC.js');
|
|
4
|
+
var React = require('react');
|
|
5
5
|
var reactNative = require('react-native');
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (typeof type === "string") return type;
|
|
11
|
-
if (typeof type === "function") {
|
|
12
|
-
return type.displayName ?? type.name ?? null;
|
|
13
|
-
}
|
|
14
|
-
if (typeof type === "object") {
|
|
15
|
-
if (type.displayName) return type.displayName;
|
|
16
|
-
if (type.render) {
|
|
17
|
-
return type.render.displayName ?? type.render.name ?? null;
|
|
18
|
-
}
|
|
19
|
-
if (type.type) return getTypeName(type.type);
|
|
20
|
-
}
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
function matchesName(fiber, name) {
|
|
24
|
-
return getTypeName(fiber.type) === name || getTypeName(fiber.elementType) === name;
|
|
25
|
-
}
|
|
26
|
-
function extractTextFromChildren(children) {
|
|
27
|
-
if (children == null) return "";
|
|
28
|
-
if (typeof children === "string") return children;
|
|
29
|
-
if (typeof children === "number") return String(children);
|
|
30
|
-
if (Array.isArray(children)) {
|
|
31
|
-
return children.map((c) => extractTextFromChildren(c)).filter(Boolean).join("");
|
|
32
|
-
}
|
|
33
|
-
return "";
|
|
34
|
-
}
|
|
35
|
-
function hasMeaningfulText(text) {
|
|
36
|
-
return !!text && /[\p{L}\p{N}]/u.test(text);
|
|
37
|
-
}
|
|
38
|
-
function findChildText(fiber) {
|
|
39
|
-
const stack = [];
|
|
40
|
-
if (fiber.child) stack.push(fiber.child);
|
|
41
|
-
const visited = /* @__PURE__ */ new WeakSet();
|
|
42
|
-
const texts = [];
|
|
43
|
-
while (stack.length > 0) {
|
|
44
|
-
const node = stack.pop();
|
|
45
|
-
if (!node || visited.has(node)) continue;
|
|
46
|
-
visited.add(node);
|
|
47
|
-
if (matchesName(node, "Text")) {
|
|
48
|
-
const text = extractTextFromChildren(node.memoizedProps?.children);
|
|
49
|
-
const trimmed = text.trim();
|
|
50
|
-
if (hasMeaningfulText(trimmed)) {
|
|
51
|
-
texts.push(trimmed);
|
|
52
|
-
if (texts.length >= 3) break;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
if (node.sibling) stack.push(node.sibling);
|
|
56
|
-
if (node.child) stack.push(node.child);
|
|
57
|
-
}
|
|
58
|
-
return texts.length > 0 ? texts.join(" \xB7 ") : void 0;
|
|
59
|
-
}
|
|
60
|
-
var SELF_REFERENTIAL_COMPONENTS = /* @__PURE__ */ new Set([
|
|
61
|
-
"AppilotsChat",
|
|
62
|
-
"AppilotsChatInner",
|
|
63
|
-
"ActionBreadcrumb",
|
|
64
|
-
"ConfirmDialog"
|
|
65
|
-
]);
|
|
66
|
-
function isAppilotsSkipMarked(props) {
|
|
67
|
-
if (!props) return false;
|
|
68
|
-
return props.__appilotsSkip === true || props["data-appilots-skip"] === true || props.appilotsSkip === true;
|
|
69
|
-
}
|
|
70
|
-
function isAppilotsSensitiveMarked(props) {
|
|
71
|
-
if (!props) return false;
|
|
72
|
-
return props.__appilotsSensitive === true || props["data-appilots-sensitive"] === true || props.appilotsSensitive === true;
|
|
73
|
-
}
|
|
74
|
-
function stringProp(props, name) {
|
|
75
|
-
const value = props?.[name];
|
|
76
|
-
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
77
|
-
}
|
|
78
|
-
function numberProp(props, name) {
|
|
79
|
-
const value = props?.[name];
|
|
80
|
-
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
81
|
-
}
|
|
82
|
-
function shouldSkipSubtree(fiber) {
|
|
83
|
-
const props = fiber.memoizedProps;
|
|
84
|
-
if (!props) return false;
|
|
85
|
-
const typeName = getTypeName(fiber.type) ?? getTypeName(fiber.elementType);
|
|
86
|
-
if (typeName && SELF_REFERENTIAL_COMPONENTS.has(typeName)) return true;
|
|
87
|
-
if (isAppilotsSkipMarked(props)) return true;
|
|
88
|
-
if (matchesName(fiber, "Modal") && props.visible === false) return true;
|
|
89
|
-
if (matchesName(fiber, "Screen") && props.activityState === 0) return true;
|
|
90
|
-
const style = props.style;
|
|
91
|
-
if (style) {
|
|
92
|
-
const flat = Array.isArray(style) ? Object.assign({}, ...style.filter(Boolean)) : style;
|
|
93
|
-
if (flat?.display === "none") return true;
|
|
94
|
-
if (flat?.opacity === 0 && props.pointerEvents === "none") return true;
|
|
95
|
-
}
|
|
96
|
-
return false;
|
|
97
|
-
}
|
|
98
|
-
function inferInputType(props) {
|
|
99
|
-
if (props.secureTextEntry || isAppilotsSensitiveMarked(props)) return "password";
|
|
100
|
-
switch (props.keyboardType) {
|
|
101
|
-
case "email-address":
|
|
102
|
-
return "email";
|
|
103
|
-
case "numeric":
|
|
104
|
-
case "number-pad":
|
|
105
|
-
case "decimal-pad":
|
|
106
|
-
return "number";
|
|
107
|
-
case "phone-pad":
|
|
108
|
-
return "phone";
|
|
109
|
-
default:
|
|
110
|
-
return "text";
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
function inferLabel(props) {
|
|
114
|
-
return props.accessibilityLabel ?? props.label ?? props.placeholder ?? props.testID;
|
|
115
|
-
}
|
|
116
|
-
function bestId(props) {
|
|
117
|
-
return props.testID ?? props.accessibilityLabel ?? void 0;
|
|
118
|
-
}
|
|
119
|
-
var ALWAYS_LIST_NAMES = /* @__PURE__ */ new Set([
|
|
120
|
-
"FlatList",
|
|
121
|
-
"SectionList",
|
|
122
|
-
"VirtualizedList",
|
|
123
|
-
// Shopify's high-perf FlatList replacement — same usage shape, same
|
|
124
|
-
// virtualization, same per-item key.
|
|
125
|
-
"FlashList"
|
|
126
|
-
]);
|
|
127
|
-
var HEURISTIC_LIST_NAMES = /* @__PURE__ */ new Set(["ScrollView"]);
|
|
128
|
-
var LIST_CELL_NAMES = /* @__PURE__ */ new Set([
|
|
129
|
-
"CellRenderer",
|
|
130
|
-
"CellRendererComponent",
|
|
131
|
-
"VirtualizedListCellContextProvider"
|
|
132
|
-
]);
|
|
133
|
-
function isAlwaysListContainer(fiber) {
|
|
134
|
-
for (const name of ALWAYS_LIST_NAMES) {
|
|
135
|
-
if (matchesName(fiber, name)) return true;
|
|
136
|
-
}
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
function isHeuristicListContainer(fiber) {
|
|
140
|
-
for (const name of HEURISTIC_LIST_NAMES) {
|
|
141
|
-
if (matchesName(fiber, name)) return true;
|
|
142
|
-
}
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
|
-
function isKnownListCell(fiber) {
|
|
146
|
-
const typeName = getTypeName(fiber.type) ?? getTypeName(fiber.elementType);
|
|
147
|
-
return !!typeName && LIST_CELL_NAMES.has(typeName);
|
|
148
|
-
}
|
|
149
|
-
function isModalFiber(fiber) {
|
|
150
|
-
return matchesName(fiber, "Modal");
|
|
151
|
-
}
|
|
152
|
-
function isVisibleModalFiber(fiber) {
|
|
153
|
-
return isModalFiber(fiber) && fiber?.memoizedProps?.visible !== false;
|
|
154
|
-
}
|
|
155
|
-
function collectVisibleModalFibers(container, excludeRoots = []) {
|
|
156
|
-
const excluded = /* @__PURE__ */ new WeakSet();
|
|
157
|
-
for (const rootFiber of excludeRoots) {
|
|
158
|
-
if (rootFiber) excluded.add(rootFiber);
|
|
159
|
-
}
|
|
160
|
-
const found = [];
|
|
161
|
-
const visited = /* @__PURE__ */ new WeakSet();
|
|
162
|
-
const stack = [];
|
|
163
|
-
if (container?.child) stack.push(container.child);
|
|
164
|
-
while (stack.length > 0) {
|
|
165
|
-
const node = stack.pop();
|
|
166
|
-
if (!node || visited.has(node)) continue;
|
|
167
|
-
visited.add(node);
|
|
168
|
-
if (node.sibling) stack.push(node.sibling);
|
|
169
|
-
if (excluded.has(node) || shouldSkipSubtree(node)) continue;
|
|
170
|
-
if (isVisibleModalFiber(node)) {
|
|
171
|
-
found.push(node);
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
if (node.child) stack.push(node.child);
|
|
175
|
-
}
|
|
176
|
-
return found;
|
|
177
|
-
}
|
|
178
|
-
function isMarkedListItem(fiber, listId) {
|
|
179
|
-
const props = fiber?.memoizedProps;
|
|
180
|
-
if (!props || props.__appilotsListItem !== true) return false;
|
|
181
|
-
if (!listId) return true;
|
|
182
|
-
return props.__appilotsListId === listId;
|
|
183
|
-
}
|
|
184
|
-
function listIdFromProps(props) {
|
|
185
|
-
return stringProp(props, "__appilotsListId") ?? stringProp(props, "appilotsListId");
|
|
186
|
-
}
|
|
187
|
-
function listMetadataFromProps(props) {
|
|
188
|
-
const id = listIdFromProps(props);
|
|
189
|
-
const itemCount = numberProp(props, "__appilotsItemCount");
|
|
190
|
-
const label = stringProp(props, "__appilotsListLabel") ?? stringProp(props, "accessibilityLabel") ?? stringProp(props, "testID");
|
|
191
|
-
const refreshing = props?.refreshing === true || props?.__appilotsRefreshing === true;
|
|
192
|
-
const empty = props?.__appilotsEmpty === true || typeof itemCount === "number" && itemCount === 0;
|
|
193
|
-
return {
|
|
194
|
-
id,
|
|
195
|
-
itemCount,
|
|
196
|
-
refreshing,
|
|
197
|
-
empty,
|
|
198
|
-
label,
|
|
199
|
-
source: id ? "auto-tracked" : void 0
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
function hasRenderableContent(fiber) {
|
|
203
|
-
const stack = [fiber];
|
|
204
|
-
const visited = /* @__PURE__ */ new WeakSet();
|
|
205
|
-
while (stack.length > 0) {
|
|
206
|
-
const node = stack.pop();
|
|
207
|
-
if (!node || visited.has(node)) continue;
|
|
208
|
-
visited.add(node);
|
|
209
|
-
if (shouldSkipSubtree(node) || isModalFiber(node)) continue;
|
|
210
|
-
const props = node.memoizedProps ?? {};
|
|
211
|
-
if (matchesName(node, "Text")) {
|
|
212
|
-
const text = extractTextFromChildren(props.children);
|
|
213
|
-
if (text && text.trim().length > 0) return true;
|
|
214
|
-
}
|
|
215
|
-
if (matchesName(node, "TextInput") || matchesName(node, "Switch")) {
|
|
216
|
-
return true;
|
|
217
|
-
}
|
|
218
|
-
if (TOUCHABLE_NAMES.has(getTypeName(node.type) ?? "") || TOUCHABLE_NAMES.has(getTypeName(node.elementType) ?? "")) {
|
|
219
|
-
return true;
|
|
220
|
-
}
|
|
221
|
-
if (node.sibling) stack.push(node.sibling);
|
|
222
|
-
if (node.child) stack.push(node.child);
|
|
223
|
-
}
|
|
224
|
-
return false;
|
|
225
|
-
}
|
|
226
|
-
function findListCellsByType(container, minItems) {
|
|
227
|
-
const cells = [];
|
|
228
|
-
const visited = /* @__PURE__ */ new WeakSet();
|
|
229
|
-
const stack = [];
|
|
230
|
-
if (container?.child) stack.push(container.child);
|
|
231
|
-
while (stack.length > 0) {
|
|
232
|
-
const node = stack.pop();
|
|
233
|
-
if (!node || visited.has(node)) continue;
|
|
234
|
-
visited.add(node);
|
|
235
|
-
if (node.sibling) stack.push(node.sibling);
|
|
236
|
-
if (shouldSkipSubtree(node) || isModalFiber(node)) continue;
|
|
237
|
-
if (isKnownListCell(node) && hasRenderableContent(node)) {
|
|
238
|
-
cells.push(node);
|
|
239
|
-
continue;
|
|
240
|
-
}
|
|
241
|
-
if (node.child) stack.push(node.child);
|
|
242
|
-
}
|
|
243
|
-
return cells.length >= minItems ? cells : null;
|
|
244
|
-
}
|
|
245
|
-
function findMarkedListItems(container, minItems, listId) {
|
|
246
|
-
const items = [];
|
|
247
|
-
const visited = /* @__PURE__ */ new WeakSet();
|
|
248
|
-
const stack = [];
|
|
249
|
-
if (container?.child) stack.push(container.child);
|
|
250
|
-
while (stack.length > 0) {
|
|
251
|
-
const node = stack.pop();
|
|
252
|
-
if (!node || visited.has(node)) continue;
|
|
253
|
-
visited.add(node);
|
|
254
|
-
if (node.sibling) stack.push(node.sibling);
|
|
255
|
-
if (shouldSkipSubtree(node) || isModalFiber(node)) continue;
|
|
256
|
-
if (isMarkedListItem(node, listId)) {
|
|
257
|
-
items.push(node);
|
|
258
|
-
continue;
|
|
259
|
-
}
|
|
260
|
-
if (node.child) stack.push(node.child);
|
|
261
|
-
}
|
|
262
|
-
if (items.length < minItems) return null;
|
|
263
|
-
items.sort((a, b) => {
|
|
264
|
-
const ai = numberProp(a.memoizedProps, "__appilotsItemIndex");
|
|
265
|
-
const bi = numberProp(b.memoizedProps, "__appilotsItemIndex");
|
|
266
|
-
if (ai === void 0 && bi === void 0) return 0;
|
|
267
|
-
if (ai === void 0) return 1;
|
|
268
|
-
if (bi === void 0) return -1;
|
|
269
|
-
return ai - bi;
|
|
270
|
-
});
|
|
271
|
-
return items;
|
|
272
|
-
}
|
|
273
|
-
function hasAuthoredReactKey(fiber) {
|
|
274
|
-
const key = fiber?.key;
|
|
275
|
-
if (key === null || key === void 0 || key === "") return false;
|
|
276
|
-
const s = String(key);
|
|
277
|
-
if (s.startsWith(".") && !s.startsWith(".$")) return false;
|
|
278
|
-
return true;
|
|
279
|
-
}
|
|
280
|
-
function findKeyedSiblingItems(container, minItems) {
|
|
281
|
-
if (!container) return null;
|
|
282
|
-
let current = container;
|
|
283
|
-
const visited = /* @__PURE__ */ new WeakSet();
|
|
284
|
-
while (current && !visited.has(current)) {
|
|
285
|
-
visited.add(current);
|
|
286
|
-
const siblings = [];
|
|
287
|
-
let cur = current.child;
|
|
288
|
-
while (cur) {
|
|
289
|
-
if (!isModalFiber(cur)) siblings.push(cur);
|
|
290
|
-
cur = cur.sibling;
|
|
291
|
-
}
|
|
292
|
-
if (siblings.length === 0) return null;
|
|
293
|
-
const keyed = siblings.filter(hasAuthoredReactKey);
|
|
294
|
-
if (keyed.length >= minItems) {
|
|
295
|
-
return keyed;
|
|
296
|
-
}
|
|
297
|
-
if (siblings.length > 1) {
|
|
298
|
-
return null;
|
|
299
|
-
}
|
|
300
|
-
current = siblings[0];
|
|
301
|
-
}
|
|
302
|
-
return null;
|
|
303
|
-
}
|
|
304
|
-
function findListItems(container, minItems = 2, preferCells = false) {
|
|
305
|
-
if (!container) return null;
|
|
306
|
-
const listId = listIdFromProps(container.memoizedProps);
|
|
307
|
-
const markedItems = findMarkedListItems(container, minItems, listId);
|
|
308
|
-
if (markedItems) return markedItems;
|
|
309
|
-
if (preferCells) {
|
|
310
|
-
const cells = findListCellsByType(container, minItems);
|
|
311
|
-
if (cells) return cells;
|
|
312
|
-
}
|
|
313
|
-
if (minItems <= 1) {
|
|
314
|
-
const multiItemLevel = findKeyedSiblingItems(container, 2);
|
|
315
|
-
if (multiItemLevel) return multiItemLevel;
|
|
316
|
-
}
|
|
317
|
-
return findKeyedSiblingItems(container, minItems) ?? findListCellsByType(container, minItems);
|
|
318
|
-
}
|
|
319
|
-
var TOUCHABLE_NAMES = /* @__PURE__ */ new Set([
|
|
320
|
-
"TouchableOpacity",
|
|
321
|
-
"TouchableHighlight",
|
|
322
|
-
"TouchableWithoutFeedback",
|
|
323
|
-
"TouchableNativeFeedback",
|
|
324
|
-
"Pressable"
|
|
325
|
-
]);
|
|
326
|
-
function hasPressHandler(fiber) {
|
|
327
|
-
const props = fiber?.memoizedProps ?? {};
|
|
328
|
-
return typeof props.onPress === "function" || typeof props.onPressIn === "function";
|
|
329
|
-
}
|
|
330
|
-
function isPressableTarget(fiber) {
|
|
331
|
-
return TOUCHABLE_NAMES.has(getTypeName(fiber.type) ?? "") || TOUCHABLE_NAMES.has(getTypeName(fiber.elementType) ?? "") || hasPressHandler(fiber);
|
|
332
|
-
}
|
|
333
|
-
function walkSubtree(root, detectLists, startInModal = false) {
|
|
334
|
-
const result = {
|
|
335
|
-
texts: [],
|
|
336
|
-
inputs: [],
|
|
337
|
-
buttons: [],
|
|
338
|
-
toggles: [],
|
|
339
|
-
sliders: [],
|
|
340
|
-
visitedFibers: 0,
|
|
341
|
-
skippedHidden: 0,
|
|
342
|
-
loading: false,
|
|
343
|
-
modalOpen: false,
|
|
344
|
-
lists: []
|
|
345
|
-
};
|
|
346
|
-
if (!root) return result;
|
|
347
|
-
const visited = /* @__PURE__ */ new WeakSet();
|
|
348
|
-
const stack = [];
|
|
349
|
-
if (root.child) stack.push({ fiber: root.child, inModal: startInModal });
|
|
350
|
-
while (stack.length > 0) {
|
|
351
|
-
const { fiber, inModal } = stack.pop();
|
|
352
|
-
if (!fiber || visited.has(fiber)) continue;
|
|
353
|
-
visited.add(fiber);
|
|
354
|
-
result.visitedFibers++;
|
|
355
|
-
if (fiber.sibling) stack.push({ fiber: fiber.sibling, inModal });
|
|
356
|
-
if (shouldSkipSubtree(fiber)) {
|
|
357
|
-
result.skippedHidden++;
|
|
358
|
-
continue;
|
|
359
|
-
}
|
|
360
|
-
if (detectLists) {
|
|
361
|
-
const isAlways = isAlwaysListContainer(fiber);
|
|
362
|
-
const isHeuristic = !isAlways && isHeuristicListContainer(fiber);
|
|
363
|
-
if (isAlways || isHeuristic) {
|
|
364
|
-
const minItems = isAlways ? 1 : 2;
|
|
365
|
-
const items = findListItems(fiber, minItems, isAlways);
|
|
366
|
-
if (items && items.length >= minItems) {
|
|
367
|
-
const containerType = getTypeName(fiber.type) ?? getTypeName(fiber.elementType) ?? "List";
|
|
368
|
-
const listIndex = result.lists.length;
|
|
369
|
-
const itemSnapshots = items.map((itemFiber, i) => {
|
|
370
|
-
const itemResult = walkSubtree(itemFiber, false, inModal);
|
|
371
|
-
result.visitedFibers += itemResult.visitedFibers;
|
|
372
|
-
result.skippedHidden += itemResult.skippedHidden;
|
|
373
|
-
if (itemResult.loading) result.loading = true;
|
|
374
|
-
if (itemResult.modalOpen) result.modalOpen = true;
|
|
375
|
-
const reactKey = typeof itemFiber.key === "string" || typeof itemFiber.key === "number" ? String(itemFiber.key) : typeof itemFiber.memoizedProps?.__appilotsItemKey === "string" || typeof itemFiber.memoizedProps?.__appilotsItemKey === "number" ? String(itemFiber.memoizedProps.__appilotsItemKey) : void 0;
|
|
376
|
-
const itemKey = typeof itemFiber.memoizedProps?.__appilotsItemKey === "string" || typeof itemFiber.memoizedProps?.__appilotsItemKey === "number" ? String(itemFiber.memoizedProps.__appilotsItemKey) : void 0;
|
|
377
|
-
const dataIndex = numberProp(itemFiber.memoizedProps, "__appilotsItemIndex");
|
|
378
|
-
return {
|
|
379
|
-
index: i + 1,
|
|
380
|
-
dataIndex,
|
|
381
|
-
reactKey,
|
|
382
|
-
itemKey,
|
|
383
|
-
syntheticId: `list-${listIndex}-item-${i + 1}`,
|
|
384
|
-
texts: dedupeStringsInternal(itemResult.texts),
|
|
385
|
-
buttons: dedupeButtonsInternal(itemResult.buttons),
|
|
386
|
-
inputs: dedupeInputsInternal(itemResult.inputs),
|
|
387
|
-
toggles: dedupeTogglesInternal(itemResult.toggles)
|
|
388
|
-
};
|
|
389
|
-
});
|
|
390
|
-
const meta2 = listMetadataFromProps(fiber.memoizedProps);
|
|
391
|
-
result.lists.push({
|
|
392
|
-
index: listIndex,
|
|
393
|
-
id: meta2.id,
|
|
394
|
-
containerType,
|
|
395
|
-
source: meta2.source ?? "fiber",
|
|
396
|
-
itemCount: meta2.itemCount,
|
|
397
|
-
visibleItemCount: itemSnapshots.length,
|
|
398
|
-
refreshing: meta2.refreshing,
|
|
399
|
-
empty: meta2.empty,
|
|
400
|
-
label: meta2.label,
|
|
401
|
-
items: itemSnapshots
|
|
402
|
-
});
|
|
403
|
-
for (const modalFiber of collectVisibleModalFibers(fiber, items)) {
|
|
404
|
-
result.modalOpen = true;
|
|
405
|
-
if (modalFiber.child) stack.push({ fiber: modalFiber.child, inModal: true });
|
|
406
|
-
}
|
|
407
|
-
continue;
|
|
408
|
-
}
|
|
409
|
-
const meta = listMetadataFromProps(fiber.memoizedProps);
|
|
410
|
-
if (meta.id || meta.itemCount !== void 0 || meta.refreshing || meta.empty) {
|
|
411
|
-
const containerType = getTypeName(fiber.type) ?? getTypeName(fiber.elementType) ?? "List";
|
|
412
|
-
result.lists.push({
|
|
413
|
-
index: result.lists.length,
|
|
414
|
-
id: meta.id,
|
|
415
|
-
containerType,
|
|
416
|
-
source: meta.source ?? "auto-tracked",
|
|
417
|
-
itemCount: meta.itemCount,
|
|
418
|
-
visibleItemCount: 0,
|
|
419
|
-
refreshing: meta.refreshing,
|
|
420
|
-
empty: meta.empty,
|
|
421
|
-
label: meta.label,
|
|
422
|
-
items: []
|
|
423
|
-
});
|
|
424
|
-
for (const modalFiber of collectVisibleModalFibers(fiber)) {
|
|
425
|
-
result.modalOpen = true;
|
|
426
|
-
if (modalFiber.child) stack.push({ fiber: modalFiber.child, inModal: true });
|
|
427
|
-
}
|
|
428
|
-
continue;
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
const props = fiber.memoizedProps ?? {};
|
|
433
|
-
if (matchesName(fiber, "Text")) {
|
|
434
|
-
const text = extractTextFromChildren(props.children);
|
|
435
|
-
if (text && text.trim().length > 0) {
|
|
436
|
-
result.texts.push(text.trim());
|
|
437
|
-
}
|
|
438
|
-
} else if (matchesName(fiber, "TextInput")) {
|
|
439
|
-
if (props.__appilotsInternal !== true) {
|
|
440
|
-
const isSecure = !!props.secureTextEntry || isAppilotsSensitiveMarked(props);
|
|
441
|
-
const rawValue = typeof props.value === "string" ? props.value : void 0;
|
|
442
|
-
const safeValue = isSecure ? rawValue && rawValue.length > 0 ? "<hidden>" : void 0 : rawValue;
|
|
443
|
-
result.inputs.push({
|
|
444
|
-
id: bestId(props),
|
|
445
|
-
label: inferLabel(props),
|
|
446
|
-
value: safeValue,
|
|
447
|
-
placeholder: props.placeholder,
|
|
448
|
-
editable: props.editable !== false,
|
|
449
|
-
secure: isSecure,
|
|
450
|
-
type: inferInputType(props),
|
|
451
|
-
...inModal ? { inModal: true } : {}
|
|
452
|
-
});
|
|
453
|
-
}
|
|
454
|
-
} else if (props.accessibilityRole === "adjustable") {
|
|
455
|
-
if (props.__appilotsInternal !== true) {
|
|
456
|
-
const av = props.accessibilityValue ?? {};
|
|
457
|
-
result.sliders.push({
|
|
458
|
-
id: bestId(props),
|
|
459
|
-
label: props.accessibilityLabel ?? props.testID,
|
|
460
|
-
value: typeof av.now === "number" ? av.now : void 0,
|
|
461
|
-
min: typeof av.min === "number" ? av.min : void 0,
|
|
462
|
-
max: typeof av.max === "number" ? av.max : void 0,
|
|
463
|
-
...inModal ? { inModal: true } : {}
|
|
464
|
-
});
|
|
465
|
-
}
|
|
466
|
-
} else if (isPressableTarget(fiber)) {
|
|
467
|
-
if (props.__appilotsInternal !== true) {
|
|
468
|
-
const label = findChildText(fiber);
|
|
469
|
-
const selected = props.accessibilityState?.selected === true;
|
|
470
|
-
result.buttons.push({
|
|
471
|
-
id: bestId(props) ?? (label ? normalizeLabel(label) : void 0),
|
|
472
|
-
label,
|
|
473
|
-
disabled: !!props.disabled,
|
|
474
|
-
...selected ? { selected: true } : {},
|
|
475
|
-
...inModal ? { inModal: true } : {}
|
|
476
|
-
});
|
|
477
|
-
}
|
|
478
|
-
} else if (matchesName(fiber, "Switch")) {
|
|
479
|
-
result.toggles.push({
|
|
480
|
-
id: bestId(props),
|
|
481
|
-
label: props.accessibilityLabel ?? props.testID,
|
|
482
|
-
value: !!props.value,
|
|
483
|
-
...inModal ? { inModal: true } : {}
|
|
484
|
-
});
|
|
485
|
-
} else if (matchesName(fiber, "ActivityIndicator")) {
|
|
486
|
-
result.loading = true;
|
|
487
|
-
} else if (matchesName(fiber, "Modal")) {
|
|
488
|
-
result.modalOpen = true;
|
|
489
|
-
if (fiber.child) stack.push({ fiber: fiber.child, inModal: true });
|
|
490
|
-
continue;
|
|
491
|
-
}
|
|
492
|
-
if (fiber.child) stack.push({ fiber: fiber.child, inModal });
|
|
493
|
-
}
|
|
494
|
-
return result;
|
|
495
|
-
}
|
|
496
|
-
function walkFiber(root) {
|
|
497
|
-
const snapshot = {
|
|
498
|
-
route: chunkAYWMBMSN_js.getCurrentScreen(),
|
|
499
|
-
texts: [],
|
|
500
|
-
inputs: [],
|
|
501
|
-
buttons: [],
|
|
502
|
-
toggles: [],
|
|
503
|
-
// Sliders come from the ComponentRegistry (useAppilotsSlider) —
|
|
504
|
-
// captureSnapshot merges them so observation only ever advertises
|
|
505
|
-
// sliders the executor can actually set (min/max/step + setValue).
|
|
506
|
-
sliders: [],
|
|
507
|
-
loading: false,
|
|
508
|
-
modalOpen: false,
|
|
509
|
-
lists: [],
|
|
510
|
-
choiceGroups: [],
|
|
511
|
-
elements: [],
|
|
512
|
-
stats: { visitedFibers: 0, skippedHidden: 0 }
|
|
513
|
-
};
|
|
514
|
-
if (!root) return snapshot;
|
|
515
|
-
const sub = walkSubtree(root, true);
|
|
516
|
-
snapshot.texts = dedupeStringsInternal(sub.texts);
|
|
517
|
-
snapshot.inputs = dedupeInputsInternal(sub.inputs);
|
|
518
|
-
snapshot.buttons = dedupeButtonsInternal(sub.buttons);
|
|
519
|
-
snapshot.toggles = dedupeTogglesInternal(sub.toggles);
|
|
520
|
-
snapshot.sliders = dedupeSliders(sub.sliders);
|
|
521
|
-
snapshot.loading = sub.loading;
|
|
522
|
-
snapshot.modalOpen = sub.modalOpen;
|
|
523
|
-
snapshot.lists = sub.lists;
|
|
524
|
-
snapshot.choiceGroups = deriveChoiceGroups(snapshot);
|
|
525
|
-
snapshot.stats.visitedFibers = sub.visitedFibers;
|
|
526
|
-
snapshot.stats.skippedHidden = sub.skippedHidden;
|
|
527
|
-
return snapshot;
|
|
528
|
-
}
|
|
529
|
-
function dedupeButtonsInternal(buttons) {
|
|
530
|
-
return dedupeButtons(buttons);
|
|
531
|
-
}
|
|
532
|
-
function dedupeInputsInternal(inputs) {
|
|
533
|
-
return dedupeInputs(inputs);
|
|
534
|
-
}
|
|
535
|
-
function dedupeTogglesInternal(toggles) {
|
|
536
|
-
return dedupeToggles(toggles);
|
|
537
|
-
}
|
|
538
|
-
function dedupeStringsInternal(strings) {
|
|
539
|
-
return dedupeStrings(strings);
|
|
540
|
-
}
|
|
541
|
-
function isCommandLikeLabel(label) {
|
|
542
|
-
if (!label) return true;
|
|
543
|
-
const normalized = normalizeLabel(label);
|
|
544
|
-
if (!normalized) return true;
|
|
545
|
-
return /^(proximo|prox|next|continuar|continue|voltar|back|confirmar|confirm|cancelar|cancel|salvar|save|enviar|submit|ok|limpar|clear|fechar|close|adicionar|add|novo|nova|new)$/i.test(
|
|
546
|
-
normalized
|
|
547
|
-
);
|
|
548
|
-
}
|
|
549
|
-
function deriveChoiceGroups(snapshot) {
|
|
550
|
-
const groups = [];
|
|
551
|
-
for (const list of snapshot.lists) {
|
|
552
|
-
const options = list.items.filter((item) => item.texts.length > 0 || item.buttons.length > 0).map((item, i) => {
|
|
553
|
-
const texts = item.texts.length > 0 ? item.texts : item.buttons.map((b) => b.label ?? b.id ?? "").filter((text) => text.length > 0);
|
|
554
|
-
return {
|
|
555
|
-
index: i + 1,
|
|
556
|
-
syntheticId: `${list.id ?? `list-${list.index}`}-choice-${i + 1}`,
|
|
557
|
-
targetId: item.syntheticId,
|
|
558
|
-
label: texts.slice(0, 2).join(" \xB7 "),
|
|
559
|
-
texts,
|
|
560
|
-
disabled: false
|
|
561
|
-
};
|
|
562
|
-
});
|
|
563
|
-
if (options.length > 0) {
|
|
564
|
-
groups.push({
|
|
565
|
-
index: groups.length,
|
|
566
|
-
id: list.id,
|
|
567
|
-
label: list.label,
|
|
568
|
-
source: "list",
|
|
569
|
-
options
|
|
570
|
-
});
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
const buttonOptions = snapshot.buttons.filter((button) => !button.disabled).filter((button) => hasMeaningfulText(button.label ?? button.id)).filter((button) => !isCommandLikeLabel(button.label ?? button.id)).map((button, i) => {
|
|
574
|
-
const label = button.label ?? button.id ?? "";
|
|
575
|
-
return {
|
|
576
|
-
index: i + 1,
|
|
577
|
-
syntheticId: `choice-buttons-option-${i + 1}`,
|
|
578
|
-
targetId: button.id ?? button.label,
|
|
579
|
-
label,
|
|
580
|
-
texts: [label],
|
|
581
|
-
selected: !!button.selected,
|
|
582
|
-
disabled: !!button.disabled
|
|
583
|
-
};
|
|
584
|
-
});
|
|
585
|
-
if (buttonOptions.length >= 2) {
|
|
586
|
-
groups.push({
|
|
587
|
-
index: groups.length,
|
|
588
|
-
id: "visible-options",
|
|
589
|
-
label: "Visible options",
|
|
590
|
-
source: "buttons",
|
|
591
|
-
options: buttonOptions
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
return groups;
|
|
595
|
-
}
|
|
596
|
-
function dedupeButtons(buttons) {
|
|
597
|
-
const seen = /* @__PURE__ */ new Set();
|
|
598
|
-
const out = [];
|
|
599
|
-
for (const b of buttons) {
|
|
600
|
-
const idTrim = b.id?.trim();
|
|
601
|
-
const labelTrim = b.label?.trim();
|
|
602
|
-
if (!idTrim && (!labelTrim || !/[a-z0-9]/i.test(labelTrim))) continue;
|
|
603
|
-
const key = `${idTrim ?? ""}|${labelTrim ?? ""}|${b.disabled ? 1 : 0}|${b.inModal ? 1 : 0}|${b.selected ? 1 : 0}`;
|
|
604
|
-
if (seen.has(key)) continue;
|
|
605
|
-
seen.add(key);
|
|
606
|
-
out.push(b);
|
|
607
|
-
}
|
|
608
|
-
return out;
|
|
609
|
-
}
|
|
610
|
-
function dedupeInputs(inputs) {
|
|
611
|
-
const seen = /* @__PURE__ */ new Set();
|
|
612
|
-
const out = [];
|
|
613
|
-
for (const i of inputs) {
|
|
614
|
-
const key = `${i.id ?? ""}|${i.label ?? ""}|${i.placeholder ?? ""}|${i.inModal ? 1 : 0}`;
|
|
615
|
-
if (seen.has(key)) continue;
|
|
616
|
-
seen.add(key);
|
|
617
|
-
out.push(i);
|
|
618
|
-
}
|
|
619
|
-
return out;
|
|
620
|
-
}
|
|
621
|
-
function dedupeSliders(sliders) {
|
|
622
|
-
const seen = /* @__PURE__ */ new Set();
|
|
623
|
-
const out = [];
|
|
624
|
-
for (const s of sliders) {
|
|
625
|
-
const key = `${s.id ?? ""}|${s.label ?? ""}|${s.inModal ? 1 : 0}`;
|
|
626
|
-
if (seen.has(key)) continue;
|
|
627
|
-
seen.add(key);
|
|
628
|
-
out.push(s);
|
|
629
|
-
}
|
|
630
|
-
return out;
|
|
631
|
-
}
|
|
632
|
-
function dedupeToggles(toggles) {
|
|
633
|
-
const seen = /* @__PURE__ */ new Set();
|
|
634
|
-
const out = [];
|
|
635
|
-
for (const t of toggles) {
|
|
636
|
-
const key = `${t.id ?? ""}|${t.label ?? ""}|${t.inModal ? 1 : 0}`;
|
|
637
|
-
if (seen.has(key)) continue;
|
|
638
|
-
seen.add(key);
|
|
639
|
-
out.push(t);
|
|
640
|
-
}
|
|
641
|
-
return out;
|
|
642
|
-
}
|
|
643
|
-
function dedupeStrings(strings) {
|
|
644
|
-
const seen = /* @__PURE__ */ new Set();
|
|
645
|
-
const out = [];
|
|
646
|
-
for (const s of strings) {
|
|
647
|
-
const trimmed = s.trim();
|
|
648
|
-
if (!trimmed) continue;
|
|
649
|
-
if (seen.has(trimmed)) continue;
|
|
650
|
-
seen.add(trimmed);
|
|
651
|
-
out.push(trimmed);
|
|
652
|
-
}
|
|
653
|
-
return out;
|
|
654
|
-
}
|
|
655
|
-
function normalizeLabel(label) {
|
|
656
|
-
return label.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9\s]/g, "").trim().replace(/\s+(.)/g, (_, c) => c.toUpperCase()).replace(/\s+/g, "");
|
|
657
|
-
}
|
|
7
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
|
+
|
|
9
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
658
10
|
|
|
659
11
|
// src/introspection/captureSnapshot.ts
|
|
660
12
|
function normalizeSliderKey(value) {
|
|
@@ -671,9 +23,9 @@ function fiberSliderMatches(fiber, registryId, registryLabel) {
|
|
|
671
23
|
function reconcileSliders(snapshot) {
|
|
672
24
|
const fiberSliders = snapshot.sliders;
|
|
673
25
|
const out = [];
|
|
674
|
-
for (const { id, kind } of
|
|
26
|
+
for (const { id, kind } of chunkYB77RYCC_js.componentRegistry.snapshot()) {
|
|
675
27
|
if (kind !== "slider") continue;
|
|
676
|
-
const entry =
|
|
28
|
+
const entry = chunkYB77RYCC_js.componentRegistry.getSlider(id);
|
|
677
29
|
if (!entry) continue;
|
|
678
30
|
const fiber = fiberSliders.find((s) => fiberSliderMatches(s, id, entry.label));
|
|
679
31
|
const visible = !!fiber || typeof entry.screen === "string" && entry.screen === snapshot.route;
|
|
@@ -696,14 +48,38 @@ function reconcileSliders(snapshot) {
|
|
|
696
48
|
}
|
|
697
49
|
snapshot.sliders = out;
|
|
698
50
|
}
|
|
51
|
+
function normalizeFieldKey(value) {
|
|
52
|
+
return (value ?? "").toLowerCase().replace(/^(input|field)[-_]/, "");
|
|
53
|
+
}
|
|
54
|
+
function canonicalizeRegisteredFields(snapshot) {
|
|
55
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
56
|
+
for (const { id, kind, label } of chunkYB77RYCC_js.componentRegistry.snapshot()) {
|
|
57
|
+
if (kind !== "field") continue;
|
|
58
|
+
if (snapshot.inputs.some((input) => input.id === id)) continue;
|
|
59
|
+
const registryLabel = (label ?? "").toLowerCase();
|
|
60
|
+
const registryKey = normalizeFieldKey(id);
|
|
61
|
+
const candidates = snapshot.inputs.filter((input) => {
|
|
62
|
+
if (claimed.has(input)) return false;
|
|
63
|
+
const inputLabel = (input.label ?? "").toLowerCase();
|
|
64
|
+
if (registryLabel && inputLabel && inputLabel === registryLabel) return true;
|
|
65
|
+
const inputKey = normalizeFieldKey(input.id);
|
|
66
|
+
return !!inputKey && !!registryKey && inputKey === registryKey;
|
|
67
|
+
});
|
|
68
|
+
if (candidates.length !== 1) continue;
|
|
69
|
+
const match = candidates[0];
|
|
70
|
+
claimed.add(match);
|
|
71
|
+
match.id = id;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
699
74
|
function mergeRegisteredLists(snapshot) {
|
|
700
|
-
const registered =
|
|
75
|
+
const registered = chunkYB77RYCC_js.listRegistry.snapshot();
|
|
701
76
|
if (registered.length === 0) return;
|
|
702
77
|
const byId = /* @__PURE__ */ new Map();
|
|
703
78
|
for (const list of snapshot.lists) {
|
|
704
79
|
if (list.id) byId.set(list.id, list);
|
|
705
80
|
}
|
|
706
81
|
for (const entry of registered) {
|
|
82
|
+
if (entry.kind === "scroll") continue;
|
|
707
83
|
const metrics = entry.getScrollMetrics?.();
|
|
708
84
|
const scrollFacts = metrics ? {
|
|
709
85
|
scrollOffsetY: Math.max(0, Math.round(metrics.offset)),
|
|
@@ -744,15 +120,70 @@ function mergeRegisteredLists(snapshot) {
|
|
|
744
120
|
});
|
|
745
121
|
}
|
|
746
122
|
}
|
|
123
|
+
function mergeRegisteredScrollables(snapshot) {
|
|
124
|
+
const registered = chunkYB77RYCC_js.listRegistry.snapshot().filter((e) => e.kind === "scroll");
|
|
125
|
+
if (registered.length === 0) return;
|
|
126
|
+
const listsById = /* @__PURE__ */ new Map();
|
|
127
|
+
for (const list of snapshot.lists) {
|
|
128
|
+
if (list.id) listsById.set(list.id, list);
|
|
129
|
+
}
|
|
130
|
+
const out = [];
|
|
131
|
+
for (const entry of registered) {
|
|
132
|
+
const metrics = entry.getScrollMetrics?.();
|
|
133
|
+
const facts = metrics ? {
|
|
134
|
+
scrollOffsetY: Math.max(0, Math.round(metrics.offset)),
|
|
135
|
+
canScrollUp: metrics.offset > 8,
|
|
136
|
+
canScrollDown: metrics.offset + metrics.visibleLength < metrics.contentLength - 8
|
|
137
|
+
} : void 0;
|
|
138
|
+
const asList = listsById.get(entry.id);
|
|
139
|
+
if (asList) {
|
|
140
|
+
if (facts) {
|
|
141
|
+
asList.scrollOffsetY = asList.scrollOffsetY ?? facts.scrollOffsetY;
|
|
142
|
+
asList.canScrollUp = asList.canScrollUp ?? facts.canScrollUp;
|
|
143
|
+
asList.canScrollDown = asList.canScrollDown ?? facts.canScrollDown;
|
|
144
|
+
}
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
out.push({
|
|
148
|
+
id: entry.id,
|
|
149
|
+
containerType: entry.component,
|
|
150
|
+
...entry.label ? { label: entry.label } : {},
|
|
151
|
+
...facts ?? {}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
if (out.length > 0) snapshot.scrollables = out;
|
|
155
|
+
}
|
|
156
|
+
function mergeNativeDialog(snapshot) {
|
|
157
|
+
const dialog = chunkYB77RYCC_js.getOpenNativeDialog();
|
|
158
|
+
if (!dialog) return;
|
|
159
|
+
snapshot.nativeDialog = {
|
|
160
|
+
id: dialog.id,
|
|
161
|
+
...dialog.title ? { title: dialog.title } : {},
|
|
162
|
+
...dialog.message ? { message: dialog.message } : {},
|
|
163
|
+
buttons: dialog.buttons.map((b) => ({
|
|
164
|
+
label: b.label,
|
|
165
|
+
...b.style ? { style: b.style } : {}
|
|
166
|
+
}))
|
|
167
|
+
};
|
|
168
|
+
snapshot.modalOpen = true;
|
|
169
|
+
}
|
|
170
|
+
var MIN_FIBERS_FOR_BLINDNESS = 200;
|
|
171
|
+
function recordBlindWalk() {
|
|
172
|
+
const walk = chunkYB77RYCC_js.getLastWalkDiagnostics();
|
|
173
|
+
if (!walk) return;
|
|
174
|
+
if (walk.visitedFibers < MIN_FIBERS_FOR_BLINDNESS) return;
|
|
175
|
+
if (chunkYB77RYCC_js.totalDetectorHits(walk.detectors) > 0) return;
|
|
176
|
+
chunkYB77RYCC_js.recordIntrospectionFailure("walk-recognized-nothing", null);
|
|
177
|
+
}
|
|
747
178
|
function captureSnapshot() {
|
|
748
|
-
const root =
|
|
179
|
+
const root = chunkYB77RYCC_js.getFiberRoot();
|
|
749
180
|
if (!root) {
|
|
750
|
-
|
|
751
|
-
"
|
|
181
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
182
|
+
"captureSnapshot: fiber root not captured yet. Ensure <AppilotsProvider> has rendered before calling this."
|
|
752
183
|
);
|
|
753
|
-
|
|
184
|
+
chunkYB77RYCC_js.recordIntrospectionFailure("never-mounted", null);
|
|
754
185
|
return {
|
|
755
|
-
route:
|
|
186
|
+
route: chunkYB77RYCC_js.getCurrentScreen(),
|
|
756
187
|
texts: [],
|
|
757
188
|
inputs: [],
|
|
758
189
|
buttons: [],
|
|
@@ -766,37 +197,84 @@ function captureSnapshot() {
|
|
|
766
197
|
};
|
|
767
198
|
}
|
|
768
199
|
const start = Date.now();
|
|
769
|
-
const snapshot = walkFiber(root);
|
|
770
|
-
|
|
200
|
+
const snapshot = chunkYB77RYCC_js.walkFiber(root);
|
|
201
|
+
recordBlindWalk();
|
|
202
|
+
const activePath = chunkYB77RYCC_js.getActiveRouteNames();
|
|
771
203
|
const deepestRoute = activePath[activePath.length - 1];
|
|
772
204
|
if (deepestRoute) snapshot.route = deepestRoute;
|
|
773
205
|
mergeRegisteredLists(snapshot);
|
|
206
|
+
mergeRegisteredScrollables(snapshot);
|
|
207
|
+
mergeNativeDialog(snapshot);
|
|
774
208
|
reconcileSliders(snapshot);
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
209
|
+
canonicalizeRegisteredFields(snapshot);
|
|
210
|
+
chunkYB77RYCC_js.clampSnapshotToWireLimits(snapshot);
|
|
211
|
+
const entries = chunkYB77RYCC_js.deriveInteractionElements(snapshot, { rectOf: chunkYB77RYCC_js.rectForNode });
|
|
212
|
+
const rectById = new Map(
|
|
213
|
+
entries.flatMap((entry) => entry.rect ? [[entry.id, entry.rect]] : [])
|
|
780
214
|
);
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
(
|
|
786
|
-
|
|
215
|
+
snapshot.elements = entries.map(chunkYB77RYCC_js.toWireElement);
|
|
216
|
+
snapshot.choiceGroups = chunkYB77RYCC_js.attachElementIdsToChoiceGroups(snapshot.choiceGroups, snapshot.elements);
|
|
217
|
+
chunkYB77RYCC_js.clampSnapshotToWireLimits(snapshot);
|
|
218
|
+
chunkYB77RYCC_js.elementRegistry.replaceAll(
|
|
219
|
+
snapshot.elements.map((element) => {
|
|
220
|
+
const rect = rectById.get(element.id);
|
|
221
|
+
return rect ? { ...element, rect } : element;
|
|
222
|
+
})
|
|
787
223
|
);
|
|
224
|
+
const elapsed = Date.now() - start;
|
|
225
|
+
const totalListItems = snapshot.lists.reduce((acc, l) => acc + l.items.length, 0);
|
|
788
226
|
const totalListDataItems = snapshot.lists.reduce(
|
|
789
227
|
(acc, l) => acc + (typeof l.itemCount === "number" ? l.itemCount : 0),
|
|
790
228
|
0
|
|
791
229
|
);
|
|
792
|
-
|
|
793
|
-
`
|
|
230
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
231
|
+
`captureSnapshot: route="${snapshot.route}" texts=${snapshot.texts.length} inputs=${snapshot.inputs.length} buttons=${snapshot.buttons.length} toggles=${snapshot.toggles.length} sliders=${snapshot.sliders.length} loading=${snapshot.loading} modal=${snapshot.modalOpen} lists=${snapshot.lists.length}(visibleItems=${totalListItems}, dataItems=${totalListDataItems}) choices=${snapshot.choiceGroups.length} elements=${snapshot.elements.length} ` + (snapshot.truncated ? "truncated=true " : "") + `(walked ${snapshot.stats?.visitedFibers ?? 0} fibers, skipped ${snapshot.stats?.skippedHidden ?? 0} hidden, ${elapsed}ms)`
|
|
794
232
|
);
|
|
795
|
-
|
|
796
|
-
`
|
|
233
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
234
|
+
`captureSnapshot detail: lists=[${snapshot.lists.map((l) => `${l.containerType}:${l.id ?? l.label ?? "?"}(rows=${l.items.length})`).join(", ")}] inputs=[${snapshot.inputs.map((i) => i.id ?? i.label ?? "?").slice(0, 12).join(", ")}] buttons=[${snapshot.buttons.map((b) => b.id ?? b.label ?? "?").slice(0, 15).join(", ")}]`
|
|
797
235
|
);
|
|
798
236
|
return snapshot;
|
|
799
237
|
}
|
|
238
|
+
function registryCounts() {
|
|
239
|
+
const counts = {
|
|
240
|
+
fields: 0,
|
|
241
|
+
toggles: 0,
|
|
242
|
+
sliders: 0,
|
|
243
|
+
targets: 0,
|
|
244
|
+
lists: chunkYB77RYCC_js.listRegistry.snapshot().length,
|
|
245
|
+
elements: chunkYB77RYCC_js.elementRegistry.size
|
|
246
|
+
};
|
|
247
|
+
for (const { kind } of chunkYB77RYCC_js.componentRegistry.snapshot()) {
|
|
248
|
+
if (kind === "field") counts.fields++;
|
|
249
|
+
else if (kind === "toggle") counts.toggles++;
|
|
250
|
+
else if (kind === "slider") counts.sliders++;
|
|
251
|
+
else if (kind === "target") counts.targets++;
|
|
252
|
+
}
|
|
253
|
+
return counts;
|
|
254
|
+
}
|
|
255
|
+
function appilotsSelfCheck() {
|
|
256
|
+
const root = chunkYB77RYCC_js.getFiberRoot();
|
|
257
|
+
const start = Date.now();
|
|
258
|
+
if (root) chunkYB77RYCC_js.walkFiber(root);
|
|
259
|
+
const elapsedMs = Date.now() - start;
|
|
260
|
+
const walk = chunkYB77RYCC_js.getLastWalkDiagnostics();
|
|
261
|
+
return {
|
|
262
|
+
sdkVersion: chunkYB77RYCC_js.SDK_VERSION,
|
|
263
|
+
reactVersion: React__default.default.version ?? null,
|
|
264
|
+
route: chunkYB77RYCC_js.getCurrentScreen() || null,
|
|
265
|
+
introspection: chunkYB77RYCC_js.getIntrospectionDiagnostics(),
|
|
266
|
+
autoTracking: chunkYB77RYCC_js.getAutoTrackingState(),
|
|
267
|
+
walk: {
|
|
268
|
+
visitedFibers: root ? walk?.visitedFibers ?? 0 : 0,
|
|
269
|
+
skippedHidden: root ? walk?.skippedHidden ?? 0 : 0,
|
|
270
|
+
elapsedMs
|
|
271
|
+
},
|
|
272
|
+
detectors: root ? walk?.detectors ?? chunkYB77RYCC_js.emptyDetectorCounts() : chunkYB77RYCC_js.emptyDetectorCounts(),
|
|
273
|
+
registry: registryCounts(),
|
|
274
|
+
nameMangling: chunkYB77RYCC_js.getNameManglingProbe(),
|
|
275
|
+
geometry: { availability: chunkYB77RYCC_js.geometryAvailability(), ...chunkYB77RYCC_js.geometryStats() }
|
|
276
|
+
};
|
|
277
|
+
}
|
|
800
278
|
|
|
801
279
|
// src/introspection/findInteractive.ts
|
|
802
280
|
function getTypeName2(type) {
|
|
@@ -810,7 +288,7 @@ function getTypeName2(type) {
|
|
|
810
288
|
}
|
|
811
289
|
return null;
|
|
812
290
|
}
|
|
813
|
-
function
|
|
291
|
+
function matchesName(fiber, name) {
|
|
814
292
|
return getTypeName2(fiber.type) === name || getTypeName2(fiber.elementType) === name;
|
|
815
293
|
}
|
|
816
294
|
var TOUCHABLE_NAMES2 = /* @__PURE__ */ new Set([
|
|
@@ -823,33 +301,33 @@ var TOUCHABLE_NAMES2 = /* @__PURE__ */ new Set([
|
|
|
823
301
|
function isTouchable(fiber) {
|
|
824
302
|
return TOUCHABLE_NAMES2.has(getTypeName2(fiber.type) ?? "") || TOUCHABLE_NAMES2.has(getTypeName2(fiber.elementType) ?? "");
|
|
825
303
|
}
|
|
826
|
-
function
|
|
304
|
+
function hasPressHandler(fiber) {
|
|
827
305
|
const props = fiber?.memoizedProps ?? {};
|
|
828
306
|
return typeof props.onPress === "function" || typeof props.onPressIn === "function";
|
|
829
307
|
}
|
|
830
|
-
function
|
|
831
|
-
return isTouchable(fiber) ||
|
|
308
|
+
function isPressableTarget(fiber) {
|
|
309
|
+
return isTouchable(fiber) || hasPressHandler(fiber);
|
|
832
310
|
}
|
|
833
|
-
var
|
|
311
|
+
var SELF_REFERENTIAL_COMPONENTS = /* @__PURE__ */ new Set([
|
|
834
312
|
"AppilotsChat",
|
|
835
313
|
"AppilotsChatInner",
|
|
836
314
|
"ActionBreadcrumb",
|
|
837
315
|
"ConfirmDialog"
|
|
838
316
|
]);
|
|
839
|
-
function
|
|
317
|
+
function isAppilotsSkipMarked(props) {
|
|
840
318
|
if (!props) return false;
|
|
841
319
|
return props.__appilotsSkip === true || props["data-appilots-skip"] === true || props.appilotsSkip === true;
|
|
842
320
|
}
|
|
843
|
-
function
|
|
321
|
+
function extractTextFromChildren(children) {
|
|
844
322
|
if (children == null) return "";
|
|
845
323
|
if (typeof children === "string") return children;
|
|
846
324
|
if (typeof children === "number") return String(children);
|
|
847
325
|
if (Array.isArray(children)) {
|
|
848
|
-
return children.map(
|
|
326
|
+
return children.map(extractTextFromChildren).filter(Boolean).join("");
|
|
849
327
|
}
|
|
850
328
|
return "";
|
|
851
329
|
}
|
|
852
|
-
function
|
|
330
|
+
function findChildText(fiber) {
|
|
853
331
|
const stack = [];
|
|
854
332
|
if (fiber.child) stack.push(fiber.child);
|
|
855
333
|
const visited = /* @__PURE__ */ new WeakSet();
|
|
@@ -857,8 +335,8 @@ function findChildText2(fiber) {
|
|
|
857
335
|
const node = stack.pop();
|
|
858
336
|
if (!node || visited.has(node)) continue;
|
|
859
337
|
visited.add(node);
|
|
860
|
-
if (
|
|
861
|
-
const text =
|
|
338
|
+
if (matchesName(node, "Text")) {
|
|
339
|
+
const text = extractTextFromChildren(node.memoizedProps?.children);
|
|
862
340
|
if (text && text.trim().length > 0) return text.trim();
|
|
863
341
|
}
|
|
864
342
|
if (node.sibling) stack.push(node.sibling);
|
|
@@ -870,10 +348,10 @@ function shouldSkipSubtree2(fiber) {
|
|
|
870
348
|
const props = fiber.memoizedProps;
|
|
871
349
|
if (!props) return false;
|
|
872
350
|
const typeName = getTypeName2(fiber.type) ?? getTypeName2(fiber.elementType);
|
|
873
|
-
if (typeName &&
|
|
874
|
-
if (
|
|
875
|
-
if (
|
|
876
|
-
if (
|
|
351
|
+
if (typeName && SELF_REFERENTIAL_COMPONENTS.has(typeName)) return true;
|
|
352
|
+
if (isAppilotsSkipMarked(props)) return true;
|
|
353
|
+
if (chunkYB77RYCC_js.isModalFiber(fiber) && props.visible === false) return true;
|
|
354
|
+
if (matchesName(fiber, "Screen") && props.activityState === 0) return true;
|
|
877
355
|
const style = props.style;
|
|
878
356
|
if (style) {
|
|
879
357
|
const flat = Array.isArray(style) ? Object.assign({}, ...style.filter(Boolean)) : style;
|
|
@@ -882,20 +360,19 @@ function shouldSkipSubtree2(fiber) {
|
|
|
882
360
|
}
|
|
883
361
|
return false;
|
|
884
362
|
}
|
|
885
|
-
|
|
886
|
-
if (!s) return "";
|
|
887
|
-
return s.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
|
|
888
|
-
}
|
|
363
|
+
var normalize = chunkYB77RYCC_js.foldForCompare;
|
|
889
364
|
function scoreMatch(fiber, queryNorm, queryRaw) {
|
|
890
365
|
const props = fiber.memoizedProps ?? {};
|
|
891
366
|
const candidates = [];
|
|
892
367
|
if (typeof props.testID === "string") candidates.push({ val: props.testID, weight: 100 });
|
|
893
|
-
if (typeof props.accessibilityLabel === "string")
|
|
368
|
+
if (typeof props.accessibilityLabel === "string")
|
|
369
|
+
candidates.push({ val: props.accessibilityLabel, weight: 95 });
|
|
894
370
|
if (typeof props.label === "string") candidates.push({ val: props.label, weight: 90 });
|
|
895
|
-
if (typeof props.placeholder === "string")
|
|
371
|
+
if (typeof props.placeholder === "string")
|
|
372
|
+
candidates.push({ val: props.placeholder, weight: 70 });
|
|
896
373
|
if (typeof props.title === "string") candidates.push({ val: props.title, weight: 85 });
|
|
897
|
-
if (
|
|
898
|
-
const childText =
|
|
374
|
+
if (isPressableTarget(fiber)) {
|
|
375
|
+
const childText = findChildText(fiber);
|
|
899
376
|
if (childText) candidates.push({ val: childText, weight: 80 });
|
|
900
377
|
}
|
|
901
378
|
let best = 0;
|
|
@@ -904,7 +381,8 @@ function scoreMatch(fiber, queryNorm, queryRaw) {
|
|
|
904
381
|
if (!vNorm) continue;
|
|
905
382
|
if (val === queryRaw) best = Math.max(best, weight + 20);
|
|
906
383
|
else if (vNorm === queryNorm) best = Math.max(best, weight + 10);
|
|
907
|
-
else if (vNorm.includes(queryNorm) || queryNorm.includes(vNorm))
|
|
384
|
+
else if (queryNorm && (vNorm.includes(queryNorm) || queryNorm.includes(vNorm)))
|
|
385
|
+
best = Math.max(best, weight - 20);
|
|
908
386
|
}
|
|
909
387
|
if (best > 0 && props.disabled === true) {
|
|
910
388
|
best = Math.max(1, best - 60);
|
|
@@ -935,6 +413,12 @@ function wrapTextInput(fiber) {
|
|
|
935
413
|
if (node && typeof node.focus === "function") {
|
|
936
414
|
node.focus();
|
|
937
415
|
}
|
|
416
|
+
},
|
|
417
|
+
submitFromKeyboard: () => {
|
|
418
|
+
const { onSubmitEditing, value } = getProps();
|
|
419
|
+
if (typeof onSubmitEditing !== "function") return false;
|
|
420
|
+
onSubmitEditing({ nativeEvent: { text: value ?? "" } });
|
|
421
|
+
return true;
|
|
938
422
|
}
|
|
939
423
|
};
|
|
940
424
|
}
|
|
@@ -972,16 +456,16 @@ function wrapTouchable(fiber, label) {
|
|
|
972
456
|
};
|
|
973
457
|
}
|
|
974
458
|
function findInteractiveByIdentifier(query, options = {}) {
|
|
975
|
-
const root =
|
|
459
|
+
const root = chunkYB77RYCC_js.getFiberRoot();
|
|
976
460
|
if (!root) {
|
|
977
|
-
|
|
461
|
+
chunkYB77RYCC_js.appilotsDebugWarn("findInteractiveByIdentifier: fiber root not captured yet");
|
|
978
462
|
return null;
|
|
979
463
|
}
|
|
980
464
|
const queryNorm = normalize(query);
|
|
981
465
|
const queryRaw = query;
|
|
982
466
|
let bestScore = 0;
|
|
983
467
|
let bestHandle = null;
|
|
984
|
-
let
|
|
468
|
+
let bestId;
|
|
985
469
|
const visited = /* @__PURE__ */ new WeakSet();
|
|
986
470
|
const stack = [];
|
|
987
471
|
if (root.child) stack.push(root.child);
|
|
@@ -992,40 +476,50 @@ function findInteractiveByIdentifier(query, options = {}) {
|
|
|
992
476
|
if (fiber.sibling) stack.push(fiber.sibling);
|
|
993
477
|
if (shouldSkipSubtree2(fiber)) continue;
|
|
994
478
|
let kind = null;
|
|
995
|
-
if (
|
|
996
|
-
else if (
|
|
997
|
-
else if (
|
|
479
|
+
if (matchesName(fiber, "TextInput")) kind = "field";
|
|
480
|
+
else if (matchesName(fiber, "Switch")) kind = "toggle";
|
|
481
|
+
else if (isPressableTarget(fiber)) kind = "target";
|
|
998
482
|
if (kind && (!options.kind || options.kind === kind)) {
|
|
999
483
|
const score = scoreMatch(fiber, queryNorm, queryRaw);
|
|
1000
484
|
if (score > bestScore) {
|
|
1001
485
|
bestScore = score;
|
|
1002
486
|
const props = fiber.memoizedProps ?? {};
|
|
1003
|
-
|
|
487
|
+
bestId = props.testID ?? props.accessibilityLabel ?? props.placeholder ?? (kind === "target" ? findChildText(fiber) : void 0);
|
|
1004
488
|
if (kind === "field") bestHandle = wrapTextInput(fiber);
|
|
1005
489
|
else if (kind === "toggle") bestHandle = wrapSwitch(fiber);
|
|
1006
|
-
else bestHandle = wrapTouchable(fiber,
|
|
490
|
+
else bestHandle = wrapTouchable(fiber, findChildText(fiber));
|
|
1007
491
|
}
|
|
1008
492
|
}
|
|
1009
493
|
if (fiber.child) stack.push(fiber.child);
|
|
1010
494
|
}
|
|
1011
495
|
if (bestHandle) {
|
|
1012
|
-
|
|
1013
|
-
`
|
|
496
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
497
|
+
`findInteractiveByIdentifier: query="${query}" \u2192 kind=${bestHandle.kind} label="${bestHandle.label ?? bestId}" score=${bestScore}`
|
|
1014
498
|
);
|
|
1015
499
|
} else {
|
|
1016
|
-
|
|
500
|
+
chunkYB77RYCC_js.appilotsDebugLog(`findInteractiveByIdentifier: query="${query}" \u2192 no match`);
|
|
1017
501
|
}
|
|
1018
502
|
return bestHandle;
|
|
1019
503
|
}
|
|
1020
504
|
|
|
1021
505
|
// src/executor/handlers/navigateHandler.ts
|
|
506
|
+
var _reportedMissingNavRef = false;
|
|
507
|
+
function reportMissingNavigationRef() {
|
|
508
|
+
if (_reportedMissingNavRef) return;
|
|
509
|
+
_reportedMissingNavRef = true;
|
|
510
|
+
console.error(
|
|
511
|
+
"[Appilots] Navigation is not wired. The SDK never received a navigation ref, so every navigate the agent attempts will fail.\n Fix: wrap your NavigationContainer with <AppilotsNavigationContainer>:\n <AppilotsProvider config={...}>\n <AppilotsNavigationContainer>\n <NavigationContainer>{/* your navigators */}</NavigationContainer>\n </AppilotsNavigationContainer>\n <AppilotsChat />\n </AppilotsProvider>\n Docs: https://docs.appilots.com/getting-started/quick-start"
|
|
512
|
+
);
|
|
513
|
+
}
|
|
1022
514
|
function categorizeNavigationError(message) {
|
|
1023
515
|
if (/screen named|was not handled by any navigator|no route|not found|not registered in any navigator|couldn'?t find a route|route .* (?:doesn'?t|does not) exist/i.test(
|
|
1024
516
|
message
|
|
1025
517
|
)) {
|
|
1026
518
|
return "component-not-found";
|
|
1027
519
|
}
|
|
1028
|
-
if (/couldn'?t find a navigation object|navigator (?:is )?not (?:rendered|ready)|not been (?:mounted|rendered)/i.test(
|
|
520
|
+
if (/couldn'?t find a navigation object|navigator (?:is )?not (?:rendered|ready)|not been (?:mounted|rendered)/i.test(
|
|
521
|
+
message
|
|
522
|
+
)) {
|
|
1029
523
|
return "screen-timeout";
|
|
1030
524
|
}
|
|
1031
525
|
return "unknown";
|
|
@@ -1052,7 +546,9 @@ function screenExistsAnywhere(state, screenName) {
|
|
|
1052
546
|
function safeNavigate(nav, screenName, params, path) {
|
|
1053
547
|
if (path && path.length > 0) {
|
|
1054
548
|
const { root, nestedParams } = buildNestedParams(path, screenName, params);
|
|
1055
|
-
|
|
549
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
550
|
+
`safeNavigate: using path-based navigation \u2014 root="${root}", nested=${JSON.stringify(nestedParams)}`
|
|
551
|
+
);
|
|
1056
552
|
nav.navigate(root, nestedParams);
|
|
1057
553
|
return;
|
|
1058
554
|
}
|
|
@@ -1067,11 +563,17 @@ function safeNavigate(nav, screenName, params, path) {
|
|
|
1067
563
|
`Screen "${screenName}" is not registered in any navigator. The screen may have been removed, may live inside a flow that is not currently mounted (e.g. Auth stack after login), or the MCP doc is stale.`
|
|
1068
564
|
);
|
|
1069
565
|
}
|
|
1070
|
-
|
|
566
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
567
|
+
`safeNavigate: screen exists in nested navigator, attempting direct navigation to "${screenName}"`
|
|
568
|
+
);
|
|
1071
569
|
nav.navigate(screenName, params);
|
|
1072
570
|
}
|
|
1073
571
|
function navigateHandler(payload, context) {
|
|
1074
|
-
|
|
572
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
573
|
+
// Params carry record ids and, on some screens, the user's own
|
|
574
|
+
// data — the count answers "were params passed?" and nothing else.
|
|
575
|
+
`navigateHandler called: screenName="${payload.screenName}" action="${payload.navigationAction}" params=${chunkYB77RYCC_js.describeValue(payload.params)}`
|
|
576
|
+
);
|
|
1075
577
|
const { navigationRef, permissions } = context;
|
|
1076
578
|
const nav = navigationRef.current;
|
|
1077
579
|
if (!permissions.canNavigate) {
|
|
@@ -1081,14 +583,15 @@ function navigateHandler(payload, context) {
|
|
|
1081
583
|
diagnose: { category: "unknown", screen: payload.screenName }
|
|
1082
584
|
};
|
|
1083
585
|
}
|
|
1084
|
-
|
|
586
|
+
const isGoBack = payload.navigationAction === "goBack";
|
|
587
|
+
if (!isGoBack && permissions.blockedScreens?.includes(payload.screenName)) {
|
|
1085
588
|
return {
|
|
1086
589
|
success: false,
|
|
1087
590
|
error: `Navigation to "${payload.screenName}" is blocked`,
|
|
1088
591
|
diagnose: { category: "unknown", screen: payload.screenName }
|
|
1089
592
|
};
|
|
1090
593
|
}
|
|
1091
|
-
if (permissions.allowedScreens && permissions.allowedScreens.length > 0 && !permissions.allowedScreens.includes(payload.screenName)) {
|
|
594
|
+
if (!isGoBack && permissions.allowedScreens && permissions.allowedScreens.length > 0 && !permissions.allowedScreens.includes(payload.screenName)) {
|
|
1092
595
|
return {
|
|
1093
596
|
success: false,
|
|
1094
597
|
error: `Navigation to "${payload.screenName}" is not in allowed screens`,
|
|
@@ -1096,10 +599,11 @@ function navigateHandler(payload, context) {
|
|
|
1096
599
|
};
|
|
1097
600
|
}
|
|
1098
601
|
if (!nav) {
|
|
602
|
+
reportMissingNavigationRef();
|
|
1099
603
|
return {
|
|
1100
604
|
success: false,
|
|
1101
|
-
error: "Navigation
|
|
1102
|
-
diagnose: { category: "
|
|
605
|
+
error: "Navigation is not wired: <AppilotsNavigationContainer> is missing, so the SDK never received the navigation ref. Wrap your <NavigationContainer> with it. This cannot be retried \u2014 it needs a change in the host app.",
|
|
606
|
+
diagnose: { category: "unknown", screen: payload.screenName }
|
|
1103
607
|
};
|
|
1104
608
|
}
|
|
1105
609
|
if (!nav.isReady || typeof nav.isReady === "function" && !nav.isReady()) {
|
|
@@ -1110,7 +614,15 @@ function navigateHandler(payload, context) {
|
|
|
1110
614
|
};
|
|
1111
615
|
}
|
|
1112
616
|
try {
|
|
1113
|
-
const {
|
|
617
|
+
const { params, navigationAction, path } = payload;
|
|
618
|
+
if (!isGoBack && !payload.screenName) {
|
|
619
|
+
return {
|
|
620
|
+
success: false,
|
|
621
|
+
error: `Navigation action "${navigationAction ?? "navigate"}" requires a screenName.`,
|
|
622
|
+
diagnose: { category: "unknown" }
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
const screenName = payload.screenName;
|
|
1114
626
|
switch (navigationAction) {
|
|
1115
627
|
case "navigate":
|
|
1116
628
|
safeNavigate(nav, screenName, params ?? {}, path);
|
|
@@ -1153,10 +665,14 @@ function navigateHandler(payload, context) {
|
|
|
1153
665
|
diagnose: { category: "unknown", screen: payload.screenName }
|
|
1154
666
|
};
|
|
1155
667
|
}
|
|
1156
|
-
|
|
668
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
669
|
+
`navigateHandler: navigation succeeded for "${payload.screenName}" (action="${payload.navigationAction}")`
|
|
670
|
+
);
|
|
1157
671
|
return { success: true };
|
|
1158
672
|
} catch (err) {
|
|
1159
|
-
|
|
673
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
674
|
+
`navigateHandler: navigation failed for "${payload.screenName}": ${err?.message}`
|
|
675
|
+
);
|
|
1160
676
|
const msg = String(err?.message ?? "Navigation failed");
|
|
1161
677
|
const category = categorizeNavigationError(msg);
|
|
1162
678
|
return {
|
|
@@ -1179,7 +695,7 @@ function parseSyntheticListItemId(id) {
|
|
|
1179
695
|
if (listIndex < 0 || itemIndex < 1) return null;
|
|
1180
696
|
return { listIndex, itemIndex };
|
|
1181
697
|
}
|
|
1182
|
-
function
|
|
698
|
+
function stringProp(props, key) {
|
|
1183
699
|
const value = props?.[key];
|
|
1184
700
|
if (typeof value === "string" && value.trim()) return value.trim();
|
|
1185
701
|
if (typeof value === "number") return String(value);
|
|
@@ -1187,33 +703,33 @@ function stringProp2(props, key) {
|
|
|
1187
703
|
}
|
|
1188
704
|
function listIdFromContainer(container) {
|
|
1189
705
|
const props = container?.memoizedProps ?? {};
|
|
1190
|
-
return
|
|
706
|
+
return stringProp(props, "__appilotsListId") ?? stringProp(props, "appilotsListId") ?? stringProp(props, "testID") ?? stringProp(props, "accessibilityLabel");
|
|
1191
707
|
}
|
|
1192
708
|
function listLabelFromContainer(container) {
|
|
1193
709
|
const props = container?.memoizedProps ?? {};
|
|
1194
|
-
return
|
|
710
|
+
return stringProp(props, "__appilotsListLabel") ?? stringProp(props, "accessibilityLabel") ?? stringProp(props, "aria-label") ?? stringProp(props, "label");
|
|
1195
711
|
}
|
|
1196
712
|
function itemKeyFromFiber(fiber) {
|
|
1197
713
|
const props = fiber?.memoizedProps ?? {};
|
|
1198
|
-
return
|
|
714
|
+
return stringProp(props, "__appilotsItemKey") ?? (fiber?.key !== void 0 && fiber?.key !== null ? String(fiber.key) : void 0);
|
|
1199
715
|
}
|
|
1200
716
|
function markedItemIndexFromFiber(fiber) {
|
|
1201
717
|
const value = fiber?.memoizedProps?.__appilotsItemIndex;
|
|
1202
718
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1203
719
|
}
|
|
1204
720
|
function normalize2(value) {
|
|
1205
|
-
return String(value ?? "")
|
|
721
|
+
return chunkYB77RYCC_js.foldForCompare(String(value ?? ""));
|
|
1206
722
|
}
|
|
1207
|
-
function
|
|
723
|
+
function hasPressHandler2(fiber) {
|
|
1208
724
|
const props = fiber?.memoizedProps ?? {};
|
|
1209
725
|
return typeof props.onPress === "function" || typeof props.onPressIn === "function";
|
|
1210
726
|
}
|
|
1211
727
|
function isPressableFiber(fiber) {
|
|
1212
|
-
const typeName = getTypeName(fiber.type) ?? getTypeName(fiber.elementType) ?? "";
|
|
1213
|
-
return TOUCHABLE_NAMES.has(typeName) ||
|
|
728
|
+
const typeName = chunkYB77RYCC_js.getTypeName(fiber.type) ?? chunkYB77RYCC_js.getTypeName(fiber.elementType) ?? "";
|
|
729
|
+
return chunkYB77RYCC_js.TOUCHABLE_NAMES.has(typeName) || hasPressHandler2(fiber);
|
|
1214
730
|
}
|
|
1215
731
|
function findListContainers(options = {}) {
|
|
1216
|
-
const root =
|
|
732
|
+
const root = chunkYB77RYCC_js.getFiberRoot();
|
|
1217
733
|
if (!root) return [];
|
|
1218
734
|
const containers = [];
|
|
1219
735
|
const visited = /* @__PURE__ */ new WeakSet();
|
|
@@ -1224,17 +740,17 @@ function findListContainers(options = {}) {
|
|
|
1224
740
|
if (!fiber || visited.has(fiber)) continue;
|
|
1225
741
|
visited.add(fiber);
|
|
1226
742
|
if (fiber.sibling) stack.push(fiber.sibling);
|
|
1227
|
-
if (shouldSkipSubtree(fiber)) continue;
|
|
1228
|
-
if (isAlwaysListContainer(fiber) || isHeuristicListContainer(fiber)) {
|
|
1229
|
-
const minItems = isAlwaysListContainer(fiber) || options.allowSingleHeuristic ? 1 : 2;
|
|
1230
|
-
const items = findListItems(fiber, minItems);
|
|
743
|
+
if (chunkYB77RYCC_js.shouldSkipSubtree(fiber)) continue;
|
|
744
|
+
if (chunkYB77RYCC_js.isAlwaysListContainer(fiber) || chunkYB77RYCC_js.isHeuristicListContainer(fiber)) {
|
|
745
|
+
const minItems = chunkYB77RYCC_js.isAlwaysListContainer(fiber) || options.allowSingleHeuristic ? 1 : 2;
|
|
746
|
+
const items = chunkYB77RYCC_js.findListItems(fiber, minItems);
|
|
1231
747
|
if (items && items.length >= minItems) {
|
|
1232
748
|
containers.push({
|
|
1233
749
|
container: fiber,
|
|
1234
750
|
items,
|
|
1235
751
|
listId: listIdFromContainer(fiber),
|
|
1236
752
|
listLabel: listLabelFromContainer(fiber),
|
|
1237
|
-
containerType: getTypeName(fiber.type) ?? getTypeName(fiber.elementType) ?? "List"
|
|
753
|
+
containerType: chunkYB77RYCC_js.getTypeName(fiber.type) ?? chunkYB77RYCC_js.getTypeName(fiber.elementType) ?? "List"
|
|
1238
754
|
});
|
|
1239
755
|
continue;
|
|
1240
756
|
}
|
|
@@ -1253,7 +769,7 @@ function findFirstTouchable(item) {
|
|
|
1253
769
|
const { fiber, includeSibling } = stack.pop();
|
|
1254
770
|
if (!fiber || visited.has(fiber)) continue;
|
|
1255
771
|
visited.add(fiber);
|
|
1256
|
-
if (shouldSkipSubtree(fiber)) continue;
|
|
772
|
+
if (chunkYB77RYCC_js.shouldSkipSubtree(fiber)) continue;
|
|
1257
773
|
if (isPressableFiber(fiber)) {
|
|
1258
774
|
const props = fiber.memoizedProps ?? {};
|
|
1259
775
|
if (typeof props.onPress === "function" || typeof props.onPressIn === "function") {
|
|
@@ -1280,7 +796,7 @@ function findTouchableFibers(item) {
|
|
|
1280
796
|
const { fiber, includeSibling } = stack.pop();
|
|
1281
797
|
if (!fiber || visited.has(fiber)) continue;
|
|
1282
798
|
visited.add(fiber);
|
|
1283
|
-
if (shouldSkipSubtree(fiber)) continue;
|
|
799
|
+
if (chunkYB77RYCC_js.shouldSkipSubtree(fiber)) continue;
|
|
1284
800
|
const props = fiber.memoizedProps ?? {};
|
|
1285
801
|
if (isPressableFiber(fiber) && (typeof props.onPress === "function" || typeof props.onPressIn === "function")) {
|
|
1286
802
|
found.push(fiber);
|
|
@@ -1324,7 +840,7 @@ function findFirstText(fiber) {
|
|
|
1324
840
|
const node = stack.pop();
|
|
1325
841
|
if (!node || visited.has(node)) continue;
|
|
1326
842
|
visited.add(node);
|
|
1327
|
-
const typeName = getTypeName(node.type) ?? getTypeName(node.elementType) ?? "";
|
|
843
|
+
const typeName = chunkYB77RYCC_js.getTypeName(node.type) ?? chunkYB77RYCC_js.getTypeName(node.elementType) ?? "";
|
|
1328
844
|
if (typeName === "Text") {
|
|
1329
845
|
const text = textFromChildren(node.memoizedProps?.children).trim();
|
|
1330
846
|
if (text) return text;
|
|
@@ -1343,7 +859,7 @@ function collectTexts(fiber) {
|
|
|
1343
859
|
const node = stack.pop();
|
|
1344
860
|
if (!node || visited.has(node)) continue;
|
|
1345
861
|
visited.add(node);
|
|
1346
|
-
const typeName = getTypeName(node.type) ?? getTypeName(node.elementType) ?? "";
|
|
862
|
+
const typeName = chunkYB77RYCC_js.getTypeName(node.type) ?? chunkYB77RYCC_js.getTypeName(node.elementType) ?? "";
|
|
1347
863
|
if (typeName === "Text") {
|
|
1348
864
|
const text = textFromChildren(node.memoizedProps?.children).trim();
|
|
1349
865
|
if (text) out.push(text);
|
|
@@ -1355,13 +871,10 @@ function collectTexts(fiber) {
|
|
|
1355
871
|
}
|
|
1356
872
|
function hasUsefulTouchableIdentity(fiber) {
|
|
1357
873
|
const props = fiber?.memoizedProps ?? {};
|
|
1358
|
-
if (
|
|
1359
|
-
if (
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
if (typeof props.label === "string" && /[a-z0-9]/i.test(props.label)) return true;
|
|
1363
|
-
const label = findFirstText(fiber);
|
|
1364
|
-
return !!label && /[a-z0-9]/i.test(label);
|
|
874
|
+
if (chunkYB77RYCC_js.isReferenceable(props.testID)) return true;
|
|
875
|
+
if (chunkYB77RYCC_js.isReferenceable(props.accessibilityLabel)) return true;
|
|
876
|
+
if (chunkYB77RYCC_js.isReferenceable(props.label)) return true;
|
|
877
|
+
return chunkYB77RYCC_js.isReferenceable(findFirstText(fiber));
|
|
1365
878
|
}
|
|
1366
879
|
function describeTouchable(fiber) {
|
|
1367
880
|
const props = fiber?.memoizedProps ?? {};
|
|
@@ -1372,15 +885,10 @@ function describeTouchable(fiber) {
|
|
|
1372
885
|
}
|
|
1373
886
|
function touchableLooksDestructive(fiber) {
|
|
1374
887
|
const descriptor = describeTouchable(fiber);
|
|
1375
|
-
if (descriptor &&
|
|
888
|
+
if (descriptor && chunkYB77RYCC_js.looksDestructiveActionLabel(descriptor)) return true;
|
|
1376
889
|
const props = fiber?.memoizedProps ?? {};
|
|
1377
|
-
const haystack = [
|
|
1378
|
-
|
|
1379
|
-
props.accessibilityLabel,
|
|
1380
|
-
props.accessibilityHint,
|
|
1381
|
-
props.label
|
|
1382
|
-
].filter((value) => typeof value === "string").join(" ");
|
|
1383
|
-
return chunkAYWMBMSN_js.looksDestructiveActionLabel(haystack);
|
|
890
|
+
const haystack = [props.testID, props.accessibilityLabel, props.accessibilityHint, props.label].filter((value) => typeof value === "string").join(" ");
|
|
891
|
+
return chunkYB77RYCC_js.looksDestructiveActionLabel(haystack);
|
|
1384
892
|
}
|
|
1385
893
|
function describeItemCandidate(listIndex, zeroBasedIndex, item) {
|
|
1386
894
|
const syntheticId = `list-${listIndex}-item-${zeroBasedIndex + 1}`;
|
|
@@ -1413,8 +921,8 @@ function pressResolvedListItem(list, itemFiber, listIndex, itemIndex) {
|
|
|
1413
921
|
(candidate) => candidate !== touchable && containsFiber(touchable, candidate)
|
|
1414
922
|
);
|
|
1415
923
|
if (primaryWrapsNestedTargets) {
|
|
1416
|
-
|
|
1417
|
-
`
|
|
924
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
925
|
+
`listItemDispatch: item "list-${listIndex}-item-${itemIndex}" has nested pressables; pressing outer row target`
|
|
1418
926
|
);
|
|
1419
927
|
} else {
|
|
1420
928
|
const candidates = safeIdentifiableTouchables.map(describeTouchable).filter((d) => !!d).slice(0, 8);
|
|
@@ -1448,14 +956,14 @@ function pressResolvedListItem(list, itemFiber, listIndex, itemIndex) {
|
|
|
1448
956
|
}
|
|
1449
957
|
return {
|
|
1450
958
|
ok: true,
|
|
1451
|
-
containerType: getTypeName(container.type) ?? getTypeName(container.elementType) ?? list.containerType
|
|
959
|
+
containerType: chunkYB77RYCC_js.getTypeName(container.type) ?? chunkYB77RYCC_js.getTypeName(container.elementType) ?? list.containerType
|
|
1452
960
|
};
|
|
1453
961
|
} catch (err) {
|
|
1454
962
|
return {
|
|
1455
963
|
ok: false,
|
|
1456
964
|
reason: "press-threw",
|
|
1457
965
|
error: err?.message ?? "press handler threw",
|
|
1458
|
-
containerType: getTypeName(container.type) ?? getTypeName(container.elementType) ?? list.containerType
|
|
966
|
+
containerType: chunkYB77RYCC_js.getTypeName(container.type) ?? chunkYB77RYCC_js.getTypeName(container.elementType) ?? list.containerType
|
|
1459
967
|
};
|
|
1460
968
|
}
|
|
1461
969
|
}
|
|
@@ -1511,7 +1019,7 @@ function candidateLists(containers, locator) {
|
|
|
1511
1019
|
return containers.map((list, listIndex) => ({ list, listIndex }));
|
|
1512
1020
|
}
|
|
1513
1021
|
function pressListItemAtOrdinal(listIndex, itemIndex) {
|
|
1514
|
-
if (!
|
|
1022
|
+
if (!chunkYB77RYCC_js.getFiberRoot()) return { ok: false, reason: "no-fiber-root" };
|
|
1515
1023
|
const containers = findListContainers({ allowSingleHeuristic: true });
|
|
1516
1024
|
if (listIndex < 0 || listIndex >= containers.length) {
|
|
1517
1025
|
return { ok: false, reason: "list-not-found" };
|
|
@@ -1524,14 +1032,14 @@ function pressListItemAtOrdinal(listIndex, itemIndex) {
|
|
|
1524
1032
|
}
|
|
1525
1033
|
return pressResolvedListItem(list, items[zeroBased], listIndex, itemIndex);
|
|
1526
1034
|
}
|
|
1527
|
-
function
|
|
1528
|
-
if (!
|
|
1035
|
+
function resolveListItemByIdentity(locator) {
|
|
1036
|
+
if (!chunkYB77RYCC_js.getFiberRoot()) return { ok: false, result: { ok: false, reason: "no-fiber-root" } };
|
|
1529
1037
|
const parsed = locator.syntheticId ? parseSyntheticListItemId(locator.syntheticId) : null;
|
|
1530
1038
|
const effective = parsed ? { ...locator, listIndex: parsed.listIndex, itemIndex: parsed.itemIndex } : locator;
|
|
1531
1039
|
const containers = findListContainers({ allowSingleHeuristic: true });
|
|
1532
1040
|
const lists = candidateLists(containers, effective);
|
|
1533
1041
|
if (lists.length === 0) {
|
|
1534
|
-
return { ok: false, reason: "list-not-found" };
|
|
1042
|
+
return { ok: false, result: { ok: false, reason: "list-not-found" } };
|
|
1535
1043
|
}
|
|
1536
1044
|
const scoredCandidates = [];
|
|
1537
1045
|
for (const { list, listIndex } of lists) {
|
|
@@ -1542,7 +1050,14 @@ function pressListItemByIdentity(locator) {
|
|
|
1542
1050
|
}
|
|
1543
1051
|
}
|
|
1544
1052
|
if (scoredCandidates.length === 0) {
|
|
1545
|
-
return {
|
|
1053
|
+
return {
|
|
1054
|
+
ok: false,
|
|
1055
|
+
result: {
|
|
1056
|
+
ok: false,
|
|
1057
|
+
reason: "item-not-found",
|
|
1058
|
+
containerType: lists[0]?.list.containerType
|
|
1059
|
+
}
|
|
1060
|
+
};
|
|
1546
1061
|
}
|
|
1547
1062
|
scoredCandidates.sort((a, b) => b.score - a.score);
|
|
1548
1063
|
const best = scoredCandidates[0];
|
|
@@ -1551,13 +1066,104 @@ function pressListItemByIdentity(locator) {
|
|
|
1551
1066
|
const candidates = tiedCandidates.map((c) => describeItemCandidate(c.listIndex, c.itemIndex - 1, c.item)).slice(0, 8);
|
|
1552
1067
|
return {
|
|
1553
1068
|
ok: false,
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1069
|
+
result: {
|
|
1070
|
+
ok: false,
|
|
1071
|
+
reason: "ambiguous-items",
|
|
1072
|
+
error: "Multiple visible list items matched the requested target with equal confidence." + (candidates.length > 0 ? ` Candidates: ${candidates.join(", ")}.` : ""),
|
|
1073
|
+
containerType: best.list.containerType,
|
|
1074
|
+
candidates
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
1078
|
+
return {
|
|
1079
|
+
ok: true,
|
|
1080
|
+
list: best.list,
|
|
1081
|
+
item: best.item,
|
|
1082
|
+
listIndex: best.listIndex,
|
|
1083
|
+
itemIndex: best.itemIndex
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1086
|
+
function findSwitchFibers(item) {
|
|
1087
|
+
if (!item) return [];
|
|
1088
|
+
const found = [];
|
|
1089
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
1090
|
+
const stack = [
|
|
1091
|
+
{ fiber: item, includeSibling: false }
|
|
1092
|
+
];
|
|
1093
|
+
while (stack.length > 0) {
|
|
1094
|
+
const { fiber, includeSibling } = stack.pop();
|
|
1095
|
+
if (!fiber || visited.has(fiber)) continue;
|
|
1096
|
+
visited.add(fiber);
|
|
1097
|
+
if (chunkYB77RYCC_js.shouldSkipSubtree(fiber)) continue;
|
|
1098
|
+
const props = fiber.memoizedProps ?? {};
|
|
1099
|
+
if (chunkYB77RYCC_js.isSwitchLike(fiber, props)) {
|
|
1100
|
+
if (props.__appilotsInternal !== true) found.push(fiber);
|
|
1101
|
+
if (includeSibling && fiber.sibling) {
|
|
1102
|
+
stack.push({ fiber: fiber.sibling, includeSibling: true });
|
|
1103
|
+
}
|
|
1104
|
+
continue;
|
|
1105
|
+
}
|
|
1106
|
+
if (includeSibling && fiber.sibling) {
|
|
1107
|
+
stack.push({ fiber: fiber.sibling, includeSibling: true });
|
|
1108
|
+
}
|
|
1109
|
+
if (fiber.child) stack.push({ fiber: fiber.child, includeSibling: true });
|
|
1110
|
+
}
|
|
1111
|
+
return found;
|
|
1112
|
+
}
|
|
1113
|
+
function toggleListItemByIdentity(locator, options) {
|
|
1114
|
+
const resolved = resolveListItemByIdentity(locator);
|
|
1115
|
+
if (!resolved.ok) return resolved.result;
|
|
1116
|
+
const { list, item } = resolved;
|
|
1117
|
+
const switches = findSwitchFibers(item);
|
|
1118
|
+
if (switches.length === 0) {
|
|
1119
|
+
return { ok: false, reason: "no-touchable", containerType: list.containerType };
|
|
1120
|
+
}
|
|
1121
|
+
if (switches.length > 1) {
|
|
1122
|
+
const candidates = switches.map((fiber, index) => describeTouchable(fiber) ?? `switch-${index + 1}`).slice(0, 8);
|
|
1123
|
+
return {
|
|
1124
|
+
ok: false,
|
|
1125
|
+
reason: "ambiguous-touchables",
|
|
1126
|
+
error: 'This row exposes more than one switch, so flipping "the" switch would be a guess.' + (candidates.length > 0 ? ` Candidates: ${candidates.join(", ")}.` : ""),
|
|
1127
|
+
containerType: list.containerType,
|
|
1557
1128
|
candidates
|
|
1558
1129
|
};
|
|
1559
1130
|
}
|
|
1560
|
-
|
|
1131
|
+
const target = switches[0];
|
|
1132
|
+
const props = target?.memoizedProps ?? {};
|
|
1133
|
+
const current = chunkYB77RYCC_js.switchValue(props);
|
|
1134
|
+
if (options?.expected !== void 0 && current === options.expected) {
|
|
1135
|
+
return { ok: true, containerType: list.containerType, value: current };
|
|
1136
|
+
}
|
|
1137
|
+
const onValueChange = props.onValueChange ?? props.onChange;
|
|
1138
|
+
if (typeof onValueChange !== "function") {
|
|
1139
|
+
return {
|
|
1140
|
+
ok: false,
|
|
1141
|
+
reason: "no-touchable",
|
|
1142
|
+
error: "The row has a switch but it exposes no onValueChange handler.",
|
|
1143
|
+
containerType: list.containerType
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
try {
|
|
1147
|
+
onValueChange(!current);
|
|
1148
|
+
} catch (err) {
|
|
1149
|
+
return {
|
|
1150
|
+
ok: false,
|
|
1151
|
+
reason: "press-threw",
|
|
1152
|
+
error: err?.message ?? "switch handler threw",
|
|
1153
|
+
containerType: list.containerType
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
return { ok: true, containerType: list.containerType, value: !current };
|
|
1157
|
+
}
|
|
1158
|
+
function pressListItemByIdentity(locator) {
|
|
1159
|
+
const resolved = resolveListItemByIdentity(locator);
|
|
1160
|
+
if (!resolved.ok) return resolved.result;
|
|
1161
|
+
return pressResolvedListItem(
|
|
1162
|
+
resolved.list,
|
|
1163
|
+
resolved.item,
|
|
1164
|
+
resolved.listIndex,
|
|
1165
|
+
resolved.itemIndex
|
|
1166
|
+
);
|
|
1561
1167
|
}
|
|
1562
1168
|
|
|
1563
1169
|
// src/executor/handlers/elementDispatch.ts
|
|
@@ -1565,7 +1171,7 @@ function screenDiagnose(targetId, category = "component-not-found") {
|
|
|
1565
1171
|
return {
|
|
1566
1172
|
category,
|
|
1567
1173
|
targetId,
|
|
1568
|
-
screen:
|
|
1174
|
+
screen: chunkYB77RYCC_js.getCurrentScreen() ?? void 0
|
|
1569
1175
|
};
|
|
1570
1176
|
}
|
|
1571
1177
|
function isPressLike(action) {
|
|
@@ -1582,10 +1188,10 @@ function elementLookupKey(value) {
|
|
|
1582
1188
|
return canonicalElementId(value).toLowerCase().replace(/[\s_]+/g, "-");
|
|
1583
1189
|
}
|
|
1584
1190
|
function findRegisteredElement(elementId) {
|
|
1585
|
-
const direct =
|
|
1191
|
+
const direct = chunkYB77RYCC_js.elementRegistry.get(elementId) ?? chunkYB77RYCC_js.elementRegistry.get(canonicalElementId(elementId));
|
|
1586
1192
|
if (direct) return direct;
|
|
1587
1193
|
const wanted = elementLookupKey(elementId);
|
|
1588
|
-
return
|
|
1194
|
+
return chunkYB77RYCC_js.elementRegistry.snapshot().find((element) => elementLookupKey(element.id) === wanted);
|
|
1589
1195
|
}
|
|
1590
1196
|
function resolveInteractionElement(elementId) {
|
|
1591
1197
|
return getLatestElement(elementId);
|
|
@@ -1786,6 +1392,46 @@ function dispatchElement(element, registry, action) {
|
|
|
1786
1392
|
};
|
|
1787
1393
|
}
|
|
1788
1394
|
if (element.role === "toggle" && (action === "toggle" || isPressLike(action))) {
|
|
1395
|
+
if (element.listContext) {
|
|
1396
|
+
const toggled = toggleListItemByIdentity(
|
|
1397
|
+
{
|
|
1398
|
+
listIndex: element.listContext.listIndex,
|
|
1399
|
+
listId: element.listContext.listId,
|
|
1400
|
+
listLabel: element.listContext.listLabel,
|
|
1401
|
+
itemIndex: element.listContext.itemIndex,
|
|
1402
|
+
itemKey: element.listContext.itemKey,
|
|
1403
|
+
reactKey: element.listContext.reactKey,
|
|
1404
|
+
syntheticId: element.listContext.syntheticId,
|
|
1405
|
+
label: element.label,
|
|
1406
|
+
texts: element.texts
|
|
1407
|
+
},
|
|
1408
|
+
// The observation's `selected` is the state BEFORE this action.
|
|
1409
|
+
// Passing the desired end state makes the flip idempotent: a
|
|
1410
|
+
// retry or a recovery hop must not undo the work and call it
|
|
1411
|
+
// success. A toggle only knows how to invert, so without this the
|
|
1412
|
+
// second attempt silently returns the row to where it started.
|
|
1413
|
+
typeof element.selected === "boolean" ? { expected: !element.selected } : void 0
|
|
1414
|
+
);
|
|
1415
|
+
if (toggled.ok) {
|
|
1416
|
+
return {
|
|
1417
|
+
success: true,
|
|
1418
|
+
// Grounded: read back off the fiber after the handler ran, not
|
|
1419
|
+
// inferred from "the call did not throw".
|
|
1420
|
+
effect: "changed"
|
|
1421
|
+
};
|
|
1422
|
+
}
|
|
1423
|
+
return {
|
|
1424
|
+
success: false,
|
|
1425
|
+
error: toggled.error ?? `Could not flip the switch in row "${element.label ?? element.id}" (${toggled.reason})`,
|
|
1426
|
+
diagnose: {
|
|
1427
|
+
...screenDiagnose(
|
|
1428
|
+
element.id,
|
|
1429
|
+
toggled.reason === "ambiguous-touchables" || toggled.reason === "ambiguous-items" ? "ambiguous-target" : "component-not-found"
|
|
1430
|
+
),
|
|
1431
|
+
...toggled.candidates && toggled.candidates.length > 0 ? { candidates: toggled.candidates } : {}
|
|
1432
|
+
}
|
|
1433
|
+
};
|
|
1434
|
+
}
|
|
1789
1435
|
const targetId = element.targetId ?? element.label ?? element.id;
|
|
1790
1436
|
return dispatchLegacyTarget(targetId, registry, "toggle");
|
|
1791
1437
|
}
|
|
@@ -1805,7 +1451,7 @@ function dispatchElement(element, registry, action) {
|
|
|
1805
1451
|
}
|
|
1806
1452
|
function dispatchStructuredElementId(identifier, action) {
|
|
1807
1453
|
if (!isElementIdentifier(identifier) || !isPressLike(action)) return null;
|
|
1808
|
-
const parsed =
|
|
1454
|
+
const parsed = chunkYB77RYCC_js.parseStableElementId(identifier);
|
|
1809
1455
|
if (!parsed || parsed.role !== "option") return null;
|
|
1810
1456
|
if (!parsed.itemKey && !parsed.listId) return null;
|
|
1811
1457
|
const pressed = pressListItemByIdentity({
|
|
@@ -1815,8 +1461,8 @@ function dispatchStructuredElementId(identifier, action) {
|
|
|
1815
1461
|
texts: parsed.itemKey ? [parsed.itemKey] : void 0
|
|
1816
1462
|
});
|
|
1817
1463
|
if (pressed.ok) {
|
|
1818
|
-
|
|
1819
|
-
`
|
|
1464
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
1465
|
+
`elementDispatch: resolved stale el id "${identifier}" via structural identity (listId="${parsed.listId}", itemKey="${parsed.itemKey}")`
|
|
1820
1466
|
);
|
|
1821
1467
|
return { success: true };
|
|
1822
1468
|
}
|
|
@@ -1840,25 +1486,24 @@ function pressElementOrTarget(identifier, registry) {
|
|
|
1840
1486
|
|
|
1841
1487
|
// src/executor/formFieldRewrite.ts
|
|
1842
1488
|
var LIST_ORDINAL_RE = /^list-\d+-item-\d+$/i;
|
|
1843
|
-
var PLATE_RE = /^[A-Z]{3}-?\d[A-Z0-9]\d{2}$/i;
|
|
1844
1489
|
function normalize4(value) {
|
|
1845
1490
|
return value.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
|
|
1846
1491
|
}
|
|
1847
1492
|
function resolveScreenForFormFields() {
|
|
1848
|
-
const activePath =
|
|
1493
|
+
const activePath = chunkYB77RYCC_js.getActiveRouteNames();
|
|
1849
1494
|
for (let i = activePath.length - 1; i >= 0; i--) {
|
|
1850
1495
|
const name = activePath[i];
|
|
1851
|
-
const meta = name ?
|
|
1496
|
+
const meta = name ? chunkYB77RYCC_js.getScreenMetadata(name) : void 0;
|
|
1852
1497
|
if (name && Array.isArray(meta?.fields) && meta.fields.length > 0) return name;
|
|
1853
1498
|
}
|
|
1854
|
-
return
|
|
1499
|
+
return chunkYB77RYCC_js.getCurrentScreen();
|
|
1855
1500
|
}
|
|
1856
1501
|
function collectKnownFormFields(registry) {
|
|
1857
1502
|
const registryFields = registry.snapshot().filter((entry) => entry.kind === "field" || entry.kind === "slider").map((entry) => ({ id: entry.id, label: entry.label }));
|
|
1858
1503
|
if (registryFields.length >= 2) return registryFields;
|
|
1859
1504
|
const screen = resolveScreenForFormFields();
|
|
1860
1505
|
if (screen) {
|
|
1861
|
-
const metaFields =
|
|
1506
|
+
const metaFields = chunkYB77RYCC_js.getScreenMetadata(screen)?.fields;
|
|
1862
1507
|
if (Array.isArray(metaFields) && metaFields.length > 0) {
|
|
1863
1508
|
return metaFields.filter((field) => !!field && typeof field.id === "string").map((field) => ({
|
|
1864
1509
|
id: field.id,
|
|
@@ -1868,7 +1513,7 @@ function collectKnownFormFields(registry) {
|
|
|
1868
1513
|
}));
|
|
1869
1514
|
}
|
|
1870
1515
|
}
|
|
1871
|
-
for (const meta of
|
|
1516
|
+
for (const meta of chunkYB77RYCC_js.getAllScreens()) {
|
|
1872
1517
|
if (Array.isArray(meta.fields) && meta.fields.length > 0) {
|
|
1873
1518
|
return meta.fields.filter((field) => !!field && typeof field.id === "string").map((field) => ({
|
|
1874
1519
|
id: field.id,
|
|
@@ -1880,9 +1525,6 @@ function collectKnownFormFields(registry) {
|
|
|
1880
1525
|
}
|
|
1881
1526
|
return registryFields;
|
|
1882
1527
|
}
|
|
1883
|
-
function fieldHaystack(field) {
|
|
1884
|
-
return normalize4(`${field.id} ${field.label ?? ""}`);
|
|
1885
|
-
}
|
|
1886
1528
|
function isMisplacedFieldId(fieldId, knownIds) {
|
|
1887
1529
|
const trimmed = fieldId.trim();
|
|
1888
1530
|
if (!trimmed) return true;
|
|
@@ -1906,50 +1548,68 @@ function valueMatchesOption(field, rawValue) {
|
|
|
1906
1548
|
return label === value || optionValue === value || value.includes(label) || value.includes(optionValue);
|
|
1907
1549
|
});
|
|
1908
1550
|
}
|
|
1551
|
+
var NUMERIC_FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
1552
|
+
"number",
|
|
1553
|
+
"numeric",
|
|
1554
|
+
"integer",
|
|
1555
|
+
"int",
|
|
1556
|
+
"decimal",
|
|
1557
|
+
"float",
|
|
1558
|
+
"range",
|
|
1559
|
+
"slider",
|
|
1560
|
+
"tel",
|
|
1561
|
+
"phone"
|
|
1562
|
+
]);
|
|
1563
|
+
var DATE_FIELD_TYPES = /* @__PURE__ */ new Set(["date", "datetime", "datetimelocal", "time", "month"]);
|
|
1564
|
+
var EMAIL_FIELD_TYPES = /* @__PURE__ */ new Set(["email"]);
|
|
1565
|
+
var CHOICE_FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
1566
|
+
"select",
|
|
1567
|
+
"picker",
|
|
1568
|
+
"dropdown",
|
|
1569
|
+
"combobox",
|
|
1570
|
+
"radio",
|
|
1571
|
+
"checkbox",
|
|
1572
|
+
"switch",
|
|
1573
|
+
"toggle",
|
|
1574
|
+
"segmented",
|
|
1575
|
+
"boolean"
|
|
1576
|
+
]);
|
|
1577
|
+
function readValueShape(rawValue) {
|
|
1578
|
+
const value = String(rawValue ?? "").trim();
|
|
1579
|
+
if (!value) return "text";
|
|
1580
|
+
if (/^-?\d+(?:[.,]\d+)?$/.test(value)) return "number";
|
|
1581
|
+
if (/^\S+@\S+\.\S+$/.test(value)) return "email";
|
|
1582
|
+
if (/^\d{4}-\d{2}-\d{2}(?:[T\s]\d{2}:\d{2}(?::\d{2})?)?$/.test(value)) return "date";
|
|
1583
|
+
if (/^\d{1,2}[/-]\d{1,2}[/-]\d{2,4}$/.test(value)) return "date";
|
|
1584
|
+
return "text";
|
|
1585
|
+
}
|
|
1586
|
+
function fieldTypeMatchesShape(field, shape) {
|
|
1587
|
+
const type = normalize4(field.type ?? "text");
|
|
1588
|
+
if (CHOICE_FIELD_TYPES.has(type)) return false;
|
|
1589
|
+
if (shape === "number") return NUMERIC_FIELD_TYPES.has(type);
|
|
1590
|
+
if (shape === "date") return DATE_FIELD_TYPES.has(type);
|
|
1591
|
+
if (shape === "email") return EMAIL_FIELD_TYPES.has(type);
|
|
1592
|
+
return false;
|
|
1593
|
+
}
|
|
1594
|
+
function fieldAcceptsFreeText(field, shape) {
|
|
1595
|
+
const type = normalize4(field.type ?? "text");
|
|
1596
|
+
if (CHOICE_FIELD_TYPES.has(type)) return false;
|
|
1597
|
+
if (NUMERIC_FIELD_TYPES.has(type)) return shape === "number";
|
|
1598
|
+
if (DATE_FIELD_TYPES.has(type)) return shape === "date";
|
|
1599
|
+
if (EMAIL_FIELD_TYPES.has(type)) return shape === "email";
|
|
1600
|
+
return true;
|
|
1601
|
+
}
|
|
1909
1602
|
function inferFieldIdForValue(rawValue, fields, used) {
|
|
1910
1603
|
const value = String(rawValue ?? "").trim();
|
|
1911
1604
|
if (!value) return void 0;
|
|
1912
|
-
const
|
|
1913
|
-
for (const field of
|
|
1914
|
-
if (used.has(field.id)) continue;
|
|
1605
|
+
const available = fields.filter((field) => field.id && !used.has(field.id));
|
|
1606
|
+
for (const field of available) {
|
|
1915
1607
|
if (valueMatchesOption(field, value)) return field.id;
|
|
1916
1608
|
}
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
if (/^(19|20)\d{2}$/.test(value)) {
|
|
1922
|
-
const field = fields.find((f) => /ano|year/.test(fieldHaystack(f)) && !used.has(f.id));
|
|
1923
|
-
if (field) return field.id;
|
|
1924
|
-
}
|
|
1925
|
-
if (/^\d+$/.test(value)) {
|
|
1926
|
-
const mileage = fields.find((f) => /quilometragem|mileage|km/.test(fieldHaystack(f)) && !used.has(f.id));
|
|
1927
|
-
if (mileage) return mileage.id;
|
|
1928
|
-
const year = fields.find((f) => /ano|year/.test(fieldHaystack(f)) && !used.has(f.id));
|
|
1929
|
-
if (year) return year.id;
|
|
1930
|
-
}
|
|
1931
|
-
if (/preto|branco|azul|vermelho|prata|black|white|red|blue|silver|gray|grey/.test(normalizedValue)) {
|
|
1932
|
-
const cor = fields.find((f) => /cor|color/.test(fieldHaystack(f)) && !used.has(f.id));
|
|
1933
|
-
if (cor) return cor.id;
|
|
1934
|
-
}
|
|
1935
|
-
const marca = fields.find((f) => /marca|brand|make/.test(fieldHaystack(f)) && !used.has(f.id));
|
|
1936
|
-
if (marca && !/model/i.test(normalizedValue)) return marca.id;
|
|
1937
|
-
const modelo = fields.find((f) => /modelo|model/.test(fieldHaystack(f)) && !used.has(f.id));
|
|
1938
|
-
if (modelo) return modelo.id;
|
|
1939
|
-
const tipo = fields.find((f) => /\btipo\b|type|vehicletype/.test(fieldHaystack(f)) && !used.has(f.id));
|
|
1940
|
-
if (tipo && /carro|car|moto|truck|van|flex|gasoline|diesel|hybrid|electric|el[eé]trico/.test(normalizedValue)) {
|
|
1941
|
-
return tipo.id;
|
|
1942
|
-
}
|
|
1943
|
-
const combustivel = fields.find((f) => /combustivel|fuel/.test(fieldHaystack(f)) && !used.has(f.id));
|
|
1944
|
-
if (combustivel && /flex|gasoline|diesel|hybrid|electric|el[eé]trico/.test(normalizedValue)) {
|
|
1945
|
-
return combustivel.id;
|
|
1946
|
-
}
|
|
1947
|
-
const nextText = fields.find((field) => {
|
|
1948
|
-
if (used.has(field.id)) return false;
|
|
1949
|
-
const type = normalize4(field.type ?? "text");
|
|
1950
|
-
return type === "text" || type === "input" || type === "number" || type === "";
|
|
1951
|
-
});
|
|
1952
|
-
return nextText?.id;
|
|
1609
|
+
const shape = readValueShape(value);
|
|
1610
|
+
const typed = available.find((field) => fieldTypeMatchesShape(field, shape));
|
|
1611
|
+
if (typed) return typed.id;
|
|
1612
|
+
return available.find((field) => fieldAcceptsFreeText(field, shape))?.id;
|
|
1953
1613
|
}
|
|
1954
1614
|
function rewriteMisplacedFormFillFields(fields, registry) {
|
|
1955
1615
|
const knownFields = collectKnownFormFields(registry);
|
|
@@ -1966,7 +1626,7 @@ function rewriteMisplacedFormFillFields(fields, registry) {
|
|
|
1966
1626
|
const inferred = inferFieldIdForValue(String(field.value ?? ""), knownFields, used);
|
|
1967
1627
|
if (!inferred) return field;
|
|
1968
1628
|
used.add(inferred);
|
|
1969
|
-
|
|
1629
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
1970
1630
|
`formFieldRewrite: ${field.fieldId} \u2192 ${inferred} (value=${JSON.stringify(field.value)})`
|
|
1971
1631
|
);
|
|
1972
1632
|
return { ...field, fieldId: inferred };
|
|
@@ -1974,28 +1634,36 @@ function rewriteMisplacedFormFillFields(fields, registry) {
|
|
|
1974
1634
|
}
|
|
1975
1635
|
|
|
1976
1636
|
// src/executor/formValidation.ts
|
|
1977
|
-
var
|
|
1978
|
-
var FORM_SUCCESS_TEXT_RE =
|
|
1637
|
+
var FORM_VALIDATION_TEXT_RE2 = chunkYB77RYCC_js.FORM_VALIDATION_TEXT_RE;
|
|
1638
|
+
var FORM_SUCCESS_TEXT_RE = chunkYB77RYCC_js.FORM_WRITE_SUCCESS_TEXT_RE;
|
|
1979
1639
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
]
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1640
|
+
function inferValidationFieldId(message, inputs) {
|
|
1641
|
+
const haystack = normalizeText(message);
|
|
1642
|
+
if (!haystack || !inputs?.length) return void 0;
|
|
1643
|
+
let best;
|
|
1644
|
+
for (const input of inputs) {
|
|
1645
|
+
const id = input?.id;
|
|
1646
|
+
if (!id) continue;
|
|
1647
|
+
for (const naming of [input.label, input.placeholder, id]) {
|
|
1648
|
+
const needle = normalizeText(naming ?? "");
|
|
1649
|
+
if (needle.length < 3) continue;
|
|
1650
|
+
if (!containsWord(haystack, needle)) continue;
|
|
1651
|
+
if (!best || needle.length > best.length) best = { id, length: needle.length };
|
|
1652
|
+
}
|
|
1991
1653
|
}
|
|
1992
|
-
return
|
|
1654
|
+
return best?.id;
|
|
1655
|
+
}
|
|
1656
|
+
function normalizeText(value) {
|
|
1657
|
+
return String(value ?? "").normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
1658
|
+
}
|
|
1659
|
+
function containsWord(haystack, needle) {
|
|
1660
|
+
return ` ${haystack} `.includes(` ${needle} `);
|
|
1993
1661
|
}
|
|
1994
1662
|
function readVisibleFormValidation(snap) {
|
|
1995
1663
|
if (!snap) return void 0;
|
|
1996
1664
|
for (const text of snap.texts ?? []) {
|
|
1997
|
-
if (!text?.trim() || !
|
|
1998
|
-
return { fieldId: inferValidationFieldId(text), message: text };
|
|
1665
|
+
if (!text?.trim() || !FORM_VALIDATION_TEXT_RE2.test(text)) continue;
|
|
1666
|
+
return { fieldId: inferValidationFieldId(text, snap.inputs), message: text };
|
|
1999
1667
|
}
|
|
2000
1668
|
return void 0;
|
|
2001
1669
|
}
|
|
@@ -2004,7 +1672,7 @@ function readVisibleFormSuccess(snap) {
|
|
|
2004
1672
|
return (snap.texts ?? []).find((text) => text?.trim() && FORM_SUCCESS_TEXT_RE.test(text));
|
|
2005
1673
|
}
|
|
2006
1674
|
function submitAsyncStillPending(submitTargetId) {
|
|
2007
|
-
const probe =
|
|
1675
|
+
const probe = chunkYB77RYCC_js.probeLoadingState(submitTargetId ?? null, chunkYB77RYCC_js.getCurrentScreen());
|
|
2008
1676
|
if (probe.loading) return true;
|
|
2009
1677
|
if (submitTargetId && probe.pressedFound && probe.pressedDisabled) return true;
|
|
2010
1678
|
return false;
|
|
@@ -2016,7 +1684,7 @@ function evaluatePostSubmitSnapshot(snap, activePath) {
|
|
|
2016
1684
|
}
|
|
2017
1685
|
const successText = readVisibleFormSuccess(snap);
|
|
2018
1686
|
if (successText) return { status: "success", message: successText };
|
|
2019
|
-
if (!
|
|
1687
|
+
if (!chunkYB77RYCC_js.snapshotShowsOpenCreateForm(snap, activePath)) {
|
|
2020
1688
|
return { status: "success" };
|
|
2021
1689
|
}
|
|
2022
1690
|
return void 0;
|
|
@@ -2032,7 +1700,7 @@ async function waitForPostSubmitOutcome(options) {
|
|
|
2032
1700
|
continue;
|
|
2033
1701
|
}
|
|
2034
1702
|
const snap2 = captureSnapshot();
|
|
2035
|
-
const activePath2 =
|
|
1703
|
+
const activePath2 = chunkYB77RYCC_js.getActiveRouteNames();
|
|
2036
1704
|
const outcome2 = evaluatePostSubmitSnapshot(snap2, activePath2);
|
|
2037
1705
|
if (outcome2) return outcome2;
|
|
2038
1706
|
await sleep(pollMs);
|
|
@@ -2044,7 +1712,7 @@ async function waitForPostSubmitOutcome(options) {
|
|
|
2044
1712
|
};
|
|
2045
1713
|
}
|
|
2046
1714
|
const snap = captureSnapshot();
|
|
2047
|
-
const activePath =
|
|
1715
|
+
const activePath = chunkYB77RYCC_js.getActiveRouteNames();
|
|
2048
1716
|
const outcome = evaluatePostSubmitSnapshot(snap, activePath);
|
|
2049
1717
|
if (outcome) return outcome;
|
|
2050
1718
|
return {
|
|
@@ -2150,16 +1818,16 @@ function findSnapshotButton(targetId) {
|
|
|
2150
1818
|
}
|
|
2151
1819
|
}
|
|
2152
1820
|
function buildUiDiagnose(targetId, cause) {
|
|
2153
|
-
const activePath =
|
|
2154
|
-
const screen = activePath[activePath.length - 1] ??
|
|
1821
|
+
const activePath = chunkYB77RYCC_js.getActiveRouteNames();
|
|
1822
|
+
const screen = activePath[activePath.length - 1] ?? chunkYB77RYCC_js.getCurrentScreen() ?? void 0;
|
|
2155
1823
|
const screenPath = activePath.length > 1 ? activePath.join("/") : screen;
|
|
2156
1824
|
const diagnose = {
|
|
2157
1825
|
category: cause === "not-found" ? "component-not-found" : cause === "disabled" ? "disabled" : "unknown",
|
|
2158
1826
|
targetId,
|
|
2159
1827
|
screen: screenPath
|
|
2160
1828
|
};
|
|
2161
|
-
if (
|
|
2162
|
-
diagnose.visibleMessage =
|
|
1829
|
+
if (chunkYB77RYCC_js.isOptionalStepAutomationFailure(targetId, screenPath, activePath)) {
|
|
1830
|
+
diagnose.visibleMessage = chunkYB77RYCC_js.OPTIONAL_STEP_AUTOMATION_HINT;
|
|
2163
1831
|
diagnose.recoverable = true;
|
|
2164
1832
|
}
|
|
2165
1833
|
return diagnose;
|
|
@@ -2217,13 +1885,15 @@ function resolveComponentId(componentId, registry, action) {
|
|
|
2217
1885
|
const snapshot = registry.snapshot();
|
|
2218
1886
|
for (const comp of snapshot) {
|
|
2219
1887
|
if (comp.id.toLowerCase() === lower) {
|
|
2220
|
-
|
|
1888
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
1889
|
+
`resolveComponentId: case-insensitive match "${componentId}" \u2192 "${comp.id}"`
|
|
1890
|
+
);
|
|
2221
1891
|
return comp.id;
|
|
2222
1892
|
}
|
|
2223
1893
|
}
|
|
2224
|
-
const currentScreen =
|
|
1894
|
+
const currentScreen = chunkYB77RYCC_js.getCurrentScreen();
|
|
2225
1895
|
if (currentScreen) {
|
|
2226
|
-
const screenMeta =
|
|
1896
|
+
const screenMeta = chunkYB77RYCC_js.getScreenMetadata(currentScreen);
|
|
2227
1897
|
const actions = screenMeta?.actions;
|
|
2228
1898
|
if (actions && Array.isArray(actions)) {
|
|
2229
1899
|
const metaAction = actions.find(
|
|
@@ -2232,12 +1902,16 @@ function resolveComponentId(componentId, registry, action) {
|
|
|
2232
1902
|
if (metaAction && typeof metaAction === "object" && metaAction.label) {
|
|
2233
1903
|
const metaLabel = metaAction.label;
|
|
2234
1904
|
const normalizedMetaLabel = metaLabel.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
|
|
2235
|
-
|
|
1905
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
1906
|
+
`resolveComponentId: found screen metadata for "${componentId}" \u2192 label="${metaLabel}"`
|
|
1907
|
+
);
|
|
2236
1908
|
for (const comp of snapshot) {
|
|
2237
1909
|
if (!comp.label) continue;
|
|
2238
1910
|
const compLabel = comp.label.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
|
|
2239
1911
|
if (compLabel === normalizedMetaLabel || compLabel.includes(normalizedMetaLabel) || normalizedMetaLabel.includes(compLabel)) {
|
|
2240
|
-
|
|
1912
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
1913
|
+
`resolveComponentId: FOUND via metadata: "${componentId}" \u2192 "${comp.id}" (label="${comp.label}")`
|
|
1914
|
+
);
|
|
2241
1915
|
return comp.id;
|
|
2242
1916
|
}
|
|
2243
1917
|
}
|
|
@@ -2252,8 +1926,8 @@ function resolveComponentId(componentId, registry, action) {
|
|
|
2252
1926
|
}));
|
|
2253
1927
|
const match = resolveTarget(componentId, candidates, { action });
|
|
2254
1928
|
if (match.status === "matched") {
|
|
2255
|
-
|
|
2256
|
-
`
|
|
1929
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
1930
|
+
`resolveComponentId: matched "${componentId}" -> "${match.id}" (tier=${match.tier})`
|
|
2257
1931
|
);
|
|
2258
1932
|
return match.id;
|
|
2259
1933
|
}
|
|
@@ -2342,8 +2016,8 @@ function setValueHandler(rawComponentId, requested, registry) {
|
|
|
2342
2016
|
try {
|
|
2343
2017
|
slider.setValue(applied);
|
|
2344
2018
|
if (applied !== requestedValue) {
|
|
2345
|
-
|
|
2346
|
-
`
|
|
2019
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2020
|
+
`uiInteractionHandler: set_value snapped ${requestedValue} \u2192 ${applied} for "${componentId}" (step=${step})`
|
|
2347
2021
|
);
|
|
2348
2022
|
}
|
|
2349
2023
|
return { success: true, effect: "changed" };
|
|
@@ -2377,11 +2051,26 @@ function checkModalOcclusion(rawComponentId, action) {
|
|
|
2377
2051
|
return null;
|
|
2378
2052
|
}
|
|
2379
2053
|
if (typeof rawComponentId !== "string" || rawComponentId.trim().length === 0) return null;
|
|
2380
|
-
const
|
|
2054
|
+
const dialog = chunkYB77RYCC_js.getOpenNativeDialog();
|
|
2055
|
+
if (dialog) {
|
|
2056
|
+
const needle = normalizeIdent(rawComponentId);
|
|
2057
|
+
if (dialog.buttons.some((b) => normalizeIdent(b.label) === needle)) return null;
|
|
2058
|
+
return {
|
|
2059
|
+
success: false,
|
|
2060
|
+
error: `"${rawComponentId}" is behind a native dialog${dialog.title ? ` ("${dialog.title}")` : ""} and cannot receive touches. Answer the dialog first \u2014 press one of: ` + dialog.buttons.map((b) => b.label).join(", "),
|
|
2061
|
+
diagnose: {
|
|
2062
|
+
category: "ambiguous-target",
|
|
2063
|
+
targetId: rawComponentId,
|
|
2064
|
+
screen: chunkYB77RYCC_js.getCurrentScreen() ?? void 0,
|
|
2065
|
+
candidates: dialog.buttons.map((b) => b.label).slice(0, 8)
|
|
2066
|
+
}
|
|
2067
|
+
};
|
|
2068
|
+
}
|
|
2069
|
+
const fiberRoot = chunkYB77RYCC_js.getFiberRoot();
|
|
2381
2070
|
if (!fiberRoot) return null;
|
|
2382
2071
|
let snap;
|
|
2383
2072
|
try {
|
|
2384
|
-
snap = walkFiber(fiberRoot);
|
|
2073
|
+
snap = chunkYB77RYCC_js.walkFiber(fiberRoot);
|
|
2385
2074
|
} catch {
|
|
2386
2075
|
return null;
|
|
2387
2076
|
}
|
|
@@ -2408,9 +2097,12 @@ function checkModalOcclusion(rawComponentId, action) {
|
|
|
2408
2097
|
modalOptionLabels.push(button.label ?? button.id);
|
|
2409
2098
|
}
|
|
2410
2099
|
}
|
|
2411
|
-
for (const toggle of snap.toggles ?? [])
|
|
2412
|
-
|
|
2413
|
-
for (const
|
|
2100
|
+
for (const toggle of snap.toggles ?? [])
|
|
2101
|
+
add(toggle.inModal ? inModal : outside, toggle.id, toggle.label);
|
|
2102
|
+
for (const input of snap.inputs ?? [])
|
|
2103
|
+
add(input.inModal ? inModal : outside, input.id, input.label);
|
|
2104
|
+
for (const slider of snap.sliders ?? [])
|
|
2105
|
+
add(slider.inModal ? inModal : outside, slider.id, slider.label);
|
|
2414
2106
|
for (const list of snap.lists ?? []) {
|
|
2415
2107
|
for (const item of list.items ?? []) {
|
|
2416
2108
|
const itemInModal = (item.buttons ?? []).some((b) => b.inModal) || (item.inputs ?? []).some((i) => i.inModal) || (item.toggles ?? []).some((t) => t.inModal);
|
|
@@ -2440,12 +2132,15 @@ function checkModalOcclusion(rawComponentId, action) {
|
|
|
2440
2132
|
}
|
|
2441
2133
|
function uiInteractionHandler(payload, context) {
|
|
2442
2134
|
const { permissions } = context;
|
|
2443
|
-
const registry = context.registry ??
|
|
2135
|
+
const registry = context.registry ?? chunkYB77RYCC_js.componentRegistry;
|
|
2444
2136
|
if (!permissions.canInteractUI) {
|
|
2445
2137
|
return {
|
|
2446
2138
|
success: false,
|
|
2447
2139
|
error: "UI interaction is not permitted",
|
|
2448
|
-
diagnose: buildUiDiagnose(
|
|
2140
|
+
diagnose: buildUiDiagnose(
|
|
2141
|
+
payload.componentId ?? payload.targetId ?? "",
|
|
2142
|
+
"unknown"
|
|
2143
|
+
)
|
|
2449
2144
|
};
|
|
2450
2145
|
}
|
|
2451
2146
|
const { action } = payload;
|
|
@@ -2459,8 +2154,8 @@ function uiInteractionHandler(payload, context) {
|
|
|
2459
2154
|
if (sliderId) {
|
|
2460
2155
|
const smuggled = payload.value ?? payload.params?.value;
|
|
2461
2156
|
if (smuggled !== void 0) {
|
|
2462
|
-
|
|
2463
|
-
`
|
|
2157
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2158
|
+
`uiInteractionHandler: "${actionStr}" on slider "${sliderId}" carried value=${JSON.stringify(smuggled)} \u2014 routing to set_value`
|
|
2464
2159
|
);
|
|
2465
2160
|
return setValueHandler(rawComponentId, smuggled, registry);
|
|
2466
2161
|
}
|
|
@@ -2470,18 +2165,53 @@ function uiInteractionHandler(payload, context) {
|
|
|
2470
2165
|
diagnose: { ...buildUiDiagnose(sliderId, "unknown"), recoverable: true }
|
|
2471
2166
|
};
|
|
2472
2167
|
}
|
|
2168
|
+
const openDialog = chunkYB77RYCC_js.getOpenNativeDialog();
|
|
2169
|
+
const isPressVerb = actionStr === "press" || actionStr === "tap" || actionStr === "click";
|
|
2170
|
+
if (openDialog && isPressVerb) {
|
|
2171
|
+
const needle = normalizeIdent(rawComponentId);
|
|
2172
|
+
const button = openDialog.buttons.find((b) => normalizeIdent(b.label) === needle);
|
|
2173
|
+
if (button) {
|
|
2174
|
+
button.press();
|
|
2175
|
+
chunkYB77RYCC_js.appilotsDebugLog(`uiInteractionHandler: pressed native dialog button "${button.label}"`);
|
|
2176
|
+
return { success: true, effect: "changed" };
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
if (!openDialog && isPressVerb) {
|
|
2180
|
+
const answered = chunkYB77RYCC_js.getLastAnsweredNativeDialog();
|
|
2181
|
+
const needle = normalizeIdent(rawComponentId);
|
|
2182
|
+
if (answered && needle) {
|
|
2183
|
+
if (answered.answeredWith && normalizeIdent(answered.answeredWith) === needle) {
|
|
2184
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2185
|
+
`uiInteractionHandler: native dialog button "${answered.answeredWith}" was already pressed and the dialog is closed \u2014 treating the repeat as done`
|
|
2186
|
+
);
|
|
2187
|
+
return { success: true, effect: "completed" };
|
|
2188
|
+
}
|
|
2189
|
+
if (answered.buttons.some((label) => normalizeIdent(label) === needle)) {
|
|
2190
|
+
return {
|
|
2191
|
+
success: false,
|
|
2192
|
+
error: `The dialog${answered.title ? ` ("${answered.title}")` : ""} was already answered with "${answered.answeredWith ?? "dismiss"}", so "${rawComponentId}" is no longer on screen. Read the current screen before acting again.`,
|
|
2193
|
+
diagnose: {
|
|
2194
|
+
category: "component-not-found",
|
|
2195
|
+
targetId: rawComponentId,
|
|
2196
|
+
screen: chunkYB77RYCC_js.getCurrentScreen() ?? void 0,
|
|
2197
|
+
recoverable: false
|
|
2198
|
+
}
|
|
2199
|
+
};
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2473
2203
|
const occluded = checkModalOcclusion(rawComponentId, actionStr);
|
|
2474
2204
|
if (occluded) {
|
|
2475
|
-
|
|
2476
|
-
`
|
|
2205
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2206
|
+
`uiInteractionHandler: blocked "${actionStr}" on "${rawComponentId}" \u2014 target is behind an open modal`
|
|
2477
2207
|
);
|
|
2478
2208
|
return occluded;
|
|
2479
2209
|
}
|
|
2480
2210
|
if (typeof rawComponentId === "string" && rawComponentId.trim().toLowerCase().startsWith("el:")) {
|
|
2481
2211
|
const result = dispatchElementOrTarget(rawComponentId, registry, actionStr);
|
|
2482
2212
|
if (result.success) {
|
|
2483
|
-
|
|
2484
|
-
`
|
|
2213
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2214
|
+
`uiInteractionHandler: interaction element dispatch succeeded for "${rawComponentId}"`
|
|
2485
2215
|
);
|
|
2486
2216
|
return { success: true };
|
|
2487
2217
|
}
|
|
@@ -2489,17 +2219,17 @@ function uiInteractionHandler(payload, context) {
|
|
|
2489
2219
|
}
|
|
2490
2220
|
const ordinal = parseSyntheticListItemId(rawComponentId);
|
|
2491
2221
|
if (ordinal && (action === "press" || actionStr === "tap" || actionStr === "click" || actionStr === "longPress")) {
|
|
2492
|
-
|
|
2493
|
-
`
|
|
2222
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2223
|
+
`uiInteractionHandler: dispatching synthetic list ordinal \u2014 componentId="${rawComponentId}" list=${ordinal.listIndex} item=${ordinal.itemIndex}`
|
|
2494
2224
|
);
|
|
2495
2225
|
const result = pressListItemAtOrdinal(ordinal.listIndex, ordinal.itemIndex);
|
|
2496
2226
|
if (result.ok) {
|
|
2497
|
-
|
|
2498
|
-
`
|
|
2227
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2228
|
+
`uiInteractionHandler: synthetic ordinal press succeeded (container=${result.containerType ?? "List"})`
|
|
2499
2229
|
);
|
|
2500
2230
|
return { success: true };
|
|
2501
2231
|
}
|
|
2502
|
-
const screen =
|
|
2232
|
+
const screen = chunkYB77RYCC_js.getCurrentScreen() ?? void 0;
|
|
2503
2233
|
if (result.reason === "list-not-found" || result.reason === "item-not-found") {
|
|
2504
2234
|
return {
|
|
2505
2235
|
success: false,
|
|
@@ -2540,7 +2270,9 @@ function uiInteractionHandler(payload, context) {
|
|
|
2540
2270
|
};
|
|
2541
2271
|
}
|
|
2542
2272
|
const componentId = resolveComponentId(rawComponentId, registry, actionStr);
|
|
2543
|
-
|
|
2273
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2274
|
+
`uiInteractionHandler: resolved componentId="${payload.componentId}" \u2192 "${componentId}"`
|
|
2275
|
+
);
|
|
2544
2276
|
const target = registry.getTarget(componentId);
|
|
2545
2277
|
if (target) {
|
|
2546
2278
|
try {
|
|
@@ -2591,7 +2323,9 @@ function uiInteractionHandler(payload, context) {
|
|
|
2591
2323
|
return { success: false, error: err?.message ?? "Focus failed" };
|
|
2592
2324
|
}
|
|
2593
2325
|
}
|
|
2594
|
-
|
|
2326
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2327
|
+
`uiInteractionHandler: registry miss for "${componentId}", falling back to fiber tree`
|
|
2328
|
+
);
|
|
2595
2329
|
const handle = findInteractiveByIdentifier(componentId, {
|
|
2596
2330
|
kind: actionStr === "toggle" ? "toggle" : actionStr === "focus" ? "field" : "target"
|
|
2597
2331
|
});
|
|
@@ -2599,7 +2333,9 @@ function uiInteractionHandler(payload, context) {
|
|
|
2599
2333
|
try {
|
|
2600
2334
|
if (actionStr === "press" && handle.kind === "target" && handle.press) {
|
|
2601
2335
|
handle.press();
|
|
2602
|
-
|
|
2336
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2337
|
+
`uiInteractionHandler: fiber fallback press succeeded for "${componentId}"`
|
|
2338
|
+
);
|
|
2603
2339
|
return { success: true };
|
|
2604
2340
|
}
|
|
2605
2341
|
if (actionStr === "press" && handle.kind === "toggle" && handle.setValue) {
|
|
@@ -2664,7 +2400,7 @@ function submitLabelHintsSubmit(label) {
|
|
|
2664
2400
|
return SUBMIT_LABEL_HINT_RE.test(trimmed);
|
|
2665
2401
|
}
|
|
2666
2402
|
function screenDeclaresSubmitAction(screenName) {
|
|
2667
|
-
const meta =
|
|
2403
|
+
const meta = chunkYB77RYCC_js.getScreenMetadata(screenName);
|
|
2668
2404
|
return Array.isArray(meta?.actions) && meta.actions.some(
|
|
2669
2405
|
(action) => typeof action === "object" && action !== null && action.type === "submit"
|
|
2670
2406
|
);
|
|
@@ -2697,7 +2433,7 @@ function resolveFormScreensForSubmit(screen, activePath, registry) {
|
|
|
2697
2433
|
} else {
|
|
2698
2434
|
push(screen);
|
|
2699
2435
|
}
|
|
2700
|
-
push(
|
|
2436
|
+
push(chunkYB77RYCC_js.getCurrentScreen() ?? void 0);
|
|
2701
2437
|
const withSubmit = [];
|
|
2702
2438
|
const rest = [];
|
|
2703
2439
|
for (const name of ordered) {
|
|
@@ -2715,7 +2451,7 @@ function collectSubmitTargetCandidates(screens, registry) {
|
|
|
2715
2451
|
candidates.push(id);
|
|
2716
2452
|
};
|
|
2717
2453
|
for (const screenName of screens) {
|
|
2718
|
-
const meta =
|
|
2454
|
+
const meta = chunkYB77RYCC_js.getScreenMetadata(screenName);
|
|
2719
2455
|
const submitMeta = Array.isArray(meta?.actions) ? meta.actions.find(
|
|
2720
2456
|
(action) => typeof action === "object" && action !== null && action.type === "submit"
|
|
2721
2457
|
) : void 0;
|
|
@@ -2745,12 +2481,10 @@ function readVisibleValidation(fieldId, label) {
|
|
|
2745
2481
|
try {
|
|
2746
2482
|
const snap = captureSnapshot();
|
|
2747
2483
|
const texts = snap.texts ?? [];
|
|
2748
|
-
const needles = [fieldId, label].filter(
|
|
2749
|
-
(s) => !!s && s.length > 0
|
|
2750
|
-
);
|
|
2484
|
+
const needles = [fieldId, label].filter((s) => !!s && s.length > 0);
|
|
2751
2485
|
for (const text of texts) {
|
|
2752
2486
|
const lower = text.toLowerCase();
|
|
2753
|
-
if (
|
|
2487
|
+
if (FORM_VALIDATION_TEXT_RE2.test(lower)) {
|
|
2754
2488
|
for (const needle of needles) {
|
|
2755
2489
|
if (lower.includes(needle.toLowerCase())) return text;
|
|
2756
2490
|
}
|
|
@@ -2761,8 +2495,8 @@ function readVisibleValidation(fieldId, label) {
|
|
|
2761
2495
|
return void 0;
|
|
2762
2496
|
}
|
|
2763
2497
|
function resolveScreenContext() {
|
|
2764
|
-
const activePath =
|
|
2765
|
-
const screen = activePath[activePath.length - 1] ??
|
|
2498
|
+
const activePath = chunkYB77RYCC_js.getActiveRouteNames();
|
|
2499
|
+
const screen = activePath[activePath.length - 1] ?? chunkYB77RYCC_js.getCurrentScreen() ?? void 0;
|
|
2766
2500
|
return { screen, activePath };
|
|
2767
2501
|
}
|
|
2768
2502
|
function selectValueApplied(fieldId, requestedValue, currentValue, registry) {
|
|
@@ -2770,36 +2504,36 @@ function selectValueApplied(fieldId, requestedValue, currentValue, registry) {
|
|
|
2770
2504
|
if (!requested) return false;
|
|
2771
2505
|
const meta = getMetadataField(fieldId, registry);
|
|
2772
2506
|
const options = Array.isArray(meta?.options) ? meta.options : [];
|
|
2773
|
-
const requestedNorm =
|
|
2774
|
-
const currentNorm =
|
|
2507
|
+
const requestedNorm = chunkYB77RYCC_js.normalize3(requested);
|
|
2508
|
+
const currentNorm = chunkYB77RYCC_js.normalize3(currentValue);
|
|
2775
2509
|
if (currentNorm === requestedNorm) return true;
|
|
2776
2510
|
for (const option of options) {
|
|
2777
2511
|
const value = typeof option?.value === "string" ? option.value : "";
|
|
2778
2512
|
const label = typeof option?.label === "string" ? option.label : "";
|
|
2779
|
-
if (
|
|
2780
|
-
if (
|
|
2781
|
-
if (
|
|
2513
|
+
if (chunkYB77RYCC_js.normalize3(value) === requestedNorm && chunkYB77RYCC_js.normalize3(label) === currentNorm) return true;
|
|
2514
|
+
if (chunkYB77RYCC_js.normalize3(label) === requestedNorm && chunkYB77RYCC_js.normalize3(label) === currentNorm) return true;
|
|
2515
|
+
if (chunkYB77RYCC_js.normalize3(value) === requestedNorm && chunkYB77RYCC_js.normalize3(value) === currentNorm) return true;
|
|
2782
2516
|
}
|
|
2783
2517
|
return false;
|
|
2784
2518
|
}
|
|
2785
2519
|
function getMetadataField(fieldId, registry) {
|
|
2786
2520
|
const screens = /* @__PURE__ */ new Set();
|
|
2787
|
-
for (const name of
|
|
2788
|
-
const current =
|
|
2521
|
+
for (const name of chunkYB77RYCC_js.getActiveRouteNames()) screens.add(name);
|
|
2522
|
+
const current = chunkYB77RYCC_js.getCurrentScreen();
|
|
2789
2523
|
if (current) screens.add(current);
|
|
2790
2524
|
if (registry) {
|
|
2791
2525
|
for (const comp of registry.snapshot()) {
|
|
2792
2526
|
if (comp.kind === "field" && comp.screen) screens.add(comp.screen);
|
|
2793
2527
|
}
|
|
2794
2528
|
}
|
|
2795
|
-
const needle =
|
|
2529
|
+
const needle = chunkYB77RYCC_js.normalize3(fieldId);
|
|
2796
2530
|
for (const screenName of screens) {
|
|
2797
|
-
const screenMeta =
|
|
2531
|
+
const screenMeta = chunkYB77RYCC_js.getScreenMetadata(screenName);
|
|
2798
2532
|
const fields = Array.isArray(screenMeta?.fields) ? screenMeta.fields : [];
|
|
2799
2533
|
const match = fields.find((field) => {
|
|
2800
2534
|
if (!field || typeof field !== "object") return false;
|
|
2801
|
-
const id = typeof field.id === "string" ?
|
|
2802
|
-
const label = typeof field.label === "string" ?
|
|
2535
|
+
const id = typeof field.id === "string" ? chunkYB77RYCC_js.normalize3(field.id) : "";
|
|
2536
|
+
const label = typeof field.label === "string" ? chunkYB77RYCC_js.normalize3(field.label) : "";
|
|
2803
2537
|
return id === needle || label === needle;
|
|
2804
2538
|
});
|
|
2805
2539
|
if (match) return match;
|
|
@@ -2811,11 +2545,11 @@ function resolveSelectOption(fieldId, value, registry) {
|
|
|
2811
2545
|
if (!requested) return void 0;
|
|
2812
2546
|
const meta = getMetadataField(fieldId, registry);
|
|
2813
2547
|
const options = Array.isArray(meta?.options) ? meta.options : [];
|
|
2814
|
-
const requestedNorm =
|
|
2548
|
+
const requestedNorm = chunkYB77RYCC_js.normalize3(requested);
|
|
2815
2549
|
for (const option of options) {
|
|
2816
2550
|
const optionValue = typeof option?.value === "string" ? option.value : "";
|
|
2817
2551
|
const optionLabel = typeof option?.label === "string" ? option.label : "";
|
|
2818
|
-
if (
|
|
2552
|
+
if (chunkYB77RYCC_js.normalize3(optionValue) === requestedNorm || chunkYB77RYCC_js.normalize3(optionLabel) === requestedNorm) {
|
|
2819
2553
|
return { value: optionValue, label: optionLabel };
|
|
2820
2554
|
}
|
|
2821
2555
|
}
|
|
@@ -2865,14 +2599,16 @@ async function tryPressSelectOption(fieldId, value, registry, options = {}) {
|
|
|
2865
2599
|
return {
|
|
2866
2600
|
success: false,
|
|
2867
2601
|
error: `No pressable option found for select field "${fieldId}"`,
|
|
2868
|
-
diagnose: { category: "component-not-found", fieldId, screen:
|
|
2602
|
+
diagnose: { category: "component-not-found", fieldId, screen: chunkYB77RYCC_js.getCurrentScreen() ?? void 0 }
|
|
2869
2603
|
};
|
|
2870
2604
|
}
|
|
2871
2605
|
function normalizeFieldType(type) {
|
|
2872
2606
|
if (typeof type !== "string") return void 0;
|
|
2873
|
-
const normalized =
|
|
2874
|
-
if (normalized === "select" || normalized === "picker" || normalized === "dropdown")
|
|
2875
|
-
|
|
2607
|
+
const normalized = chunkYB77RYCC_js.normalize3(type);
|
|
2608
|
+
if (normalized === "select" || normalized === "picker" || normalized === "dropdown")
|
|
2609
|
+
return "select";
|
|
2610
|
+
if (normalized === "toggle" || normalized === "switch" || normalized === "checkbox")
|
|
2611
|
+
return "toggle";
|
|
2876
2612
|
if (normalized === "date") return "date";
|
|
2877
2613
|
if (normalized === "number" || normalized === "numeric") return "number";
|
|
2878
2614
|
if (normalized === "custom") return "custom";
|
|
@@ -2898,7 +2634,7 @@ function fieldCueTerms(fieldId, label) {
|
|
|
2898
2634
|
);
|
|
2899
2635
|
const terms = /* @__PURE__ */ new Set();
|
|
2900
2636
|
for (const value of raw) {
|
|
2901
|
-
const normalized =
|
|
2637
|
+
const normalized = chunkYB77RYCC_js.normalize3(value);
|
|
2902
2638
|
if (normalized.length >= 3 && normalized !== "id") terms.add(normalized);
|
|
2903
2639
|
}
|
|
2904
2640
|
return [...terms];
|
|
@@ -2906,20 +2642,17 @@ function fieldCueTerms(fieldId, label) {
|
|
|
2906
2642
|
function snapshotHasFieldCue(snap, fieldId, label) {
|
|
2907
2643
|
const terms = fieldCueTerms(fieldId, label);
|
|
2908
2644
|
if (terms.length === 0) return false;
|
|
2909
|
-
const visible = [
|
|
2910
|
-
...snap.texts ?? [],
|
|
2911
|
-
...(snap.buttons ?? []).map((b) => b.label ?? b.id ?? "")
|
|
2912
|
-
].map((text) => chunkAYWMBMSN_js.normalize3(text)).filter(Boolean);
|
|
2645
|
+
const visible = [...snap.texts ?? [], ...(snap.buttons ?? []).map((b) => b.label ?? b.id ?? "")].map((text) => chunkYB77RYCC_js.normalize3(text)).filter(Boolean);
|
|
2913
2646
|
return visible.some((text) => terms.some((term) => text.includes(term) || term.includes(text)));
|
|
2914
2647
|
}
|
|
2915
2648
|
function scoreCandidateText(value, texts) {
|
|
2916
|
-
const valueNorm =
|
|
2649
|
+
const valueNorm = chunkYB77RYCC_js.normalize3(String(value ?? ""));
|
|
2917
2650
|
if (!valueNorm) return 0;
|
|
2918
2651
|
let best = 0;
|
|
2919
2652
|
for (const text of texts) {
|
|
2920
|
-
const textNorm =
|
|
2653
|
+
const textNorm = chunkYB77RYCC_js.normalize3(text);
|
|
2921
2654
|
if (!textNorm) continue;
|
|
2922
|
-
best = Math.max(best,
|
|
2655
|
+
best = Math.max(best, chunkYB77RYCC_js.matchScore(valueNorm, textNorm));
|
|
2923
2656
|
}
|
|
2924
2657
|
return best;
|
|
2925
2658
|
}
|
|
@@ -2933,7 +2666,7 @@ function optionTexts(option) {
|
|
|
2933
2666
|
function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue, registry) {
|
|
2934
2667
|
const fieldLabel = getFieldLabel(fieldId, registry);
|
|
2935
2668
|
const fieldCueVisible = snapshotHasFieldCue(snap, fieldId, fieldLabel);
|
|
2936
|
-
const genericValue =
|
|
2669
|
+
const genericValue = chunkYB77RYCC_js.isGenericSelectValue(value);
|
|
2937
2670
|
const candidates = [];
|
|
2938
2671
|
let order = 0;
|
|
2939
2672
|
const choiceGroups = snap.choiceGroups ?? [];
|
|
@@ -2945,7 +2678,7 @@ function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue,
|
|
|
2945
2678
|
const groupCueScore = Math.max(
|
|
2946
2679
|
globalCueScore,
|
|
2947
2680
|
...groupTexts.map((text) => {
|
|
2948
|
-
const normalized =
|
|
2681
|
+
const normalized = chunkYB77RYCC_js.normalize3(text);
|
|
2949
2682
|
return fieldCueTerms(fieldId, fieldLabel).some(
|
|
2950
2683
|
(term) => normalized.includes(term) || term.includes(normalized)
|
|
2951
2684
|
) ? 80 : 0;
|
|
@@ -2982,10 +2715,8 @@ function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue,
|
|
|
2982
2715
|
const elementCueScore = Math.max(
|
|
2983
2716
|
fieldCueVisible && elements.length <= 12 ? 50 : 0,
|
|
2984
2717
|
...cueTexts.map((text) => {
|
|
2985
|
-
const normalized =
|
|
2986
|
-
return fieldTerms.some(
|
|
2987
|
-
(term) => normalized.includes(term) || term.includes(normalized)
|
|
2988
|
-
) ? 80 : 0;
|
|
2718
|
+
const normalized = chunkYB77RYCC_js.normalize3(text);
|
|
2719
|
+
return fieldTerms.some((term) => normalized.includes(term) || term.includes(normalized)) ? 80 : 0;
|
|
2989
2720
|
})
|
|
2990
2721
|
);
|
|
2991
2722
|
const valueScore = genericValue ? 0 : scoreCandidateText(value, texts);
|
|
@@ -3042,7 +2773,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
|
|
|
3042
2773
|
return {
|
|
3043
2774
|
success: false,
|
|
3044
2775
|
error: err?.message ?? "Could not capture visible choices",
|
|
3045
|
-
diagnose: { category: "unknown", fieldId, screen:
|
|
2776
|
+
diagnose: { category: "unknown", fieldId, screen: chunkYB77RYCC_js.getCurrentScreen() ?? void 0 }
|
|
3046
2777
|
};
|
|
3047
2778
|
}
|
|
3048
2779
|
const candidates = buildChoiceCandidates(
|
|
@@ -3057,7 +2788,11 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
|
|
|
3057
2788
|
return {
|
|
3058
2789
|
success: false,
|
|
3059
2790
|
error: `No visible option found for select field "${fieldId}"`,
|
|
3060
|
-
diagnose: {
|
|
2791
|
+
diagnose: {
|
|
2792
|
+
category: "component-not-found",
|
|
2793
|
+
fieldId,
|
|
2794
|
+
screen: chunkYB77RYCC_js.getCurrentScreen() ?? void 0
|
|
2795
|
+
}
|
|
3061
2796
|
};
|
|
3062
2797
|
}
|
|
3063
2798
|
const pressed = pressTargetByIdOrLabel(candidate.targetId, registry);
|
|
@@ -3070,7 +2805,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
|
|
|
3070
2805
|
}
|
|
3071
2806
|
function isContinuationButton(label) {
|
|
3072
2807
|
if (!label) return false;
|
|
3073
|
-
return /^(next|continue|proximo|prox|continuar|avancar|avançar)$/i.test(
|
|
2808
|
+
return /^(next|continue|proximo|prox|continuar|avancar|avançar)$/i.test(chunkYB77RYCC_js.normalize3(label));
|
|
3074
2809
|
}
|
|
3075
2810
|
function pressContinuationButton(registry) {
|
|
3076
2811
|
const snap = captureSnapshot();
|
|
@@ -3083,38 +2818,40 @@ function pressContinuationButton(registry) {
|
|
|
3083
2818
|
return {
|
|
3084
2819
|
success: false,
|
|
3085
2820
|
error: "No enabled continuation button is visible",
|
|
3086
|
-
diagnose: { category: "component-not-found", screen:
|
|
2821
|
+
diagnose: { category: "component-not-found", screen: chunkYB77RYCC_js.getCurrentScreen() ?? void 0 }
|
|
3087
2822
|
};
|
|
3088
2823
|
}
|
|
3089
2824
|
return pressTargetByIdOrLabel(id, registry);
|
|
3090
2825
|
}
|
|
3091
2826
|
function findField(fieldId, registry) {
|
|
3092
|
-
|
|
2827
|
+
chunkYB77RYCC_js.appilotsDebugLog(`findField: searching for fieldId="${fieldId}"`);
|
|
3093
2828
|
const exact = registry.getField(fieldId);
|
|
3094
2829
|
if (exact) {
|
|
3095
|
-
|
|
2830
|
+
chunkYB77RYCC_js.appilotsDebugLog(`findField: FOUND exact match for fieldId="${fieldId}"`);
|
|
3096
2831
|
return exact;
|
|
3097
2832
|
}
|
|
3098
2833
|
const lower = fieldId.toLowerCase();
|
|
3099
2834
|
const snapshot = registry.snapshot();
|
|
3100
2835
|
for (const comp of snapshot) {
|
|
3101
2836
|
if (comp.kind === "field" && comp.id.toLowerCase() === lower) {
|
|
3102
|
-
|
|
2837
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2838
|
+
`findField: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
|
|
2839
|
+
);
|
|
3103
2840
|
return registry.getField(comp.id);
|
|
3104
2841
|
}
|
|
3105
2842
|
}
|
|
3106
|
-
const currentScreenForTieBreak =
|
|
3107
|
-
const needle =
|
|
2843
|
+
const currentScreenForTieBreak = chunkYB77RYCC_js.getCurrentScreen();
|
|
2844
|
+
const needle = chunkYB77RYCC_js.normalize3(fieldId);
|
|
3108
2845
|
let bestComp;
|
|
3109
2846
|
let bestScore = 0;
|
|
3110
2847
|
let bestOnCurrentScreen = false;
|
|
3111
2848
|
for (const comp of snapshot) {
|
|
3112
2849
|
if (comp.kind !== "field") continue;
|
|
3113
|
-
const candidates = [
|
|
3114
|
-
if (comp.label) candidates.push(
|
|
2850
|
+
const candidates = [chunkYB77RYCC_js.normalize3(comp.id)];
|
|
2851
|
+
if (comp.label) candidates.push(chunkYB77RYCC_js.normalize3(comp.label));
|
|
3115
2852
|
let candidateScore = 0;
|
|
3116
2853
|
for (const cand of candidates) {
|
|
3117
|
-
const s =
|
|
2854
|
+
const s = chunkYB77RYCC_js.matchScore(needle, cand);
|
|
3118
2855
|
if (s > candidateScore) candidateScore = s;
|
|
3119
2856
|
}
|
|
3120
2857
|
if (candidateScore === 0) continue;
|
|
@@ -3127,14 +2864,14 @@ function findField(fieldId, registry) {
|
|
|
3127
2864
|
}
|
|
3128
2865
|
}
|
|
3129
2866
|
if (bestComp && bestScore >= 75) {
|
|
3130
|
-
|
|
3131
|
-
`
|
|
2867
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2868
|
+
`findField: scored match "${fieldId}" -> "${bestComp.id}" (label="${bestComp.label}", score=${bestScore})`
|
|
3132
2869
|
);
|
|
3133
2870
|
return registry.getField(bestComp.id);
|
|
3134
2871
|
}
|
|
3135
|
-
const currentScreen =
|
|
2872
|
+
const currentScreen = chunkYB77RYCC_js.getCurrentScreen();
|
|
3136
2873
|
if (currentScreen) {
|
|
3137
|
-
const screenMeta =
|
|
2874
|
+
const screenMeta = chunkYB77RYCC_js.getScreenMetadata(currentScreen);
|
|
3138
2875
|
const fields = screenMeta?.fields;
|
|
3139
2876
|
if (fields && Array.isArray(fields)) {
|
|
3140
2877
|
const metaField = fields.find(
|
|
@@ -3142,20 +2879,20 @@ function findField(fieldId, registry) {
|
|
|
3142
2879
|
);
|
|
3143
2880
|
if (metaField && typeof metaField === "object" && metaField.label) {
|
|
3144
2881
|
const metaLabel = metaField.label;
|
|
3145
|
-
const metaNeedle =
|
|
2882
|
+
const metaNeedle = chunkYB77RYCC_js.normalize3(metaLabel);
|
|
3146
2883
|
let mBest;
|
|
3147
2884
|
let mBestScore = 0;
|
|
3148
2885
|
for (const comp of snapshot) {
|
|
3149
2886
|
if (comp.kind !== "field" || !comp.label) continue;
|
|
3150
|
-
const score =
|
|
2887
|
+
const score = chunkYB77RYCC_js.matchScore(metaNeedle, chunkYB77RYCC_js.normalize3(comp.label));
|
|
3151
2888
|
if (score > mBestScore) {
|
|
3152
2889
|
mBestScore = score;
|
|
3153
2890
|
mBest = comp;
|
|
3154
2891
|
}
|
|
3155
2892
|
}
|
|
3156
2893
|
if (mBest && mBestScore >= 60) {
|
|
3157
|
-
|
|
3158
|
-
`
|
|
2894
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2895
|
+
`findField: FOUND via screen metadata translation: fieldId="${fieldId}" -> metaLabel="${metaLabel}" -> registered="${mBest.id}" (score=${mBestScore})`
|
|
3159
2896
|
);
|
|
3160
2897
|
return registry.getField(mBest.id);
|
|
3161
2898
|
}
|
|
@@ -3163,32 +2900,34 @@ function findField(fieldId, registry) {
|
|
|
3163
2900
|
}
|
|
3164
2901
|
}
|
|
3165
2902
|
if (bestComp && bestScore >= 40) {
|
|
3166
|
-
|
|
3167
|
-
`
|
|
2903
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2904
|
+
`findField: weak substring match "${fieldId}" -> "${bestComp.id}" (label="${bestComp.label}", score=${bestScore})`
|
|
3168
2905
|
);
|
|
3169
2906
|
return registry.getField(bestComp.id);
|
|
3170
2907
|
}
|
|
3171
|
-
|
|
2908
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
3172
2909
|
`findField: NOT FOUND \u2014 fieldId="${fieldId}" not in registry. Available fields: ${snapshot.filter((c) => c.kind === "field").map((c) => `"${c.id}" (label: ${c.label})`).join(", ") || "none"}`
|
|
3173
2910
|
);
|
|
3174
2911
|
return void 0;
|
|
3175
2912
|
}
|
|
3176
2913
|
function findToggle(fieldId, registry) {
|
|
3177
|
-
|
|
2914
|
+
chunkYB77RYCC_js.appilotsDebugLog(`findToggle: searching for fieldId="${fieldId}"`);
|
|
3178
2915
|
const exact = registry.getToggle(fieldId);
|
|
3179
2916
|
if (exact) {
|
|
3180
|
-
|
|
2917
|
+
chunkYB77RYCC_js.appilotsDebugLog(`findToggle: FOUND exact match for "${fieldId}"`);
|
|
3181
2918
|
return exact;
|
|
3182
2919
|
}
|
|
3183
2920
|
const lower = fieldId.toLowerCase();
|
|
3184
2921
|
const snapshot = registry.snapshot();
|
|
3185
2922
|
for (const comp of snapshot) {
|
|
3186
2923
|
if (comp.kind === "toggle" && comp.id.toLowerCase() === lower) {
|
|
3187
|
-
|
|
2924
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2925
|
+
`findToggle: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
|
|
2926
|
+
);
|
|
3188
2927
|
return registry.getToggle(comp.id);
|
|
3189
2928
|
}
|
|
3190
2929
|
}
|
|
3191
|
-
|
|
2930
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
3192
2931
|
`findToggle: NOT FOUND \u2014 fieldId="${fieldId}" not in registry. Available toggles: ${snapshot.filter((c) => c.kind === "toggle").map((c) => `"${c.id}"`).join(", ") || "none"}`
|
|
3193
2932
|
);
|
|
3194
2933
|
return void 0;
|
|
@@ -3199,7 +2938,9 @@ function findSlider(fieldId, registry) {
|
|
|
3199
2938
|
const lower = fieldId.toLowerCase();
|
|
3200
2939
|
for (const comp of registry.snapshot()) {
|
|
3201
2940
|
if (comp.kind === "slider" && comp.id.toLowerCase() === lower) {
|
|
3202
|
-
|
|
2941
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2942
|
+
`findSlider: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
|
|
2943
|
+
);
|
|
3203
2944
|
return registry.getSlider(comp.id);
|
|
3204
2945
|
}
|
|
3205
2946
|
}
|
|
@@ -3208,7 +2949,7 @@ function findSlider(fieldId, registry) {
|
|
|
3208
2949
|
var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
3209
2950
|
async function formFillHandler(payload, context) {
|
|
3210
2951
|
const { permissions } = context;
|
|
3211
|
-
const registry = context.registry ??
|
|
2952
|
+
const registry = context.registry ?? chunkYB77RYCC_js.componentRegistry;
|
|
3212
2953
|
const { screen, activePath } = resolveScreenContext();
|
|
3213
2954
|
const screenPath = activePath.length > 1 ? activePath.join("/") : screen;
|
|
3214
2955
|
if (!permissions.canFillForms) {
|
|
@@ -3227,11 +2968,11 @@ async function formFillHandler(payload, context) {
|
|
|
3227
2968
|
}
|
|
3228
2969
|
const registrySnapshot = registry.snapshot();
|
|
3229
2970
|
if (registrySnapshot.length === 0) {
|
|
3230
|
-
|
|
2971
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
3231
2972
|
"formFillHandler: registry is EMPTY \u2014 auto-tracking may not be active. Ensure enableAppilotsAutoTracking() runs before components mount."
|
|
3232
2973
|
);
|
|
3233
2974
|
} else {
|
|
3234
|
-
|
|
2975
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3235
2976
|
`[Appilots formFillHandler] Registry has ${registrySnapshot.length} components:`,
|
|
3236
2977
|
registrySnapshot.map((c) => `${c.kind}:${c.id}`).join(", ")
|
|
3237
2978
|
);
|
|
@@ -3239,7 +2980,7 @@ async function formFillHandler(payload, context) {
|
|
|
3239
2980
|
const fieldResults = [];
|
|
3240
2981
|
let allSuccess = true;
|
|
3241
2982
|
let selectedChoiceThisBatch = false;
|
|
3242
|
-
|
|
2983
|
+
chunkYB77RYCC_js.appilotsDebugLog(`formFillHandler: processing ${payload.fields.length} fields`);
|
|
3243
2984
|
const availableFieldIds = () => registry.snapshot().filter((comp) => comp.kind === "field").map((comp) => `${comp.id}${comp.label ? ` (${comp.label})` : ""}`).slice(0, 8);
|
|
3244
2985
|
const isElementIdField = (field) => typeof field.fieldId === "string" && field.fieldId.trim().toLowerCase().startsWith("el:");
|
|
3245
2986
|
for (const field of payload.fields.filter(isElementIdField)) {
|
|
@@ -3266,13 +3007,13 @@ async function formFillHandler(payload, context) {
|
|
|
3266
3007
|
const { fieldId, fieldType, value } = field;
|
|
3267
3008
|
const effectiveFieldType = getEffectiveFieldType(fieldId, fieldType, registry);
|
|
3268
3009
|
let selectFailure;
|
|
3269
|
-
|
|
3270
|
-
`
|
|
3010
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3011
|
+
`formFillHandler: looking up fieldId="${fieldId}" fieldType="${fieldType}" effectiveFieldType="${effectiveFieldType}" value=${chunkYB77RYCC_js.describeValue(value)}`
|
|
3271
3012
|
);
|
|
3272
3013
|
const fieldEntry = findField(fieldId, registry);
|
|
3273
3014
|
if (fieldEntry) {
|
|
3274
3015
|
try {
|
|
3275
|
-
|
|
3016
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3276
3017
|
`formFillHandler: found field "${fieldId}" via registry, calling setValue(<${String(value).length} chars>)`
|
|
3277
3018
|
);
|
|
3278
3019
|
const beforeValue = effectiveFieldType === "date" ? fieldEntry.getValue?.() ?? "" : void 0;
|
|
@@ -3303,7 +3044,7 @@ async function formFillHandler(payload, context) {
|
|
|
3303
3044
|
after = fieldEntry.getValue?.() ?? "";
|
|
3304
3045
|
}
|
|
3305
3046
|
if (!selectValueApplied(fieldId, value, after, registry)) {
|
|
3306
|
-
|
|
3047
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
3307
3048
|
`formFillHandler: select field "${fieldId}" setValue did not stick (wrote <${String(value).length} chars>, current is <${String(after ?? "").length} chars>), trying visible choice fallback`
|
|
3308
3049
|
);
|
|
3309
3050
|
const selectResult = await selectVisibleChoice(fieldId, value, registry, {
|
|
@@ -3318,7 +3059,11 @@ async function formFillHandler(payload, context) {
|
|
|
3318
3059
|
fieldId,
|
|
3319
3060
|
success: false,
|
|
3320
3061
|
error: selectResult.error ?? `Select value "${String(value)}" was not applied for "${fieldId}"`,
|
|
3321
|
-
diagnose: selectResult.diagnose ?? {
|
|
3062
|
+
diagnose: selectResult.diagnose ?? {
|
|
3063
|
+
category: "component-not-found",
|
|
3064
|
+
fieldId,
|
|
3065
|
+
screen: screenPath
|
|
3066
|
+
}
|
|
3322
3067
|
});
|
|
3323
3068
|
allSuccess = false;
|
|
3324
3069
|
continue;
|
|
@@ -3373,7 +3118,9 @@ async function formFillHandler(payload, context) {
|
|
|
3373
3118
|
continue;
|
|
3374
3119
|
}
|
|
3375
3120
|
try {
|
|
3376
|
-
sliderEntry.setValue(
|
|
3121
|
+
sliderEntry.setValue(
|
|
3122
|
+
snapSliderValue(numeric, sliderEntry.min, sliderEntry.max, sliderEntry.step)
|
|
3123
|
+
);
|
|
3377
3124
|
fieldResults.push({ fieldId, success: true });
|
|
3378
3125
|
} catch (err) {
|
|
3379
3126
|
fieldResults.push({
|
|
@@ -3422,8 +3169,8 @@ async function formFillHandler(payload, context) {
|
|
|
3422
3169
|
}
|
|
3423
3170
|
if (selectResult.success) {
|
|
3424
3171
|
selectedChoiceThisBatch = true;
|
|
3425
|
-
|
|
3426
|
-
`
|
|
3172
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3173
|
+
`formFillHandler: selected visible option for "${fieldId}"` + (selectResult.selectedLabel ? ` \u2192 "${selectResult.selectedLabel}"` : "")
|
|
3427
3174
|
);
|
|
3428
3175
|
await sleep2(120);
|
|
3429
3176
|
fieldResults.push({ fieldId, success: true });
|
|
@@ -3431,7 +3178,7 @@ async function formFillHandler(payload, context) {
|
|
|
3431
3178
|
}
|
|
3432
3179
|
selectFailure = selectResult;
|
|
3433
3180
|
}
|
|
3434
|
-
|
|
3181
|
+
chunkYB77RYCC_js.appilotsDebugLog(`formFillHandler: registry miss for "${fieldId}", falling back to fiber tree`);
|
|
3435
3182
|
const handle = findInteractiveByIdentifier(fieldId, {
|
|
3436
3183
|
kind: effectiveFieldType === "toggle" ? "toggle" : "field"
|
|
3437
3184
|
});
|
|
@@ -3439,7 +3186,9 @@ async function formFillHandler(payload, context) {
|
|
|
3439
3186
|
try {
|
|
3440
3187
|
handle.focus?.();
|
|
3441
3188
|
handle.setValue(value);
|
|
3442
|
-
|
|
3189
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3190
|
+
`formFillHandler: fiber fallback succeeded for "${fieldId}" \u2192 label="${handle.label}"`
|
|
3191
|
+
);
|
|
3443
3192
|
fieldResults.push({ fieldId, success: true });
|
|
3444
3193
|
continue;
|
|
3445
3194
|
} catch (err) {
|
|
@@ -3476,14 +3225,22 @@ async function formFillHandler(payload, context) {
|
|
|
3476
3225
|
if (payload.submitAfterFill === true) {
|
|
3477
3226
|
if (!allSuccess) {
|
|
3478
3227
|
const failedIds = fieldResults.filter((result) => !result.success).map((result) => result.fieldId);
|
|
3479
|
-
|
|
3228
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
3480
3229
|
"formFillHandler: submitAfterFill=true requested but some fields failed; NOT submitting" + (failedIds.length > 0 ? ` (failed: ${failedIds.join(", ")})` : "")
|
|
3481
3230
|
);
|
|
3482
3231
|
} else {
|
|
3483
3232
|
await sleep2(120);
|
|
3484
|
-
const submitResult = pressSubmitButton(
|
|
3233
|
+
const submitResult = pressSubmitButton(
|
|
3234
|
+
{
|
|
3235
|
+
screen,
|
|
3236
|
+
screenPath,
|
|
3237
|
+
activePath,
|
|
3238
|
+
filledFieldIds: fieldResults.filter((r) => r.success).map((r) => r.fieldId)
|
|
3239
|
+
},
|
|
3240
|
+
registry
|
|
3241
|
+
);
|
|
3485
3242
|
if (!submitResult.success) {
|
|
3486
|
-
|
|
3243
|
+
chunkYB77RYCC_js.appilotsDebugWarn(`formFillHandler: submitAfterFill failed \u2014 ${submitResult.error}`);
|
|
3487
3244
|
return {
|
|
3488
3245
|
success: false,
|
|
3489
3246
|
error: submitResult.error,
|
|
@@ -3495,7 +3252,7 @@ async function formFillHandler(payload, context) {
|
|
|
3495
3252
|
submitTargetId: submitResult.pressedTargetId
|
|
3496
3253
|
});
|
|
3497
3254
|
if (postSubmit.status === "pending") {
|
|
3498
|
-
|
|
3255
|
+
chunkYB77RYCC_js.appilotsDebugWarn(`formFillHandler: submit still pending \u2014 ${postSubmit.message}`);
|
|
3499
3256
|
return {
|
|
3500
3257
|
success: false,
|
|
3501
3258
|
error: postSubmit.message,
|
|
@@ -3504,7 +3261,7 @@ async function formFillHandler(payload, context) {
|
|
|
3504
3261
|
};
|
|
3505
3262
|
}
|
|
3506
3263
|
if (postSubmit.status === "failure") {
|
|
3507
|
-
|
|
3264
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
3508
3265
|
`formFillHandler: submit rejected by visible validation \u2014 ${postSubmit.message}`
|
|
3509
3266
|
);
|
|
3510
3267
|
return {
|
|
@@ -3519,7 +3276,7 @@ async function formFillHandler(payload, context) {
|
|
|
3519
3276
|
}
|
|
3520
3277
|
};
|
|
3521
3278
|
}
|
|
3522
|
-
|
|
3279
|
+
chunkYB77RYCC_js.appilotsDebugLog("formFillHandler: submitAfterFill \u2014 submit completed");
|
|
3523
3280
|
}
|
|
3524
3281
|
}
|
|
3525
3282
|
const aggregatedDiagnose = aggregateFieldDiagnoses(fieldResults, screenPath);
|
|
@@ -3531,18 +3288,18 @@ async function formFillHandler(payload, context) {
|
|
|
3531
3288
|
};
|
|
3532
3289
|
}
|
|
3533
3290
|
function pressSubmitButton(context, registry) {
|
|
3534
|
-
const activePath = context.activePath ??
|
|
3291
|
+
const activePath = context.activePath ?? chunkYB77RYCC_js.getActiveRouteNames();
|
|
3535
3292
|
const hintScreen = context.screen ?? context.screenPath;
|
|
3536
3293
|
const formScreens = resolveFormScreensForSubmit(hintScreen, activePath, registry);
|
|
3537
|
-
const resolvedScreen = formScreens.find((name) => screenDeclaresSubmit(name)) ?? formScreens[0] ?? hintScreen ??
|
|
3294
|
+
const resolvedScreen = formScreens.find((name) => screenDeclaresSubmit(name)) ?? formScreens[0] ?? hintScreen ?? chunkYB77RYCC_js.getCurrentScreen() ?? void 0;
|
|
3538
3295
|
const candidates = collectSubmitTargetCandidates(formScreens, registry);
|
|
3539
3296
|
for (const candidate of candidates) {
|
|
3540
3297
|
const target = registry.getTarget(candidate);
|
|
3541
3298
|
if (target) {
|
|
3542
3299
|
try {
|
|
3543
3300
|
target.press();
|
|
3544
|
-
|
|
3545
|
-
`
|
|
3301
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3302
|
+
`formFillHandler: submitAfterFill \u2014 pressed registry target "${candidate}"` + (resolvedScreen ? ` on screen "${resolvedScreen}"` : "")
|
|
3546
3303
|
);
|
|
3547
3304
|
return { success: true, pressedTargetId: candidate };
|
|
3548
3305
|
} catch (err) {
|
|
@@ -3555,7 +3312,7 @@ function pressSubmitButton(context, registry) {
|
|
|
3555
3312
|
}
|
|
3556
3313
|
}
|
|
3557
3314
|
for (const screenName of formScreens) {
|
|
3558
|
-
const screenMeta =
|
|
3315
|
+
const screenMeta = chunkYB77RYCC_js.getScreenMetadata(screenName);
|
|
3559
3316
|
const submitMeta = Array.isArray(screenMeta?.actions) ? screenMeta.actions.find(
|
|
3560
3317
|
(action) => typeof action === "object" && action !== null && action.type === "submit"
|
|
3561
3318
|
) : void 0;
|
|
@@ -3566,9 +3323,7 @@ function pressSubmitButton(context, registry) {
|
|
|
3566
3323
|
if (handle?.press) {
|
|
3567
3324
|
try {
|
|
3568
3325
|
handle.press();
|
|
3569
|
-
|
|
3570
|
-
`[Appilots] formFillHandler: submitAfterFill \u2014 fiber fallback "${submitLabel}"`
|
|
3571
|
-
);
|
|
3326
|
+
chunkYB77RYCC_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 fiber fallback "${submitLabel}"`);
|
|
3572
3327
|
return { success: true, pressedTargetId: submitId ?? submitLabel };
|
|
3573
3328
|
} catch (err) {
|
|
3574
3329
|
return {
|
|
@@ -3590,9 +3345,7 @@ function pressSubmitButton(context, registry) {
|
|
|
3590
3345
|
if (id) {
|
|
3591
3346
|
const pressed = pressTargetByIdOrLabel(id, registry);
|
|
3592
3347
|
if (pressed.success) {
|
|
3593
|
-
|
|
3594
|
-
`[Appilots] formFillHandler: submitAfterFill \u2014 pressed visible heuristic "${id}"`
|
|
3595
|
-
);
|
|
3348
|
+
chunkYB77RYCC_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 pressed visible heuristic "${id}"`);
|
|
3596
3349
|
return { success: true, pressedTargetId: id };
|
|
3597
3350
|
}
|
|
3598
3351
|
}
|
|
@@ -3606,8 +3359,8 @@ function pressSubmitButton(context, registry) {
|
|
|
3606
3359
|
if (target) {
|
|
3607
3360
|
try {
|
|
3608
3361
|
target.press();
|
|
3609
|
-
|
|
3610
|
-
`
|
|
3362
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3363
|
+
`formFillHandler: submitAfterFill \u2014 pressed by label heuristic "${comp.label}"`
|
|
3611
3364
|
);
|
|
3612
3365
|
return { success: true, pressedTargetId: comp.id };
|
|
3613
3366
|
} catch (err) {
|
|
@@ -3619,9 +3372,16 @@ function pressSubmitButton(context, registry) {
|
|
|
3619
3372
|
}
|
|
3620
3373
|
}
|
|
3621
3374
|
}
|
|
3375
|
+
for (const fieldId of [...context.filledFieldIds ?? []].reverse()) {
|
|
3376
|
+
const handle = findInteractiveByIdentifier(fieldId, { kind: "field" });
|
|
3377
|
+
if (handle?.submitFromKeyboard?.()) {
|
|
3378
|
+
chunkYB77RYCC_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 return key on "${fieldId}"`);
|
|
3379
|
+
return { success: true, pressedTargetId: fieldId };
|
|
3380
|
+
}
|
|
3381
|
+
}
|
|
3622
3382
|
return {
|
|
3623
3383
|
success: false,
|
|
3624
|
-
error: 'submitAfterFill requested but no submit button
|
|
3384
|
+
error: 'submitAfterFill requested but the screen has no submit button and no field that submits on return (declare it via registerScreen({ actions: [{ type: "submit", ... }] }) for reliable behavior)',
|
|
3625
3385
|
diagnose: { category: "component-not-found", screen: resolvedScreen }
|
|
3626
3386
|
};
|
|
3627
3387
|
}
|
|
@@ -3661,12 +3421,12 @@ function buildDiagnose(category, targetId, candidates) {
|
|
|
3661
3421
|
return {
|
|
3662
3422
|
category,
|
|
3663
3423
|
targetId,
|
|
3664
|
-
screen:
|
|
3424
|
+
screen: chunkYB77RYCC_js.getCurrentScreen() ?? void 0,
|
|
3665
3425
|
...candidates && candidates.length > 0 ? { candidates: candidates.slice(0, 8) } : {}
|
|
3666
3426
|
};
|
|
3667
3427
|
}
|
|
3668
3428
|
function resolveListEntry(listId) {
|
|
3669
|
-
const entries =
|
|
3429
|
+
const entries = chunkYB77RYCC_js.listRegistry.snapshot();
|
|
3670
3430
|
if (entries.length === 0) return {};
|
|
3671
3431
|
if (listId) {
|
|
3672
3432
|
const wanted = normalizeId2(listId);
|
|
@@ -3675,6 +3435,8 @@ function resolveListEntry(listId) {
|
|
|
3675
3435
|
return { candidates: entries.map((e) => e.id) };
|
|
3676
3436
|
}
|
|
3677
3437
|
if (entries.length === 1) return { entry: entries[0] };
|
|
3438
|
+
const lists = entries.filter((e) => e.kind === "list");
|
|
3439
|
+
if (lists.length === 1) return { entry: lists[0] };
|
|
3678
3440
|
return { candidates: entries.map((e) => e.id) };
|
|
3679
3441
|
}
|
|
3680
3442
|
function pageOffset(metrics, direction) {
|
|
@@ -3714,7 +3476,7 @@ async function scrollListHandler(payload, context) {
|
|
|
3714
3476
|
}
|
|
3715
3477
|
const { entry, candidates } = resolveListEntry(payload.listId);
|
|
3716
3478
|
if (!entry) {
|
|
3717
|
-
const detail = candidates && candidates.length > 0 ? payload.listId ? `List "${payload.listId}" is not registered. Known lists: ${candidates.join(", ")}` : `Multiple lists are on screen \u2014 specify listId. Known lists: ${candidates.join(", ")}` : "
|
|
3479
|
+
const detail = candidates && candidates.length > 0 ? payload.listId ? `List "${payload.listId}" is not registered. Known lists: ${candidates.join(", ")}` : `Multiple lists are on screen \u2014 specify listId. Known lists: ${candidates.join(", ")}` : "Nothing scrollable is registered on the current screen (enableAppilotsAutoTracking() may be off).";
|
|
3718
3480
|
return {
|
|
3719
3481
|
success: false,
|
|
3720
3482
|
error: detail,
|
|
@@ -3722,6 +3484,13 @@ async function scrollListHandler(payload, context) {
|
|
|
3722
3484
|
};
|
|
3723
3485
|
}
|
|
3724
3486
|
if (toIndex !== void 0) {
|
|
3487
|
+
if (entry.kind === "scroll") {
|
|
3488
|
+
return {
|
|
3489
|
+
success: false,
|
|
3490
|
+
error: `"${entry.id}" is a scrollable screen, not a list \u2014 it has no numbered items. Use direction "down"/"up" to page through it.`,
|
|
3491
|
+
diagnose: buildDiagnose("validation", entry.id)
|
|
3492
|
+
};
|
|
3493
|
+
}
|
|
3725
3494
|
if (typeof entry.itemCount === "number" && toIndex > entry.itemCount) {
|
|
3726
3495
|
return {
|
|
3727
3496
|
success: false,
|
|
@@ -3756,14 +3525,14 @@ async function scrollListHandler(payload, context) {
|
|
|
3756
3525
|
}
|
|
3757
3526
|
return {
|
|
3758
3527
|
success: false,
|
|
3759
|
-
error: `
|
|
3528
|
+
error: `"${entry.id}" does not expose a scrollable handle`,
|
|
3760
3529
|
diagnose: buildDiagnose("unknown", entry.id)
|
|
3761
3530
|
};
|
|
3762
3531
|
}
|
|
3763
3532
|
|
|
3764
3533
|
// src/executor/handlers/confirmHandler.ts
|
|
3765
3534
|
async function confirmHandler(_actionId, _payload) {
|
|
3766
|
-
return { success: true };
|
|
3535
|
+
return { success: true, effect: "unknown" };
|
|
3767
3536
|
}
|
|
3768
3537
|
|
|
3769
3538
|
// src/executor/postInteractionSettle.ts
|
|
@@ -3775,29 +3544,61 @@ function targetIdFromPayload(payload) {
|
|
|
3775
3544
|
if (typeof targetId === "string" && targetId.trim()) return targetId.trim();
|
|
3776
3545
|
return "";
|
|
3777
3546
|
}
|
|
3547
|
+
function hashFieldValue(value) {
|
|
3548
|
+
let hash = 2166136261;
|
|
3549
|
+
for (let i = 0; i < value.length; i++) {
|
|
3550
|
+
hash ^= value.charCodeAt(i);
|
|
3551
|
+
hash = Math.imul(hash, 16777619);
|
|
3552
|
+
}
|
|
3553
|
+
return (hash >>> 0).toString(36);
|
|
3554
|
+
}
|
|
3555
|
+
var DISCRETE_FIELD_TYPES = /* @__PURE__ */ new Set(["select", "date"]);
|
|
3556
|
+
function discreteFieldSignature() {
|
|
3557
|
+
const sigs = [];
|
|
3558
|
+
for (const { id, kind } of chunkYB77RYCC_js.componentRegistry.snapshot()) {
|
|
3559
|
+
if (kind !== "field") continue;
|
|
3560
|
+
const entry = chunkYB77RYCC_js.componentRegistry.getField(id);
|
|
3561
|
+
if (!entry || !DISCRETE_FIELD_TYPES.has(entry.fieldType ?? "")) continue;
|
|
3562
|
+
try {
|
|
3563
|
+
sigs.push(`${id}:${hashFieldValue(String(entry.getValue() ?? ""))}`);
|
|
3564
|
+
} catch {
|
|
3565
|
+
}
|
|
3566
|
+
}
|
|
3567
|
+
return sigs.sort().join(",");
|
|
3568
|
+
}
|
|
3778
3569
|
async function waitForPostInteractionSettle(payload) {
|
|
3779
3570
|
const targetId = targetIdFromPayload(payload);
|
|
3780
|
-
const fromScreen =
|
|
3781
|
-
const baseline =
|
|
3571
|
+
const fromScreen = chunkYB77RYCC_js.getCurrentScreen();
|
|
3572
|
+
const baseline = chunkYB77RYCC_js.probeLoadingState(targetId || null, fromScreen);
|
|
3573
|
+
const baselineFields = discreteFieldSignature();
|
|
3574
|
+
const readable = baseline.fingerprint !== "";
|
|
3782
3575
|
await sleepMs(100);
|
|
3783
|
-
const afterPress =
|
|
3576
|
+
const afterPress = chunkYB77RYCC_js.probeLoadingState(targetId || null, chunkYB77RYCC_js.getCurrentScreen());
|
|
3784
3577
|
const modalOrLoading = afterPress.modalOpen || afterPress.loading || afterPress.pressedDisabled;
|
|
3785
3578
|
const fingerprintChanged = afterPress.fingerprint !== baseline.fingerprint;
|
|
3786
|
-
const
|
|
3579
|
+
const verdict = () => {
|
|
3580
|
+
if (!readable) return { effect: "unknown" };
|
|
3581
|
+
const settled = chunkYB77RYCC_js.probeLoadingState(targetId || null, chunkYB77RYCC_js.getCurrentScreen());
|
|
3582
|
+
if (settled.fingerprint === "") return { effect: "unknown" };
|
|
3583
|
+
if (discreteFieldSignature() !== baselineFields) return { effect: "changed" };
|
|
3584
|
+
return { effect: settled.fingerprint !== baseline.fingerprint ? "changed" : "none" };
|
|
3585
|
+
};
|
|
3586
|
+
const capMs = chunkYB77RYCC_js.isListItemPressTarget(targetId) ? 5e3 : 1e4;
|
|
3787
3587
|
if (modalOrLoading || fingerprintChanged) {
|
|
3788
|
-
await
|
|
3588
|
+
await chunkYB77RYCC_js.waitForLoadingSettle({
|
|
3789
3589
|
pressedComponentId: targetId || null,
|
|
3790
3590
|
fromScreen,
|
|
3791
3591
|
maxMs: capMs
|
|
3792
3592
|
});
|
|
3793
|
-
return;
|
|
3593
|
+
return verdict();
|
|
3794
3594
|
}
|
|
3795
|
-
if (
|
|
3796
|
-
await
|
|
3595
|
+
if (chunkYB77RYCC_js.isListItemPressTarget(targetId)) {
|
|
3596
|
+
await chunkYB77RYCC_js.waitForLoadingSettle({
|
|
3797
3597
|
fromScreen,
|
|
3798
3598
|
maxMs: 3e3
|
|
3799
3599
|
});
|
|
3800
3600
|
}
|
|
3601
|
+
return verdict();
|
|
3801
3602
|
}
|
|
3802
3603
|
|
|
3803
3604
|
// src/executor/ActionExecutor.ts
|
|
@@ -3813,7 +3614,7 @@ function validateActionPayload(action) {
|
|
|
3813
3614
|
error: message,
|
|
3814
3615
|
diagnose: {
|
|
3815
3616
|
category: "validation",
|
|
3816
|
-
screen:
|
|
3617
|
+
screen: chunkYB77RYCC_js.getCurrentScreen() ?? void 0,
|
|
3817
3618
|
...ids ?? {}
|
|
3818
3619
|
}
|
|
3819
3620
|
});
|
|
@@ -3852,10 +3653,9 @@ function validateActionPayload(action) {
|
|
|
3852
3653
|
const hasIndex = typeof payload.toIndex === "number";
|
|
3853
3654
|
const hasDirection = payload.direction === "up" || payload.direction === "down";
|
|
3854
3655
|
if (!hasIndex && !hasDirection) {
|
|
3855
|
-
return invalid(
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
);
|
|
3656
|
+
return invalid('scroll_list action needs toIndex (1-based) or direction ("up"/"down")', {
|
|
3657
|
+
targetId: typeof payload.listId === "string" ? payload.listId : void 0
|
|
3658
|
+
});
|
|
3859
3659
|
}
|
|
3860
3660
|
return null;
|
|
3861
3661
|
}
|
|
@@ -3863,24 +3663,48 @@ function validateActionPayload(action) {
|
|
|
3863
3663
|
return null;
|
|
3864
3664
|
}
|
|
3865
3665
|
}
|
|
3666
|
+
function effectFor(payload, observed) {
|
|
3667
|
+
if (observed === "none" && isDestructivePayload(payload)) return "unknown";
|
|
3668
|
+
return observed;
|
|
3669
|
+
}
|
|
3670
|
+
function isDestructivePayload(payload) {
|
|
3671
|
+
if (!payload || typeof payload !== "object") return false;
|
|
3672
|
+
const p = payload;
|
|
3673
|
+
if (p.destructive === true) return true;
|
|
3674
|
+
const params = p.params;
|
|
3675
|
+
return !!params && typeof params === "object" && params.destructive === true;
|
|
3676
|
+
}
|
|
3866
3677
|
async function executeAction(action, context) {
|
|
3867
|
-
|
|
3678
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3679
|
+
`executeAction called: type="${action.type}", id="${action.id}", payload=${JSON.stringify(action.payload)}`
|
|
3680
|
+
);
|
|
3868
3681
|
const permissions = context.permissions ?? DEFAULT_PERMISSIONS;
|
|
3869
|
-
if (permissions.allowedActions && permissions.allowedActions.length > 0 && !permissions.allowedActions.includes(action.type)) {
|
|
3870
|
-
return {
|
|
3871
|
-
success: false,
|
|
3872
|
-
error: `Action type "${action.type}" is not in the allowed actions list`
|
|
3873
|
-
};
|
|
3874
|
-
}
|
|
3875
3682
|
context.emit({
|
|
3876
3683
|
type: "agent:action:start",
|
|
3877
3684
|
timestamp: Date.now(),
|
|
3878
3685
|
data: { actionId: action.id, actionType: action.type }
|
|
3879
3686
|
});
|
|
3687
|
+
if (permissions.allowedActions && permissions.allowedActions.length > 0 && !permissions.allowedActions.includes(action.type)) {
|
|
3688
|
+
const result2 = {
|
|
3689
|
+
success: false,
|
|
3690
|
+
error: `Action type "${action.type}" is not in the allowed actions list`
|
|
3691
|
+
};
|
|
3692
|
+
context.emit({
|
|
3693
|
+
type: "agent:action:error",
|
|
3694
|
+
timestamp: Date.now(),
|
|
3695
|
+
data: {
|
|
3696
|
+
actionId: action.id,
|
|
3697
|
+
actionType: action.type,
|
|
3698
|
+
success: false,
|
|
3699
|
+
error: result2.error
|
|
3700
|
+
}
|
|
3701
|
+
});
|
|
3702
|
+
return result2;
|
|
3703
|
+
}
|
|
3880
3704
|
let result;
|
|
3881
3705
|
const validationFailure = validateActionPayload(action);
|
|
3882
3706
|
if (validationFailure) {
|
|
3883
|
-
|
|
3707
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
3884
3708
|
`executeAction: payload validation failed for type="${action.type}" id="${action.id}": ${validationFailure.error}`
|
|
3885
3709
|
);
|
|
3886
3710
|
context.emit({
|
|
@@ -3907,28 +3731,28 @@ async function executeAction(action, context) {
|
|
|
3907
3731
|
case "form_fill":
|
|
3908
3732
|
result = await formFillHandler(action.payload, {
|
|
3909
3733
|
permissions,
|
|
3910
|
-
registry: context.registry ??
|
|
3734
|
+
registry: context.registry ?? chunkYB77RYCC_js.getDefaultRegistry()
|
|
3911
3735
|
});
|
|
3912
3736
|
break;
|
|
3913
|
-
case "ui_interaction":
|
|
3914
|
-
|
|
3737
|
+
case "ui_interaction": {
|
|
3738
|
+
const payload = action.payload;
|
|
3739
|
+
result = uiInteractionHandler(payload, {
|
|
3915
3740
|
permissions,
|
|
3916
|
-
registry: context.registry ??
|
|
3741
|
+
registry: context.registry ?? chunkYB77RYCC_js.getDefaultRegistry()
|
|
3917
3742
|
});
|
|
3918
3743
|
if (result.success) {
|
|
3919
|
-
await waitForPostInteractionSettle(
|
|
3744
|
+
const settle = await waitForPostInteractionSettle(payload);
|
|
3745
|
+
result.effect = result.effect ?? effectFor(payload, settle.effect);
|
|
3920
3746
|
}
|
|
3921
3747
|
break;
|
|
3748
|
+
}
|
|
3922
3749
|
case "scroll_list":
|
|
3923
3750
|
result = await scrollListHandler(action.payload, {
|
|
3924
3751
|
permissions
|
|
3925
3752
|
});
|
|
3926
3753
|
break;
|
|
3927
3754
|
case "confirm":
|
|
3928
|
-
result = await confirmHandler(
|
|
3929
|
-
action.id,
|
|
3930
|
-
action.payload
|
|
3931
|
-
);
|
|
3755
|
+
result = await confirmHandler(action.id, action.payload);
|
|
3932
3756
|
break;
|
|
3933
3757
|
case "custom":
|
|
3934
3758
|
result = {
|
|
@@ -3943,7 +3767,7 @@ async function executeAction(action, context) {
|
|
|
3943
3767
|
};
|
|
3944
3768
|
}
|
|
3945
3769
|
} catch (err) {
|
|
3946
|
-
|
|
3770
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
3947
3771
|
`executeAction: exception during action type="${action.type}" id="${action.id}": ${err?.message}`
|
|
3948
3772
|
);
|
|
3949
3773
|
result = {
|
|
@@ -3951,7 +3775,9 @@ async function executeAction(action, context) {
|
|
|
3951
3775
|
error: err?.message ?? "Action execution failed unexpectedly"
|
|
3952
3776
|
};
|
|
3953
3777
|
}
|
|
3954
|
-
|
|
3778
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3779
|
+
`executeAction result: type="${action.type}", id="${action.id}", success=${result.success}, error=${result.error ?? "none"}`
|
|
3780
|
+
);
|
|
3955
3781
|
context.emit({
|
|
3956
3782
|
type: result.success ? "agent:action:complete" : "agent:action:error",
|
|
3957
3783
|
timestamp: Date.now(),
|
|
@@ -4003,9 +3829,7 @@ var _patchedAlert = (title, message, buttons, options) => {
|
|
|
4003
3829
|
return suppression.originalAlert(title, message, buttons, options);
|
|
4004
3830
|
}
|
|
4005
3831
|
suppression.consumed = true;
|
|
4006
|
-
|
|
4007
|
-
"[Appilots] Suppressing native Alert during already-confirmed destructive agent action"
|
|
4008
|
-
);
|
|
3832
|
+
chunkYB77RYCC_js.appilotsDebugLog("Suppressing native Alert during already-confirmed destructive agent action");
|
|
4009
3833
|
try {
|
|
4010
3834
|
suppression.pending = Promise.resolve(button.onPress()).then(() => void 0).catch((err) => reportHandlerFailure(err));
|
|
4011
3835
|
} catch (err) {
|
|
@@ -4058,35 +3882,35 @@ async function runWithConfirmedDestructiveContext(enabled, host, fn) {
|
|
|
4058
3882
|
// src/platform/reactNativeAdapter.ts
|
|
4059
3883
|
var POST_ACTION_LOADING_MAX_MS = 6e3;
|
|
4060
3884
|
function resolveScreenMetadata() {
|
|
4061
|
-
const activePath =
|
|
3885
|
+
const activePath = chunkYB77RYCC_js.getActiveRouteNames();
|
|
4062
3886
|
for (let i = activePath.length - 1; i >= 0; i--) {
|
|
4063
3887
|
const name = activePath[i];
|
|
4064
|
-
const meta = name ?
|
|
3888
|
+
const meta = name ? chunkYB77RYCC_js.getScreenMetadata(name) : void 0;
|
|
4065
3889
|
if (meta && (Array.isArray(meta.fields) && meta.fields.length > 0 || Array.isArray(meta.actions) && meta.actions.length > 0)) {
|
|
4066
3890
|
return meta;
|
|
4067
3891
|
}
|
|
4068
3892
|
}
|
|
4069
|
-
const screen =
|
|
4070
|
-
return screen ?
|
|
3893
|
+
const screen = chunkYB77RYCC_js.getCurrentScreen();
|
|
3894
|
+
return screen ? chunkYB77RYCC_js.getScreenMetadata(screen) : void 0;
|
|
4071
3895
|
}
|
|
4072
3896
|
function buildAgentContext(extras = {}) {
|
|
4073
3897
|
const context = {};
|
|
4074
3898
|
context.platform = "react-native";
|
|
4075
|
-
const screen =
|
|
3899
|
+
const screen = chunkYB77RYCC_js.getCurrentScreen();
|
|
4076
3900
|
if (screen) context.currentScreen = screen;
|
|
4077
|
-
const navigationState =
|
|
3901
|
+
const navigationState = chunkYB77RYCC_js.getNavigationStateSnapshot();
|
|
4078
3902
|
if (navigationState) context.navigationState = navigationState;
|
|
4079
3903
|
const screenMeta = resolveScreenMetadata();
|
|
4080
3904
|
if (screenMeta) context.screenMetadata = screenMeta;
|
|
4081
3905
|
try {
|
|
4082
3906
|
context.snapshot = captureSnapshot();
|
|
4083
3907
|
} catch (err) {
|
|
4084
|
-
|
|
3908
|
+
chunkYB77RYCC_js.appilotsDebugWarn("buildAgentContext: captureSnapshot failed", err);
|
|
4085
3909
|
}
|
|
4086
|
-
const registry =
|
|
3910
|
+
const registry = chunkYB77RYCC_js.componentRegistry.snapshot();
|
|
4087
3911
|
const filtered = screen ? registry.filter((c) => !c.screen || c.screen === screen) : registry;
|
|
4088
3912
|
if (filtered.length > 0) context.registeredComponents = filtered;
|
|
4089
|
-
const registeredLists =
|
|
3913
|
+
const registeredLists = chunkYB77RYCC_js.listRegistry.snapshot();
|
|
4090
3914
|
if (registeredLists.length > 0) {
|
|
4091
3915
|
context.registeredLists = registeredLists.map(
|
|
4092
3916
|
({ scrollToIndex, scrollToOffset, getScrollMetrics, dataPreview, ...rest }) => rest
|
|
@@ -4103,12 +3927,12 @@ function resolveActionHints(screen, pressedComponentId, actionPayload) {
|
|
|
4103
3927
|
}
|
|
4104
3928
|
}
|
|
4105
3929
|
if (!screen || !pressedComponentId) return void 0;
|
|
4106
|
-
const meta =
|
|
3930
|
+
const meta = chunkYB77RYCC_js.getScreenMetadata(screen);
|
|
4107
3931
|
const actions = meta?.actions;
|
|
4108
3932
|
if (!actions || actions.length === 0) return void 0;
|
|
4109
3933
|
for (const a of actions) {
|
|
4110
3934
|
if (typeof a === "string") continue;
|
|
4111
|
-
if (
|
|
3935
|
+
if (chunkYB77RYCC_js.idLooselyMatches(a.id, pressedComponentId)) {
|
|
4112
3936
|
const inferred = a.appilotsInferred;
|
|
4113
3937
|
if (inferred && typeof inferred === "object") return inferred;
|
|
4114
3938
|
return void 0;
|
|
@@ -4123,71 +3947,68 @@ async function settleTurn(input) {
|
|
|
4123
3947
|
const successById = new Map(input.results.map((r) => [r.actionId, r.success]));
|
|
4124
3948
|
const typeById = new Map(input.results.map((r) => [r.actionId, r.type]));
|
|
4125
3949
|
if (input.hadNavigate) {
|
|
4126
|
-
const settle = await
|
|
3950
|
+
const settle = await chunkYB77RYCC_js.waitForScreenSettle({
|
|
4127
3951
|
expectingChange: true,
|
|
4128
3952
|
fromScreen: input.preNavigateScreen ?? null,
|
|
4129
3953
|
fromSignature: input.preNavigateSignature ?? null,
|
|
4130
3954
|
targetScreen: navigateTargetScreen,
|
|
4131
3955
|
maxMs: 3500
|
|
4132
3956
|
});
|
|
4133
|
-
|
|
4134
|
-
`
|
|
3957
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3958
|
+
`settleTurn: post-navigate settle done \u2014 screen="${settle.screen}" transitioned=${settle.transitioned} timedOut=${settle.timedOut} waitedMs=${settle.waitedMs}`
|
|
4135
3959
|
);
|
|
4136
|
-
const navigationMoved = settle.transitioned ||
|
|
4137
|
-
input.preNavigateScreen ?? null,
|
|
4138
|
-
input.preNavigateSignature ?? null
|
|
4139
|
-
) || !!navigateTargetScreen && !!settle.screen && chunkAYWMBMSN_js.routesBelongToSameFeature(settle.screen, navigateTargetScreen);
|
|
3960
|
+
const navigationMoved = settle.transitioned || chunkYB77RYCC_js.screenDepartedBaseline(input.preNavigateScreen ?? null, input.preNavigateSignature ?? null) || !!navigateTargetScreen && !!settle.screen && chunkYB77RYCC_js.routesBelongToSameFeature(settle.screen, navigateTargetScreen);
|
|
4140
3961
|
if (!navigationMoved) {
|
|
4141
|
-
|
|
3962
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
4142
3963
|
`tool-without-effect: navigate emitted but screen did not change (stayed at "${input.preNavigateScreen ?? "unknown"}", waitedMs=${settle.waitedMs}). Likely causes: target screenName missing from MCP doc, nested-nav path absent, or React Navigation rejected the route.`
|
|
4143
3964
|
);
|
|
4144
3965
|
for (const [actionId, type] of typeById) {
|
|
4145
3966
|
if (type === "navigate") toolWithoutEffectIds.add(actionId);
|
|
4146
3967
|
}
|
|
4147
3968
|
}
|
|
4148
|
-
const loadSettle = await
|
|
3969
|
+
const loadSettle = await chunkYB77RYCC_js.waitForLoadingSettle({
|
|
4149
3970
|
fromScreen: settle.screen ?? null,
|
|
4150
3971
|
maxMs: 3e3
|
|
4151
3972
|
});
|
|
4152
|
-
|
|
4153
|
-
`
|
|
3973
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3974
|
+
`settleTurn: post-navigate loading settle \u2014 settled=${loadSettle.settled} loadingPending=${loadSettle.loadingPending} probes=${loadSettle.probeCount} waitedMs=${loadSettle.waitedMs}`
|
|
4154
3975
|
);
|
|
4155
3976
|
if (loadSettle.loadingPending) loadingPending = true;
|
|
4156
3977
|
} else {
|
|
4157
3978
|
const pressedAction = turnActions.find(
|
|
4158
3979
|
(a) => a.type === "ui_interaction" && a.payload?.componentId === pressedId
|
|
4159
3980
|
);
|
|
4160
|
-
const hints = resolveActionHints(
|
|
3981
|
+
const hints = resolveActionHints(chunkYB77RYCC_js.getCurrentScreen(), pressedId, pressedAction?.payload);
|
|
4161
3982
|
const settleCapMs = hints?.isAsyncTrigger === true ? 1e4 : POST_ACTION_LOADING_MAX_MS;
|
|
4162
|
-
const loadSettle = await
|
|
3983
|
+
const loadSettle = await chunkYB77RYCC_js.waitForLoadingSettle({
|
|
4163
3984
|
pressedComponentId: pressedId,
|
|
4164
|
-
fromScreen:
|
|
3985
|
+
fromScreen: chunkYB77RYCC_js.getCurrentScreen(),
|
|
4165
3986
|
maxMs: settleCapMs
|
|
4166
3987
|
});
|
|
4167
|
-
|
|
4168
|
-
`
|
|
3988
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3989
|
+
`settleTurn: post-action loading settle \u2014 pressedId="${pressedId ?? ""}" settled=${loadSettle.settled} transitioned=${loadSettle.transitioned} loadingPending=${loadSettle.loadingPending} probes=${loadSettle.probeCount} waitedMs=${loadSettle.waitedMs} cap=${settleCapMs}${hints?.isAsyncTrigger ? " (mcp-inferred)" : ""}`
|
|
4169
3990
|
);
|
|
4170
3991
|
if (loadSettle.loadingPending) loadingPending = true;
|
|
4171
3992
|
const listPressActions = turnActions.filter((action) => {
|
|
4172
|
-
const target =
|
|
4173
|
-
return target ?
|
|
3993
|
+
const target = chunkYB77RYCC_js.actionPressTargetId(action);
|
|
3994
|
+
return target ? chunkYB77RYCC_js.isListItemPressTarget(target) : false;
|
|
4174
3995
|
});
|
|
4175
3996
|
if (listPressActions.length > 0) {
|
|
4176
|
-
const baselineFingerprint =
|
|
4177
|
-
const postPressSettle = await
|
|
3997
|
+
const baselineFingerprint = chunkYB77RYCC_js.probeLoadingState(pressedId, chunkYB77RYCC_js.getCurrentScreen()).fingerprint;
|
|
3998
|
+
const postPressSettle = await chunkYB77RYCC_js.waitForScreenSettle({
|
|
4178
3999
|
expectingChange: true,
|
|
4179
4000
|
fromScreen: input.preNavigateScreen ?? null,
|
|
4180
4001
|
fromSignature: input.preNavigateSignature ?? null,
|
|
4181
4002
|
maxMs: 2500
|
|
4182
4003
|
});
|
|
4183
|
-
await
|
|
4004
|
+
await chunkYB77RYCC_js.waitForLoadingSettle({
|
|
4184
4005
|
pressedComponentId: pressedId,
|
|
4185
|
-
fromScreen:
|
|
4006
|
+
fromScreen: chunkYB77RYCC_js.getCurrentScreen(),
|
|
4186
4007
|
maxMs: 4e3
|
|
4187
4008
|
});
|
|
4188
|
-
const afterFingerprint =
|
|
4189
|
-
|
|
4190
|
-
`
|
|
4009
|
+
const afterFingerprint = chunkYB77RYCC_js.probeLoadingState(pressedId, chunkYB77RYCC_js.getCurrentScreen()).fingerprint;
|
|
4010
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
4011
|
+
`settleTurn: post-list-press settle \u2014 screen="${postPressSettle.screen}" transitioned=${postPressSettle.transitioned} timedOut=${postPressSettle.timedOut} waitedMs=${postPressSettle.waitedMs}`
|
|
4191
4012
|
);
|
|
4192
4013
|
if (!postPressSettle.transitioned && baselineFingerprint === afterFingerprint) {
|
|
4193
4014
|
for (const action of listPressActions) {
|
|
@@ -4202,15 +4023,15 @@ async function settleTurn(input) {
|
|
|
4202
4023
|
}
|
|
4203
4024
|
var reactNativeChatAdapter = {
|
|
4204
4025
|
buildContext: buildAgentContext,
|
|
4205
|
-
getCurrentScreen:
|
|
4206
|
-
getCurrentScreenSignature:
|
|
4026
|
+
getCurrentScreen: chunkYB77RYCC_js.getCurrentScreen,
|
|
4027
|
+
getCurrentScreenSignature: chunkYB77RYCC_js.getCurrentScreenSignature,
|
|
4207
4028
|
settleTurn
|
|
4208
4029
|
};
|
|
4209
4030
|
function createReactNativeActionRunner(getOptions) {
|
|
4210
4031
|
return {
|
|
4211
4032
|
async execute(action, { confirmedDestructive }) {
|
|
4212
4033
|
const { permissions, emit, navigationRef, suppressNativeConfirm } = getOptions();
|
|
4213
|
-
const navRef = navigationRef?.current ? navigationRef : { current:
|
|
4034
|
+
const navRef = navigationRef?.current ? navigationRef : { current: chunkYB77RYCC_js.getNavigationRef() };
|
|
4214
4035
|
return runWithConfirmedDestructiveContext(
|
|
4215
4036
|
confirmedDestructive && suppressNativeConfirm !== false,
|
|
4216
4037
|
reactNative.Alert,
|
|
@@ -4221,21 +4042,21 @@ function createReactNativeActionRunner(getOptions) {
|
|
|
4221
4042
|
})
|
|
4222
4043
|
);
|
|
4223
4044
|
},
|
|
4224
|
-
getCurrentScreen:
|
|
4225
|
-
getCurrentScreenSignature:
|
|
4045
|
+
getCurrentScreen: chunkYB77RYCC_js.getCurrentScreen,
|
|
4046
|
+
getCurrentScreenSignature: chunkYB77RYCC_js.getCurrentScreenSignature,
|
|
4226
4047
|
getScreenActionsMetadata(screen) {
|
|
4227
|
-
return
|
|
4048
|
+
return chunkYB77RYCC_js.getScreenMetadata(screen)?.actions;
|
|
4228
4049
|
},
|
|
4229
|
-
waitForScreenSettle:
|
|
4050
|
+
waitForScreenSettle: chunkYB77RYCC_js.waitForScreenSettle
|
|
4230
4051
|
};
|
|
4231
4052
|
}
|
|
4232
4053
|
|
|
4233
4054
|
// src/hooks/useAppilotsChat.ts
|
|
4234
4055
|
function useAppilotsChat(options = {}) {
|
|
4235
|
-
const { client, emit, subscribe } =
|
|
4236
|
-
const machine =
|
|
4237
|
-
() => new
|
|
4238
|
-
{ client, adapter: reactNativeChatAdapter, emit, warn:
|
|
4056
|
+
const { client, emit, subscribe } = chunkYB77RYCC_js.useAppilotsContext();
|
|
4057
|
+
const machine = React.useMemo(
|
|
4058
|
+
() => new chunkYB77RYCC_js.ChatSessionMachine(
|
|
4059
|
+
{ client, adapter: reactNativeChatAdapter, emit, warn: chunkYB77RYCC_js.appilotsDebugWarn },
|
|
4239
4060
|
options
|
|
4240
4061
|
),
|
|
4241
4062
|
// A new machine per client/provider instance — options are pushed in
|
|
@@ -4243,20 +4064,20 @@ function useAppilotsChat(options = {}) {
|
|
|
4243
4064
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
4244
4065
|
[client, emit]
|
|
4245
4066
|
);
|
|
4246
|
-
const optionsRef =
|
|
4067
|
+
const optionsRef = React.useRef(options);
|
|
4247
4068
|
optionsRef.current = options;
|
|
4248
4069
|
machine.setOptions(options);
|
|
4249
|
-
const state =
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
const requestHuman =
|
|
4070
|
+
const state = React.useSyncExternalStore(machine.subscribeState, machine.getState, machine.getState);
|
|
4071
|
+
React.useEffect(() => subscribe(machine.handleEvent), [subscribe, machine]);
|
|
4072
|
+
React.useEffect(() => () => machine.dispose(), [machine]);
|
|
4073
|
+
const requestHuman = React.useCallback(
|
|
4253
4074
|
(reason) => machine.requestHuman(reason),
|
|
4254
4075
|
[machine]
|
|
4255
4076
|
);
|
|
4256
|
-
const sendMessage =
|
|
4257
|
-
const cancelMessage =
|
|
4258
|
-
const clearMessages =
|
|
4259
|
-
const clearError =
|
|
4077
|
+
const sendMessage = React.useCallback((content) => machine.sendMessage(content), [machine]);
|
|
4078
|
+
const cancelMessage = React.useCallback(() => machine.cancelMessage(), [machine]);
|
|
4079
|
+
const clearMessages = React.useCallback(() => machine.clearMessages(), [machine]);
|
|
4080
|
+
const clearError = React.useCallback(() => machine.clearError(), [machine]);
|
|
4260
4081
|
return {
|
|
4261
4082
|
messages: state.messages,
|
|
4262
4083
|
isLoading: state.isLoading,
|
|
@@ -4278,9 +4099,9 @@ var DEFAULT_PERMISSIONS2 = {
|
|
|
4278
4099
|
canSubmitForms: true
|
|
4279
4100
|
};
|
|
4280
4101
|
function useAppilotsActions(options = {}) {
|
|
4281
|
-
const { client, subscribe, config, emit } =
|
|
4102
|
+
const { client, subscribe, config, emit } = chunkYB77RYCC_js.useAppilotsContext();
|
|
4282
4103
|
const { navigationRef, autoExecute = false } = options;
|
|
4283
|
-
const runnerOptionsRef =
|
|
4104
|
+
const runnerOptionsRef = React.useRef({
|
|
4284
4105
|
permissions: config.permissions ?? DEFAULT_PERMISSIONS2,
|
|
4285
4106
|
emit,
|
|
4286
4107
|
navigationRef,
|
|
@@ -4292,13 +4113,13 @@ function useAppilotsActions(options = {}) {
|
|
|
4292
4113
|
navigationRef,
|
|
4293
4114
|
suppressNativeConfirm: config.suppressNativeConfirm
|
|
4294
4115
|
};
|
|
4295
|
-
const machine =
|
|
4296
|
-
() => new
|
|
4116
|
+
const machine = React.useMemo(
|
|
4117
|
+
() => new chunkYB77RYCC_js.ActionQueueMachine(
|
|
4297
4118
|
{
|
|
4298
4119
|
client,
|
|
4299
4120
|
adapter: createReactNativeActionRunner(() => runnerOptionsRef.current),
|
|
4300
4121
|
emit,
|
|
4301
|
-
warn:
|
|
4122
|
+
warn: chunkYB77RYCC_js.appilotsDebugWarn
|
|
4302
4123
|
},
|
|
4303
4124
|
{ autoExecute }
|
|
4304
4125
|
),
|
|
@@ -4306,16 +4127,16 @@ function useAppilotsActions(options = {}) {
|
|
|
4306
4127
|
[client, emit]
|
|
4307
4128
|
);
|
|
4308
4129
|
machine.setOptions({ autoExecute });
|
|
4309
|
-
const state =
|
|
4310
|
-
|
|
4311
|
-
|
|
4130
|
+
const state = React.useSyncExternalStore(machine.subscribeState, machine.getState, machine.getState);
|
|
4131
|
+
React.useEffect(() => subscribe(machine.handleEvent), [subscribe, machine]);
|
|
4132
|
+
React.useEffect(() => {
|
|
4312
4133
|
if (autoExecute) machine.scheduleDrain();
|
|
4313
4134
|
}, [autoExecute, machine, state.actions]);
|
|
4314
|
-
const approveAction =
|
|
4135
|
+
const approveAction = React.useCallback(
|
|
4315
4136
|
(actionId) => machine.approveAction(actionId),
|
|
4316
4137
|
[machine]
|
|
4317
4138
|
);
|
|
4318
|
-
const rejectAction =
|
|
4139
|
+
const rejectAction = React.useCallback((actionId) => machine.rejectAction(actionId), [machine]);
|
|
4319
4140
|
return {
|
|
4320
4141
|
pendingActions: state.actions.filter((a) => a.status === "pending"),
|
|
4321
4142
|
executingActions: state.actions.filter((a) => a.status === "executing"),
|
|
@@ -4355,18 +4176,18 @@ function shouldShowSuggestedPrompts(args) {
|
|
|
4355
4176
|
|
|
4356
4177
|
// src/hooks/useSuggestedPrompts.ts
|
|
4357
4178
|
function useSuggestedPrompts(options) {
|
|
4358
|
-
const { client } =
|
|
4179
|
+
const { client } = chunkYB77RYCC_js.useAppilotsContext();
|
|
4359
4180
|
const { enabled, limit = 4 } = options;
|
|
4360
|
-
const [prompts, setPrompts] =
|
|
4361
|
-
const [isLoading, setIsLoading] =
|
|
4362
|
-
const [refreshTick, setRefreshTick] =
|
|
4363
|
-
const requestIdRef =
|
|
4364
|
-
|
|
4181
|
+
const [prompts, setPrompts] = React.useState([]);
|
|
4182
|
+
const [isLoading, setIsLoading] = React.useState(false);
|
|
4183
|
+
const [refreshTick, setRefreshTick] = React.useState(0);
|
|
4184
|
+
const requestIdRef = React.useRef(0);
|
|
4185
|
+
React.useEffect(() => {
|
|
4365
4186
|
if (!enabled) return;
|
|
4366
4187
|
const requestId = ++requestIdRef.current;
|
|
4367
4188
|
let cancelled = false;
|
|
4368
|
-
const screen =
|
|
4369
|
-
const localDev = screen ? (
|
|
4189
|
+
const screen = chunkYB77RYCC_js.getCurrentScreen() ?? void 0;
|
|
4190
|
+
const localDev = screen ? (chunkYB77RYCC_js.getScreenMetadata(screen)?.suggestedPrompts ?? []).map((text) => ({
|
|
4370
4191
|
text,
|
|
4371
4192
|
source: "dev-defined"
|
|
4372
4193
|
})) : [];
|
|
@@ -4380,7 +4201,7 @@ function useSuggestedPrompts(options) {
|
|
|
4380
4201
|
if (cancelled || requestIdRef.current !== requestId) return;
|
|
4381
4202
|
setPrompts(mergePromptSources(localDev, data, limit));
|
|
4382
4203
|
}).catch((err) => {
|
|
4383
|
-
|
|
4204
|
+
chunkYB77RYCC_js.appilotsDebugWarn("useSuggestedPrompts: fetch failed", err);
|
|
4384
4205
|
}).finally(() => {
|
|
4385
4206
|
if (cancelled || requestIdRef.current !== requestId) return;
|
|
4386
4207
|
setIsLoading(false);
|
|
@@ -4389,11 +4210,11 @@ function useSuggestedPrompts(options) {
|
|
|
4389
4210
|
cancelled = true;
|
|
4390
4211
|
};
|
|
4391
4212
|
}, [client, enabled, limit, refreshTick]);
|
|
4392
|
-
|
|
4213
|
+
React.useEffect(() => {
|
|
4393
4214
|
if (!enabled) return;
|
|
4394
|
-
let lastScreen =
|
|
4215
|
+
let lastScreen = chunkYB77RYCC_js.getCurrentScreen();
|
|
4395
4216
|
const interval = setInterval(() => {
|
|
4396
|
-
const current =
|
|
4217
|
+
const current = chunkYB77RYCC_js.getCurrentScreen();
|
|
4397
4218
|
if (current !== lastScreen) {
|
|
4398
4219
|
lastScreen = current;
|
|
4399
4220
|
setRefreshTick((t) => t + 1);
|
|
@@ -4408,14 +4229,14 @@ function useSuggestedPrompts(options) {
|
|
|
4408
4229
|
};
|
|
4409
4230
|
}
|
|
4410
4231
|
function useAppilotsNavigation() {
|
|
4411
|
-
const { emit } =
|
|
4412
|
-
const [currentScreen, setCurrentScreenState] =
|
|
4413
|
-
const [navigationHistory, setNavigationHistory] =
|
|
4414
|
-
const navigationRef =
|
|
4415
|
-
const setCurrentScreen2 =
|
|
4232
|
+
const { emit } = chunkYB77RYCC_js.useAppilotsContext();
|
|
4233
|
+
const [currentScreen, setCurrentScreenState] = React.useState(null);
|
|
4234
|
+
const [navigationHistory, setNavigationHistory] = React.useState([]);
|
|
4235
|
+
const navigationRef = React.useRef(null);
|
|
4236
|
+
const setCurrentScreen2 = React.useCallback(
|
|
4416
4237
|
(screenName) => {
|
|
4417
4238
|
setCurrentScreenState(screenName);
|
|
4418
|
-
|
|
4239
|
+
chunkYB77RYCC_js.setCurrentScreen(screenName);
|
|
4419
4240
|
setNavigationHistory((prev) => [...prev, screenName]);
|
|
4420
4241
|
emit({
|
|
4421
4242
|
type: "navigation:change",
|
|
@@ -4425,7 +4246,7 @@ function useAppilotsNavigation() {
|
|
|
4425
4246
|
},
|
|
4426
4247
|
[emit]
|
|
4427
4248
|
);
|
|
4428
|
-
|
|
4249
|
+
React.useEffect(() => {
|
|
4429
4250
|
const nav = navigationRef.current;
|
|
4430
4251
|
if (!nav?.addListener) return;
|
|
4431
4252
|
const unsubscribe = nav.addListener("state", () => {
|
|
@@ -4446,7 +4267,7 @@ function useAppilotsNavigation() {
|
|
|
4446
4267
|
|
|
4447
4268
|
// src/hooks/useAppilots.ts
|
|
4448
4269
|
function useAppilots() {
|
|
4449
|
-
const { config, client } =
|
|
4270
|
+
const { config, client } = chunkYB77RYCC_js.useAppilotsContext();
|
|
4450
4271
|
const chat = useAppilotsChat();
|
|
4451
4272
|
const navigation = useAppilotsNavigation();
|
|
4452
4273
|
const actions = useAppilotsActions();
|
|
@@ -4475,17 +4296,17 @@ function useAppilots() {
|
|
|
4475
4296
|
}
|
|
4476
4297
|
function useAppilotsField(id, options) {
|
|
4477
4298
|
const { value, onChangeText, ref, fieldType, label, screen } = options;
|
|
4478
|
-
const registry =
|
|
4479
|
-
const valueRef =
|
|
4480
|
-
const onChangeRef =
|
|
4299
|
+
const registry = chunkYB77RYCC_js.useResolvedRegistry();
|
|
4300
|
+
const valueRef = React.useRef(value);
|
|
4301
|
+
const onChangeRef = React.useRef(onChangeText);
|
|
4481
4302
|
valueRef.current = value;
|
|
4482
4303
|
onChangeRef.current = onChangeText;
|
|
4483
|
-
const getValue =
|
|
4484
|
-
const setValue =
|
|
4485
|
-
const focus =
|
|
4304
|
+
const getValue = React.useCallback(() => valueRef.current, []);
|
|
4305
|
+
const setValue = React.useCallback((v) => onChangeRef.current(v), []);
|
|
4306
|
+
const focus = React.useCallback(() => {
|
|
4486
4307
|
ref?.current?.focus?.();
|
|
4487
4308
|
}, [ref]);
|
|
4488
|
-
|
|
4309
|
+
React.useEffect(() => {
|
|
4489
4310
|
const entry = {
|
|
4490
4311
|
kind: "field",
|
|
4491
4312
|
getValue,
|
|
@@ -4503,17 +4324,17 @@ function useAppilotsField(id, options) {
|
|
|
4503
4324
|
}
|
|
4504
4325
|
function useAppilotsTarget(id, options) {
|
|
4505
4326
|
const { onPress, onLongPress, onScrollTo, label, screen } = options;
|
|
4506
|
-
const registry =
|
|
4507
|
-
const onPressRef =
|
|
4508
|
-
const onLongPressRef =
|
|
4509
|
-
const onScrollToRef =
|
|
4327
|
+
const registry = chunkYB77RYCC_js.useResolvedRegistry();
|
|
4328
|
+
const onPressRef = React.useRef(onPress);
|
|
4329
|
+
const onLongPressRef = React.useRef(onLongPress);
|
|
4330
|
+
const onScrollToRef = React.useRef(onScrollTo);
|
|
4510
4331
|
onPressRef.current = onPress;
|
|
4511
4332
|
onLongPressRef.current = onLongPress;
|
|
4512
4333
|
onScrollToRef.current = onScrollTo;
|
|
4513
|
-
const press =
|
|
4514
|
-
const longPress =
|
|
4515
|
-
const scrollTo =
|
|
4516
|
-
|
|
4334
|
+
const press = React.useCallback(() => onPressRef.current(), []);
|
|
4335
|
+
const longPress = React.useCallback(() => onLongPressRef.current?.(), []);
|
|
4336
|
+
const scrollTo = React.useCallback(() => onScrollToRef.current?.(), []);
|
|
4337
|
+
React.useEffect(() => {
|
|
4517
4338
|
const entry = {
|
|
4518
4339
|
kind: "target",
|
|
4519
4340
|
press,
|
|
@@ -4530,14 +4351,14 @@ function useAppilotsTarget(id, options) {
|
|
|
4530
4351
|
}
|
|
4531
4352
|
function useAppilotsToggle(id, options) {
|
|
4532
4353
|
const { value, onValueChange, label, screen } = options;
|
|
4533
|
-
const registry =
|
|
4534
|
-
const valueRef =
|
|
4535
|
-
const onChangeRef =
|
|
4354
|
+
const registry = chunkYB77RYCC_js.useResolvedRegistry();
|
|
4355
|
+
const valueRef = React.useRef(value);
|
|
4356
|
+
const onChangeRef = React.useRef(onValueChange);
|
|
4536
4357
|
valueRef.current = value;
|
|
4537
4358
|
onChangeRef.current = onValueChange;
|
|
4538
|
-
const getValue =
|
|
4539
|
-
const setValue =
|
|
4540
|
-
|
|
4359
|
+
const getValue = React.useCallback(() => valueRef.current, []);
|
|
4360
|
+
const setValue = React.useCallback((v) => onChangeRef.current(v), []);
|
|
4361
|
+
React.useEffect(() => {
|
|
4541
4362
|
const entry = {
|
|
4542
4363
|
kind: "toggle",
|
|
4543
4364
|
getValue,
|
|
@@ -4553,14 +4374,14 @@ function useAppilotsToggle(id, options) {
|
|
|
4553
4374
|
}
|
|
4554
4375
|
function useAppilotsSlider(id, options) {
|
|
4555
4376
|
const { value, onValueChange, min, max, step, label, screen } = options;
|
|
4556
|
-
const registry =
|
|
4557
|
-
const valueRef =
|
|
4558
|
-
const onChangeRef =
|
|
4377
|
+
const registry = chunkYB77RYCC_js.useResolvedRegistry();
|
|
4378
|
+
const valueRef = React.useRef(value);
|
|
4379
|
+
const onChangeRef = React.useRef(onValueChange);
|
|
4559
4380
|
valueRef.current = value;
|
|
4560
4381
|
onChangeRef.current = onValueChange;
|
|
4561
|
-
const getValue =
|
|
4562
|
-
const setValue =
|
|
4563
|
-
|
|
4382
|
+
const getValue = React.useCallback(() => valueRef.current, []);
|
|
4383
|
+
const setValue = React.useCallback((v) => onChangeRef.current(v), []);
|
|
4384
|
+
React.useEffect(() => {
|
|
4564
4385
|
const entry = {
|
|
4565
4386
|
kind: "slider",
|
|
4566
4387
|
getValue,
|
|
@@ -4578,6 +4399,7 @@ function useAppilotsSlider(id, options) {
|
|
|
4578
4399
|
}, [id, registry, getValue, setValue, min, max, step, label, screen]);
|
|
4579
4400
|
}
|
|
4580
4401
|
|
|
4402
|
+
exports.appilotsSelfCheck = appilotsSelfCheck;
|
|
4581
4403
|
exports.captureSnapshot = captureSnapshot;
|
|
4582
4404
|
exports.executeAction = executeAction;
|
|
4583
4405
|
exports.shouldShowSuggestedPrompts = shouldShowSuggestedPrompts;
|