@appilots/sdk 0.7.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 +46 -4
- package/dist/.build-meta.json +5 -0
- package/dist/{chunk-KYFAXT6V.js → chunk-2GCWCPSD.js} +19 -16
- package/dist/{chunk-R4D34FEW.mjs → chunk-AHHDOUVX.mjs} +2151 -333
- package/dist/{chunk-DR75QTYK.mjs → chunk-IHPLS5FE.mjs} +16 -13
- package/dist/{chunk-HFRIB4YN.js → chunk-VX7AL4SA.js} +1049 -1162
- package/dist/{chunk-KUFWRJC4.mjs → chunk-XHR65V2W.mjs} +831 -949
- package/dist/{chunk-DZ7QRFHD.js → chunk-YB77RYCC.js} +2178 -332
- 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-nI-s3Exg.d.mts → index-BPZ0j71S.d.mts} +315 -15
- package/dist/{index-nI-s3Exg.d.ts → index-BPZ0j71S.d.ts} +315 -15
- package/dist/index.d.mts +325 -22
- package/dist/index.d.ts +325 -22
- package/dist/index.js +340 -227
- package/dist/index.mjs +274 -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 +16 -6
- 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: chunkDZ7QRFHD_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,35 +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
|
-
|
|
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]] : [])
|
|
214
|
+
);
|
|
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
|
+
})
|
|
779
223
|
);
|
|
780
|
-
chunkDZ7QRFHD_js.elementRegistry.replaceAll(snapshot.elements);
|
|
781
224
|
const elapsed = Date.now() - start;
|
|
782
|
-
const totalListItems = snapshot.lists.reduce(
|
|
783
|
-
(acc, l) => acc + l.items.length,
|
|
784
|
-
0
|
|
785
|
-
);
|
|
225
|
+
const totalListItems = snapshot.lists.reduce((acc, l) => acc + l.items.length, 0);
|
|
786
226
|
const totalListDataItems = snapshot.lists.reduce(
|
|
787
227
|
(acc, l) => acc + (typeof l.itemCount === "number" ? l.itemCount : 0),
|
|
788
228
|
0
|
|
789
229
|
);
|
|
790
|
-
|
|
791
|
-
`
|
|
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)`
|
|
792
232
|
);
|
|
793
|
-
|
|
794
|
-
`
|
|
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(", ")}]`
|
|
795
235
|
);
|
|
796
236
|
return snapshot;
|
|
797
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
|
+
}
|
|
798
278
|
|
|
799
279
|
// src/introspection/findInteractive.ts
|
|
800
280
|
function getTypeName2(type) {
|
|
@@ -808,7 +288,7 @@ function getTypeName2(type) {
|
|
|
808
288
|
}
|
|
809
289
|
return null;
|
|
810
290
|
}
|
|
811
|
-
function
|
|
291
|
+
function matchesName(fiber, name) {
|
|
812
292
|
return getTypeName2(fiber.type) === name || getTypeName2(fiber.elementType) === name;
|
|
813
293
|
}
|
|
814
294
|
var TOUCHABLE_NAMES2 = /* @__PURE__ */ new Set([
|
|
@@ -821,33 +301,33 @@ var TOUCHABLE_NAMES2 = /* @__PURE__ */ new Set([
|
|
|
821
301
|
function isTouchable(fiber) {
|
|
822
302
|
return TOUCHABLE_NAMES2.has(getTypeName2(fiber.type) ?? "") || TOUCHABLE_NAMES2.has(getTypeName2(fiber.elementType) ?? "");
|
|
823
303
|
}
|
|
824
|
-
function
|
|
304
|
+
function hasPressHandler(fiber) {
|
|
825
305
|
const props = fiber?.memoizedProps ?? {};
|
|
826
306
|
return typeof props.onPress === "function" || typeof props.onPressIn === "function";
|
|
827
307
|
}
|
|
828
|
-
function
|
|
829
|
-
return isTouchable(fiber) ||
|
|
308
|
+
function isPressableTarget(fiber) {
|
|
309
|
+
return isTouchable(fiber) || hasPressHandler(fiber);
|
|
830
310
|
}
|
|
831
|
-
var
|
|
311
|
+
var SELF_REFERENTIAL_COMPONENTS = /* @__PURE__ */ new Set([
|
|
832
312
|
"AppilotsChat",
|
|
833
313
|
"AppilotsChatInner",
|
|
834
314
|
"ActionBreadcrumb",
|
|
835
315
|
"ConfirmDialog"
|
|
836
316
|
]);
|
|
837
|
-
function
|
|
317
|
+
function isAppilotsSkipMarked(props) {
|
|
838
318
|
if (!props) return false;
|
|
839
319
|
return props.__appilotsSkip === true || props["data-appilots-skip"] === true || props.appilotsSkip === true;
|
|
840
320
|
}
|
|
841
|
-
function
|
|
321
|
+
function extractTextFromChildren(children) {
|
|
842
322
|
if (children == null) return "";
|
|
843
323
|
if (typeof children === "string") return children;
|
|
844
324
|
if (typeof children === "number") return String(children);
|
|
845
325
|
if (Array.isArray(children)) {
|
|
846
|
-
return children.map(
|
|
326
|
+
return children.map(extractTextFromChildren).filter(Boolean).join("");
|
|
847
327
|
}
|
|
848
328
|
return "";
|
|
849
329
|
}
|
|
850
|
-
function
|
|
330
|
+
function findChildText(fiber) {
|
|
851
331
|
const stack = [];
|
|
852
332
|
if (fiber.child) stack.push(fiber.child);
|
|
853
333
|
const visited = /* @__PURE__ */ new WeakSet();
|
|
@@ -855,8 +335,8 @@ function findChildText2(fiber) {
|
|
|
855
335
|
const node = stack.pop();
|
|
856
336
|
if (!node || visited.has(node)) continue;
|
|
857
337
|
visited.add(node);
|
|
858
|
-
if (
|
|
859
|
-
const text =
|
|
338
|
+
if (matchesName(node, "Text")) {
|
|
339
|
+
const text = extractTextFromChildren(node.memoizedProps?.children);
|
|
860
340
|
if (text && text.trim().length > 0) return text.trim();
|
|
861
341
|
}
|
|
862
342
|
if (node.sibling) stack.push(node.sibling);
|
|
@@ -868,10 +348,10 @@ function shouldSkipSubtree2(fiber) {
|
|
|
868
348
|
const props = fiber.memoizedProps;
|
|
869
349
|
if (!props) return false;
|
|
870
350
|
const typeName = getTypeName2(fiber.type) ?? getTypeName2(fiber.elementType);
|
|
871
|
-
if (typeName &&
|
|
872
|
-
if (
|
|
873
|
-
if (
|
|
874
|
-
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;
|
|
875
355
|
const style = props.style;
|
|
876
356
|
if (style) {
|
|
877
357
|
const flat = Array.isArray(style) ? Object.assign({}, ...style.filter(Boolean)) : style;
|
|
@@ -880,20 +360,19 @@ function shouldSkipSubtree2(fiber) {
|
|
|
880
360
|
}
|
|
881
361
|
return false;
|
|
882
362
|
}
|
|
883
|
-
|
|
884
|
-
if (!s) return "";
|
|
885
|
-
return s.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
|
|
886
|
-
}
|
|
363
|
+
var normalize = chunkYB77RYCC_js.foldForCompare;
|
|
887
364
|
function scoreMatch(fiber, queryNorm, queryRaw) {
|
|
888
365
|
const props = fiber.memoizedProps ?? {};
|
|
889
366
|
const candidates = [];
|
|
890
367
|
if (typeof props.testID === "string") candidates.push({ val: props.testID, weight: 100 });
|
|
891
|
-
if (typeof props.accessibilityLabel === "string")
|
|
368
|
+
if (typeof props.accessibilityLabel === "string")
|
|
369
|
+
candidates.push({ val: props.accessibilityLabel, weight: 95 });
|
|
892
370
|
if (typeof props.label === "string") candidates.push({ val: props.label, weight: 90 });
|
|
893
|
-
if (typeof props.placeholder === "string")
|
|
371
|
+
if (typeof props.placeholder === "string")
|
|
372
|
+
candidates.push({ val: props.placeholder, weight: 70 });
|
|
894
373
|
if (typeof props.title === "string") candidates.push({ val: props.title, weight: 85 });
|
|
895
|
-
if (
|
|
896
|
-
const childText =
|
|
374
|
+
if (isPressableTarget(fiber)) {
|
|
375
|
+
const childText = findChildText(fiber);
|
|
897
376
|
if (childText) candidates.push({ val: childText, weight: 80 });
|
|
898
377
|
}
|
|
899
378
|
let best = 0;
|
|
@@ -902,7 +381,8 @@ function scoreMatch(fiber, queryNorm, queryRaw) {
|
|
|
902
381
|
if (!vNorm) continue;
|
|
903
382
|
if (val === queryRaw) best = Math.max(best, weight + 20);
|
|
904
383
|
else if (vNorm === queryNorm) best = Math.max(best, weight + 10);
|
|
905
|
-
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);
|
|
906
386
|
}
|
|
907
387
|
if (best > 0 && props.disabled === true) {
|
|
908
388
|
best = Math.max(1, best - 60);
|
|
@@ -933,6 +413,12 @@ function wrapTextInput(fiber) {
|
|
|
933
413
|
if (node && typeof node.focus === "function") {
|
|
934
414
|
node.focus();
|
|
935
415
|
}
|
|
416
|
+
},
|
|
417
|
+
submitFromKeyboard: () => {
|
|
418
|
+
const { onSubmitEditing, value } = getProps();
|
|
419
|
+
if (typeof onSubmitEditing !== "function") return false;
|
|
420
|
+
onSubmitEditing({ nativeEvent: { text: value ?? "" } });
|
|
421
|
+
return true;
|
|
936
422
|
}
|
|
937
423
|
};
|
|
938
424
|
}
|
|
@@ -970,16 +456,16 @@ function wrapTouchable(fiber, label) {
|
|
|
970
456
|
};
|
|
971
457
|
}
|
|
972
458
|
function findInteractiveByIdentifier(query, options = {}) {
|
|
973
|
-
const root =
|
|
459
|
+
const root = chunkYB77RYCC_js.getFiberRoot();
|
|
974
460
|
if (!root) {
|
|
975
|
-
|
|
461
|
+
chunkYB77RYCC_js.appilotsDebugWarn("findInteractiveByIdentifier: fiber root not captured yet");
|
|
976
462
|
return null;
|
|
977
463
|
}
|
|
978
464
|
const queryNorm = normalize(query);
|
|
979
465
|
const queryRaw = query;
|
|
980
466
|
let bestScore = 0;
|
|
981
467
|
let bestHandle = null;
|
|
982
|
-
let
|
|
468
|
+
let bestId;
|
|
983
469
|
const visited = /* @__PURE__ */ new WeakSet();
|
|
984
470
|
const stack = [];
|
|
985
471
|
if (root.child) stack.push(root.child);
|
|
@@ -990,40 +476,50 @@ function findInteractiveByIdentifier(query, options = {}) {
|
|
|
990
476
|
if (fiber.sibling) stack.push(fiber.sibling);
|
|
991
477
|
if (shouldSkipSubtree2(fiber)) continue;
|
|
992
478
|
let kind = null;
|
|
993
|
-
if (
|
|
994
|
-
else if (
|
|
995
|
-
else if (
|
|
479
|
+
if (matchesName(fiber, "TextInput")) kind = "field";
|
|
480
|
+
else if (matchesName(fiber, "Switch")) kind = "toggle";
|
|
481
|
+
else if (isPressableTarget(fiber)) kind = "target";
|
|
996
482
|
if (kind && (!options.kind || options.kind === kind)) {
|
|
997
483
|
const score = scoreMatch(fiber, queryNorm, queryRaw);
|
|
998
484
|
if (score > bestScore) {
|
|
999
485
|
bestScore = score;
|
|
1000
486
|
const props = fiber.memoizedProps ?? {};
|
|
1001
|
-
|
|
487
|
+
bestId = props.testID ?? props.accessibilityLabel ?? props.placeholder ?? (kind === "target" ? findChildText(fiber) : void 0);
|
|
1002
488
|
if (kind === "field") bestHandle = wrapTextInput(fiber);
|
|
1003
489
|
else if (kind === "toggle") bestHandle = wrapSwitch(fiber);
|
|
1004
|
-
else bestHandle = wrapTouchable(fiber,
|
|
490
|
+
else bestHandle = wrapTouchable(fiber, findChildText(fiber));
|
|
1005
491
|
}
|
|
1006
492
|
}
|
|
1007
493
|
if (fiber.child) stack.push(fiber.child);
|
|
1008
494
|
}
|
|
1009
495
|
if (bestHandle) {
|
|
1010
|
-
|
|
1011
|
-
`
|
|
496
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
497
|
+
`findInteractiveByIdentifier: query="${query}" \u2192 kind=${bestHandle.kind} label="${bestHandle.label ?? bestId}" score=${bestScore}`
|
|
1012
498
|
);
|
|
1013
499
|
} else {
|
|
1014
|
-
|
|
500
|
+
chunkYB77RYCC_js.appilotsDebugLog(`findInteractiveByIdentifier: query="${query}" \u2192 no match`);
|
|
1015
501
|
}
|
|
1016
502
|
return bestHandle;
|
|
1017
503
|
}
|
|
1018
504
|
|
|
1019
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
|
+
}
|
|
1020
514
|
function categorizeNavigationError(message) {
|
|
1021
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(
|
|
1022
516
|
message
|
|
1023
517
|
)) {
|
|
1024
518
|
return "component-not-found";
|
|
1025
519
|
}
|
|
1026
|
-
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
|
+
)) {
|
|
1027
523
|
return "screen-timeout";
|
|
1028
524
|
}
|
|
1029
525
|
return "unknown";
|
|
@@ -1050,7 +546,9 @@ function screenExistsAnywhere(state, screenName) {
|
|
|
1050
546
|
function safeNavigate(nav, screenName, params, path) {
|
|
1051
547
|
if (path && path.length > 0) {
|
|
1052
548
|
const { root, nestedParams } = buildNestedParams(path, screenName, params);
|
|
1053
|
-
|
|
549
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
550
|
+
`safeNavigate: using path-based navigation \u2014 root="${root}", nested=${JSON.stringify(nestedParams)}`
|
|
551
|
+
);
|
|
1054
552
|
nav.navigate(root, nestedParams);
|
|
1055
553
|
return;
|
|
1056
554
|
}
|
|
@@ -1065,11 +563,17 @@ function safeNavigate(nav, screenName, params, path) {
|
|
|
1065
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.`
|
|
1066
564
|
);
|
|
1067
565
|
}
|
|
1068
|
-
|
|
566
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
567
|
+
`safeNavigate: screen exists in nested navigator, attempting direct navigation to "${screenName}"`
|
|
568
|
+
);
|
|
1069
569
|
nav.navigate(screenName, params);
|
|
1070
570
|
}
|
|
1071
571
|
function navigateHandler(payload, context) {
|
|
1072
|
-
|
|
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
|
+
);
|
|
1073
577
|
const { navigationRef, permissions } = context;
|
|
1074
578
|
const nav = navigationRef.current;
|
|
1075
579
|
if (!permissions.canNavigate) {
|
|
@@ -1079,14 +583,15 @@ function navigateHandler(payload, context) {
|
|
|
1079
583
|
diagnose: { category: "unknown", screen: payload.screenName }
|
|
1080
584
|
};
|
|
1081
585
|
}
|
|
1082
|
-
|
|
586
|
+
const isGoBack = payload.navigationAction === "goBack";
|
|
587
|
+
if (!isGoBack && permissions.blockedScreens?.includes(payload.screenName)) {
|
|
1083
588
|
return {
|
|
1084
589
|
success: false,
|
|
1085
590
|
error: `Navigation to "${payload.screenName}" is blocked`,
|
|
1086
591
|
diagnose: { category: "unknown", screen: payload.screenName }
|
|
1087
592
|
};
|
|
1088
593
|
}
|
|
1089
|
-
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)) {
|
|
1090
595
|
return {
|
|
1091
596
|
success: false,
|
|
1092
597
|
error: `Navigation to "${payload.screenName}" is not in allowed screens`,
|
|
@@ -1094,10 +599,11 @@ function navigateHandler(payload, context) {
|
|
|
1094
599
|
};
|
|
1095
600
|
}
|
|
1096
601
|
if (!nav) {
|
|
602
|
+
reportMissingNavigationRef();
|
|
1097
603
|
return {
|
|
1098
604
|
success: false,
|
|
1099
|
-
error: "Navigation
|
|
1100
|
-
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 }
|
|
1101
607
|
};
|
|
1102
608
|
}
|
|
1103
609
|
if (!nav.isReady || typeof nav.isReady === "function" && !nav.isReady()) {
|
|
@@ -1108,7 +614,15 @@ function navigateHandler(payload, context) {
|
|
|
1108
614
|
};
|
|
1109
615
|
}
|
|
1110
616
|
try {
|
|
1111
|
-
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;
|
|
1112
626
|
switch (navigationAction) {
|
|
1113
627
|
case "navigate":
|
|
1114
628
|
safeNavigate(nav, screenName, params ?? {}, path);
|
|
@@ -1151,10 +665,14 @@ function navigateHandler(payload, context) {
|
|
|
1151
665
|
diagnose: { category: "unknown", screen: payload.screenName }
|
|
1152
666
|
};
|
|
1153
667
|
}
|
|
1154
|
-
|
|
668
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
669
|
+
`navigateHandler: navigation succeeded for "${payload.screenName}" (action="${payload.navigationAction}")`
|
|
670
|
+
);
|
|
1155
671
|
return { success: true };
|
|
1156
672
|
} catch (err) {
|
|
1157
|
-
|
|
673
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
674
|
+
`navigateHandler: navigation failed for "${payload.screenName}": ${err?.message}`
|
|
675
|
+
);
|
|
1158
676
|
const msg = String(err?.message ?? "Navigation failed");
|
|
1159
677
|
const category = categorizeNavigationError(msg);
|
|
1160
678
|
return {
|
|
@@ -1177,7 +695,7 @@ function parseSyntheticListItemId(id) {
|
|
|
1177
695
|
if (listIndex < 0 || itemIndex < 1) return null;
|
|
1178
696
|
return { listIndex, itemIndex };
|
|
1179
697
|
}
|
|
1180
|
-
function
|
|
698
|
+
function stringProp(props, key) {
|
|
1181
699
|
const value = props?.[key];
|
|
1182
700
|
if (typeof value === "string" && value.trim()) return value.trim();
|
|
1183
701
|
if (typeof value === "number") return String(value);
|
|
@@ -1185,33 +703,33 @@ function stringProp2(props, key) {
|
|
|
1185
703
|
}
|
|
1186
704
|
function listIdFromContainer(container) {
|
|
1187
705
|
const props = container?.memoizedProps ?? {};
|
|
1188
|
-
return
|
|
706
|
+
return stringProp(props, "__appilotsListId") ?? stringProp(props, "appilotsListId") ?? stringProp(props, "testID") ?? stringProp(props, "accessibilityLabel");
|
|
1189
707
|
}
|
|
1190
708
|
function listLabelFromContainer(container) {
|
|
1191
709
|
const props = container?.memoizedProps ?? {};
|
|
1192
|
-
return
|
|
710
|
+
return stringProp(props, "__appilotsListLabel") ?? stringProp(props, "accessibilityLabel") ?? stringProp(props, "aria-label") ?? stringProp(props, "label");
|
|
1193
711
|
}
|
|
1194
712
|
function itemKeyFromFiber(fiber) {
|
|
1195
713
|
const props = fiber?.memoizedProps ?? {};
|
|
1196
|
-
return
|
|
714
|
+
return stringProp(props, "__appilotsItemKey") ?? (fiber?.key !== void 0 && fiber?.key !== null ? String(fiber.key) : void 0);
|
|
1197
715
|
}
|
|
1198
716
|
function markedItemIndexFromFiber(fiber) {
|
|
1199
717
|
const value = fiber?.memoizedProps?.__appilotsItemIndex;
|
|
1200
718
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1201
719
|
}
|
|
1202
720
|
function normalize2(value) {
|
|
1203
|
-
return String(value ?? "")
|
|
721
|
+
return chunkYB77RYCC_js.foldForCompare(String(value ?? ""));
|
|
1204
722
|
}
|
|
1205
|
-
function
|
|
723
|
+
function hasPressHandler2(fiber) {
|
|
1206
724
|
const props = fiber?.memoizedProps ?? {};
|
|
1207
725
|
return typeof props.onPress === "function" || typeof props.onPressIn === "function";
|
|
1208
726
|
}
|
|
1209
727
|
function isPressableFiber(fiber) {
|
|
1210
|
-
const typeName = getTypeName(fiber.type) ?? getTypeName(fiber.elementType) ?? "";
|
|
1211
|
-
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);
|
|
1212
730
|
}
|
|
1213
731
|
function findListContainers(options = {}) {
|
|
1214
|
-
const root =
|
|
732
|
+
const root = chunkYB77RYCC_js.getFiberRoot();
|
|
1215
733
|
if (!root) return [];
|
|
1216
734
|
const containers = [];
|
|
1217
735
|
const visited = /* @__PURE__ */ new WeakSet();
|
|
@@ -1222,17 +740,17 @@ function findListContainers(options = {}) {
|
|
|
1222
740
|
if (!fiber || visited.has(fiber)) continue;
|
|
1223
741
|
visited.add(fiber);
|
|
1224
742
|
if (fiber.sibling) stack.push(fiber.sibling);
|
|
1225
|
-
if (shouldSkipSubtree(fiber)) continue;
|
|
1226
|
-
if (isAlwaysListContainer(fiber) || isHeuristicListContainer(fiber)) {
|
|
1227
|
-
const minItems = isAlwaysListContainer(fiber) || options.allowSingleHeuristic ? 1 : 2;
|
|
1228
|
-
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);
|
|
1229
747
|
if (items && items.length >= minItems) {
|
|
1230
748
|
containers.push({
|
|
1231
749
|
container: fiber,
|
|
1232
750
|
items,
|
|
1233
751
|
listId: listIdFromContainer(fiber),
|
|
1234
752
|
listLabel: listLabelFromContainer(fiber),
|
|
1235
|
-
containerType: getTypeName(fiber.type) ?? getTypeName(fiber.elementType) ?? "List"
|
|
753
|
+
containerType: chunkYB77RYCC_js.getTypeName(fiber.type) ?? chunkYB77RYCC_js.getTypeName(fiber.elementType) ?? "List"
|
|
1236
754
|
});
|
|
1237
755
|
continue;
|
|
1238
756
|
}
|
|
@@ -1251,7 +769,7 @@ function findFirstTouchable(item) {
|
|
|
1251
769
|
const { fiber, includeSibling } = stack.pop();
|
|
1252
770
|
if (!fiber || visited.has(fiber)) continue;
|
|
1253
771
|
visited.add(fiber);
|
|
1254
|
-
if (shouldSkipSubtree(fiber)) continue;
|
|
772
|
+
if (chunkYB77RYCC_js.shouldSkipSubtree(fiber)) continue;
|
|
1255
773
|
if (isPressableFiber(fiber)) {
|
|
1256
774
|
const props = fiber.memoizedProps ?? {};
|
|
1257
775
|
if (typeof props.onPress === "function" || typeof props.onPressIn === "function") {
|
|
@@ -1278,7 +796,7 @@ function findTouchableFibers(item) {
|
|
|
1278
796
|
const { fiber, includeSibling } = stack.pop();
|
|
1279
797
|
if (!fiber || visited.has(fiber)) continue;
|
|
1280
798
|
visited.add(fiber);
|
|
1281
|
-
if (shouldSkipSubtree(fiber)) continue;
|
|
799
|
+
if (chunkYB77RYCC_js.shouldSkipSubtree(fiber)) continue;
|
|
1282
800
|
const props = fiber.memoizedProps ?? {};
|
|
1283
801
|
if (isPressableFiber(fiber) && (typeof props.onPress === "function" || typeof props.onPressIn === "function")) {
|
|
1284
802
|
found.push(fiber);
|
|
@@ -1322,7 +840,7 @@ function findFirstText(fiber) {
|
|
|
1322
840
|
const node = stack.pop();
|
|
1323
841
|
if (!node || visited.has(node)) continue;
|
|
1324
842
|
visited.add(node);
|
|
1325
|
-
const typeName = getTypeName(node.type) ?? getTypeName(node.elementType) ?? "";
|
|
843
|
+
const typeName = chunkYB77RYCC_js.getTypeName(node.type) ?? chunkYB77RYCC_js.getTypeName(node.elementType) ?? "";
|
|
1326
844
|
if (typeName === "Text") {
|
|
1327
845
|
const text = textFromChildren(node.memoizedProps?.children).trim();
|
|
1328
846
|
if (text) return text;
|
|
@@ -1341,7 +859,7 @@ function collectTexts(fiber) {
|
|
|
1341
859
|
const node = stack.pop();
|
|
1342
860
|
if (!node || visited.has(node)) continue;
|
|
1343
861
|
visited.add(node);
|
|
1344
|
-
const typeName = getTypeName(node.type) ?? getTypeName(node.elementType) ?? "";
|
|
862
|
+
const typeName = chunkYB77RYCC_js.getTypeName(node.type) ?? chunkYB77RYCC_js.getTypeName(node.elementType) ?? "";
|
|
1345
863
|
if (typeName === "Text") {
|
|
1346
864
|
const text = textFromChildren(node.memoizedProps?.children).trim();
|
|
1347
865
|
if (text) out.push(text);
|
|
@@ -1353,13 +871,10 @@ function collectTexts(fiber) {
|
|
|
1353
871
|
}
|
|
1354
872
|
function hasUsefulTouchableIdentity(fiber) {
|
|
1355
873
|
const props = fiber?.memoizedProps ?? {};
|
|
1356
|
-
if (
|
|
1357
|
-
if (
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
if (typeof props.label === "string" && /[a-z0-9]/i.test(props.label)) return true;
|
|
1361
|
-
const label = findFirstText(fiber);
|
|
1362
|
-
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));
|
|
1363
878
|
}
|
|
1364
879
|
function describeTouchable(fiber) {
|
|
1365
880
|
const props = fiber?.memoizedProps ?? {};
|
|
@@ -1370,15 +885,10 @@ function describeTouchable(fiber) {
|
|
|
1370
885
|
}
|
|
1371
886
|
function touchableLooksDestructive(fiber) {
|
|
1372
887
|
const descriptor = describeTouchable(fiber);
|
|
1373
|
-
if (descriptor &&
|
|
888
|
+
if (descriptor && chunkYB77RYCC_js.looksDestructiveActionLabel(descriptor)) return true;
|
|
1374
889
|
const props = fiber?.memoizedProps ?? {};
|
|
1375
|
-
const haystack = [
|
|
1376
|
-
|
|
1377
|
-
props.accessibilityLabel,
|
|
1378
|
-
props.accessibilityHint,
|
|
1379
|
-
props.label
|
|
1380
|
-
].filter((value) => typeof value === "string").join(" ");
|
|
1381
|
-
return chunkDZ7QRFHD_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);
|
|
1382
892
|
}
|
|
1383
893
|
function describeItemCandidate(listIndex, zeroBasedIndex, item) {
|
|
1384
894
|
const syntheticId = `list-${listIndex}-item-${zeroBasedIndex + 1}`;
|
|
@@ -1411,8 +921,8 @@ function pressResolvedListItem(list, itemFiber, listIndex, itemIndex) {
|
|
|
1411
921
|
(candidate) => candidate !== touchable && containsFiber(touchable, candidate)
|
|
1412
922
|
);
|
|
1413
923
|
if (primaryWrapsNestedTargets) {
|
|
1414
|
-
|
|
1415
|
-
`
|
|
924
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
925
|
+
`listItemDispatch: item "list-${listIndex}-item-${itemIndex}" has nested pressables; pressing outer row target`
|
|
1416
926
|
);
|
|
1417
927
|
} else {
|
|
1418
928
|
const candidates = safeIdentifiableTouchables.map(describeTouchable).filter((d) => !!d).slice(0, 8);
|
|
@@ -1446,14 +956,14 @@ function pressResolvedListItem(list, itemFiber, listIndex, itemIndex) {
|
|
|
1446
956
|
}
|
|
1447
957
|
return {
|
|
1448
958
|
ok: true,
|
|
1449
|
-
containerType: getTypeName(container.type) ?? getTypeName(container.elementType) ?? list.containerType
|
|
959
|
+
containerType: chunkYB77RYCC_js.getTypeName(container.type) ?? chunkYB77RYCC_js.getTypeName(container.elementType) ?? list.containerType
|
|
1450
960
|
};
|
|
1451
961
|
} catch (err) {
|
|
1452
962
|
return {
|
|
1453
963
|
ok: false,
|
|
1454
964
|
reason: "press-threw",
|
|
1455
965
|
error: err?.message ?? "press handler threw",
|
|
1456
|
-
containerType: getTypeName(container.type) ?? getTypeName(container.elementType) ?? list.containerType
|
|
966
|
+
containerType: chunkYB77RYCC_js.getTypeName(container.type) ?? chunkYB77RYCC_js.getTypeName(container.elementType) ?? list.containerType
|
|
1457
967
|
};
|
|
1458
968
|
}
|
|
1459
969
|
}
|
|
@@ -1509,7 +1019,7 @@ function candidateLists(containers, locator) {
|
|
|
1509
1019
|
return containers.map((list, listIndex) => ({ list, listIndex }));
|
|
1510
1020
|
}
|
|
1511
1021
|
function pressListItemAtOrdinal(listIndex, itemIndex) {
|
|
1512
|
-
if (!
|
|
1022
|
+
if (!chunkYB77RYCC_js.getFiberRoot()) return { ok: false, reason: "no-fiber-root" };
|
|
1513
1023
|
const containers = findListContainers({ allowSingleHeuristic: true });
|
|
1514
1024
|
if (listIndex < 0 || listIndex >= containers.length) {
|
|
1515
1025
|
return { ok: false, reason: "list-not-found" };
|
|
@@ -1522,14 +1032,14 @@ function pressListItemAtOrdinal(listIndex, itemIndex) {
|
|
|
1522
1032
|
}
|
|
1523
1033
|
return pressResolvedListItem(list, items[zeroBased], listIndex, itemIndex);
|
|
1524
1034
|
}
|
|
1525
|
-
function
|
|
1526
|
-
if (!
|
|
1035
|
+
function resolveListItemByIdentity(locator) {
|
|
1036
|
+
if (!chunkYB77RYCC_js.getFiberRoot()) return { ok: false, result: { ok: false, reason: "no-fiber-root" } };
|
|
1527
1037
|
const parsed = locator.syntheticId ? parseSyntheticListItemId(locator.syntheticId) : null;
|
|
1528
1038
|
const effective = parsed ? { ...locator, listIndex: parsed.listIndex, itemIndex: parsed.itemIndex } : locator;
|
|
1529
1039
|
const containers = findListContainers({ allowSingleHeuristic: true });
|
|
1530
1040
|
const lists = candidateLists(containers, effective);
|
|
1531
1041
|
if (lists.length === 0) {
|
|
1532
|
-
return { ok: false, reason: "list-not-found" };
|
|
1042
|
+
return { ok: false, result: { ok: false, reason: "list-not-found" } };
|
|
1533
1043
|
}
|
|
1534
1044
|
const scoredCandidates = [];
|
|
1535
1045
|
for (const { list, listIndex } of lists) {
|
|
@@ -1540,7 +1050,14 @@ function pressListItemByIdentity(locator) {
|
|
|
1540
1050
|
}
|
|
1541
1051
|
}
|
|
1542
1052
|
if (scoredCandidates.length === 0) {
|
|
1543
|
-
return {
|
|
1053
|
+
return {
|
|
1054
|
+
ok: false,
|
|
1055
|
+
result: {
|
|
1056
|
+
ok: false,
|
|
1057
|
+
reason: "item-not-found",
|
|
1058
|
+
containerType: lists[0]?.list.containerType
|
|
1059
|
+
}
|
|
1060
|
+
};
|
|
1544
1061
|
}
|
|
1545
1062
|
scoredCandidates.sort((a, b) => b.score - a.score);
|
|
1546
1063
|
const best = scoredCandidates[0];
|
|
@@ -1549,13 +1066,104 @@ function pressListItemByIdentity(locator) {
|
|
|
1549
1066
|
const candidates = tiedCandidates.map((c) => describeItemCandidate(c.listIndex, c.itemIndex - 1, c.item)).slice(0, 8);
|
|
1550
1067
|
return {
|
|
1551
1068
|
ok: false,
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
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,
|
|
1555
1128
|
candidates
|
|
1556
1129
|
};
|
|
1557
1130
|
}
|
|
1558
|
-
|
|
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
|
+
);
|
|
1559
1167
|
}
|
|
1560
1168
|
|
|
1561
1169
|
// src/executor/handlers/elementDispatch.ts
|
|
@@ -1563,7 +1171,7 @@ function screenDiagnose(targetId, category = "component-not-found") {
|
|
|
1563
1171
|
return {
|
|
1564
1172
|
category,
|
|
1565
1173
|
targetId,
|
|
1566
|
-
screen:
|
|
1174
|
+
screen: chunkYB77RYCC_js.getCurrentScreen() ?? void 0
|
|
1567
1175
|
};
|
|
1568
1176
|
}
|
|
1569
1177
|
function isPressLike(action) {
|
|
@@ -1580,10 +1188,10 @@ function elementLookupKey(value) {
|
|
|
1580
1188
|
return canonicalElementId(value).toLowerCase().replace(/[\s_]+/g, "-");
|
|
1581
1189
|
}
|
|
1582
1190
|
function findRegisteredElement(elementId) {
|
|
1583
|
-
const direct =
|
|
1191
|
+
const direct = chunkYB77RYCC_js.elementRegistry.get(elementId) ?? chunkYB77RYCC_js.elementRegistry.get(canonicalElementId(elementId));
|
|
1584
1192
|
if (direct) return direct;
|
|
1585
1193
|
const wanted = elementLookupKey(elementId);
|
|
1586
|
-
return
|
|
1194
|
+
return chunkYB77RYCC_js.elementRegistry.snapshot().find((element) => elementLookupKey(element.id) === wanted);
|
|
1587
1195
|
}
|
|
1588
1196
|
function resolveInteractionElement(elementId) {
|
|
1589
1197
|
return getLatestElement(elementId);
|
|
@@ -1784,6 +1392,46 @@ function dispatchElement(element, registry, action) {
|
|
|
1784
1392
|
};
|
|
1785
1393
|
}
|
|
1786
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
|
+
}
|
|
1787
1435
|
const targetId = element.targetId ?? element.label ?? element.id;
|
|
1788
1436
|
return dispatchLegacyTarget(targetId, registry, "toggle");
|
|
1789
1437
|
}
|
|
@@ -1803,7 +1451,7 @@ function dispatchElement(element, registry, action) {
|
|
|
1803
1451
|
}
|
|
1804
1452
|
function dispatchStructuredElementId(identifier, action) {
|
|
1805
1453
|
if (!isElementIdentifier(identifier) || !isPressLike(action)) return null;
|
|
1806
|
-
const parsed =
|
|
1454
|
+
const parsed = chunkYB77RYCC_js.parseStableElementId(identifier);
|
|
1807
1455
|
if (!parsed || parsed.role !== "option") return null;
|
|
1808
1456
|
if (!parsed.itemKey && !parsed.listId) return null;
|
|
1809
1457
|
const pressed = pressListItemByIdentity({
|
|
@@ -1813,8 +1461,8 @@ function dispatchStructuredElementId(identifier, action) {
|
|
|
1813
1461
|
texts: parsed.itemKey ? [parsed.itemKey] : void 0
|
|
1814
1462
|
});
|
|
1815
1463
|
if (pressed.ok) {
|
|
1816
|
-
|
|
1817
|
-
`
|
|
1464
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
1465
|
+
`elementDispatch: resolved stale el id "${identifier}" via structural identity (listId="${parsed.listId}", itemKey="${parsed.itemKey}")`
|
|
1818
1466
|
);
|
|
1819
1467
|
return { success: true };
|
|
1820
1468
|
}
|
|
@@ -1838,25 +1486,24 @@ function pressElementOrTarget(identifier, registry) {
|
|
|
1838
1486
|
|
|
1839
1487
|
// src/executor/formFieldRewrite.ts
|
|
1840
1488
|
var LIST_ORDINAL_RE = /^list-\d+-item-\d+$/i;
|
|
1841
|
-
var PLATE_RE = /^[A-Z]{3}-?\d[A-Z0-9]\d{2}$/i;
|
|
1842
1489
|
function normalize4(value) {
|
|
1843
1490
|
return value.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
|
|
1844
1491
|
}
|
|
1845
1492
|
function resolveScreenForFormFields() {
|
|
1846
|
-
const activePath =
|
|
1493
|
+
const activePath = chunkYB77RYCC_js.getActiveRouteNames();
|
|
1847
1494
|
for (let i = activePath.length - 1; i >= 0; i--) {
|
|
1848
1495
|
const name = activePath[i];
|
|
1849
|
-
const meta = name ?
|
|
1496
|
+
const meta = name ? chunkYB77RYCC_js.getScreenMetadata(name) : void 0;
|
|
1850
1497
|
if (name && Array.isArray(meta?.fields) && meta.fields.length > 0) return name;
|
|
1851
1498
|
}
|
|
1852
|
-
return
|
|
1499
|
+
return chunkYB77RYCC_js.getCurrentScreen();
|
|
1853
1500
|
}
|
|
1854
1501
|
function collectKnownFormFields(registry) {
|
|
1855
1502
|
const registryFields = registry.snapshot().filter((entry) => entry.kind === "field" || entry.kind === "slider").map((entry) => ({ id: entry.id, label: entry.label }));
|
|
1856
1503
|
if (registryFields.length >= 2) return registryFields;
|
|
1857
1504
|
const screen = resolveScreenForFormFields();
|
|
1858
1505
|
if (screen) {
|
|
1859
|
-
const metaFields =
|
|
1506
|
+
const metaFields = chunkYB77RYCC_js.getScreenMetadata(screen)?.fields;
|
|
1860
1507
|
if (Array.isArray(metaFields) && metaFields.length > 0) {
|
|
1861
1508
|
return metaFields.filter((field) => !!field && typeof field.id === "string").map((field) => ({
|
|
1862
1509
|
id: field.id,
|
|
@@ -1866,7 +1513,7 @@ function collectKnownFormFields(registry) {
|
|
|
1866
1513
|
}));
|
|
1867
1514
|
}
|
|
1868
1515
|
}
|
|
1869
|
-
for (const meta of
|
|
1516
|
+
for (const meta of chunkYB77RYCC_js.getAllScreens()) {
|
|
1870
1517
|
if (Array.isArray(meta.fields) && meta.fields.length > 0) {
|
|
1871
1518
|
return meta.fields.filter((field) => !!field && typeof field.id === "string").map((field) => ({
|
|
1872
1519
|
id: field.id,
|
|
@@ -1878,9 +1525,6 @@ function collectKnownFormFields(registry) {
|
|
|
1878
1525
|
}
|
|
1879
1526
|
return registryFields;
|
|
1880
1527
|
}
|
|
1881
|
-
function fieldHaystack(field) {
|
|
1882
|
-
return normalize4(`${field.id} ${field.label ?? ""}`);
|
|
1883
|
-
}
|
|
1884
1528
|
function isMisplacedFieldId(fieldId, knownIds) {
|
|
1885
1529
|
const trimmed = fieldId.trim();
|
|
1886
1530
|
if (!trimmed) return true;
|
|
@@ -1904,50 +1548,68 @@ function valueMatchesOption(field, rawValue) {
|
|
|
1904
1548
|
return label === value || optionValue === value || value.includes(label) || value.includes(optionValue);
|
|
1905
1549
|
});
|
|
1906
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
|
+
}
|
|
1907
1602
|
function inferFieldIdForValue(rawValue, fields, used) {
|
|
1908
1603
|
const value = String(rawValue ?? "").trim();
|
|
1909
1604
|
if (!value) return void 0;
|
|
1910
|
-
const
|
|
1911
|
-
for (const field of
|
|
1912
|
-
if (used.has(field.id)) continue;
|
|
1605
|
+
const available = fields.filter((field) => field.id && !used.has(field.id));
|
|
1606
|
+
for (const field of available) {
|
|
1913
1607
|
if (valueMatchesOption(field, value)) return field.id;
|
|
1914
1608
|
}
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
if (/^(19|20)\d{2}$/.test(value)) {
|
|
1920
|
-
const field = fields.find((f) => /ano|year/.test(fieldHaystack(f)) && !used.has(f.id));
|
|
1921
|
-
if (field) return field.id;
|
|
1922
|
-
}
|
|
1923
|
-
if (/^\d+$/.test(value)) {
|
|
1924
|
-
const mileage = fields.find((f) => /quilometragem|mileage|km/.test(fieldHaystack(f)) && !used.has(f.id));
|
|
1925
|
-
if (mileage) return mileage.id;
|
|
1926
|
-
const year = fields.find((f) => /ano|year/.test(fieldHaystack(f)) && !used.has(f.id));
|
|
1927
|
-
if (year) return year.id;
|
|
1928
|
-
}
|
|
1929
|
-
if (/preto|branco|azul|vermelho|prata|black|white|red|blue|silver|gray|grey/.test(normalizedValue)) {
|
|
1930
|
-
const cor = fields.find((f) => /cor|color/.test(fieldHaystack(f)) && !used.has(f.id));
|
|
1931
|
-
if (cor) return cor.id;
|
|
1932
|
-
}
|
|
1933
|
-
const marca = fields.find((f) => /marca|brand|make/.test(fieldHaystack(f)) && !used.has(f.id));
|
|
1934
|
-
if (marca && !/model/i.test(normalizedValue)) return marca.id;
|
|
1935
|
-
const modelo = fields.find((f) => /modelo|model/.test(fieldHaystack(f)) && !used.has(f.id));
|
|
1936
|
-
if (modelo) return modelo.id;
|
|
1937
|
-
const tipo = fields.find((f) => /\btipo\b|type|vehicletype/.test(fieldHaystack(f)) && !used.has(f.id));
|
|
1938
|
-
if (tipo && /carro|car|moto|truck|van|flex|gasoline|diesel|hybrid|electric|el[eé]trico/.test(normalizedValue)) {
|
|
1939
|
-
return tipo.id;
|
|
1940
|
-
}
|
|
1941
|
-
const combustivel = fields.find((f) => /combustivel|fuel/.test(fieldHaystack(f)) && !used.has(f.id));
|
|
1942
|
-
if (combustivel && /flex|gasoline|diesel|hybrid|electric|el[eé]trico/.test(normalizedValue)) {
|
|
1943
|
-
return combustivel.id;
|
|
1944
|
-
}
|
|
1945
|
-
const nextText = fields.find((field) => {
|
|
1946
|
-
if (used.has(field.id)) return false;
|
|
1947
|
-
const type = normalize4(field.type ?? "text");
|
|
1948
|
-
return type === "text" || type === "input" || type === "number" || type === "";
|
|
1949
|
-
});
|
|
1950
|
-
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;
|
|
1951
1613
|
}
|
|
1952
1614
|
function rewriteMisplacedFormFillFields(fields, registry) {
|
|
1953
1615
|
const knownFields = collectKnownFormFields(registry);
|
|
@@ -1964,7 +1626,7 @@ function rewriteMisplacedFormFillFields(fields, registry) {
|
|
|
1964
1626
|
const inferred = inferFieldIdForValue(String(field.value ?? ""), knownFields, used);
|
|
1965
1627
|
if (!inferred) return field;
|
|
1966
1628
|
used.add(inferred);
|
|
1967
|
-
|
|
1629
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
1968
1630
|
`formFieldRewrite: ${field.fieldId} \u2192 ${inferred} (value=${JSON.stringify(field.value)})`
|
|
1969
1631
|
);
|
|
1970
1632
|
return { ...field, fieldId: inferred };
|
|
@@ -1972,28 +1634,36 @@ function rewriteMisplacedFormFillFields(fields, registry) {
|
|
|
1972
1634
|
}
|
|
1973
1635
|
|
|
1974
1636
|
// src/executor/formValidation.ts
|
|
1975
|
-
var
|
|
1976
|
-
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;
|
|
1977
1639
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
]
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
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
|
+
}
|
|
1989
1653
|
}
|
|
1990
|
-
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} `);
|
|
1991
1661
|
}
|
|
1992
1662
|
function readVisibleFormValidation(snap) {
|
|
1993
1663
|
if (!snap) return void 0;
|
|
1994
1664
|
for (const text of snap.texts ?? []) {
|
|
1995
|
-
if (!text?.trim() || !
|
|
1996
|
-
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 };
|
|
1997
1667
|
}
|
|
1998
1668
|
return void 0;
|
|
1999
1669
|
}
|
|
@@ -2002,7 +1672,7 @@ function readVisibleFormSuccess(snap) {
|
|
|
2002
1672
|
return (snap.texts ?? []).find((text) => text?.trim() && FORM_SUCCESS_TEXT_RE.test(text));
|
|
2003
1673
|
}
|
|
2004
1674
|
function submitAsyncStillPending(submitTargetId) {
|
|
2005
|
-
const probe =
|
|
1675
|
+
const probe = chunkYB77RYCC_js.probeLoadingState(submitTargetId ?? null, chunkYB77RYCC_js.getCurrentScreen());
|
|
2006
1676
|
if (probe.loading) return true;
|
|
2007
1677
|
if (submitTargetId && probe.pressedFound && probe.pressedDisabled) return true;
|
|
2008
1678
|
return false;
|
|
@@ -2014,7 +1684,7 @@ function evaluatePostSubmitSnapshot(snap, activePath) {
|
|
|
2014
1684
|
}
|
|
2015
1685
|
const successText = readVisibleFormSuccess(snap);
|
|
2016
1686
|
if (successText) return { status: "success", message: successText };
|
|
2017
|
-
if (!
|
|
1687
|
+
if (!chunkYB77RYCC_js.snapshotShowsOpenCreateForm(snap, activePath)) {
|
|
2018
1688
|
return { status: "success" };
|
|
2019
1689
|
}
|
|
2020
1690
|
return void 0;
|
|
@@ -2030,7 +1700,7 @@ async function waitForPostSubmitOutcome(options) {
|
|
|
2030
1700
|
continue;
|
|
2031
1701
|
}
|
|
2032
1702
|
const snap2 = captureSnapshot();
|
|
2033
|
-
const activePath2 =
|
|
1703
|
+
const activePath2 = chunkYB77RYCC_js.getActiveRouteNames();
|
|
2034
1704
|
const outcome2 = evaluatePostSubmitSnapshot(snap2, activePath2);
|
|
2035
1705
|
if (outcome2) return outcome2;
|
|
2036
1706
|
await sleep(pollMs);
|
|
@@ -2042,7 +1712,7 @@ async function waitForPostSubmitOutcome(options) {
|
|
|
2042
1712
|
};
|
|
2043
1713
|
}
|
|
2044
1714
|
const snap = captureSnapshot();
|
|
2045
|
-
const activePath =
|
|
1715
|
+
const activePath = chunkYB77RYCC_js.getActiveRouteNames();
|
|
2046
1716
|
const outcome = evaluatePostSubmitSnapshot(snap, activePath);
|
|
2047
1717
|
if (outcome) return outcome;
|
|
2048
1718
|
return {
|
|
@@ -2148,16 +1818,16 @@ function findSnapshotButton(targetId) {
|
|
|
2148
1818
|
}
|
|
2149
1819
|
}
|
|
2150
1820
|
function buildUiDiagnose(targetId, cause) {
|
|
2151
|
-
const activePath =
|
|
2152
|
-
const screen = activePath[activePath.length - 1] ??
|
|
1821
|
+
const activePath = chunkYB77RYCC_js.getActiveRouteNames();
|
|
1822
|
+
const screen = activePath[activePath.length - 1] ?? chunkYB77RYCC_js.getCurrentScreen() ?? void 0;
|
|
2153
1823
|
const screenPath = activePath.length > 1 ? activePath.join("/") : screen;
|
|
2154
1824
|
const diagnose = {
|
|
2155
1825
|
category: cause === "not-found" ? "component-not-found" : cause === "disabled" ? "disabled" : "unknown",
|
|
2156
1826
|
targetId,
|
|
2157
1827
|
screen: screenPath
|
|
2158
1828
|
};
|
|
2159
|
-
if (
|
|
2160
|
-
diagnose.visibleMessage =
|
|
1829
|
+
if (chunkYB77RYCC_js.isOptionalStepAutomationFailure(targetId, screenPath, activePath)) {
|
|
1830
|
+
diagnose.visibleMessage = chunkYB77RYCC_js.OPTIONAL_STEP_AUTOMATION_HINT;
|
|
2161
1831
|
diagnose.recoverable = true;
|
|
2162
1832
|
}
|
|
2163
1833
|
return diagnose;
|
|
@@ -2215,13 +1885,15 @@ function resolveComponentId(componentId, registry, action) {
|
|
|
2215
1885
|
const snapshot = registry.snapshot();
|
|
2216
1886
|
for (const comp of snapshot) {
|
|
2217
1887
|
if (comp.id.toLowerCase() === lower) {
|
|
2218
|
-
|
|
1888
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
1889
|
+
`resolveComponentId: case-insensitive match "${componentId}" \u2192 "${comp.id}"`
|
|
1890
|
+
);
|
|
2219
1891
|
return comp.id;
|
|
2220
1892
|
}
|
|
2221
1893
|
}
|
|
2222
|
-
const currentScreen =
|
|
1894
|
+
const currentScreen = chunkYB77RYCC_js.getCurrentScreen();
|
|
2223
1895
|
if (currentScreen) {
|
|
2224
|
-
const screenMeta =
|
|
1896
|
+
const screenMeta = chunkYB77RYCC_js.getScreenMetadata(currentScreen);
|
|
2225
1897
|
const actions = screenMeta?.actions;
|
|
2226
1898
|
if (actions && Array.isArray(actions)) {
|
|
2227
1899
|
const metaAction = actions.find(
|
|
@@ -2230,12 +1902,16 @@ function resolveComponentId(componentId, registry, action) {
|
|
|
2230
1902
|
if (metaAction && typeof metaAction === "object" && metaAction.label) {
|
|
2231
1903
|
const metaLabel = metaAction.label;
|
|
2232
1904
|
const normalizedMetaLabel = metaLabel.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
|
|
2233
|
-
|
|
1905
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
1906
|
+
`resolveComponentId: found screen metadata for "${componentId}" \u2192 label="${metaLabel}"`
|
|
1907
|
+
);
|
|
2234
1908
|
for (const comp of snapshot) {
|
|
2235
1909
|
if (!comp.label) continue;
|
|
2236
1910
|
const compLabel = comp.label.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
|
|
2237
1911
|
if (compLabel === normalizedMetaLabel || compLabel.includes(normalizedMetaLabel) || normalizedMetaLabel.includes(compLabel)) {
|
|
2238
|
-
|
|
1912
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
1913
|
+
`resolveComponentId: FOUND via metadata: "${componentId}" \u2192 "${comp.id}" (label="${comp.label}")`
|
|
1914
|
+
);
|
|
2239
1915
|
return comp.id;
|
|
2240
1916
|
}
|
|
2241
1917
|
}
|
|
@@ -2250,8 +1926,8 @@ function resolveComponentId(componentId, registry, action) {
|
|
|
2250
1926
|
}));
|
|
2251
1927
|
const match = resolveTarget(componentId, candidates, { action });
|
|
2252
1928
|
if (match.status === "matched") {
|
|
2253
|
-
|
|
2254
|
-
`
|
|
1929
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
1930
|
+
`resolveComponentId: matched "${componentId}" -> "${match.id}" (tier=${match.tier})`
|
|
2255
1931
|
);
|
|
2256
1932
|
return match.id;
|
|
2257
1933
|
}
|
|
@@ -2340,8 +2016,8 @@ function setValueHandler(rawComponentId, requested, registry) {
|
|
|
2340
2016
|
try {
|
|
2341
2017
|
slider.setValue(applied);
|
|
2342
2018
|
if (applied !== requestedValue) {
|
|
2343
|
-
|
|
2344
|
-
`
|
|
2019
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2020
|
+
`uiInteractionHandler: set_value snapped ${requestedValue} \u2192 ${applied} for "${componentId}" (step=${step})`
|
|
2345
2021
|
);
|
|
2346
2022
|
}
|
|
2347
2023
|
return { success: true, effect: "changed" };
|
|
@@ -2375,11 +2051,26 @@ function checkModalOcclusion(rawComponentId, action) {
|
|
|
2375
2051
|
return null;
|
|
2376
2052
|
}
|
|
2377
2053
|
if (typeof rawComponentId !== "string" || rawComponentId.trim().length === 0) return null;
|
|
2378
|
-
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();
|
|
2379
2070
|
if (!fiberRoot) return null;
|
|
2380
2071
|
let snap;
|
|
2381
2072
|
try {
|
|
2382
|
-
snap = walkFiber(fiberRoot);
|
|
2073
|
+
snap = chunkYB77RYCC_js.walkFiber(fiberRoot);
|
|
2383
2074
|
} catch {
|
|
2384
2075
|
return null;
|
|
2385
2076
|
}
|
|
@@ -2406,9 +2097,12 @@ function checkModalOcclusion(rawComponentId, action) {
|
|
|
2406
2097
|
modalOptionLabels.push(button.label ?? button.id);
|
|
2407
2098
|
}
|
|
2408
2099
|
}
|
|
2409
|
-
for (const toggle of snap.toggles ?? [])
|
|
2410
|
-
|
|
2411
|
-
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);
|
|
2412
2106
|
for (const list of snap.lists ?? []) {
|
|
2413
2107
|
for (const item of list.items ?? []) {
|
|
2414
2108
|
const itemInModal = (item.buttons ?? []).some((b) => b.inModal) || (item.inputs ?? []).some((i) => i.inModal) || (item.toggles ?? []).some((t) => t.inModal);
|
|
@@ -2438,12 +2132,15 @@ function checkModalOcclusion(rawComponentId, action) {
|
|
|
2438
2132
|
}
|
|
2439
2133
|
function uiInteractionHandler(payload, context) {
|
|
2440
2134
|
const { permissions } = context;
|
|
2441
|
-
const registry = context.registry ??
|
|
2135
|
+
const registry = context.registry ?? chunkYB77RYCC_js.componentRegistry;
|
|
2442
2136
|
if (!permissions.canInteractUI) {
|
|
2443
2137
|
return {
|
|
2444
2138
|
success: false,
|
|
2445
2139
|
error: "UI interaction is not permitted",
|
|
2446
|
-
diagnose: buildUiDiagnose(
|
|
2140
|
+
diagnose: buildUiDiagnose(
|
|
2141
|
+
payload.componentId ?? payload.targetId ?? "",
|
|
2142
|
+
"unknown"
|
|
2143
|
+
)
|
|
2447
2144
|
};
|
|
2448
2145
|
}
|
|
2449
2146
|
const { action } = payload;
|
|
@@ -2457,8 +2154,8 @@ function uiInteractionHandler(payload, context) {
|
|
|
2457
2154
|
if (sliderId) {
|
|
2458
2155
|
const smuggled = payload.value ?? payload.params?.value;
|
|
2459
2156
|
if (smuggled !== void 0) {
|
|
2460
|
-
|
|
2461
|
-
`
|
|
2157
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2158
|
+
`uiInteractionHandler: "${actionStr}" on slider "${sliderId}" carried value=${JSON.stringify(smuggled)} \u2014 routing to set_value`
|
|
2462
2159
|
);
|
|
2463
2160
|
return setValueHandler(rawComponentId, smuggled, registry);
|
|
2464
2161
|
}
|
|
@@ -2468,18 +2165,53 @@ function uiInteractionHandler(payload, context) {
|
|
|
2468
2165
|
diagnose: { ...buildUiDiagnose(sliderId, "unknown"), recoverable: true }
|
|
2469
2166
|
};
|
|
2470
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
|
+
}
|
|
2471
2203
|
const occluded = checkModalOcclusion(rawComponentId, actionStr);
|
|
2472
2204
|
if (occluded) {
|
|
2473
|
-
|
|
2474
|
-
`
|
|
2205
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2206
|
+
`uiInteractionHandler: blocked "${actionStr}" on "${rawComponentId}" \u2014 target is behind an open modal`
|
|
2475
2207
|
);
|
|
2476
2208
|
return occluded;
|
|
2477
2209
|
}
|
|
2478
2210
|
if (typeof rawComponentId === "string" && rawComponentId.trim().toLowerCase().startsWith("el:")) {
|
|
2479
2211
|
const result = dispatchElementOrTarget(rawComponentId, registry, actionStr);
|
|
2480
2212
|
if (result.success) {
|
|
2481
|
-
|
|
2482
|
-
`
|
|
2213
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2214
|
+
`uiInteractionHandler: interaction element dispatch succeeded for "${rawComponentId}"`
|
|
2483
2215
|
);
|
|
2484
2216
|
return { success: true };
|
|
2485
2217
|
}
|
|
@@ -2487,17 +2219,17 @@ function uiInteractionHandler(payload, context) {
|
|
|
2487
2219
|
}
|
|
2488
2220
|
const ordinal = parseSyntheticListItemId(rawComponentId);
|
|
2489
2221
|
if (ordinal && (action === "press" || actionStr === "tap" || actionStr === "click" || actionStr === "longPress")) {
|
|
2490
|
-
|
|
2491
|
-
`
|
|
2222
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2223
|
+
`uiInteractionHandler: dispatching synthetic list ordinal \u2014 componentId="${rawComponentId}" list=${ordinal.listIndex} item=${ordinal.itemIndex}`
|
|
2492
2224
|
);
|
|
2493
2225
|
const result = pressListItemAtOrdinal(ordinal.listIndex, ordinal.itemIndex);
|
|
2494
2226
|
if (result.ok) {
|
|
2495
|
-
|
|
2496
|
-
`
|
|
2227
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2228
|
+
`uiInteractionHandler: synthetic ordinal press succeeded (container=${result.containerType ?? "List"})`
|
|
2497
2229
|
);
|
|
2498
2230
|
return { success: true };
|
|
2499
2231
|
}
|
|
2500
|
-
const screen =
|
|
2232
|
+
const screen = chunkYB77RYCC_js.getCurrentScreen() ?? void 0;
|
|
2501
2233
|
if (result.reason === "list-not-found" || result.reason === "item-not-found") {
|
|
2502
2234
|
return {
|
|
2503
2235
|
success: false,
|
|
@@ -2538,7 +2270,9 @@ function uiInteractionHandler(payload, context) {
|
|
|
2538
2270
|
};
|
|
2539
2271
|
}
|
|
2540
2272
|
const componentId = resolveComponentId(rawComponentId, registry, actionStr);
|
|
2541
|
-
|
|
2273
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2274
|
+
`uiInteractionHandler: resolved componentId="${payload.componentId}" \u2192 "${componentId}"`
|
|
2275
|
+
);
|
|
2542
2276
|
const target = registry.getTarget(componentId);
|
|
2543
2277
|
if (target) {
|
|
2544
2278
|
try {
|
|
@@ -2589,7 +2323,9 @@ function uiInteractionHandler(payload, context) {
|
|
|
2589
2323
|
return { success: false, error: err?.message ?? "Focus failed" };
|
|
2590
2324
|
}
|
|
2591
2325
|
}
|
|
2592
|
-
|
|
2326
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2327
|
+
`uiInteractionHandler: registry miss for "${componentId}", falling back to fiber tree`
|
|
2328
|
+
);
|
|
2593
2329
|
const handle = findInteractiveByIdentifier(componentId, {
|
|
2594
2330
|
kind: actionStr === "toggle" ? "toggle" : actionStr === "focus" ? "field" : "target"
|
|
2595
2331
|
});
|
|
@@ -2597,7 +2333,9 @@ function uiInteractionHandler(payload, context) {
|
|
|
2597
2333
|
try {
|
|
2598
2334
|
if (actionStr === "press" && handle.kind === "target" && handle.press) {
|
|
2599
2335
|
handle.press();
|
|
2600
|
-
|
|
2336
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2337
|
+
`uiInteractionHandler: fiber fallback press succeeded for "${componentId}"`
|
|
2338
|
+
);
|
|
2601
2339
|
return { success: true };
|
|
2602
2340
|
}
|
|
2603
2341
|
if (actionStr === "press" && handle.kind === "toggle" && handle.setValue) {
|
|
@@ -2662,7 +2400,7 @@ function submitLabelHintsSubmit(label) {
|
|
|
2662
2400
|
return SUBMIT_LABEL_HINT_RE.test(trimmed);
|
|
2663
2401
|
}
|
|
2664
2402
|
function screenDeclaresSubmitAction(screenName) {
|
|
2665
|
-
const meta =
|
|
2403
|
+
const meta = chunkYB77RYCC_js.getScreenMetadata(screenName);
|
|
2666
2404
|
return Array.isArray(meta?.actions) && meta.actions.some(
|
|
2667
2405
|
(action) => typeof action === "object" && action !== null && action.type === "submit"
|
|
2668
2406
|
);
|
|
@@ -2695,7 +2433,7 @@ function resolveFormScreensForSubmit(screen, activePath, registry) {
|
|
|
2695
2433
|
} else {
|
|
2696
2434
|
push(screen);
|
|
2697
2435
|
}
|
|
2698
|
-
push(
|
|
2436
|
+
push(chunkYB77RYCC_js.getCurrentScreen() ?? void 0);
|
|
2699
2437
|
const withSubmit = [];
|
|
2700
2438
|
const rest = [];
|
|
2701
2439
|
for (const name of ordered) {
|
|
@@ -2713,7 +2451,7 @@ function collectSubmitTargetCandidates(screens, registry) {
|
|
|
2713
2451
|
candidates.push(id);
|
|
2714
2452
|
};
|
|
2715
2453
|
for (const screenName of screens) {
|
|
2716
|
-
const meta =
|
|
2454
|
+
const meta = chunkYB77RYCC_js.getScreenMetadata(screenName);
|
|
2717
2455
|
const submitMeta = Array.isArray(meta?.actions) ? meta.actions.find(
|
|
2718
2456
|
(action) => typeof action === "object" && action !== null && action.type === "submit"
|
|
2719
2457
|
) : void 0;
|
|
@@ -2743,12 +2481,10 @@ function readVisibleValidation(fieldId, label) {
|
|
|
2743
2481
|
try {
|
|
2744
2482
|
const snap = captureSnapshot();
|
|
2745
2483
|
const texts = snap.texts ?? [];
|
|
2746
|
-
const needles = [fieldId, label].filter(
|
|
2747
|
-
(s) => !!s && s.length > 0
|
|
2748
|
-
);
|
|
2484
|
+
const needles = [fieldId, label].filter((s) => !!s && s.length > 0);
|
|
2749
2485
|
for (const text of texts) {
|
|
2750
2486
|
const lower = text.toLowerCase();
|
|
2751
|
-
if (
|
|
2487
|
+
if (FORM_VALIDATION_TEXT_RE2.test(lower)) {
|
|
2752
2488
|
for (const needle of needles) {
|
|
2753
2489
|
if (lower.includes(needle.toLowerCase())) return text;
|
|
2754
2490
|
}
|
|
@@ -2759,8 +2495,8 @@ function readVisibleValidation(fieldId, label) {
|
|
|
2759
2495
|
return void 0;
|
|
2760
2496
|
}
|
|
2761
2497
|
function resolveScreenContext() {
|
|
2762
|
-
const activePath =
|
|
2763
|
-
const screen = activePath[activePath.length - 1] ??
|
|
2498
|
+
const activePath = chunkYB77RYCC_js.getActiveRouteNames();
|
|
2499
|
+
const screen = activePath[activePath.length - 1] ?? chunkYB77RYCC_js.getCurrentScreen() ?? void 0;
|
|
2764
2500
|
return { screen, activePath };
|
|
2765
2501
|
}
|
|
2766
2502
|
function selectValueApplied(fieldId, requestedValue, currentValue, registry) {
|
|
@@ -2768,36 +2504,36 @@ function selectValueApplied(fieldId, requestedValue, currentValue, registry) {
|
|
|
2768
2504
|
if (!requested) return false;
|
|
2769
2505
|
const meta = getMetadataField(fieldId, registry);
|
|
2770
2506
|
const options = Array.isArray(meta?.options) ? meta.options : [];
|
|
2771
|
-
const requestedNorm =
|
|
2772
|
-
const currentNorm =
|
|
2507
|
+
const requestedNorm = chunkYB77RYCC_js.normalize3(requested);
|
|
2508
|
+
const currentNorm = chunkYB77RYCC_js.normalize3(currentValue);
|
|
2773
2509
|
if (currentNorm === requestedNorm) return true;
|
|
2774
2510
|
for (const option of options) {
|
|
2775
2511
|
const value = typeof option?.value === "string" ? option.value : "";
|
|
2776
2512
|
const label = typeof option?.label === "string" ? option.label : "";
|
|
2777
|
-
if (
|
|
2778
|
-
if (
|
|
2779
|
-
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;
|
|
2780
2516
|
}
|
|
2781
2517
|
return false;
|
|
2782
2518
|
}
|
|
2783
2519
|
function getMetadataField(fieldId, registry) {
|
|
2784
2520
|
const screens = /* @__PURE__ */ new Set();
|
|
2785
|
-
for (const name of
|
|
2786
|
-
const current =
|
|
2521
|
+
for (const name of chunkYB77RYCC_js.getActiveRouteNames()) screens.add(name);
|
|
2522
|
+
const current = chunkYB77RYCC_js.getCurrentScreen();
|
|
2787
2523
|
if (current) screens.add(current);
|
|
2788
2524
|
if (registry) {
|
|
2789
2525
|
for (const comp of registry.snapshot()) {
|
|
2790
2526
|
if (comp.kind === "field" && comp.screen) screens.add(comp.screen);
|
|
2791
2527
|
}
|
|
2792
2528
|
}
|
|
2793
|
-
const needle =
|
|
2529
|
+
const needle = chunkYB77RYCC_js.normalize3(fieldId);
|
|
2794
2530
|
for (const screenName of screens) {
|
|
2795
|
-
const screenMeta =
|
|
2531
|
+
const screenMeta = chunkYB77RYCC_js.getScreenMetadata(screenName);
|
|
2796
2532
|
const fields = Array.isArray(screenMeta?.fields) ? screenMeta.fields : [];
|
|
2797
2533
|
const match = fields.find((field) => {
|
|
2798
2534
|
if (!field || typeof field !== "object") return false;
|
|
2799
|
-
const id = typeof field.id === "string" ?
|
|
2800
|
-
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) : "";
|
|
2801
2537
|
return id === needle || label === needle;
|
|
2802
2538
|
});
|
|
2803
2539
|
if (match) return match;
|
|
@@ -2809,11 +2545,11 @@ function resolveSelectOption(fieldId, value, registry) {
|
|
|
2809
2545
|
if (!requested) return void 0;
|
|
2810
2546
|
const meta = getMetadataField(fieldId, registry);
|
|
2811
2547
|
const options = Array.isArray(meta?.options) ? meta.options : [];
|
|
2812
|
-
const requestedNorm =
|
|
2548
|
+
const requestedNorm = chunkYB77RYCC_js.normalize3(requested);
|
|
2813
2549
|
for (const option of options) {
|
|
2814
2550
|
const optionValue = typeof option?.value === "string" ? option.value : "";
|
|
2815
2551
|
const optionLabel = typeof option?.label === "string" ? option.label : "";
|
|
2816
|
-
if (
|
|
2552
|
+
if (chunkYB77RYCC_js.normalize3(optionValue) === requestedNorm || chunkYB77RYCC_js.normalize3(optionLabel) === requestedNorm) {
|
|
2817
2553
|
return { value: optionValue, label: optionLabel };
|
|
2818
2554
|
}
|
|
2819
2555
|
}
|
|
@@ -2863,14 +2599,16 @@ async function tryPressSelectOption(fieldId, value, registry, options = {}) {
|
|
|
2863
2599
|
return {
|
|
2864
2600
|
success: false,
|
|
2865
2601
|
error: `No pressable option found for select field "${fieldId}"`,
|
|
2866
|
-
diagnose: { category: "component-not-found", fieldId, screen:
|
|
2602
|
+
diagnose: { category: "component-not-found", fieldId, screen: chunkYB77RYCC_js.getCurrentScreen() ?? void 0 }
|
|
2867
2603
|
};
|
|
2868
2604
|
}
|
|
2869
2605
|
function normalizeFieldType(type) {
|
|
2870
2606
|
if (typeof type !== "string") return void 0;
|
|
2871
|
-
const normalized =
|
|
2872
|
-
if (normalized === "select" || normalized === "picker" || normalized === "dropdown")
|
|
2873
|
-
|
|
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";
|
|
2874
2612
|
if (normalized === "date") return "date";
|
|
2875
2613
|
if (normalized === "number" || normalized === "numeric") return "number";
|
|
2876
2614
|
if (normalized === "custom") return "custom";
|
|
@@ -2896,7 +2634,7 @@ function fieldCueTerms(fieldId, label) {
|
|
|
2896
2634
|
);
|
|
2897
2635
|
const terms = /* @__PURE__ */ new Set();
|
|
2898
2636
|
for (const value of raw) {
|
|
2899
|
-
const normalized =
|
|
2637
|
+
const normalized = chunkYB77RYCC_js.normalize3(value);
|
|
2900
2638
|
if (normalized.length >= 3 && normalized !== "id") terms.add(normalized);
|
|
2901
2639
|
}
|
|
2902
2640
|
return [...terms];
|
|
@@ -2904,20 +2642,17 @@ function fieldCueTerms(fieldId, label) {
|
|
|
2904
2642
|
function snapshotHasFieldCue(snap, fieldId, label) {
|
|
2905
2643
|
const terms = fieldCueTerms(fieldId, label);
|
|
2906
2644
|
if (terms.length === 0) return false;
|
|
2907
|
-
const visible = [
|
|
2908
|
-
...snap.texts ?? [],
|
|
2909
|
-
...(snap.buttons ?? []).map((b) => b.label ?? b.id ?? "")
|
|
2910
|
-
].map((text) => chunkDZ7QRFHD_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);
|
|
2911
2646
|
return visible.some((text) => terms.some((term) => text.includes(term) || term.includes(text)));
|
|
2912
2647
|
}
|
|
2913
2648
|
function scoreCandidateText(value, texts) {
|
|
2914
|
-
const valueNorm =
|
|
2649
|
+
const valueNorm = chunkYB77RYCC_js.normalize3(String(value ?? ""));
|
|
2915
2650
|
if (!valueNorm) return 0;
|
|
2916
2651
|
let best = 0;
|
|
2917
2652
|
for (const text of texts) {
|
|
2918
|
-
const textNorm =
|
|
2653
|
+
const textNorm = chunkYB77RYCC_js.normalize3(text);
|
|
2919
2654
|
if (!textNorm) continue;
|
|
2920
|
-
best = Math.max(best,
|
|
2655
|
+
best = Math.max(best, chunkYB77RYCC_js.matchScore(valueNorm, textNorm));
|
|
2921
2656
|
}
|
|
2922
2657
|
return best;
|
|
2923
2658
|
}
|
|
@@ -2931,7 +2666,7 @@ function optionTexts(option) {
|
|
|
2931
2666
|
function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue, registry) {
|
|
2932
2667
|
const fieldLabel = getFieldLabel(fieldId, registry);
|
|
2933
2668
|
const fieldCueVisible = snapshotHasFieldCue(snap, fieldId, fieldLabel);
|
|
2934
|
-
const genericValue =
|
|
2669
|
+
const genericValue = chunkYB77RYCC_js.isGenericSelectValue(value);
|
|
2935
2670
|
const candidates = [];
|
|
2936
2671
|
let order = 0;
|
|
2937
2672
|
const choiceGroups = snap.choiceGroups ?? [];
|
|
@@ -2943,7 +2678,7 @@ function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue,
|
|
|
2943
2678
|
const groupCueScore = Math.max(
|
|
2944
2679
|
globalCueScore,
|
|
2945
2680
|
...groupTexts.map((text) => {
|
|
2946
|
-
const normalized =
|
|
2681
|
+
const normalized = chunkYB77RYCC_js.normalize3(text);
|
|
2947
2682
|
return fieldCueTerms(fieldId, fieldLabel).some(
|
|
2948
2683
|
(term) => normalized.includes(term) || term.includes(normalized)
|
|
2949
2684
|
) ? 80 : 0;
|
|
@@ -2980,10 +2715,8 @@ function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue,
|
|
|
2980
2715
|
const elementCueScore = Math.max(
|
|
2981
2716
|
fieldCueVisible && elements.length <= 12 ? 50 : 0,
|
|
2982
2717
|
...cueTexts.map((text) => {
|
|
2983
|
-
const normalized =
|
|
2984
|
-
return fieldTerms.some(
|
|
2985
|
-
(term) => normalized.includes(term) || term.includes(normalized)
|
|
2986
|
-
) ? 80 : 0;
|
|
2718
|
+
const normalized = chunkYB77RYCC_js.normalize3(text);
|
|
2719
|
+
return fieldTerms.some((term) => normalized.includes(term) || term.includes(normalized)) ? 80 : 0;
|
|
2987
2720
|
})
|
|
2988
2721
|
);
|
|
2989
2722
|
const valueScore = genericValue ? 0 : scoreCandidateText(value, texts);
|
|
@@ -3040,7 +2773,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
|
|
|
3040
2773
|
return {
|
|
3041
2774
|
success: false,
|
|
3042
2775
|
error: err?.message ?? "Could not capture visible choices",
|
|
3043
|
-
diagnose: { category: "unknown", fieldId, screen:
|
|
2776
|
+
diagnose: { category: "unknown", fieldId, screen: chunkYB77RYCC_js.getCurrentScreen() ?? void 0 }
|
|
3044
2777
|
};
|
|
3045
2778
|
}
|
|
3046
2779
|
const candidates = buildChoiceCandidates(
|
|
@@ -3055,7 +2788,11 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
|
|
|
3055
2788
|
return {
|
|
3056
2789
|
success: false,
|
|
3057
2790
|
error: `No visible option found for select field "${fieldId}"`,
|
|
3058
|
-
diagnose: {
|
|
2791
|
+
diagnose: {
|
|
2792
|
+
category: "component-not-found",
|
|
2793
|
+
fieldId,
|
|
2794
|
+
screen: chunkYB77RYCC_js.getCurrentScreen() ?? void 0
|
|
2795
|
+
}
|
|
3059
2796
|
};
|
|
3060
2797
|
}
|
|
3061
2798
|
const pressed = pressTargetByIdOrLabel(candidate.targetId, registry);
|
|
@@ -3068,7 +2805,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
|
|
|
3068
2805
|
}
|
|
3069
2806
|
function isContinuationButton(label) {
|
|
3070
2807
|
if (!label) return false;
|
|
3071
|
-
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));
|
|
3072
2809
|
}
|
|
3073
2810
|
function pressContinuationButton(registry) {
|
|
3074
2811
|
const snap = captureSnapshot();
|
|
@@ -3081,38 +2818,40 @@ function pressContinuationButton(registry) {
|
|
|
3081
2818
|
return {
|
|
3082
2819
|
success: false,
|
|
3083
2820
|
error: "No enabled continuation button is visible",
|
|
3084
|
-
diagnose: { category: "component-not-found", screen:
|
|
2821
|
+
diagnose: { category: "component-not-found", screen: chunkYB77RYCC_js.getCurrentScreen() ?? void 0 }
|
|
3085
2822
|
};
|
|
3086
2823
|
}
|
|
3087
2824
|
return pressTargetByIdOrLabel(id, registry);
|
|
3088
2825
|
}
|
|
3089
2826
|
function findField(fieldId, registry) {
|
|
3090
|
-
|
|
2827
|
+
chunkYB77RYCC_js.appilotsDebugLog(`findField: searching for fieldId="${fieldId}"`);
|
|
3091
2828
|
const exact = registry.getField(fieldId);
|
|
3092
2829
|
if (exact) {
|
|
3093
|
-
|
|
2830
|
+
chunkYB77RYCC_js.appilotsDebugLog(`findField: FOUND exact match for fieldId="${fieldId}"`);
|
|
3094
2831
|
return exact;
|
|
3095
2832
|
}
|
|
3096
2833
|
const lower = fieldId.toLowerCase();
|
|
3097
2834
|
const snapshot = registry.snapshot();
|
|
3098
2835
|
for (const comp of snapshot) {
|
|
3099
2836
|
if (comp.kind === "field" && comp.id.toLowerCase() === lower) {
|
|
3100
|
-
|
|
2837
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2838
|
+
`findField: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
|
|
2839
|
+
);
|
|
3101
2840
|
return registry.getField(comp.id);
|
|
3102
2841
|
}
|
|
3103
2842
|
}
|
|
3104
|
-
const currentScreenForTieBreak =
|
|
3105
|
-
const needle =
|
|
2843
|
+
const currentScreenForTieBreak = chunkYB77RYCC_js.getCurrentScreen();
|
|
2844
|
+
const needle = chunkYB77RYCC_js.normalize3(fieldId);
|
|
3106
2845
|
let bestComp;
|
|
3107
2846
|
let bestScore = 0;
|
|
3108
2847
|
let bestOnCurrentScreen = false;
|
|
3109
2848
|
for (const comp of snapshot) {
|
|
3110
2849
|
if (comp.kind !== "field") continue;
|
|
3111
|
-
const candidates = [
|
|
3112
|
-
if (comp.label) candidates.push(
|
|
2850
|
+
const candidates = [chunkYB77RYCC_js.normalize3(comp.id)];
|
|
2851
|
+
if (comp.label) candidates.push(chunkYB77RYCC_js.normalize3(comp.label));
|
|
3113
2852
|
let candidateScore = 0;
|
|
3114
2853
|
for (const cand of candidates) {
|
|
3115
|
-
const s =
|
|
2854
|
+
const s = chunkYB77RYCC_js.matchScore(needle, cand);
|
|
3116
2855
|
if (s > candidateScore) candidateScore = s;
|
|
3117
2856
|
}
|
|
3118
2857
|
if (candidateScore === 0) continue;
|
|
@@ -3125,14 +2864,14 @@ function findField(fieldId, registry) {
|
|
|
3125
2864
|
}
|
|
3126
2865
|
}
|
|
3127
2866
|
if (bestComp && bestScore >= 75) {
|
|
3128
|
-
|
|
3129
|
-
`
|
|
2867
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2868
|
+
`findField: scored match "${fieldId}" -> "${bestComp.id}" (label="${bestComp.label}", score=${bestScore})`
|
|
3130
2869
|
);
|
|
3131
2870
|
return registry.getField(bestComp.id);
|
|
3132
2871
|
}
|
|
3133
|
-
const currentScreen =
|
|
2872
|
+
const currentScreen = chunkYB77RYCC_js.getCurrentScreen();
|
|
3134
2873
|
if (currentScreen) {
|
|
3135
|
-
const screenMeta =
|
|
2874
|
+
const screenMeta = chunkYB77RYCC_js.getScreenMetadata(currentScreen);
|
|
3136
2875
|
const fields = screenMeta?.fields;
|
|
3137
2876
|
if (fields && Array.isArray(fields)) {
|
|
3138
2877
|
const metaField = fields.find(
|
|
@@ -3140,20 +2879,20 @@ function findField(fieldId, registry) {
|
|
|
3140
2879
|
);
|
|
3141
2880
|
if (metaField && typeof metaField === "object" && metaField.label) {
|
|
3142
2881
|
const metaLabel = metaField.label;
|
|
3143
|
-
const metaNeedle =
|
|
2882
|
+
const metaNeedle = chunkYB77RYCC_js.normalize3(metaLabel);
|
|
3144
2883
|
let mBest;
|
|
3145
2884
|
let mBestScore = 0;
|
|
3146
2885
|
for (const comp of snapshot) {
|
|
3147
2886
|
if (comp.kind !== "field" || !comp.label) continue;
|
|
3148
|
-
const score =
|
|
2887
|
+
const score = chunkYB77RYCC_js.matchScore(metaNeedle, chunkYB77RYCC_js.normalize3(comp.label));
|
|
3149
2888
|
if (score > mBestScore) {
|
|
3150
2889
|
mBestScore = score;
|
|
3151
2890
|
mBest = comp;
|
|
3152
2891
|
}
|
|
3153
2892
|
}
|
|
3154
2893
|
if (mBest && mBestScore >= 60) {
|
|
3155
|
-
|
|
3156
|
-
`
|
|
2894
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2895
|
+
`findField: FOUND via screen metadata translation: fieldId="${fieldId}" -> metaLabel="${metaLabel}" -> registered="${mBest.id}" (score=${mBestScore})`
|
|
3157
2896
|
);
|
|
3158
2897
|
return registry.getField(mBest.id);
|
|
3159
2898
|
}
|
|
@@ -3161,32 +2900,34 @@ function findField(fieldId, registry) {
|
|
|
3161
2900
|
}
|
|
3162
2901
|
}
|
|
3163
2902
|
if (bestComp && bestScore >= 40) {
|
|
3164
|
-
|
|
3165
|
-
`
|
|
2903
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2904
|
+
`findField: weak substring match "${fieldId}" -> "${bestComp.id}" (label="${bestComp.label}", score=${bestScore})`
|
|
3166
2905
|
);
|
|
3167
2906
|
return registry.getField(bestComp.id);
|
|
3168
2907
|
}
|
|
3169
|
-
|
|
2908
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
3170
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"}`
|
|
3171
2910
|
);
|
|
3172
2911
|
return void 0;
|
|
3173
2912
|
}
|
|
3174
2913
|
function findToggle(fieldId, registry) {
|
|
3175
|
-
|
|
2914
|
+
chunkYB77RYCC_js.appilotsDebugLog(`findToggle: searching for fieldId="${fieldId}"`);
|
|
3176
2915
|
const exact = registry.getToggle(fieldId);
|
|
3177
2916
|
if (exact) {
|
|
3178
|
-
|
|
2917
|
+
chunkYB77RYCC_js.appilotsDebugLog(`findToggle: FOUND exact match for "${fieldId}"`);
|
|
3179
2918
|
return exact;
|
|
3180
2919
|
}
|
|
3181
2920
|
const lower = fieldId.toLowerCase();
|
|
3182
2921
|
const snapshot = registry.snapshot();
|
|
3183
2922
|
for (const comp of snapshot) {
|
|
3184
2923
|
if (comp.kind === "toggle" && comp.id.toLowerCase() === lower) {
|
|
3185
|
-
|
|
2924
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2925
|
+
`findToggle: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
|
|
2926
|
+
);
|
|
3186
2927
|
return registry.getToggle(comp.id);
|
|
3187
2928
|
}
|
|
3188
2929
|
}
|
|
3189
|
-
|
|
2930
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
3190
2931
|
`findToggle: NOT FOUND \u2014 fieldId="${fieldId}" not in registry. Available toggles: ${snapshot.filter((c) => c.kind === "toggle").map((c) => `"${c.id}"`).join(", ") || "none"}`
|
|
3191
2932
|
);
|
|
3192
2933
|
return void 0;
|
|
@@ -3197,7 +2938,9 @@ function findSlider(fieldId, registry) {
|
|
|
3197
2938
|
const lower = fieldId.toLowerCase();
|
|
3198
2939
|
for (const comp of registry.snapshot()) {
|
|
3199
2940
|
if (comp.kind === "slider" && comp.id.toLowerCase() === lower) {
|
|
3200
|
-
|
|
2941
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
2942
|
+
`findSlider: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
|
|
2943
|
+
);
|
|
3201
2944
|
return registry.getSlider(comp.id);
|
|
3202
2945
|
}
|
|
3203
2946
|
}
|
|
@@ -3206,7 +2949,7 @@ function findSlider(fieldId, registry) {
|
|
|
3206
2949
|
var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
3207
2950
|
async function formFillHandler(payload, context) {
|
|
3208
2951
|
const { permissions } = context;
|
|
3209
|
-
const registry = context.registry ??
|
|
2952
|
+
const registry = context.registry ?? chunkYB77RYCC_js.componentRegistry;
|
|
3210
2953
|
const { screen, activePath } = resolveScreenContext();
|
|
3211
2954
|
const screenPath = activePath.length > 1 ? activePath.join("/") : screen;
|
|
3212
2955
|
if (!permissions.canFillForms) {
|
|
@@ -3225,11 +2968,11 @@ async function formFillHandler(payload, context) {
|
|
|
3225
2968
|
}
|
|
3226
2969
|
const registrySnapshot = registry.snapshot();
|
|
3227
2970
|
if (registrySnapshot.length === 0) {
|
|
3228
|
-
|
|
2971
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
3229
2972
|
"formFillHandler: registry is EMPTY \u2014 auto-tracking may not be active. Ensure enableAppilotsAutoTracking() runs before components mount."
|
|
3230
2973
|
);
|
|
3231
2974
|
} else {
|
|
3232
|
-
|
|
2975
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3233
2976
|
`[Appilots formFillHandler] Registry has ${registrySnapshot.length} components:`,
|
|
3234
2977
|
registrySnapshot.map((c) => `${c.kind}:${c.id}`).join(", ")
|
|
3235
2978
|
);
|
|
@@ -3237,7 +2980,7 @@ async function formFillHandler(payload, context) {
|
|
|
3237
2980
|
const fieldResults = [];
|
|
3238
2981
|
let allSuccess = true;
|
|
3239
2982
|
let selectedChoiceThisBatch = false;
|
|
3240
|
-
|
|
2983
|
+
chunkYB77RYCC_js.appilotsDebugLog(`formFillHandler: processing ${payload.fields.length} fields`);
|
|
3241
2984
|
const availableFieldIds = () => registry.snapshot().filter((comp) => comp.kind === "field").map((comp) => `${comp.id}${comp.label ? ` (${comp.label})` : ""}`).slice(0, 8);
|
|
3242
2985
|
const isElementIdField = (field) => typeof field.fieldId === "string" && field.fieldId.trim().toLowerCase().startsWith("el:");
|
|
3243
2986
|
for (const field of payload.fields.filter(isElementIdField)) {
|
|
@@ -3264,13 +3007,13 @@ async function formFillHandler(payload, context) {
|
|
|
3264
3007
|
const { fieldId, fieldType, value } = field;
|
|
3265
3008
|
const effectiveFieldType = getEffectiveFieldType(fieldId, fieldType, registry);
|
|
3266
3009
|
let selectFailure;
|
|
3267
|
-
|
|
3268
|
-
`
|
|
3010
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3011
|
+
`formFillHandler: looking up fieldId="${fieldId}" fieldType="${fieldType}" effectiveFieldType="${effectiveFieldType}" value=${chunkYB77RYCC_js.describeValue(value)}`
|
|
3269
3012
|
);
|
|
3270
3013
|
const fieldEntry = findField(fieldId, registry);
|
|
3271
3014
|
if (fieldEntry) {
|
|
3272
3015
|
try {
|
|
3273
|
-
|
|
3016
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3274
3017
|
`formFillHandler: found field "${fieldId}" via registry, calling setValue(<${String(value).length} chars>)`
|
|
3275
3018
|
);
|
|
3276
3019
|
const beforeValue = effectiveFieldType === "date" ? fieldEntry.getValue?.() ?? "" : void 0;
|
|
@@ -3301,7 +3044,7 @@ async function formFillHandler(payload, context) {
|
|
|
3301
3044
|
after = fieldEntry.getValue?.() ?? "";
|
|
3302
3045
|
}
|
|
3303
3046
|
if (!selectValueApplied(fieldId, value, after, registry)) {
|
|
3304
|
-
|
|
3047
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
3305
3048
|
`formFillHandler: select field "${fieldId}" setValue did not stick (wrote <${String(value).length} chars>, current is <${String(after ?? "").length} chars>), trying visible choice fallback`
|
|
3306
3049
|
);
|
|
3307
3050
|
const selectResult = await selectVisibleChoice(fieldId, value, registry, {
|
|
@@ -3316,7 +3059,11 @@ async function formFillHandler(payload, context) {
|
|
|
3316
3059
|
fieldId,
|
|
3317
3060
|
success: false,
|
|
3318
3061
|
error: selectResult.error ?? `Select value "${String(value)}" was not applied for "${fieldId}"`,
|
|
3319
|
-
diagnose: selectResult.diagnose ?? {
|
|
3062
|
+
diagnose: selectResult.diagnose ?? {
|
|
3063
|
+
category: "component-not-found",
|
|
3064
|
+
fieldId,
|
|
3065
|
+
screen: screenPath
|
|
3066
|
+
}
|
|
3320
3067
|
});
|
|
3321
3068
|
allSuccess = false;
|
|
3322
3069
|
continue;
|
|
@@ -3371,7 +3118,9 @@ async function formFillHandler(payload, context) {
|
|
|
3371
3118
|
continue;
|
|
3372
3119
|
}
|
|
3373
3120
|
try {
|
|
3374
|
-
sliderEntry.setValue(
|
|
3121
|
+
sliderEntry.setValue(
|
|
3122
|
+
snapSliderValue(numeric, sliderEntry.min, sliderEntry.max, sliderEntry.step)
|
|
3123
|
+
);
|
|
3375
3124
|
fieldResults.push({ fieldId, success: true });
|
|
3376
3125
|
} catch (err) {
|
|
3377
3126
|
fieldResults.push({
|
|
@@ -3420,8 +3169,8 @@ async function formFillHandler(payload, context) {
|
|
|
3420
3169
|
}
|
|
3421
3170
|
if (selectResult.success) {
|
|
3422
3171
|
selectedChoiceThisBatch = true;
|
|
3423
|
-
|
|
3424
|
-
`
|
|
3172
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3173
|
+
`formFillHandler: selected visible option for "${fieldId}"` + (selectResult.selectedLabel ? ` \u2192 "${selectResult.selectedLabel}"` : "")
|
|
3425
3174
|
);
|
|
3426
3175
|
await sleep2(120);
|
|
3427
3176
|
fieldResults.push({ fieldId, success: true });
|
|
@@ -3429,7 +3178,7 @@ async function formFillHandler(payload, context) {
|
|
|
3429
3178
|
}
|
|
3430
3179
|
selectFailure = selectResult;
|
|
3431
3180
|
}
|
|
3432
|
-
|
|
3181
|
+
chunkYB77RYCC_js.appilotsDebugLog(`formFillHandler: registry miss for "${fieldId}", falling back to fiber tree`);
|
|
3433
3182
|
const handle = findInteractiveByIdentifier(fieldId, {
|
|
3434
3183
|
kind: effectiveFieldType === "toggle" ? "toggle" : "field"
|
|
3435
3184
|
});
|
|
@@ -3437,7 +3186,9 @@ async function formFillHandler(payload, context) {
|
|
|
3437
3186
|
try {
|
|
3438
3187
|
handle.focus?.();
|
|
3439
3188
|
handle.setValue(value);
|
|
3440
|
-
|
|
3189
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3190
|
+
`formFillHandler: fiber fallback succeeded for "${fieldId}" \u2192 label="${handle.label}"`
|
|
3191
|
+
);
|
|
3441
3192
|
fieldResults.push({ fieldId, success: true });
|
|
3442
3193
|
continue;
|
|
3443
3194
|
} catch (err) {
|
|
@@ -3474,14 +3225,22 @@ async function formFillHandler(payload, context) {
|
|
|
3474
3225
|
if (payload.submitAfterFill === true) {
|
|
3475
3226
|
if (!allSuccess) {
|
|
3476
3227
|
const failedIds = fieldResults.filter((result) => !result.success).map((result) => result.fieldId);
|
|
3477
|
-
|
|
3228
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
3478
3229
|
"formFillHandler: submitAfterFill=true requested but some fields failed; NOT submitting" + (failedIds.length > 0 ? ` (failed: ${failedIds.join(", ")})` : "")
|
|
3479
3230
|
);
|
|
3480
3231
|
} else {
|
|
3481
3232
|
await sleep2(120);
|
|
3482
|
-
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
|
+
);
|
|
3483
3242
|
if (!submitResult.success) {
|
|
3484
|
-
|
|
3243
|
+
chunkYB77RYCC_js.appilotsDebugWarn(`formFillHandler: submitAfterFill failed \u2014 ${submitResult.error}`);
|
|
3485
3244
|
return {
|
|
3486
3245
|
success: false,
|
|
3487
3246
|
error: submitResult.error,
|
|
@@ -3493,7 +3252,7 @@ async function formFillHandler(payload, context) {
|
|
|
3493
3252
|
submitTargetId: submitResult.pressedTargetId
|
|
3494
3253
|
});
|
|
3495
3254
|
if (postSubmit.status === "pending") {
|
|
3496
|
-
|
|
3255
|
+
chunkYB77RYCC_js.appilotsDebugWarn(`formFillHandler: submit still pending \u2014 ${postSubmit.message}`);
|
|
3497
3256
|
return {
|
|
3498
3257
|
success: false,
|
|
3499
3258
|
error: postSubmit.message,
|
|
@@ -3502,7 +3261,7 @@ async function formFillHandler(payload, context) {
|
|
|
3502
3261
|
};
|
|
3503
3262
|
}
|
|
3504
3263
|
if (postSubmit.status === "failure") {
|
|
3505
|
-
|
|
3264
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
3506
3265
|
`formFillHandler: submit rejected by visible validation \u2014 ${postSubmit.message}`
|
|
3507
3266
|
);
|
|
3508
3267
|
return {
|
|
@@ -3517,7 +3276,7 @@ async function formFillHandler(payload, context) {
|
|
|
3517
3276
|
}
|
|
3518
3277
|
};
|
|
3519
3278
|
}
|
|
3520
|
-
|
|
3279
|
+
chunkYB77RYCC_js.appilotsDebugLog("formFillHandler: submitAfterFill \u2014 submit completed");
|
|
3521
3280
|
}
|
|
3522
3281
|
}
|
|
3523
3282
|
const aggregatedDiagnose = aggregateFieldDiagnoses(fieldResults, screenPath);
|
|
@@ -3529,18 +3288,18 @@ async function formFillHandler(payload, context) {
|
|
|
3529
3288
|
};
|
|
3530
3289
|
}
|
|
3531
3290
|
function pressSubmitButton(context, registry) {
|
|
3532
|
-
const activePath = context.activePath ??
|
|
3291
|
+
const activePath = context.activePath ?? chunkYB77RYCC_js.getActiveRouteNames();
|
|
3533
3292
|
const hintScreen = context.screen ?? context.screenPath;
|
|
3534
3293
|
const formScreens = resolveFormScreensForSubmit(hintScreen, activePath, registry);
|
|
3535
|
-
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;
|
|
3536
3295
|
const candidates = collectSubmitTargetCandidates(formScreens, registry);
|
|
3537
3296
|
for (const candidate of candidates) {
|
|
3538
3297
|
const target = registry.getTarget(candidate);
|
|
3539
3298
|
if (target) {
|
|
3540
3299
|
try {
|
|
3541
3300
|
target.press();
|
|
3542
|
-
|
|
3543
|
-
`
|
|
3301
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3302
|
+
`formFillHandler: submitAfterFill \u2014 pressed registry target "${candidate}"` + (resolvedScreen ? ` on screen "${resolvedScreen}"` : "")
|
|
3544
3303
|
);
|
|
3545
3304
|
return { success: true, pressedTargetId: candidate };
|
|
3546
3305
|
} catch (err) {
|
|
@@ -3553,7 +3312,7 @@ function pressSubmitButton(context, registry) {
|
|
|
3553
3312
|
}
|
|
3554
3313
|
}
|
|
3555
3314
|
for (const screenName of formScreens) {
|
|
3556
|
-
const screenMeta =
|
|
3315
|
+
const screenMeta = chunkYB77RYCC_js.getScreenMetadata(screenName);
|
|
3557
3316
|
const submitMeta = Array.isArray(screenMeta?.actions) ? screenMeta.actions.find(
|
|
3558
3317
|
(action) => typeof action === "object" && action !== null && action.type === "submit"
|
|
3559
3318
|
) : void 0;
|
|
@@ -3564,9 +3323,7 @@ function pressSubmitButton(context, registry) {
|
|
|
3564
3323
|
if (handle?.press) {
|
|
3565
3324
|
try {
|
|
3566
3325
|
handle.press();
|
|
3567
|
-
|
|
3568
|
-
`[Appilots] formFillHandler: submitAfterFill \u2014 fiber fallback "${submitLabel}"`
|
|
3569
|
-
);
|
|
3326
|
+
chunkYB77RYCC_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 fiber fallback "${submitLabel}"`);
|
|
3570
3327
|
return { success: true, pressedTargetId: submitId ?? submitLabel };
|
|
3571
3328
|
} catch (err) {
|
|
3572
3329
|
return {
|
|
@@ -3588,9 +3345,7 @@ function pressSubmitButton(context, registry) {
|
|
|
3588
3345
|
if (id) {
|
|
3589
3346
|
const pressed = pressTargetByIdOrLabel(id, registry);
|
|
3590
3347
|
if (pressed.success) {
|
|
3591
|
-
|
|
3592
|
-
`[Appilots] formFillHandler: submitAfterFill \u2014 pressed visible heuristic "${id}"`
|
|
3593
|
-
);
|
|
3348
|
+
chunkYB77RYCC_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 pressed visible heuristic "${id}"`);
|
|
3594
3349
|
return { success: true, pressedTargetId: id };
|
|
3595
3350
|
}
|
|
3596
3351
|
}
|
|
@@ -3604,8 +3359,8 @@ function pressSubmitButton(context, registry) {
|
|
|
3604
3359
|
if (target) {
|
|
3605
3360
|
try {
|
|
3606
3361
|
target.press();
|
|
3607
|
-
|
|
3608
|
-
`
|
|
3362
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3363
|
+
`formFillHandler: submitAfterFill \u2014 pressed by label heuristic "${comp.label}"`
|
|
3609
3364
|
);
|
|
3610
3365
|
return { success: true, pressedTargetId: comp.id };
|
|
3611
3366
|
} catch (err) {
|
|
@@ -3617,9 +3372,16 @@ function pressSubmitButton(context, registry) {
|
|
|
3617
3372
|
}
|
|
3618
3373
|
}
|
|
3619
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
|
+
}
|
|
3620
3382
|
return {
|
|
3621
3383
|
success: false,
|
|
3622
|
-
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)',
|
|
3623
3385
|
diagnose: { category: "component-not-found", screen: resolvedScreen }
|
|
3624
3386
|
};
|
|
3625
3387
|
}
|
|
@@ -3659,12 +3421,12 @@ function buildDiagnose(category, targetId, candidates) {
|
|
|
3659
3421
|
return {
|
|
3660
3422
|
category,
|
|
3661
3423
|
targetId,
|
|
3662
|
-
screen:
|
|
3424
|
+
screen: chunkYB77RYCC_js.getCurrentScreen() ?? void 0,
|
|
3663
3425
|
...candidates && candidates.length > 0 ? { candidates: candidates.slice(0, 8) } : {}
|
|
3664
3426
|
};
|
|
3665
3427
|
}
|
|
3666
3428
|
function resolveListEntry(listId) {
|
|
3667
|
-
const entries =
|
|
3429
|
+
const entries = chunkYB77RYCC_js.listRegistry.snapshot();
|
|
3668
3430
|
if (entries.length === 0) return {};
|
|
3669
3431
|
if (listId) {
|
|
3670
3432
|
const wanted = normalizeId2(listId);
|
|
@@ -3673,6 +3435,8 @@ function resolveListEntry(listId) {
|
|
|
3673
3435
|
return { candidates: entries.map((e) => e.id) };
|
|
3674
3436
|
}
|
|
3675
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] };
|
|
3676
3440
|
return { candidates: entries.map((e) => e.id) };
|
|
3677
3441
|
}
|
|
3678
3442
|
function pageOffset(metrics, direction) {
|
|
@@ -3712,7 +3476,7 @@ async function scrollListHandler(payload, context) {
|
|
|
3712
3476
|
}
|
|
3713
3477
|
const { entry, candidates } = resolveListEntry(payload.listId);
|
|
3714
3478
|
if (!entry) {
|
|
3715
|
-
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).";
|
|
3716
3480
|
return {
|
|
3717
3481
|
success: false,
|
|
3718
3482
|
error: detail,
|
|
@@ -3720,6 +3484,13 @@ async function scrollListHandler(payload, context) {
|
|
|
3720
3484
|
};
|
|
3721
3485
|
}
|
|
3722
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
|
+
}
|
|
3723
3494
|
if (typeof entry.itemCount === "number" && toIndex > entry.itemCount) {
|
|
3724
3495
|
return {
|
|
3725
3496
|
success: false,
|
|
@@ -3754,14 +3525,14 @@ async function scrollListHandler(payload, context) {
|
|
|
3754
3525
|
}
|
|
3755
3526
|
return {
|
|
3756
3527
|
success: false,
|
|
3757
|
-
error: `
|
|
3528
|
+
error: `"${entry.id}" does not expose a scrollable handle`,
|
|
3758
3529
|
diagnose: buildDiagnose("unknown", entry.id)
|
|
3759
3530
|
};
|
|
3760
3531
|
}
|
|
3761
3532
|
|
|
3762
3533
|
// src/executor/handlers/confirmHandler.ts
|
|
3763
3534
|
async function confirmHandler(_actionId, _payload) {
|
|
3764
|
-
return { success: true };
|
|
3535
|
+
return { success: true, effect: "unknown" };
|
|
3765
3536
|
}
|
|
3766
3537
|
|
|
3767
3538
|
// src/executor/postInteractionSettle.ts
|
|
@@ -3773,29 +3544,61 @@ function targetIdFromPayload(payload) {
|
|
|
3773
3544
|
if (typeof targetId === "string" && targetId.trim()) return targetId.trim();
|
|
3774
3545
|
return "";
|
|
3775
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
|
+
}
|
|
3776
3569
|
async function waitForPostInteractionSettle(payload) {
|
|
3777
3570
|
const targetId = targetIdFromPayload(payload);
|
|
3778
|
-
const fromScreen =
|
|
3779
|
-
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 !== "";
|
|
3780
3575
|
await sleepMs(100);
|
|
3781
|
-
const afterPress =
|
|
3576
|
+
const afterPress = chunkYB77RYCC_js.probeLoadingState(targetId || null, chunkYB77RYCC_js.getCurrentScreen());
|
|
3782
3577
|
const modalOrLoading = afterPress.modalOpen || afterPress.loading || afterPress.pressedDisabled;
|
|
3783
3578
|
const fingerprintChanged = afterPress.fingerprint !== baseline.fingerprint;
|
|
3784
|
-
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;
|
|
3785
3587
|
if (modalOrLoading || fingerprintChanged) {
|
|
3786
|
-
await
|
|
3588
|
+
await chunkYB77RYCC_js.waitForLoadingSettle({
|
|
3787
3589
|
pressedComponentId: targetId || null,
|
|
3788
3590
|
fromScreen,
|
|
3789
3591
|
maxMs: capMs
|
|
3790
3592
|
});
|
|
3791
|
-
return;
|
|
3593
|
+
return verdict();
|
|
3792
3594
|
}
|
|
3793
|
-
if (
|
|
3794
|
-
await
|
|
3595
|
+
if (chunkYB77RYCC_js.isListItemPressTarget(targetId)) {
|
|
3596
|
+
await chunkYB77RYCC_js.waitForLoadingSettle({
|
|
3795
3597
|
fromScreen,
|
|
3796
3598
|
maxMs: 3e3
|
|
3797
3599
|
});
|
|
3798
3600
|
}
|
|
3601
|
+
return verdict();
|
|
3799
3602
|
}
|
|
3800
3603
|
|
|
3801
3604
|
// src/executor/ActionExecutor.ts
|
|
@@ -3811,7 +3614,7 @@ function validateActionPayload(action) {
|
|
|
3811
3614
|
error: message,
|
|
3812
3615
|
diagnose: {
|
|
3813
3616
|
category: "validation",
|
|
3814
|
-
screen:
|
|
3617
|
+
screen: chunkYB77RYCC_js.getCurrentScreen() ?? void 0,
|
|
3815
3618
|
...ids ?? {}
|
|
3816
3619
|
}
|
|
3817
3620
|
});
|
|
@@ -3850,10 +3653,9 @@ function validateActionPayload(action) {
|
|
|
3850
3653
|
const hasIndex = typeof payload.toIndex === "number";
|
|
3851
3654
|
const hasDirection = payload.direction === "up" || payload.direction === "down";
|
|
3852
3655
|
if (!hasIndex && !hasDirection) {
|
|
3853
|
-
return invalid(
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
);
|
|
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
|
+
});
|
|
3857
3659
|
}
|
|
3858
3660
|
return null;
|
|
3859
3661
|
}
|
|
@@ -3861,24 +3663,48 @@ function validateActionPayload(action) {
|
|
|
3861
3663
|
return null;
|
|
3862
3664
|
}
|
|
3863
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
|
+
}
|
|
3864
3677
|
async function executeAction(action, context) {
|
|
3865
|
-
|
|
3678
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3679
|
+
`executeAction called: type="${action.type}", id="${action.id}", payload=${JSON.stringify(action.payload)}`
|
|
3680
|
+
);
|
|
3866
3681
|
const permissions = context.permissions ?? DEFAULT_PERMISSIONS;
|
|
3867
|
-
if (permissions.allowedActions && permissions.allowedActions.length > 0 && !permissions.allowedActions.includes(action.type)) {
|
|
3868
|
-
return {
|
|
3869
|
-
success: false,
|
|
3870
|
-
error: `Action type "${action.type}" is not in the allowed actions list`
|
|
3871
|
-
};
|
|
3872
|
-
}
|
|
3873
3682
|
context.emit({
|
|
3874
3683
|
type: "agent:action:start",
|
|
3875
3684
|
timestamp: Date.now(),
|
|
3876
3685
|
data: { actionId: action.id, actionType: action.type }
|
|
3877
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
|
+
}
|
|
3878
3704
|
let result;
|
|
3879
3705
|
const validationFailure = validateActionPayload(action);
|
|
3880
3706
|
if (validationFailure) {
|
|
3881
|
-
|
|
3707
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
3882
3708
|
`executeAction: payload validation failed for type="${action.type}" id="${action.id}": ${validationFailure.error}`
|
|
3883
3709
|
);
|
|
3884
3710
|
context.emit({
|
|
@@ -3905,28 +3731,28 @@ async function executeAction(action, context) {
|
|
|
3905
3731
|
case "form_fill":
|
|
3906
3732
|
result = await formFillHandler(action.payload, {
|
|
3907
3733
|
permissions,
|
|
3908
|
-
registry: context.registry ??
|
|
3734
|
+
registry: context.registry ?? chunkYB77RYCC_js.getDefaultRegistry()
|
|
3909
3735
|
});
|
|
3910
3736
|
break;
|
|
3911
|
-
case "ui_interaction":
|
|
3912
|
-
|
|
3737
|
+
case "ui_interaction": {
|
|
3738
|
+
const payload = action.payload;
|
|
3739
|
+
result = uiInteractionHandler(payload, {
|
|
3913
3740
|
permissions,
|
|
3914
|
-
registry: context.registry ??
|
|
3741
|
+
registry: context.registry ?? chunkYB77RYCC_js.getDefaultRegistry()
|
|
3915
3742
|
});
|
|
3916
3743
|
if (result.success) {
|
|
3917
|
-
await waitForPostInteractionSettle(
|
|
3744
|
+
const settle = await waitForPostInteractionSettle(payload);
|
|
3745
|
+
result.effect = result.effect ?? effectFor(payload, settle.effect);
|
|
3918
3746
|
}
|
|
3919
3747
|
break;
|
|
3748
|
+
}
|
|
3920
3749
|
case "scroll_list":
|
|
3921
3750
|
result = await scrollListHandler(action.payload, {
|
|
3922
3751
|
permissions
|
|
3923
3752
|
});
|
|
3924
3753
|
break;
|
|
3925
3754
|
case "confirm":
|
|
3926
|
-
result = await confirmHandler(
|
|
3927
|
-
action.id,
|
|
3928
|
-
action.payload
|
|
3929
|
-
);
|
|
3755
|
+
result = await confirmHandler(action.id, action.payload);
|
|
3930
3756
|
break;
|
|
3931
3757
|
case "custom":
|
|
3932
3758
|
result = {
|
|
@@ -3941,7 +3767,7 @@ async function executeAction(action, context) {
|
|
|
3941
3767
|
};
|
|
3942
3768
|
}
|
|
3943
3769
|
} catch (err) {
|
|
3944
|
-
|
|
3770
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
3945
3771
|
`executeAction: exception during action type="${action.type}" id="${action.id}": ${err?.message}`
|
|
3946
3772
|
);
|
|
3947
3773
|
result = {
|
|
@@ -3949,7 +3775,9 @@ async function executeAction(action, context) {
|
|
|
3949
3775
|
error: err?.message ?? "Action execution failed unexpectedly"
|
|
3950
3776
|
};
|
|
3951
3777
|
}
|
|
3952
|
-
|
|
3778
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3779
|
+
`executeAction result: type="${action.type}", id="${action.id}", success=${result.success}, error=${result.error ?? "none"}`
|
|
3780
|
+
);
|
|
3953
3781
|
context.emit({
|
|
3954
3782
|
type: result.success ? "agent:action:complete" : "agent:action:error",
|
|
3955
3783
|
timestamp: Date.now(),
|
|
@@ -3965,37 +3793,124 @@ async function executeAction(action, context) {
|
|
|
3965
3793
|
});
|
|
3966
3794
|
return result;
|
|
3967
3795
|
}
|
|
3796
|
+
|
|
3797
|
+
// src/platform/confirmedDestructiveAlert.ts
|
|
3798
|
+
var SUPPRESSION_WINDOW_MS = 1e3;
|
|
3799
|
+
var _active = null;
|
|
3800
|
+
function resolveConfirmButton(buttons) {
|
|
3801
|
+
if (!buttons || buttons.length === 0) return void 0;
|
|
3802
|
+
const destructive = buttons.find(
|
|
3803
|
+
(button) => button.style === "destructive" && typeof button.onPress === "function"
|
|
3804
|
+
);
|
|
3805
|
+
if (destructive) return destructive;
|
|
3806
|
+
return buttons.find(
|
|
3807
|
+
(button) => button.style !== "cancel" && typeof button.onPress === "function"
|
|
3808
|
+
);
|
|
3809
|
+
}
|
|
3810
|
+
function restore(suppression) {
|
|
3811
|
+
if (suppression.timer) {
|
|
3812
|
+
clearTimeout(suppression.timer);
|
|
3813
|
+
suppression.timer = null;
|
|
3814
|
+
}
|
|
3815
|
+
if (_active !== suppression) return;
|
|
3816
|
+
if (suppression.host.alert === _patchedAlert) {
|
|
3817
|
+
suppression.host.alert = suppression.originalAlert;
|
|
3818
|
+
}
|
|
3819
|
+
_active = null;
|
|
3820
|
+
}
|
|
3821
|
+
var _patchedAlert = (title, message, buttons, options) => {
|
|
3822
|
+
const suppression = _active;
|
|
3823
|
+
if (!suppression) return;
|
|
3824
|
+
if (suppression.consumed) {
|
|
3825
|
+
return suppression.originalAlert(title, message, buttons, options);
|
|
3826
|
+
}
|
|
3827
|
+
const button = resolveConfirmButton(buttons);
|
|
3828
|
+
if (!button?.onPress) {
|
|
3829
|
+
return suppression.originalAlert(title, message, buttons, options);
|
|
3830
|
+
}
|
|
3831
|
+
suppression.consumed = true;
|
|
3832
|
+
chunkYB77RYCC_js.appilotsDebugLog("Suppressing native Alert during already-confirmed destructive agent action");
|
|
3833
|
+
try {
|
|
3834
|
+
suppression.pending = Promise.resolve(button.onPress()).then(() => void 0).catch((err) => reportHandlerFailure(err));
|
|
3835
|
+
} catch (err) {
|
|
3836
|
+
reportHandlerFailure(err);
|
|
3837
|
+
suppression.pending = null;
|
|
3838
|
+
}
|
|
3839
|
+
};
|
|
3840
|
+
function reportHandlerFailure(err) {
|
|
3841
|
+
console.error("[Appilots] The app\u2019s Alert handler threw while being auto-confirmed", err);
|
|
3842
|
+
}
|
|
3843
|
+
async function runWithConfirmedDestructiveContext(enabled, host, fn) {
|
|
3844
|
+
if (!enabled) return fn();
|
|
3845
|
+
if (_active) {
|
|
3846
|
+
_active.depth += 1;
|
|
3847
|
+
const joined = _active;
|
|
3848
|
+
try {
|
|
3849
|
+
return await fn();
|
|
3850
|
+
} finally {
|
|
3851
|
+
joined.depth -= 1;
|
|
3852
|
+
if (joined.depth === 0) {
|
|
3853
|
+
if (joined.pending) await joined.pending.catch(() => void 0);
|
|
3854
|
+
restore(joined);
|
|
3855
|
+
}
|
|
3856
|
+
}
|
|
3857
|
+
}
|
|
3858
|
+
const suppression = {
|
|
3859
|
+
host,
|
|
3860
|
+
originalAlert: host.alert,
|
|
3861
|
+
depth: 1,
|
|
3862
|
+
consumed: false,
|
|
3863
|
+
pending: null,
|
|
3864
|
+
timer: null
|
|
3865
|
+
};
|
|
3866
|
+
_active = suppression;
|
|
3867
|
+
host.alert = _patchedAlert;
|
|
3868
|
+
suppression.timer = setTimeout(() => {
|
|
3869
|
+
if (!suppression.consumed) restore(suppression);
|
|
3870
|
+
}, SUPPRESSION_WINDOW_MS);
|
|
3871
|
+
suppression.timer?.unref?.();
|
|
3872
|
+
try {
|
|
3873
|
+
const result = await fn();
|
|
3874
|
+
if (suppression.pending) await suppression.pending.catch(() => void 0);
|
|
3875
|
+
return result;
|
|
3876
|
+
} finally {
|
|
3877
|
+
suppression.depth -= 1;
|
|
3878
|
+
if (suppression.depth === 0) restore(suppression);
|
|
3879
|
+
}
|
|
3880
|
+
}
|
|
3881
|
+
|
|
3882
|
+
// src/platform/reactNativeAdapter.ts
|
|
3968
3883
|
var POST_ACTION_LOADING_MAX_MS = 6e3;
|
|
3969
3884
|
function resolveScreenMetadata() {
|
|
3970
|
-
const activePath =
|
|
3885
|
+
const activePath = chunkYB77RYCC_js.getActiveRouteNames();
|
|
3971
3886
|
for (let i = activePath.length - 1; i >= 0; i--) {
|
|
3972
3887
|
const name = activePath[i];
|
|
3973
|
-
const meta = name ?
|
|
3888
|
+
const meta = name ? chunkYB77RYCC_js.getScreenMetadata(name) : void 0;
|
|
3974
3889
|
if (meta && (Array.isArray(meta.fields) && meta.fields.length > 0 || Array.isArray(meta.actions) && meta.actions.length > 0)) {
|
|
3975
3890
|
return meta;
|
|
3976
3891
|
}
|
|
3977
3892
|
}
|
|
3978
|
-
const screen =
|
|
3979
|
-
return screen ?
|
|
3893
|
+
const screen = chunkYB77RYCC_js.getCurrentScreen();
|
|
3894
|
+
return screen ? chunkYB77RYCC_js.getScreenMetadata(screen) : void 0;
|
|
3980
3895
|
}
|
|
3981
3896
|
function buildAgentContext(extras = {}) {
|
|
3982
3897
|
const context = {};
|
|
3983
3898
|
context.platform = "react-native";
|
|
3984
|
-
const screen =
|
|
3899
|
+
const screen = chunkYB77RYCC_js.getCurrentScreen();
|
|
3985
3900
|
if (screen) context.currentScreen = screen;
|
|
3986
|
-
const navigationState =
|
|
3901
|
+
const navigationState = chunkYB77RYCC_js.getNavigationStateSnapshot();
|
|
3987
3902
|
if (navigationState) context.navigationState = navigationState;
|
|
3988
3903
|
const screenMeta = resolveScreenMetadata();
|
|
3989
3904
|
if (screenMeta) context.screenMetadata = screenMeta;
|
|
3990
3905
|
try {
|
|
3991
3906
|
context.snapshot = captureSnapshot();
|
|
3992
3907
|
} catch (err) {
|
|
3993
|
-
|
|
3908
|
+
chunkYB77RYCC_js.appilotsDebugWarn("buildAgentContext: captureSnapshot failed", err);
|
|
3994
3909
|
}
|
|
3995
|
-
const registry =
|
|
3910
|
+
const registry = chunkYB77RYCC_js.componentRegistry.snapshot();
|
|
3996
3911
|
const filtered = screen ? registry.filter((c) => !c.screen || c.screen === screen) : registry;
|
|
3997
3912
|
if (filtered.length > 0) context.registeredComponents = filtered;
|
|
3998
|
-
const registeredLists =
|
|
3913
|
+
const registeredLists = chunkYB77RYCC_js.listRegistry.snapshot();
|
|
3999
3914
|
if (registeredLists.length > 0) {
|
|
4000
3915
|
context.registeredLists = registeredLists.map(
|
|
4001
3916
|
({ scrollToIndex, scrollToOffset, getScrollMetrics, dataPreview, ...rest }) => rest
|
|
@@ -4012,12 +3927,12 @@ function resolveActionHints(screen, pressedComponentId, actionPayload) {
|
|
|
4012
3927
|
}
|
|
4013
3928
|
}
|
|
4014
3929
|
if (!screen || !pressedComponentId) return void 0;
|
|
4015
|
-
const meta =
|
|
3930
|
+
const meta = chunkYB77RYCC_js.getScreenMetadata(screen);
|
|
4016
3931
|
const actions = meta?.actions;
|
|
4017
3932
|
if (!actions || actions.length === 0) return void 0;
|
|
4018
3933
|
for (const a of actions) {
|
|
4019
3934
|
if (typeof a === "string") continue;
|
|
4020
|
-
if (
|
|
3935
|
+
if (chunkYB77RYCC_js.idLooselyMatches(a.id, pressedComponentId)) {
|
|
4021
3936
|
const inferred = a.appilotsInferred;
|
|
4022
3937
|
if (inferred && typeof inferred === "object") return inferred;
|
|
4023
3938
|
return void 0;
|
|
@@ -4032,71 +3947,68 @@ async function settleTurn(input) {
|
|
|
4032
3947
|
const successById = new Map(input.results.map((r) => [r.actionId, r.success]));
|
|
4033
3948
|
const typeById = new Map(input.results.map((r) => [r.actionId, r.type]));
|
|
4034
3949
|
if (input.hadNavigate) {
|
|
4035
|
-
const settle = await
|
|
3950
|
+
const settle = await chunkYB77RYCC_js.waitForScreenSettle({
|
|
4036
3951
|
expectingChange: true,
|
|
4037
3952
|
fromScreen: input.preNavigateScreen ?? null,
|
|
4038
3953
|
fromSignature: input.preNavigateSignature ?? null,
|
|
4039
3954
|
targetScreen: navigateTargetScreen,
|
|
4040
3955
|
maxMs: 3500
|
|
4041
3956
|
});
|
|
4042
|
-
|
|
4043
|
-
`
|
|
3957
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3958
|
+
`settleTurn: post-navigate settle done \u2014 screen="${settle.screen}" transitioned=${settle.transitioned} timedOut=${settle.timedOut} waitedMs=${settle.waitedMs}`
|
|
4044
3959
|
);
|
|
4045
|
-
const navigationMoved = settle.transitioned ||
|
|
4046
|
-
input.preNavigateScreen ?? null,
|
|
4047
|
-
input.preNavigateSignature ?? null
|
|
4048
|
-
) || !!navigateTargetScreen && !!settle.screen && chunkDZ7QRFHD_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);
|
|
4049
3961
|
if (!navigationMoved) {
|
|
4050
|
-
|
|
3962
|
+
chunkYB77RYCC_js.appilotsDebugWarn(
|
|
4051
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.`
|
|
4052
3964
|
);
|
|
4053
3965
|
for (const [actionId, type] of typeById) {
|
|
4054
3966
|
if (type === "navigate") toolWithoutEffectIds.add(actionId);
|
|
4055
3967
|
}
|
|
4056
3968
|
}
|
|
4057
|
-
const loadSettle = await
|
|
3969
|
+
const loadSettle = await chunkYB77RYCC_js.waitForLoadingSettle({
|
|
4058
3970
|
fromScreen: settle.screen ?? null,
|
|
4059
3971
|
maxMs: 3e3
|
|
4060
3972
|
});
|
|
4061
|
-
|
|
4062
|
-
`
|
|
3973
|
+
chunkYB77RYCC_js.appilotsDebugLog(
|
|
3974
|
+
`settleTurn: post-navigate loading settle \u2014 settled=${loadSettle.settled} loadingPending=${loadSettle.loadingPending} probes=${loadSettle.probeCount} waitedMs=${loadSettle.waitedMs}`
|
|
4063
3975
|
);
|
|
4064
3976
|
if (loadSettle.loadingPending) loadingPending = true;
|
|
4065
3977
|
} else {
|
|
4066
3978
|
const pressedAction = turnActions.find(
|
|
4067
3979
|
(a) => a.type === "ui_interaction" && a.payload?.componentId === pressedId
|
|
4068
3980
|
);
|
|
4069
|
-
const hints = resolveActionHints(
|
|
3981
|
+
const hints = resolveActionHints(chunkYB77RYCC_js.getCurrentScreen(), pressedId, pressedAction?.payload);
|
|
4070
3982
|
const settleCapMs = hints?.isAsyncTrigger === true ? 1e4 : POST_ACTION_LOADING_MAX_MS;
|
|
4071
|
-
const loadSettle = await
|
|
3983
|
+
const loadSettle = await chunkYB77RYCC_js.waitForLoadingSettle({
|
|
4072
3984
|
pressedComponentId: pressedId,
|
|
4073
|
-
fromScreen:
|
|
3985
|
+
fromScreen: chunkYB77RYCC_js.getCurrentScreen(),
|
|
4074
3986
|
maxMs: settleCapMs
|
|
4075
3987
|
});
|
|
4076
|
-
|
|
4077
|
-
`
|
|
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)" : ""}`
|
|
4078
3990
|
);
|
|
4079
3991
|
if (loadSettle.loadingPending) loadingPending = true;
|
|
4080
3992
|
const listPressActions = turnActions.filter((action) => {
|
|
4081
|
-
const target =
|
|
4082
|
-
return target ?
|
|
3993
|
+
const target = chunkYB77RYCC_js.actionPressTargetId(action);
|
|
3994
|
+
return target ? chunkYB77RYCC_js.isListItemPressTarget(target) : false;
|
|
4083
3995
|
});
|
|
4084
3996
|
if (listPressActions.length > 0) {
|
|
4085
|
-
const baselineFingerprint =
|
|
4086
|
-
const postPressSettle = await
|
|
3997
|
+
const baselineFingerprint = chunkYB77RYCC_js.probeLoadingState(pressedId, chunkYB77RYCC_js.getCurrentScreen()).fingerprint;
|
|
3998
|
+
const postPressSettle = await chunkYB77RYCC_js.waitForScreenSettle({
|
|
4087
3999
|
expectingChange: true,
|
|
4088
4000
|
fromScreen: input.preNavigateScreen ?? null,
|
|
4089
4001
|
fromSignature: input.preNavigateSignature ?? null,
|
|
4090
4002
|
maxMs: 2500
|
|
4091
4003
|
});
|
|
4092
|
-
await
|
|
4004
|
+
await chunkYB77RYCC_js.waitForLoadingSettle({
|
|
4093
4005
|
pressedComponentId: pressedId,
|
|
4094
|
-
fromScreen:
|
|
4006
|
+
fromScreen: chunkYB77RYCC_js.getCurrentScreen(),
|
|
4095
4007
|
maxMs: 4e3
|
|
4096
4008
|
});
|
|
4097
|
-
const afterFingerprint =
|
|
4098
|
-
|
|
4099
|
-
`
|
|
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}`
|
|
4100
4012
|
);
|
|
4101
4013
|
if (!postPressSettle.transitioned && baselineFingerprint === afterFingerprint) {
|
|
4102
4014
|
for (const action of listPressActions) {
|
|
@@ -4111,46 +4023,18 @@ async function settleTurn(input) {
|
|
|
4111
4023
|
}
|
|
4112
4024
|
var reactNativeChatAdapter = {
|
|
4113
4025
|
buildContext: buildAgentContext,
|
|
4114
|
-
getCurrentScreen:
|
|
4115
|
-
getCurrentScreenSignature:
|
|
4026
|
+
getCurrentScreen: chunkYB77RYCC_js.getCurrentScreen,
|
|
4027
|
+
getCurrentScreenSignature: chunkYB77RYCC_js.getCurrentScreenSignature,
|
|
4116
4028
|
settleTurn
|
|
4117
4029
|
};
|
|
4118
|
-
async function runWithConfirmedDestructiveContext(enabled, fn) {
|
|
4119
|
-
if (!enabled) return fn();
|
|
4120
|
-
const originalAlert = reactNative.Alert.alert;
|
|
4121
|
-
let consumed = false;
|
|
4122
|
-
let alertWork = null;
|
|
4123
|
-
reactNative.Alert.alert = (title, message, buttons, options) => {
|
|
4124
|
-
if (consumed) {
|
|
4125
|
-
return originalAlert(title, message, buttons, options);
|
|
4126
|
-
}
|
|
4127
|
-
const destructive = buttons?.find((button) => button.style === "destructive");
|
|
4128
|
-
const actionable = destructive ?? buttons?.find((button) => button.style !== "cancel" && typeof button.onPress === "function");
|
|
4129
|
-
if (actionable?.onPress) {
|
|
4130
|
-
consumed = true;
|
|
4131
|
-
console.log(
|
|
4132
|
-
"[Appilots] Suppressing native Alert during already-confirmed destructive agent action"
|
|
4133
|
-
);
|
|
4134
|
-
alertWork = Promise.resolve(actionable.onPress()).then(() => void 0);
|
|
4135
|
-
return;
|
|
4136
|
-
}
|
|
4137
|
-
return originalAlert(title, message, buttons, options);
|
|
4138
|
-
};
|
|
4139
|
-
try {
|
|
4140
|
-
const result = await fn();
|
|
4141
|
-
if (alertWork) await alertWork;
|
|
4142
|
-
return result;
|
|
4143
|
-
} finally {
|
|
4144
|
-
reactNative.Alert.alert = originalAlert;
|
|
4145
|
-
}
|
|
4146
|
-
}
|
|
4147
4030
|
function createReactNativeActionRunner(getOptions) {
|
|
4148
4031
|
return {
|
|
4149
4032
|
async execute(action, { confirmedDestructive }) {
|
|
4150
|
-
const { permissions, emit, navigationRef } = getOptions();
|
|
4151
|
-
const navRef = navigationRef?.current ? navigationRef : { current:
|
|
4033
|
+
const { permissions, emit, navigationRef, suppressNativeConfirm } = getOptions();
|
|
4034
|
+
const navRef = navigationRef?.current ? navigationRef : { current: chunkYB77RYCC_js.getNavigationRef() };
|
|
4152
4035
|
return runWithConfirmedDestructiveContext(
|
|
4153
|
-
confirmedDestructive,
|
|
4036
|
+
confirmedDestructive && suppressNativeConfirm !== false,
|
|
4037
|
+
reactNative.Alert,
|
|
4154
4038
|
() => executeAction(action, {
|
|
4155
4039
|
navigationRef: navRef,
|
|
4156
4040
|
permissions,
|
|
@@ -4158,21 +4042,21 @@ function createReactNativeActionRunner(getOptions) {
|
|
|
4158
4042
|
})
|
|
4159
4043
|
);
|
|
4160
4044
|
},
|
|
4161
|
-
getCurrentScreen:
|
|
4162
|
-
getCurrentScreenSignature:
|
|
4045
|
+
getCurrentScreen: chunkYB77RYCC_js.getCurrentScreen,
|
|
4046
|
+
getCurrentScreenSignature: chunkYB77RYCC_js.getCurrentScreenSignature,
|
|
4163
4047
|
getScreenActionsMetadata(screen) {
|
|
4164
|
-
return
|
|
4048
|
+
return chunkYB77RYCC_js.getScreenMetadata(screen)?.actions;
|
|
4165
4049
|
},
|
|
4166
|
-
waitForScreenSettle:
|
|
4050
|
+
waitForScreenSettle: chunkYB77RYCC_js.waitForScreenSettle
|
|
4167
4051
|
};
|
|
4168
4052
|
}
|
|
4169
4053
|
|
|
4170
4054
|
// src/hooks/useAppilotsChat.ts
|
|
4171
4055
|
function useAppilotsChat(options = {}) {
|
|
4172
|
-
const { client, emit, subscribe } =
|
|
4173
|
-
const machine =
|
|
4174
|
-
() => new
|
|
4175
|
-
{ 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 },
|
|
4176
4060
|
options
|
|
4177
4061
|
),
|
|
4178
4062
|
// A new machine per client/provider instance — options are pushed in
|
|
@@ -4180,20 +4064,20 @@ function useAppilotsChat(options = {}) {
|
|
|
4180
4064
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
4181
4065
|
[client, emit]
|
|
4182
4066
|
);
|
|
4183
|
-
const optionsRef =
|
|
4067
|
+
const optionsRef = React.useRef(options);
|
|
4184
4068
|
optionsRef.current = options;
|
|
4185
4069
|
machine.setOptions(options);
|
|
4186
|
-
const state =
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
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(
|
|
4190
4074
|
(reason) => machine.requestHuman(reason),
|
|
4191
4075
|
[machine]
|
|
4192
4076
|
);
|
|
4193
|
-
const sendMessage =
|
|
4194
|
-
const cancelMessage =
|
|
4195
|
-
const clearMessages =
|
|
4196
|
-
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]);
|
|
4197
4081
|
return {
|
|
4198
4082
|
messages: state.messages,
|
|
4199
4083
|
isLoading: state.isLoading,
|
|
@@ -4215,25 +4099,27 @@ var DEFAULT_PERMISSIONS2 = {
|
|
|
4215
4099
|
canSubmitForms: true
|
|
4216
4100
|
};
|
|
4217
4101
|
function useAppilotsActions(options = {}) {
|
|
4218
|
-
const { client, subscribe, config, emit } =
|
|
4102
|
+
const { client, subscribe, config, emit } = chunkYB77RYCC_js.useAppilotsContext();
|
|
4219
4103
|
const { navigationRef, autoExecute = false } = options;
|
|
4220
|
-
const runnerOptionsRef =
|
|
4104
|
+
const runnerOptionsRef = React.useRef({
|
|
4221
4105
|
permissions: config.permissions ?? DEFAULT_PERMISSIONS2,
|
|
4222
4106
|
emit,
|
|
4223
|
-
navigationRef
|
|
4107
|
+
navigationRef,
|
|
4108
|
+
suppressNativeConfirm: config.suppressNativeConfirm
|
|
4224
4109
|
});
|
|
4225
4110
|
runnerOptionsRef.current = {
|
|
4226
4111
|
permissions: config.permissions ?? DEFAULT_PERMISSIONS2,
|
|
4227
4112
|
emit,
|
|
4228
|
-
navigationRef
|
|
4113
|
+
navigationRef,
|
|
4114
|
+
suppressNativeConfirm: config.suppressNativeConfirm
|
|
4229
4115
|
};
|
|
4230
|
-
const machine =
|
|
4231
|
-
() => new
|
|
4116
|
+
const machine = React.useMemo(
|
|
4117
|
+
() => new chunkYB77RYCC_js.ActionQueueMachine(
|
|
4232
4118
|
{
|
|
4233
4119
|
client,
|
|
4234
4120
|
adapter: createReactNativeActionRunner(() => runnerOptionsRef.current),
|
|
4235
4121
|
emit,
|
|
4236
|
-
warn:
|
|
4122
|
+
warn: chunkYB77RYCC_js.appilotsDebugWarn
|
|
4237
4123
|
},
|
|
4238
4124
|
{ autoExecute }
|
|
4239
4125
|
),
|
|
@@ -4241,16 +4127,16 @@ function useAppilotsActions(options = {}) {
|
|
|
4241
4127
|
[client, emit]
|
|
4242
4128
|
);
|
|
4243
4129
|
machine.setOptions({ autoExecute });
|
|
4244
|
-
const state =
|
|
4245
|
-
|
|
4246
|
-
|
|
4130
|
+
const state = React.useSyncExternalStore(machine.subscribeState, machine.getState, machine.getState);
|
|
4131
|
+
React.useEffect(() => subscribe(machine.handleEvent), [subscribe, machine]);
|
|
4132
|
+
React.useEffect(() => {
|
|
4247
4133
|
if (autoExecute) machine.scheduleDrain();
|
|
4248
4134
|
}, [autoExecute, machine, state.actions]);
|
|
4249
|
-
const approveAction =
|
|
4135
|
+
const approveAction = React.useCallback(
|
|
4250
4136
|
(actionId) => machine.approveAction(actionId),
|
|
4251
4137
|
[machine]
|
|
4252
4138
|
);
|
|
4253
|
-
const rejectAction =
|
|
4139
|
+
const rejectAction = React.useCallback((actionId) => machine.rejectAction(actionId), [machine]);
|
|
4254
4140
|
return {
|
|
4255
4141
|
pendingActions: state.actions.filter((a) => a.status === "pending"),
|
|
4256
4142
|
executingActions: state.actions.filter((a) => a.status === "executing"),
|
|
@@ -4290,18 +4176,18 @@ function shouldShowSuggestedPrompts(args) {
|
|
|
4290
4176
|
|
|
4291
4177
|
// src/hooks/useSuggestedPrompts.ts
|
|
4292
4178
|
function useSuggestedPrompts(options) {
|
|
4293
|
-
const { client } =
|
|
4179
|
+
const { client } = chunkYB77RYCC_js.useAppilotsContext();
|
|
4294
4180
|
const { enabled, limit = 4 } = options;
|
|
4295
|
-
const [prompts, setPrompts] =
|
|
4296
|
-
const [isLoading, setIsLoading] =
|
|
4297
|
-
const [refreshTick, setRefreshTick] =
|
|
4298
|
-
const requestIdRef =
|
|
4299
|
-
|
|
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(() => {
|
|
4300
4186
|
if (!enabled) return;
|
|
4301
4187
|
const requestId = ++requestIdRef.current;
|
|
4302
4188
|
let cancelled = false;
|
|
4303
|
-
const screen =
|
|
4304
|
-
const localDev = screen ? (
|
|
4189
|
+
const screen = chunkYB77RYCC_js.getCurrentScreen() ?? void 0;
|
|
4190
|
+
const localDev = screen ? (chunkYB77RYCC_js.getScreenMetadata(screen)?.suggestedPrompts ?? []).map((text) => ({
|
|
4305
4191
|
text,
|
|
4306
4192
|
source: "dev-defined"
|
|
4307
4193
|
})) : [];
|
|
@@ -4315,7 +4201,7 @@ function useSuggestedPrompts(options) {
|
|
|
4315
4201
|
if (cancelled || requestIdRef.current !== requestId) return;
|
|
4316
4202
|
setPrompts(mergePromptSources(localDev, data, limit));
|
|
4317
4203
|
}).catch((err) => {
|
|
4318
|
-
|
|
4204
|
+
chunkYB77RYCC_js.appilotsDebugWarn("useSuggestedPrompts: fetch failed", err);
|
|
4319
4205
|
}).finally(() => {
|
|
4320
4206
|
if (cancelled || requestIdRef.current !== requestId) return;
|
|
4321
4207
|
setIsLoading(false);
|
|
@@ -4324,11 +4210,11 @@ function useSuggestedPrompts(options) {
|
|
|
4324
4210
|
cancelled = true;
|
|
4325
4211
|
};
|
|
4326
4212
|
}, [client, enabled, limit, refreshTick]);
|
|
4327
|
-
|
|
4213
|
+
React.useEffect(() => {
|
|
4328
4214
|
if (!enabled) return;
|
|
4329
|
-
let lastScreen =
|
|
4215
|
+
let lastScreen = chunkYB77RYCC_js.getCurrentScreen();
|
|
4330
4216
|
const interval = setInterval(() => {
|
|
4331
|
-
const current =
|
|
4217
|
+
const current = chunkYB77RYCC_js.getCurrentScreen();
|
|
4332
4218
|
if (current !== lastScreen) {
|
|
4333
4219
|
lastScreen = current;
|
|
4334
4220
|
setRefreshTick((t) => t + 1);
|
|
@@ -4343,14 +4229,14 @@ function useSuggestedPrompts(options) {
|
|
|
4343
4229
|
};
|
|
4344
4230
|
}
|
|
4345
4231
|
function useAppilotsNavigation() {
|
|
4346
|
-
const { emit } =
|
|
4347
|
-
const [currentScreen, setCurrentScreenState] =
|
|
4348
|
-
const [navigationHistory, setNavigationHistory] =
|
|
4349
|
-
const navigationRef =
|
|
4350
|
-
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(
|
|
4351
4237
|
(screenName) => {
|
|
4352
4238
|
setCurrentScreenState(screenName);
|
|
4353
|
-
|
|
4239
|
+
chunkYB77RYCC_js.setCurrentScreen(screenName);
|
|
4354
4240
|
setNavigationHistory((prev) => [...prev, screenName]);
|
|
4355
4241
|
emit({
|
|
4356
4242
|
type: "navigation:change",
|
|
@@ -4360,7 +4246,7 @@ function useAppilotsNavigation() {
|
|
|
4360
4246
|
},
|
|
4361
4247
|
[emit]
|
|
4362
4248
|
);
|
|
4363
|
-
|
|
4249
|
+
React.useEffect(() => {
|
|
4364
4250
|
const nav = navigationRef.current;
|
|
4365
4251
|
if (!nav?.addListener) return;
|
|
4366
4252
|
const unsubscribe = nav.addListener("state", () => {
|
|
@@ -4381,7 +4267,7 @@ function useAppilotsNavigation() {
|
|
|
4381
4267
|
|
|
4382
4268
|
// src/hooks/useAppilots.ts
|
|
4383
4269
|
function useAppilots() {
|
|
4384
|
-
const { config, client } =
|
|
4270
|
+
const { config, client } = chunkYB77RYCC_js.useAppilotsContext();
|
|
4385
4271
|
const chat = useAppilotsChat();
|
|
4386
4272
|
const navigation = useAppilotsNavigation();
|
|
4387
4273
|
const actions = useAppilotsActions();
|
|
@@ -4410,17 +4296,17 @@ function useAppilots() {
|
|
|
4410
4296
|
}
|
|
4411
4297
|
function useAppilotsField(id, options) {
|
|
4412
4298
|
const { value, onChangeText, ref, fieldType, label, screen } = options;
|
|
4413
|
-
const registry =
|
|
4414
|
-
const valueRef =
|
|
4415
|
-
const onChangeRef =
|
|
4299
|
+
const registry = chunkYB77RYCC_js.useResolvedRegistry();
|
|
4300
|
+
const valueRef = React.useRef(value);
|
|
4301
|
+
const onChangeRef = React.useRef(onChangeText);
|
|
4416
4302
|
valueRef.current = value;
|
|
4417
4303
|
onChangeRef.current = onChangeText;
|
|
4418
|
-
const getValue =
|
|
4419
|
-
const setValue =
|
|
4420
|
-
const focus =
|
|
4304
|
+
const getValue = React.useCallback(() => valueRef.current, []);
|
|
4305
|
+
const setValue = React.useCallback((v) => onChangeRef.current(v), []);
|
|
4306
|
+
const focus = React.useCallback(() => {
|
|
4421
4307
|
ref?.current?.focus?.();
|
|
4422
4308
|
}, [ref]);
|
|
4423
|
-
|
|
4309
|
+
React.useEffect(() => {
|
|
4424
4310
|
const entry = {
|
|
4425
4311
|
kind: "field",
|
|
4426
4312
|
getValue,
|
|
@@ -4438,17 +4324,17 @@ function useAppilotsField(id, options) {
|
|
|
4438
4324
|
}
|
|
4439
4325
|
function useAppilotsTarget(id, options) {
|
|
4440
4326
|
const { onPress, onLongPress, onScrollTo, label, screen } = options;
|
|
4441
|
-
const registry =
|
|
4442
|
-
const onPressRef =
|
|
4443
|
-
const onLongPressRef =
|
|
4444
|
-
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);
|
|
4445
4331
|
onPressRef.current = onPress;
|
|
4446
4332
|
onLongPressRef.current = onLongPress;
|
|
4447
4333
|
onScrollToRef.current = onScrollTo;
|
|
4448
|
-
const press =
|
|
4449
|
-
const longPress =
|
|
4450
|
-
const scrollTo =
|
|
4451
|
-
|
|
4334
|
+
const press = React.useCallback(() => onPressRef.current(), []);
|
|
4335
|
+
const longPress = React.useCallback(() => onLongPressRef.current?.(), []);
|
|
4336
|
+
const scrollTo = React.useCallback(() => onScrollToRef.current?.(), []);
|
|
4337
|
+
React.useEffect(() => {
|
|
4452
4338
|
const entry = {
|
|
4453
4339
|
kind: "target",
|
|
4454
4340
|
press,
|
|
@@ -4465,14 +4351,14 @@ function useAppilotsTarget(id, options) {
|
|
|
4465
4351
|
}
|
|
4466
4352
|
function useAppilotsToggle(id, options) {
|
|
4467
4353
|
const { value, onValueChange, label, screen } = options;
|
|
4468
|
-
const registry =
|
|
4469
|
-
const valueRef =
|
|
4470
|
-
const onChangeRef =
|
|
4354
|
+
const registry = chunkYB77RYCC_js.useResolvedRegistry();
|
|
4355
|
+
const valueRef = React.useRef(value);
|
|
4356
|
+
const onChangeRef = React.useRef(onValueChange);
|
|
4471
4357
|
valueRef.current = value;
|
|
4472
4358
|
onChangeRef.current = onValueChange;
|
|
4473
|
-
const getValue =
|
|
4474
|
-
const setValue =
|
|
4475
|
-
|
|
4359
|
+
const getValue = React.useCallback(() => valueRef.current, []);
|
|
4360
|
+
const setValue = React.useCallback((v) => onChangeRef.current(v), []);
|
|
4361
|
+
React.useEffect(() => {
|
|
4476
4362
|
const entry = {
|
|
4477
4363
|
kind: "toggle",
|
|
4478
4364
|
getValue,
|
|
@@ -4488,14 +4374,14 @@ function useAppilotsToggle(id, options) {
|
|
|
4488
4374
|
}
|
|
4489
4375
|
function useAppilotsSlider(id, options) {
|
|
4490
4376
|
const { value, onValueChange, min, max, step, label, screen } = options;
|
|
4491
|
-
const registry =
|
|
4492
|
-
const valueRef =
|
|
4493
|
-
const onChangeRef =
|
|
4377
|
+
const registry = chunkYB77RYCC_js.useResolvedRegistry();
|
|
4378
|
+
const valueRef = React.useRef(value);
|
|
4379
|
+
const onChangeRef = React.useRef(onValueChange);
|
|
4494
4380
|
valueRef.current = value;
|
|
4495
4381
|
onChangeRef.current = onValueChange;
|
|
4496
|
-
const getValue =
|
|
4497
|
-
const setValue =
|
|
4498
|
-
|
|
4382
|
+
const getValue = React.useCallback(() => valueRef.current, []);
|
|
4383
|
+
const setValue = React.useCallback((v) => onChangeRef.current(v), []);
|
|
4384
|
+
React.useEffect(() => {
|
|
4499
4385
|
const entry = {
|
|
4500
4386
|
kind: "slider",
|
|
4501
4387
|
getValue,
|
|
@@ -4513,6 +4399,7 @@ function useAppilotsSlider(id, options) {
|
|
|
4513
4399
|
}, [id, registry, getValue, setValue, min, max, step, label, screen]);
|
|
4514
4400
|
}
|
|
4515
4401
|
|
|
4402
|
+
exports.appilotsSelfCheck = appilotsSelfCheck;
|
|
4516
4403
|
exports.captureSnapshot = captureSnapshot;
|
|
4517
4404
|
exports.executeAction = executeAction;
|
|
4518
4405
|
exports.shouldShowSuggestedPrompts = shouldShowSuggestedPrompts;
|