@appilots/sdk 0.8.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/dist/.build-meta.json +5 -0
- package/dist/{chunk-N7EAOLBP.js → chunk-2YPEQTL2.js} +956 -1134
- package/dist/{chunk-ZSEACJKU.mjs → chunk-3K7ORC4X.mjs} +16 -13
- package/dist/{chunk-AYWMBMSN.js → chunk-55Y2AQE7.js} +1992 -384
- package/dist/{chunk-C2KVVJ5K.mjs → chunk-G6KI7KVH.mjs} +1968 -386
- package/dist/{chunk-H7BMQTXH.js → chunk-IZEWWAA7.js} +19 -16
- package/dist/{chunk-MHWVRZYF.mjs → chunk-NA5H4IHH.mjs} +736 -919
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.js +11 -11
- package/dist/hooks/index.mjs +2 -2
- package/dist/{index-BdYY-dvG.d.mts → index-BPZ0j71S.d.mts} +254 -6
- package/dist/{index-BdYY-dvG.d.ts → index-BPZ0j71S.d.ts} +254 -6
- package/dist/index.d.mts +306 -21
- package/dist/index.d.ts +306 -21
- package/dist/index.js +337 -229
- package/dist/index.mjs +269 -173
- package/dist/navigation/index.d.mts +171 -3
- package/dist/navigation/index.d.ts +171 -3
- package/dist/navigation/index.js +13 -13
- package/dist/navigation/index.mjs +2 -2
- package/metro.d.ts +16 -1
- package/metro.js +104 -10
- package/package.json +4 -2
- package/dist/registerScreen-D1oGm28T.d.mts +0 -159
- package/dist/registerScreen-D1oGm28T.d.ts +0 -159
|
@@ -14,6 +14,153 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
14
14
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
+
// ../shared/dist/chunk-UEMUBXFH.mjs
|
|
18
|
+
var DEFAULT_API_BASE_URL = "https://api.appilots.com";
|
|
19
|
+
var APPILOTS_API_PATH_PREFIX = "/api/v1";
|
|
20
|
+
function normalizeApiBaseUrl(configured) {
|
|
21
|
+
const raw = (configured ?? DEFAULT_API_BASE_URL).trim().replace(/\/+$/, "");
|
|
22
|
+
if (!raw) return `${DEFAULT_API_BASE_URL}${APPILOTS_API_PATH_PREFIX}`;
|
|
23
|
+
if (new RegExp(`${APPILOTS_API_PATH_PREFIX}(/|$)`).test(raw)) return raw;
|
|
24
|
+
return `${raw}${APPILOTS_API_PATH_PREFIX}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ../shared/dist/screen-text/index.mjs
|
|
28
|
+
function build(table, extra = []) {
|
|
29
|
+
return [...Object.values(table).flat(), ...extra].join("|");
|
|
30
|
+
}
|
|
31
|
+
var VALIDATION = {
|
|
32
|
+
pt: [
|
|
33
|
+
"inv[a\xE1]lid",
|
|
34
|
+
"obrigat[o\xF3]ri",
|
|
35
|
+
"j[a\xE1]\\s+existe",
|
|
36
|
+
"duplicad",
|
|
37
|
+
"muito\\s+curto",
|
|
38
|
+
"n[a\xE3]o\\s+(?:foi|pode)",
|
|
39
|
+
"deve\\s+ser",
|
|
40
|
+
"selecione",
|
|
41
|
+
"escolha",
|
|
42
|
+
"preencha",
|
|
43
|
+
"corrija"
|
|
44
|
+
],
|
|
45
|
+
en: [
|
|
46
|
+
"invalid",
|
|
47
|
+
"required",
|
|
48
|
+
"already\\s+exists",
|
|
49
|
+
"too\\s+short",
|
|
50
|
+
"must\\s+be",
|
|
51
|
+
"select\\s+(?:the|a|an)",
|
|
52
|
+
"please\\s+(?:enter|choose|select|fill)",
|
|
53
|
+
"can'?t\\s+be\\s+(?:empty|blank)",
|
|
54
|
+
"cannot\\s+be\\s+(?:empty|blank)"
|
|
55
|
+
],
|
|
56
|
+
es: [
|
|
57
|
+
"obligatori",
|
|
58
|
+
"ya\\s+existe",
|
|
59
|
+
"demasiado\\s+corto",
|
|
60
|
+
"debe\\s+ser",
|
|
61
|
+
"seleccione",
|
|
62
|
+
"elija",
|
|
63
|
+
"complet[ae]\\s+(?:el|los|este)",
|
|
64
|
+
"no\\s+puede\\s+(?:estar|quedar)\\s+vac"
|
|
65
|
+
],
|
|
66
|
+
fr: [
|
|
67
|
+
"invalide",
|
|
68
|
+
"obligatoire",
|
|
69
|
+
"existe\\s+d[e\xE9]j[a\xE0]",
|
|
70
|
+
"trop\\s+court",
|
|
71
|
+
"doit\\s+[\xEAe]tre",
|
|
72
|
+
"s[e\xE9]lectionnez",
|
|
73
|
+
"choisissez",
|
|
74
|
+
"veuillez\\s+(?:saisir|choisir|remplir|s[e\xE9]lectionner)",
|
|
75
|
+
"ne\\s+peut\\s+pas\\s+[\xEAe]tre\\s+vide"
|
|
76
|
+
]
|
|
77
|
+
};
|
|
78
|
+
var VALIDATION_SHARED = ["format[oa]?\\b", "\\bformat\\b"];
|
|
79
|
+
var WRITE_SUCCESS = {
|
|
80
|
+
pt: [
|
|
81
|
+
"cadastrad[oa]s?\\s+com\\s+sucesso",
|
|
82
|
+
"registrad[oa]s?\\s+com\\s+sucesso",
|
|
83
|
+
"salv[oa]s?\\s+com\\s+sucesso",
|
|
84
|
+
"criad[oa]s?\\s+com\\s+sucesso",
|
|
85
|
+
"atualizad[oa]s?\\s+com\\s+sucesso",
|
|
86
|
+
"foi\\s+cadastrad[oa]",
|
|
87
|
+
"foi\\s+registrad[oa]",
|
|
88
|
+
"foi\\s+salv[oa]",
|
|
89
|
+
"foi\\s+criad[oa]"
|
|
90
|
+
],
|
|
91
|
+
en: [
|
|
92
|
+
"successfully\\s+(?:registered|saved|created|updated|added)",
|
|
93
|
+
"(?:has\\s+been|was)\\s+(?:registered|saved|created|updated|added)"
|
|
94
|
+
],
|
|
95
|
+
es: [
|
|
96
|
+
"registrad[oa]s?\\s+(?:exitosamente|correctamente|con\\s+[e\xE9]xito)",
|
|
97
|
+
"guardad[oa]s?\\s+(?:correctamente|con\\s+[e\xE9]xito)",
|
|
98
|
+
"cread[oa]s?\\s+(?:correctamente|con\\s+[e\xE9]xito)",
|
|
99
|
+
"se\\s+ha\\s+(?:guardado|creado|registrado|actualizado)"
|
|
100
|
+
],
|
|
101
|
+
fr: [
|
|
102
|
+
"(?:enregistr|cr[e\xE9]|ajout|mis\\s+[a\xE0]\\s+jour)[e\xE9]?e?s?\\s+avec\\s+succ[e\xE8]s",
|
|
103
|
+
"a\\s+[e\xE9]t[e\xE9]\\s+(?:enregistr|cr[e\xE9]|ajout|sauvegard)[e\xE9]e?"
|
|
104
|
+
]
|
|
105
|
+
};
|
|
106
|
+
var COMPLETION_CLAIM = {
|
|
107
|
+
pt: [
|
|
108
|
+
"j[a\xE1]\\s+(?:cadastrei|registrei|salvei|criei)",
|
|
109
|
+
"conclu[i\xED]\\s+o\\s+cadastro",
|
|
110
|
+
"cadastro\\s+(?:foi\\s+)?(?:conclu[i\xED]do|realizado|feito)"
|
|
111
|
+
],
|
|
112
|
+
en: [
|
|
113
|
+
"i(?:'|\u2019)?ve\\s+(?:registered|saved|created|added)",
|
|
114
|
+
"i\\s+have\\s+(?:registered|saved|created|added)"
|
|
115
|
+
],
|
|
116
|
+
es: ["ya\\s+(?:lo\\s+|la\\s+)?(?:registr[e\xE9]|guard[e\xE9]|cre[e\xE9])"],
|
|
117
|
+
fr: ["j(?:e\\s+l(?:'|\u2019)ai|(?:'|\u2019)ai)\\s+(?:enregistr|cr[e\xE9]|ajout|sauvegard)[e\xE9]"]
|
|
118
|
+
};
|
|
119
|
+
var SUBMIT_CONTROL = {
|
|
120
|
+
pt: ["cadastrar", "registrar", "salvar", "enviar", "confirmar"],
|
|
121
|
+
en: ["submit", "register", "save", "confirm"],
|
|
122
|
+
es: ["guardar", "registrar", "enviar", "confirmar", "aceptar"],
|
|
123
|
+
fr: ["enregistrer", "soumettre", "envoyer", "confirmer", "valider"]
|
|
124
|
+
};
|
|
125
|
+
var SUBMIT_LABEL_EXTRA = {
|
|
126
|
+
pt: ["criar", "adicionar", "concluir", "finalizar"],
|
|
127
|
+
en: ["create", "add", "done", "finish", "continue"],
|
|
128
|
+
es: ["crear", "a[\xF1n]adir", "agregar", "continuar", "finalizar"],
|
|
129
|
+
fr: ["cr[e\xE9]er", "ajouter", "terminer", "continuer"]
|
|
130
|
+
};
|
|
131
|
+
var CREATE_EDIT_ROUTE = {
|
|
132
|
+
pt: ["cadastr", "criar", "novo", "nova", "registr", "edit"],
|
|
133
|
+
en: ["create", "edit", "form", "new", "add"],
|
|
134
|
+
es: ["crear", "nuevo", "nueva", "editar", "alta"],
|
|
135
|
+
fr: ["cr[e\xE9]er", "nouveau", "nouvelle", "modifier", "ajout"]
|
|
136
|
+
};
|
|
137
|
+
var WRITE_INTENT = {
|
|
138
|
+
pt: ["cadastr\\w*", "registr\\w*", "cria\\w*", "adiciona\\w*", "salv\\w*"],
|
|
139
|
+
en: [
|
|
140
|
+
"creat(?:e|es|ed|ing|ion)",
|
|
141
|
+
"save[sd]?",
|
|
142
|
+
"saving",
|
|
143
|
+
"add(?:s|ed|ing)?",
|
|
144
|
+
"submit\\w*",
|
|
145
|
+
"register\\w*"
|
|
146
|
+
],
|
|
147
|
+
es: ["crea\\w*", "guarda\\w*", "a[n\xF1]ad\\w*", "agrega\\w*", "registra\\w*"],
|
|
148
|
+
fr: ["cr[e\xE9][e\xE9]\\w*", "enregistr\\w*", "ajout\\w*", "sauvegard\\w*", "soumet\\w*"]
|
|
149
|
+
};
|
|
150
|
+
var FORM_VALIDATION_TEXT_RE = new RegExp(`(${build(VALIDATION, VALIDATION_SHARED)})`, "i");
|
|
151
|
+
var FORM_WRITE_SUCCESS_TEXT_RE = new RegExp(`\\b(${build(WRITE_SUCCESS)})`, "i");
|
|
152
|
+
new RegExp(`\\b(${build(WRITE_INTENT)})\\b`, "i");
|
|
153
|
+
new RegExp(
|
|
154
|
+
`\\b(${build(WRITE_SUCCESS)}|${build(COMPLETION_CLAIM)})`,
|
|
155
|
+
"i"
|
|
156
|
+
);
|
|
157
|
+
var SUBMIT_CONTROL_RE = new RegExp(`(${build(SUBMIT_CONTROL)})`, "i");
|
|
158
|
+
new RegExp(
|
|
159
|
+
`(${build(SUBMIT_CONTROL)}|${build(SUBMIT_LABEL_EXTRA)})`,
|
|
160
|
+
"i"
|
|
161
|
+
);
|
|
162
|
+
var CREATE_EDIT_ROUTE_RE = new RegExp(`(${build(CREATE_EDIT_ROUTE)})`, "i");
|
|
163
|
+
|
|
17
164
|
// ../shared/dist/chunk-43YQ52Q7.mjs
|
|
18
165
|
var SENSITIVE_FIELD_NAME_RE = /(\b|_|-)(password|senha|contrase[ñn]a|mot[\s_-]*de[\s_-]*passe|passwd|pwd|secret|token|api[\s_-]*key|access[\s_-]*key|private[\s_-]*key|cvv|cvc|cvn|cvc2|cid|pin(?:[\s_-]*code)?|otp|one[\s_-]*time[\s_-]*code|2fa|mfa|security[\s_-]*code|c[óo]digo[\s_-]*seguran[çc]a|c[óo]digo[\s_-]*verifica[çc][ãa]o|verification[\s_-]*code)(\b|_|-)/i;
|
|
19
166
|
function isSensitiveFieldName(id, label, placeholder, type) {
|
|
@@ -28,6 +175,39 @@ function isSensitiveFieldName(id, label, placeholder, type) {
|
|
|
28
175
|
|
|
29
176
|
// ../client-core/dist/index.mjs
|
|
30
177
|
var SDK_VERSION = "0.1.0";
|
|
178
|
+
var _enabled;
|
|
179
|
+
var _resolve;
|
|
180
|
+
function setAppilotsDebugEnabled(enabled) {
|
|
181
|
+
_enabled = enabled;
|
|
182
|
+
}
|
|
183
|
+
function setAppilotsDebugResolver(resolve) {
|
|
184
|
+
_resolve = resolve;
|
|
185
|
+
}
|
|
186
|
+
function isAppilotsDebugEnabled() {
|
|
187
|
+
if (_enabled !== void 0) return _enabled;
|
|
188
|
+
try {
|
|
189
|
+
return _resolve?.() === true;
|
|
190
|
+
} catch {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function appilotsDebugLog(...args) {
|
|
195
|
+
if (!isAppilotsDebugEnabled()) return;
|
|
196
|
+
console.log("[Appilots]", ...args);
|
|
197
|
+
}
|
|
198
|
+
function appilotsDebugWarn(...args) {
|
|
199
|
+
if (!isAppilotsDebugEnabled()) return;
|
|
200
|
+
console.log("[Appilots]", ...args);
|
|
201
|
+
}
|
|
202
|
+
function describeValue(value) {
|
|
203
|
+
if (value === void 0) return "undefined";
|
|
204
|
+
if (value === null) return "null";
|
|
205
|
+
if (typeof value === "string") return `string(len=${value.length})`;
|
|
206
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
207
|
+
if (Array.isArray(value)) return `array(len=${value.length})`;
|
|
208
|
+
if (typeof value === "object") return `object(keys=${Object.keys(value).length})`;
|
|
209
|
+
return typeof value;
|
|
210
|
+
}
|
|
31
211
|
var StreamTransportError = class extends Error {
|
|
32
212
|
constructor(message) {
|
|
33
213
|
super(message);
|
|
@@ -58,6 +238,13 @@ function parseRetryAfter(...candidates) {
|
|
|
58
238
|
return 60;
|
|
59
239
|
}
|
|
60
240
|
var CONTINUATION_TIMEOUT_MS = 15e4;
|
|
241
|
+
function safeJson(text) {
|
|
242
|
+
try {
|
|
243
|
+
return JSON.parse(text || "{}");
|
|
244
|
+
} catch {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
61
248
|
var AppilotsClient = class {
|
|
62
249
|
baseUrl;
|
|
63
250
|
projectId;
|
|
@@ -72,7 +259,7 @@ var AppilotsClient = class {
|
|
|
72
259
|
identified = false;
|
|
73
260
|
constructor(options) {
|
|
74
261
|
this.projectId = options.projectId;
|
|
75
|
-
this.baseUrl = (options.apiBaseUrl
|
|
262
|
+
this.baseUrl = normalizeApiBaseUrl(options.apiBaseUrl);
|
|
76
263
|
this.timeout = options.timeout ?? 6e4;
|
|
77
264
|
this.debug = options.debug ?? false;
|
|
78
265
|
this.mcpVersion = options.mcpVersion;
|
|
@@ -91,8 +278,25 @@ var AppilotsClient = class {
|
|
|
91
278
|
...options.headers
|
|
92
279
|
};
|
|
93
280
|
}
|
|
281
|
+
/**
|
|
282
|
+
* A 404 on an `/agent/*` path is almost never a missing record — those
|
|
283
|
+
* routes are static. It means the request reached SOMETHING that is not
|
|
284
|
+
* this API, or reached it at the wrong mount point, and the server's own
|
|
285
|
+
* message ("Route not found") tells the integrator nothing about which.
|
|
286
|
+
*
|
|
287
|
+
* The symptom is unmistakable once you have seen it: every message
|
|
288
|
+
* fails, including a plain "hello" that needs no tool at all, because
|
|
289
|
+
* nothing ever reaches the agent. Left as-is it reads like the agent is
|
|
290
|
+
* broken.
|
|
291
|
+
*/
|
|
292
|
+
explainIfMisroutedBaseUrl(status, json, fallback) {
|
|
293
|
+
if (status !== 404) return fallback;
|
|
294
|
+
const code = json?.error?.code;
|
|
295
|
+
if (code !== "NOT_FOUND") return fallback;
|
|
296
|
+
return `${fallback} \u2014 the Appilots API answered 404 for every path under ${this.baseUrl}. That usually means apiBaseUrl points somewhere this API is not mounted. The hosted API is https://api.appilots.com${APPILOTS_API_PATH_PREFIX}; a local stack is http://localhost:4000${APPILOTS_API_PATH_PREFIX}.`;
|
|
297
|
+
}
|
|
94
298
|
log(...args) {
|
|
95
|
-
if (this.debug)
|
|
299
|
+
if (this.debug) appilotsDebugLog("[AppilotsClient]", ...args);
|
|
96
300
|
}
|
|
97
301
|
describeNonJsonResponse(url, response, body) {
|
|
98
302
|
const contentType = response.headers?.get?.("content-type") ?? "unknown content-type";
|
|
@@ -126,13 +330,10 @@ var AppilotsClient = class {
|
|
|
126
330
|
if (response.status === 429) {
|
|
127
331
|
throw new RateLimitedError(
|
|
128
332
|
errorMsg,
|
|
129
|
-
parseRetryAfter(
|
|
130
|
-
json?.error?.retryAfterSeconds,
|
|
131
|
-
response.headers?.get?.("retry-after")
|
|
132
|
-
)
|
|
333
|
+
parseRetryAfter(json?.error?.retryAfterSeconds, response.headers?.get?.("retry-after"))
|
|
133
334
|
);
|
|
134
335
|
}
|
|
135
|
-
throw new Error(errorMsg);
|
|
336
|
+
throw new Error(this.explainIfMisroutedBaseUrl(response.status, json, errorMsg));
|
|
136
337
|
}
|
|
137
338
|
return json.data ?? json;
|
|
138
339
|
} finally {
|
|
@@ -247,7 +448,11 @@ var AppilotsClient = class {
|
|
|
247
448
|
content: data.message.summary,
|
|
248
449
|
timestamp: Date.now()
|
|
249
450
|
} : void 0;
|
|
250
|
-
this.log("Response received:", {
|
|
451
|
+
this.log("Response received:", {
|
|
452
|
+
messageId: message.id,
|
|
453
|
+
actions: actions?.length ?? 0,
|
|
454
|
+
hasSummary: !!summaryMessage
|
|
455
|
+
});
|
|
251
456
|
return {
|
|
252
457
|
sessionId: this.sessionId,
|
|
253
458
|
message,
|
|
@@ -388,17 +593,17 @@ var AppilotsClient = class {
|
|
|
388
593
|
fail(
|
|
389
594
|
new RateLimitedError(
|
|
390
595
|
message2,
|
|
391
|
-
parseRetryAfter(
|
|
392
|
-
retryAfterSeconds,
|
|
393
|
-
xhr.getResponseHeader?.("retry-after")
|
|
394
|
-
)
|
|
596
|
+
parseRetryAfter(retryAfterSeconds, xhr.getResponseHeader?.("retry-after"))
|
|
395
597
|
)
|
|
396
598
|
);
|
|
397
599
|
return;
|
|
398
600
|
}
|
|
399
|
-
|
|
400
|
-
|
|
601
|
+
const explained = this.explainIfMisroutedBaseUrl(
|
|
602
|
+
xhr.status,
|
|
603
|
+
safeJson(xhr.responseText),
|
|
604
|
+
message2
|
|
401
605
|
);
|
|
606
|
+
fail(sawAnyEvent ? new Error(explained) : new StreamTransportError(explained));
|
|
402
607
|
return;
|
|
403
608
|
}
|
|
404
609
|
if (!doneEvent) {
|
|
@@ -580,7 +785,9 @@ var AppilotsClient = class {
|
|
|
580
785
|
};
|
|
581
786
|
case "navigate":
|
|
582
787
|
return {
|
|
583
|
-
|
|
788
|
+
// No `?? ''` here: an empty string would make a goBack look
|
|
789
|
+
// like a navigate to a nameless screen further down (#398).
|
|
790
|
+
screenName: typeof payload.screenName === "string" ? payload.screenName : void 0,
|
|
584
791
|
params: payload.params,
|
|
585
792
|
navigationAction: payload.navigationAction ?? "navigate",
|
|
586
793
|
path: Array.isArray(payload.path) ? payload.path : void 0
|
|
@@ -1113,8 +1320,15 @@ function subscribeAppilotsDebugTraces(listener) {
|
|
|
1113
1320
|
};
|
|
1114
1321
|
}
|
|
1115
1322
|
var INTERNAL_MARKER_RE = /^\[(?:Permission policy notice|Recovery exhausted|User rejected the proposed action)[^\]]*\]:\s*/i;
|
|
1116
|
-
var
|
|
1117
|
-
var
|
|
1323
|
+
var INTERNAL_ID_SRC = 'el:[^\\s".]+|list-\\d+-item-\\d+';
|
|
1324
|
+
var TECHNICAL_FIELD_SRC = "\\b(?:targetId|componentId|screenName|actionId|fieldId|elementId|testID|test-id|accessibilityId|accessibility-id)\\s*[:=_-]\\s*\\S+";
|
|
1325
|
+
var TECHNICAL_SELECTOR_RE = new RegExp(`${INTERNAL_ID_SRC}|${TECHNICAL_FIELD_SRC}`, "i");
|
|
1326
|
+
var TOOL_NAME_SRC = "(?:form_fill|ui_interaction|scroll_list)\\b";
|
|
1327
|
+
var TOOL_VERB_WITH_ID_SRC = `(?:press|click|tap|navigate)\\w*\\b[^\\n]{0,40}?(?:${INTERNAL_ID_SRC})`;
|
|
1328
|
+
var TECHNICAL_TRACE_RE = new RegExp(
|
|
1329
|
+
`(^|\\n)\\s*(?:Results:|[-*]\\s*[\u2713\u2717]\\s+|${TOOL_NAME_SRC}|${TOOL_VERB_WITH_ID_SRC}|(?:Cliquei|Clicked)\\s+em\\s+(?:${INTERNAL_ID_SRC}|[A-Za-z][\\w-]*:))`,
|
|
1330
|
+
"i"
|
|
1331
|
+
);
|
|
1118
1332
|
function sanitizeVisibleAssistantContent(content) {
|
|
1119
1333
|
return content.split("\n").map((line) => line.replace(INTERNAL_MARKER_RE, "").trimEnd()).filter((line) => !INTERNAL_MARKER_RE.test(line)).join("\n").trim();
|
|
1120
1334
|
}
|
|
@@ -1122,7 +1336,7 @@ function humanizeAssistantFallback(content) {
|
|
|
1122
1336
|
let text = sanitizeVisibleAssistantContent(content).replace(/\blist-\d+-item-\d+\b/gi, "o item da lista").replace(/\bel:[^\s".]+/gi, "o elemento").replace(
|
|
1123
1337
|
/"\s*(?:press|click|tap|navigate|form_fill|ui_interaction|scroll_list)\s+on\s+[^"]+"/gi,
|
|
1124
1338
|
'"a a\xE7\xE3o solicitada"'
|
|
1125
|
-
).
|
|
1339
|
+
).trim();
|
|
1126
1340
|
if (text.length < 16) return null;
|
|
1127
1341
|
const probe = {
|
|
1128
1342
|
role: "assistant",
|
|
@@ -1137,9 +1351,8 @@ function isInternalTraceMessage(message) {
|
|
|
1137
1351
|
if (!content) return true;
|
|
1138
1352
|
return TECHNICAL_TRACE_RE.test(content) || TECHNICAL_SELECTOR_RE.test(content);
|
|
1139
1353
|
}
|
|
1140
|
-
var CREATE_FORM_ROUTE_RE =
|
|
1141
|
-
var SUBMIT_BUTTON_RE =
|
|
1142
|
-
var FORM_VALIDATION_TEXT_RE = /(inv[aá]lid|obrigat[oó]ri|required|invalid|j[aá]\s+existe|already\s+exists|duplicad|formato|format|too\s+short|muito\s+curto|n[aã]o\s+(?:foi|pode)|must\s+be|deve\s+ser|selecione|escolha|select\s+(?:the|a|o|an))/i;
|
|
1354
|
+
var CREATE_FORM_ROUTE_RE = CREATE_EDIT_ROUTE_RE;
|
|
1355
|
+
var SUBMIT_BUTTON_RE = SUBMIT_CONTROL_RE;
|
|
1143
1356
|
function normalize2(value) {
|
|
1144
1357
|
return value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
|
|
1145
1358
|
}
|
|
@@ -1157,7 +1370,9 @@ function snapshotHasVisibleSubmitButton(snap) {
|
|
|
1157
1370
|
);
|
|
1158
1371
|
}
|
|
1159
1372
|
function snapshotHasVisibleValidation(snap) {
|
|
1160
|
-
return (snap.texts ?? []).some(
|
|
1373
|
+
return (snap.texts ?? []).some(
|
|
1374
|
+
(text) => typeof text === "string" && FORM_VALIDATION_TEXT_RE.test(text)
|
|
1375
|
+
);
|
|
1161
1376
|
}
|
|
1162
1377
|
function snapshotShowsOpenCreateForm(snap, activePath = []) {
|
|
1163
1378
|
if (!snap) return false;
|
|
@@ -1574,9 +1789,10 @@ var ChatSessionMachine = class {
|
|
|
1574
1789
|
};
|
|
1575
1790
|
}
|
|
1576
1791
|
const hasToolWithoutEffect = toolWithoutEffectIds.has(actionId);
|
|
1792
|
+
const observedNoEffect = hasToolWithoutEffect || r.effect === "none";
|
|
1577
1793
|
let recoveryAttempt = 0;
|
|
1578
1794
|
let recoveryExhausted = false;
|
|
1579
|
-
if (!r.success ||
|
|
1795
|
+
if (!r.skipped && (!r.success || observedNoEffect)) {
|
|
1580
1796
|
const previous = this.recoveryCountByFingerprint.get(r.fingerprint) ?? 0;
|
|
1581
1797
|
const next = previous + 1;
|
|
1582
1798
|
this.recoveryCountByFingerprint.set(r.fingerprint, next);
|
|
@@ -1593,16 +1809,18 @@ var ChatSessionMachine = class {
|
|
|
1593
1809
|
recoveryAttempt,
|
|
1594
1810
|
recoveryExhausted,
|
|
1595
1811
|
toolWithoutEffect: hasToolWithoutEffect,
|
|
1596
|
-
effect:
|
|
1812
|
+
effect: observedNoEffect ? "none" : r.effect,
|
|
1597
1813
|
userVisibleStatusKey: r.userVisibleStatusKey
|
|
1598
1814
|
};
|
|
1599
1815
|
});
|
|
1600
1816
|
const exhausted = results.filter((r) => r.recoveryExhausted);
|
|
1601
1817
|
this.setState({
|
|
1602
|
-
loadingStatusKey: results.some(
|
|
1818
|
+
loadingStatusKey: results.some(
|
|
1819
|
+
(r) => !r.success || r.toolWithoutEffect || r.effect === "none"
|
|
1820
|
+
) ? "statusAdjusting" : "statusAnalyzing"
|
|
1603
1821
|
});
|
|
1604
|
-
|
|
1605
|
-
`
|
|
1822
|
+
appilotsDebugLog(
|
|
1823
|
+
`ChatSessionMachine: running continuation hop=${turn.hop} (${results.filter((r) => r.success).length}/${results.length} succeeded` + (exhausted.length > 0 ? `, ${exhausted.length} recovery-exhausted` : "") + ")"
|
|
1606
1824
|
);
|
|
1607
1825
|
const response = await this.deps.client.continueAgent(results, context, turn.hop);
|
|
1608
1826
|
this.addAssistantMessage(response.message);
|
|
@@ -1675,6 +1893,7 @@ var ChatSessionMachine = class {
|
|
|
1675
1893
|
const diagnose = event.data?.diagnose;
|
|
1676
1894
|
const effect = event.data?.effect;
|
|
1677
1895
|
const userVisibleStatusKey = event.data?.userVisibleStatusKey;
|
|
1896
|
+
const skipped = event.data?.skipped === true;
|
|
1678
1897
|
const existing = turn.results.get(actionId);
|
|
1679
1898
|
if (existing) {
|
|
1680
1899
|
existing.success = success;
|
|
@@ -1682,6 +1901,7 @@ var ChatSessionMachine = class {
|
|
|
1682
1901
|
existing.diagnose = diagnose;
|
|
1683
1902
|
existing.effect = effect;
|
|
1684
1903
|
existing.userVisibleStatusKey = userVisibleStatusKey;
|
|
1904
|
+
existing.skipped = skipped;
|
|
1685
1905
|
}
|
|
1686
1906
|
turn.reportedIds.add(actionId);
|
|
1687
1907
|
if (turn.reportedIds.size >= turn.actionIds.size) {
|
|
@@ -1718,8 +1938,8 @@ var ChatSessionMachine = class {
|
|
|
1718
1938
|
this.abortController = abortController;
|
|
1719
1939
|
try {
|
|
1720
1940
|
const context = this.deps.adapter.buildContext();
|
|
1721
|
-
|
|
1722
|
-
`
|
|
1941
|
+
appilotsDebugLog(
|
|
1942
|
+
`ChatSessionMachine sendMessage: context \u2014 currentScreen="${context.currentScreen ?? "unknown"}", snapshot={texts:${context.snapshot?.texts?.length ?? 0}, inputs:${context.snapshot?.inputs?.length ?? 0}, buttons:${context.snapshot?.buttons?.length ?? 0}, elements:${context.snapshot?.elements?.length ?? 0}, lists:${context.snapshot?.lists?.length ?? 0}, listItems:${(context.snapshot?.lists ?? []).reduce((acc, l) => acc + (l.items?.length ?? 0), 0)}, choiceGroups:${context.snapshot?.choiceGroups?.length ?? 0}}`
|
|
1723
1943
|
);
|
|
1724
1944
|
let response;
|
|
1725
1945
|
if (streamingEnabled) {
|
|
@@ -1747,9 +1967,7 @@ var ChatSessionMachine = class {
|
|
|
1747
1967
|
});
|
|
1748
1968
|
} catch (err) {
|
|
1749
1969
|
if (err instanceof StreamTransportError) {
|
|
1750
|
-
|
|
1751
|
-
`[Appilots] streaming unavailable, falling back to JSON: ${err.message}`
|
|
1752
|
-
);
|
|
1970
|
+
appilotsDebugWarn(`streaming unavailable, falling back to JSON: ${err.message}`);
|
|
1753
1971
|
response = await this.deps.client.sendMessage(content.trim(), context);
|
|
1754
1972
|
} else {
|
|
1755
1973
|
throw err;
|
|
@@ -1758,8 +1976,8 @@ var ChatSessionMachine = class {
|
|
|
1758
1976
|
} else {
|
|
1759
1977
|
response = await this.deps.client.sendMessage(content.trim(), context);
|
|
1760
1978
|
}
|
|
1761
|
-
|
|
1762
|
-
`
|
|
1979
|
+
appilotsDebugLog(
|
|
1980
|
+
`ChatSessionMachine sendMessage: response received \u2014 actions=${response.actions?.length ?? 0}, hasSummary=${!!response.summaryMessage}`
|
|
1763
1981
|
);
|
|
1764
1982
|
removeStreamingPlaceholder();
|
|
1765
1983
|
this.addAssistantMessage(response.message);
|
|
@@ -1849,7 +2067,11 @@ function isStructuredRisky(value) {
|
|
|
1849
2067
|
}
|
|
1850
2068
|
function actionMetadataRequiresConfirmation(meta) {
|
|
1851
2069
|
if (meta.requiresConfirmation === true || meta.destructive === true || meta.effect === "destructive" || meta.riskLevel === "high" || meta.risk === "destructive") {
|
|
1852
|
-
return {
|
|
2070
|
+
return {
|
|
2071
|
+
required: true,
|
|
2072
|
+
label: typeof meta.label === "string" ? meta.label : void 0,
|
|
2073
|
+
source: "screen-metadata"
|
|
2074
|
+
};
|
|
1853
2075
|
}
|
|
1854
2076
|
return { required: false };
|
|
1855
2077
|
}
|
|
@@ -1890,13 +2112,9 @@ function toDestructiveConfirmPayload(confirm, policy, fallbackLabel) {
|
|
|
1890
2112
|
const labelText = policy.label ?? existingDescription ?? fallbackLabel ?? "esta a\xE7\xE3o";
|
|
1891
2113
|
return {
|
|
1892
2114
|
...payload,
|
|
1893
|
-
title: "A\xE7\xE3o destrutiva",
|
|
1894
|
-
message: `Tem certeza que deseja "${labelText}"?`,
|
|
1895
2115
|
actionDescription: labelText,
|
|
1896
2116
|
severity: "danger",
|
|
1897
|
-
destructive: true
|
|
1898
|
-
confirmLabel: typeof payload.confirmLabel === "string" && payload.confirmLabel ? payload.confirmLabel : "Sim, executar",
|
|
1899
|
-
cancelLabel: typeof payload.cancelLabel === "string" && payload.cancelLabel ? payload.cancelLabel : "Cancelar"
|
|
2117
|
+
destructive: true
|
|
1900
2118
|
};
|
|
1901
2119
|
}
|
|
1902
2120
|
function confirmNeedsDestructiveUpgrade(confirm) {
|
|
@@ -1962,8 +2180,8 @@ var ActionQueueMachine = class {
|
|
|
1962
2180
|
if (event.type !== "agent:action:start") return;
|
|
1963
2181
|
const action = event.data?.action;
|
|
1964
2182
|
if (!action?.id) return;
|
|
1965
|
-
|
|
1966
|
-
`
|
|
2183
|
+
appilotsDebugLog(
|
|
2184
|
+
`ActionQueueMachine: received agent:action:start event, action id="${action.id}", type="${action.type}"`
|
|
1967
2185
|
);
|
|
1968
2186
|
if (this.state.actions.some((a) => a.id === action.id)) return;
|
|
1969
2187
|
this.setActions([...this.state.actions, action]);
|
|
@@ -2064,8 +2282,8 @@ var ActionQueueMachine = class {
|
|
|
2064
2282
|
if (!policy.required) return false;
|
|
2065
2283
|
const confirmId = `confirm-local-${target.id}`;
|
|
2066
2284
|
if (this.state.actions.some((a) => a.id === confirmId)) return true;
|
|
2067
|
-
|
|
2068
|
-
`
|
|
2285
|
+
appilotsDebugLog(
|
|
2286
|
+
`ActionQueueMachine: action "${componentId || target.id}" requires confirmation (${policy.source ?? "local-policy"}) \u2014 synthesising local confirm (id="${confirmId}")`
|
|
2069
2287
|
);
|
|
2070
2288
|
const synth = {
|
|
2071
2289
|
id: confirmId,
|
|
@@ -2111,13 +2329,13 @@ var ActionQueueMachine = class {
|
|
|
2111
2329
|
const pending = this.state.actions.filter(
|
|
2112
2330
|
(a) => a.status === "pending" && !this.processed.has(a.id)
|
|
2113
2331
|
);
|
|
2114
|
-
|
|
2115
|
-
`
|
|
2332
|
+
appilotsDebugLog(
|
|
2333
|
+
`ActionQueueMachine: autoExecute check \u2014 ${pending.length} pending action(s) to process`
|
|
2116
2334
|
);
|
|
2117
2335
|
let lastWasNavigate = false;
|
|
2118
2336
|
let preNavScreen = null;
|
|
2119
2337
|
let preNavSignature = null;
|
|
2120
|
-
for (const action of pending) {
|
|
2338
|
+
for (const [index, action] of pending.entries()) {
|
|
2121
2339
|
if (action.type === "confirm") {
|
|
2122
2340
|
continue;
|
|
2123
2341
|
}
|
|
@@ -2127,14 +2345,14 @@ var ActionQueueMachine = class {
|
|
|
2127
2345
|
const gate = findGatingConfirm(action, this.state.actions);
|
|
2128
2346
|
if (gate) {
|
|
2129
2347
|
if (gate.status === "pending" || gate.status === "executing") {
|
|
2130
|
-
|
|
2131
|
-
`
|
|
2348
|
+
appilotsDebugLog(
|
|
2349
|
+
`ActionQueueMachine: action id="${action.id}" is gated by confirm id="${gate.id}" (status=${gate.status}); waiting for user decision`
|
|
2132
2350
|
);
|
|
2133
2351
|
continue;
|
|
2134
2352
|
}
|
|
2135
2353
|
if (gate.status === "failed") {
|
|
2136
|
-
|
|
2137
|
-
`
|
|
2354
|
+
appilotsDebugLog(
|
|
2355
|
+
`ActionQueueMachine: confirm id="${gate.id}" was rejected; skipping gated action id="${action.id}"`
|
|
2138
2356
|
);
|
|
2139
2357
|
this.processed.add(action.id);
|
|
2140
2358
|
this.updateActions(
|
|
@@ -2166,12 +2384,12 @@ var ActionQueueMachine = class {
|
|
|
2166
2384
|
fromSignature: preNavSignature,
|
|
2167
2385
|
maxMs: 3500
|
|
2168
2386
|
});
|
|
2169
|
-
|
|
2170
|
-
`
|
|
2387
|
+
appilotsDebugLog(
|
|
2388
|
+
`ActionQueueMachine: post-navigate settle done \u2014 screen="${settle.screen}" transitioned=${settle.transitioned} timedOut=${settle.timedOut} waitedMs=${settle.waitedMs}`
|
|
2171
2389
|
);
|
|
2172
2390
|
}
|
|
2173
|
-
|
|
2174
|
-
`
|
|
2391
|
+
appilotsDebugLog(
|
|
2392
|
+
`ActionQueueMachine: auto-executing action id="${action.id}" type="${action.type}"`
|
|
2175
2393
|
);
|
|
2176
2394
|
this.processed.add(action.id);
|
|
2177
2395
|
if (action.type === "navigate") {
|
|
@@ -2180,20 +2398,67 @@ var ActionQueueMachine = class {
|
|
|
2180
2398
|
}
|
|
2181
2399
|
const succeeded = await this.approveAction(action.id);
|
|
2182
2400
|
if (!succeeded) {
|
|
2401
|
+
const failed = this.state.actions.find((candidate) => candidate.id === action.id);
|
|
2183
2402
|
this.warn(
|
|
2184
2403
|
`ActionQueueMachine: stopping current action batch after failed action id="${action.id}"`
|
|
2185
2404
|
);
|
|
2405
|
+
await this.skipRemainingBatchActions(pending.slice(index + 1), action, failed?.error);
|
|
2186
2406
|
break;
|
|
2187
2407
|
}
|
|
2188
2408
|
lastWasNavigate = action.type === "navigate";
|
|
2189
2409
|
}
|
|
2190
2410
|
}
|
|
2411
|
+
/**
|
|
2412
|
+
* A turn is an all-terminal contract: ChatSessionMachine cannot ask the
|
|
2413
|
+
* server for the next step until every action in the current batch has
|
|
2414
|
+
* reported a completion or an error. When an early action fails we must
|
|
2415
|
+
* not execute dependent actions, but leaving them `pending` deadlocks the
|
|
2416
|
+
* whole turn. Mark the untouched suffix as failed/skipped and emit the
|
|
2417
|
+
* same terminal event a real executor would have emitted.
|
|
2418
|
+
*/
|
|
2419
|
+
async skipRemainingBatchActions(remaining, failedAction, failureReason) {
|
|
2420
|
+
const skipped = remaining.filter((candidate) => {
|
|
2421
|
+
const current = this.state.actions.find((action) => action.id === candidate.id);
|
|
2422
|
+
if (current?.status !== "pending" || this.processed.has(candidate.id)) return false;
|
|
2423
|
+
if (candidate.type === "confirm") return false;
|
|
2424
|
+
const gate = findGatingConfirm(candidate, this.state.actions);
|
|
2425
|
+
if (gate && (gate.status === "pending" || gate.status === "executing")) return false;
|
|
2426
|
+
return true;
|
|
2427
|
+
});
|
|
2428
|
+
if (skipped.length === 0) return;
|
|
2429
|
+
const reason = `Skipped because previous action "${failedAction.id}" failed` + (failureReason ? `: ${failureReason}` : "");
|
|
2430
|
+
const skippedIds = new Set(skipped.map((action) => action.id));
|
|
2431
|
+
for (const action of skipped) this.processed.add(action.id);
|
|
2432
|
+
this.updateActions(
|
|
2433
|
+
(prev) => prev.map(
|
|
2434
|
+
(action) => skippedIds.has(action.id) ? { ...action, status: "failed", error: reason } : action
|
|
2435
|
+
)
|
|
2436
|
+
);
|
|
2437
|
+
for (const action of skipped) {
|
|
2438
|
+
try {
|
|
2439
|
+
await this.deps.client.completeAction(action.id, false, reason);
|
|
2440
|
+
} catch {
|
|
2441
|
+
}
|
|
2442
|
+
this.deps.emit({
|
|
2443
|
+
type: "agent:action:error",
|
|
2444
|
+
timestamp: Date.now(),
|
|
2445
|
+
data: {
|
|
2446
|
+
actionId: action.id,
|
|
2447
|
+
actionType: action.type,
|
|
2448
|
+
success: false,
|
|
2449
|
+
error: reason,
|
|
2450
|
+
skipped: true,
|
|
2451
|
+
blockedByActionId: failedAction.id
|
|
2452
|
+
}
|
|
2453
|
+
});
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2191
2456
|
// ── Approve & execute an action ─────────────────────────────
|
|
2192
2457
|
async approveAction(actionId) {
|
|
2193
2458
|
const action = this.state.actions.find((a) => a.id === actionId);
|
|
2194
2459
|
if (!action) return false;
|
|
2195
|
-
|
|
2196
|
-
`
|
|
2460
|
+
appilotsDebugLog(
|
|
2461
|
+
`ActionQueueMachine: action status transition: pending \u2192 executing (id="${actionId}", type="${action.type}")`
|
|
2197
2462
|
);
|
|
2198
2463
|
this.updateActions(
|
|
2199
2464
|
(prev) => prev.map((a) => a.id === actionId ? { ...a, status: "executing" } : a)
|
|
@@ -2205,8 +2470,8 @@ var ActionQueueMachine = class {
|
|
|
2205
2470
|
{ confirmedDestructive }
|
|
2206
2471
|
);
|
|
2207
2472
|
if (result.success) {
|
|
2208
|
-
|
|
2209
|
-
`
|
|
2473
|
+
appilotsDebugLog(
|
|
2474
|
+
`ActionQueueMachine: action status transition: executing \u2192 completed (id="${actionId}", type="${action.type}")`
|
|
2210
2475
|
);
|
|
2211
2476
|
this.updateActions(
|
|
2212
2477
|
(prev) => prev.map((a) => a.id === actionId ? { ...a, status: "completed" } : a)
|
|
@@ -2285,9 +2550,7 @@ var ActionQueueMachine = class {
|
|
|
2285
2550
|
return this.state.actions.filter((a) => a.status === "executing");
|
|
2286
2551
|
}
|
|
2287
2552
|
get completedActions() {
|
|
2288
|
-
return this.state.actions.filter(
|
|
2289
|
-
(a) => a.status === "completed" || a.status === "failed"
|
|
2290
|
-
);
|
|
2553
|
+
return this.state.actions.filter((a) => a.status === "completed" || a.status === "failed");
|
|
2291
2554
|
}
|
|
2292
2555
|
};
|
|
2293
2556
|
function normalize3(s) {
|
|
@@ -2316,13 +2579,11 @@ function normalizeId(value) {
|
|
|
2316
2579
|
function isOptionalCosmeticTargetId(targetId) {
|
|
2317
2580
|
if (typeof targetId !== "string" || !targetId.trim()) return false;
|
|
2318
2581
|
const id = normalizeId(targetId);
|
|
2319
|
-
return /
|
|
2582
|
+
return /sheetaction|sheet-action|photo-sheet|actionsheet|action-sheet/.test(id);
|
|
2320
2583
|
}
|
|
2321
2584
|
function routeLooksLikeFormContext(route) {
|
|
2322
2585
|
const haystack = normalizeId(route ?? "");
|
|
2323
|
-
return /create|edit|form|cadastr|register|novo|
|
|
2324
|
-
haystack
|
|
2325
|
-
);
|
|
2586
|
+
return /create|edit|form|cadastr|criar|register|registr|novo|nova/.test(haystack);
|
|
2326
2587
|
}
|
|
2327
2588
|
function screenPathParts(screen) {
|
|
2328
2589
|
if (!screen) return [];
|
|
@@ -2697,6 +2958,7 @@ function listItemElement(route, list, item) {
|
|
|
2697
2958
|
list.id ?? list.label ?? `list-${list.index}`,
|
|
2698
2959
|
key
|
|
2699
2960
|
]);
|
|
2961
|
+
const provenance = item.itemKey || item.reactKey ? "declared" : label ? "derived" : "positional";
|
|
2700
2962
|
const inModal = (item.buttons ?? []).some((button) => button.inModal) || (item.inputs ?? []).some((input) => input.inModal) || (item.toggles ?? []).some((toggle) => toggle.inModal);
|
|
2701
2963
|
return {
|
|
2702
2964
|
id,
|
|
@@ -2706,6 +2968,7 @@ function listItemElement(route, list, item) {
|
|
|
2706
2968
|
actions: ["press"],
|
|
2707
2969
|
disabled: false,
|
|
2708
2970
|
source: "list",
|
|
2971
|
+
provenance,
|
|
2709
2972
|
targetId: item.syntheticId,
|
|
2710
2973
|
...inModal ? { inModal: true } : {},
|
|
2711
2974
|
listContext: {
|
|
@@ -2735,17 +2998,14 @@ function buttonElement(route, button, index) {
|
|
|
2735
2998
|
disabled: button.disabled,
|
|
2736
2999
|
selected: button.selected,
|
|
2737
3000
|
source: "button",
|
|
3001
|
+
...button.provenance ? { provenance: button.provenance } : {},
|
|
2738
3002
|
targetId: button.id ?? button.label,
|
|
2739
3003
|
...button.inModal ? { inModal: true } : {}
|
|
2740
3004
|
};
|
|
2741
3005
|
}
|
|
2742
3006
|
function inputElement(route, input, index) {
|
|
2743
3007
|
const label = input.label ?? input.placeholder ?? input.id;
|
|
2744
|
-
const id = stableElementId([
|
|
2745
|
-
"input",
|
|
2746
|
-
route ?? "unknown",
|
|
2747
|
-
input.id ?? label ?? `input-${index}`
|
|
2748
|
-
]);
|
|
3008
|
+
const id = stableElementId(["input", route ?? "unknown", input.id ?? label ?? `input-${index}`]);
|
|
2749
3009
|
return {
|
|
2750
3010
|
id,
|
|
2751
3011
|
role: "input",
|
|
@@ -2754,6 +3014,7 @@ function inputElement(route, input, index) {
|
|
|
2754
3014
|
actions: ["focus", "setValue"],
|
|
2755
3015
|
disabled: input.editable === false,
|
|
2756
3016
|
source: "input",
|
|
3017
|
+
...input.provenance ? { provenance: input.provenance } : {},
|
|
2757
3018
|
targetId: input.id ?? input.label ?? input.placeholder,
|
|
2758
3019
|
...input.inModal ? { inModal: true } : {}
|
|
2759
3020
|
};
|
|
@@ -2773,10 +3034,45 @@ function toggleElement(route, toggle, index) {
|
|
|
2773
3034
|
actions: ["toggle", "press"],
|
|
2774
3035
|
selected: toggle.value,
|
|
2775
3036
|
source: "toggle",
|
|
3037
|
+
...toggle.provenance ? { provenance: toggle.provenance } : {},
|
|
2776
3038
|
targetId: toggle.id ?? toggle.label,
|
|
2777
3039
|
...toggle.inModal ? { inModal: true } : {}
|
|
2778
3040
|
};
|
|
2779
3041
|
}
|
|
3042
|
+
function listItemToggleElement(route, list, item, toggle, toggleIndex) {
|
|
3043
|
+
const rowLabel = labelForListItem(item);
|
|
3044
|
+
const label = toggle.label ?? rowLabel ?? toggle.id;
|
|
3045
|
+
const key = item.itemKey ?? item.reactKey ?? rowLabel ?? item.syntheticId;
|
|
3046
|
+
const id = stableElementId([
|
|
3047
|
+
"toggle",
|
|
3048
|
+
route ?? "unknown",
|
|
3049
|
+
list.id ?? list.label ?? `list-${list.index}`,
|
|
3050
|
+
key,
|
|
3051
|
+
toggle.id ?? `toggle-${toggleIndex}`
|
|
3052
|
+
]);
|
|
3053
|
+
return {
|
|
3054
|
+
id,
|
|
3055
|
+
role: "toggle",
|
|
3056
|
+
label,
|
|
3057
|
+
// The row's texts are what the user actually says out loud.
|
|
3058
|
+
texts: uniqueTexts([label, ...item.texts ?? []]),
|
|
3059
|
+
actions: ["toggle", "press"],
|
|
3060
|
+
selected: toggle.value,
|
|
3061
|
+
source: "list",
|
|
3062
|
+
...toggle.provenance ? { provenance: toggle.provenance } : {},
|
|
3063
|
+
targetId: toggle.id,
|
|
3064
|
+
listContext: {
|
|
3065
|
+
listIndex: list.index,
|
|
3066
|
+
listId: list.id,
|
|
3067
|
+
listLabel: list.label,
|
|
3068
|
+
itemIndex: item.index,
|
|
3069
|
+
itemKey: item.itemKey,
|
|
3070
|
+
reactKey: item.reactKey,
|
|
3071
|
+
syntheticId: item.syntheticId
|
|
3072
|
+
},
|
|
3073
|
+
...toggle.inModal ? { inModal: true } : {}
|
|
3074
|
+
};
|
|
3075
|
+
}
|
|
2780
3076
|
function sliderElement(route, slider, index) {
|
|
2781
3077
|
const label = slider.label ?? slider.id;
|
|
2782
3078
|
const id = stableElementId([
|
|
@@ -2792,37 +3088,48 @@ function sliderElement(route, slider, index) {
|
|
|
2792
3088
|
actions: ["setValue"],
|
|
2793
3089
|
disabled: slider.disabled,
|
|
2794
3090
|
source: "slider",
|
|
3091
|
+
...slider.provenance ? { provenance: slider.provenance } : {},
|
|
2795
3092
|
targetId: slider.id ?? slider.label,
|
|
2796
3093
|
...slider.inModal ? { inModal: true } : {}
|
|
2797
3094
|
};
|
|
2798
3095
|
}
|
|
2799
|
-
function deriveInteractionElements(snapshot) {
|
|
3096
|
+
function deriveInteractionElements(snapshot, options) {
|
|
2800
3097
|
const elements = [];
|
|
2801
3098
|
const seen = /* @__PURE__ */ new Set();
|
|
2802
|
-
const
|
|
3099
|
+
const rectOf = options?.rectOf;
|
|
3100
|
+
const push = (element, node) => {
|
|
2803
3101
|
if (!element.id || seen.has(element.id)) return;
|
|
2804
3102
|
seen.add(element.id);
|
|
2805
|
-
|
|
3103
|
+
const rect = rectOf && node !== void 0 ? rectOf(node) : void 0;
|
|
3104
|
+
elements.push(rect ? { ...element, rect } : element);
|
|
2806
3105
|
};
|
|
2807
3106
|
for (const list of snapshot.lists ?? []) {
|
|
2808
3107
|
for (const item of list.items ?? []) {
|
|
2809
|
-
push(listItemElement(snapshot.route, list, item));
|
|
3108
|
+
push(listItemElement(snapshot.route, list, item), item);
|
|
3109
|
+
for (const [toggleIndex, toggle] of (item.toggles ?? []).entries()) {
|
|
3110
|
+
push(listItemToggleElement(snapshot.route, list, item, toggle, toggleIndex), toggle);
|
|
3111
|
+
}
|
|
2810
3112
|
}
|
|
2811
3113
|
}
|
|
2812
3114
|
for (const [index, button] of (snapshot.buttons ?? []).entries()) {
|
|
2813
|
-
push(buttonElement(snapshot.route, button, index));
|
|
3115
|
+
push(buttonElement(snapshot.route, button, index), button);
|
|
2814
3116
|
}
|
|
2815
3117
|
for (const [index, input] of (snapshot.inputs ?? []).entries()) {
|
|
2816
|
-
push(inputElement(snapshot.route, input, index));
|
|
3118
|
+
push(inputElement(snapshot.route, input, index), input);
|
|
2817
3119
|
}
|
|
2818
3120
|
for (const [index, toggle] of (snapshot.toggles ?? []).entries()) {
|
|
2819
|
-
push(toggleElement(snapshot.route, toggle, index));
|
|
3121
|
+
push(toggleElement(snapshot.route, toggle, index), toggle);
|
|
2820
3122
|
}
|
|
2821
3123
|
for (const [index, slider] of (snapshot.sliders ?? []).entries()) {
|
|
2822
|
-
push(sliderElement(snapshot.route, slider, index));
|
|
3124
|
+
push(sliderElement(snapshot.route, slider, index), slider);
|
|
2823
3125
|
}
|
|
2824
3126
|
return elements;
|
|
2825
3127
|
}
|
|
3128
|
+
function toWireElement(entry) {
|
|
3129
|
+
if (entry.rect === void 0) return entry;
|
|
3130
|
+
const { rect: _rect, ...wire } = entry;
|
|
3131
|
+
return wire;
|
|
3132
|
+
}
|
|
2826
3133
|
function findElementForChoice(elements, option) {
|
|
2827
3134
|
if (option.targetId) {
|
|
2828
3135
|
const byTarget = elements.find((element) => element.targetId === option.targetId);
|
|
@@ -2863,6 +3170,7 @@ var WIRE_LIMITS = {
|
|
|
2863
3170
|
listItems: 500,
|
|
2864
3171
|
listDataPreview: 500,
|
|
2865
3172
|
listDataPreviewTextLength: 500,
|
|
3173
|
+
scrollables: 20,
|
|
2866
3174
|
choiceGroups: 100,
|
|
2867
3175
|
choiceOptions: 200,
|
|
2868
3176
|
elements: 1e3,
|
|
@@ -2943,6 +3251,9 @@ function clampSnapshotToWireLimits(snapshot) {
|
|
|
2943
3251
|
snapshot.lists = (cut.array(snapshot.lists, WIRE_LIMITS.lists) ?? []).map(
|
|
2944
3252
|
(list) => clampList(cut, list)
|
|
2945
3253
|
);
|
|
3254
|
+
if (snapshot.scrollables) {
|
|
3255
|
+
snapshot.scrollables = cut.array(snapshot.scrollables, WIRE_LIMITS.scrollables);
|
|
3256
|
+
}
|
|
2946
3257
|
snapshot.choiceGroups = (cut.array(snapshot.choiceGroups, WIRE_LIMITS.choiceGroups) ?? []).map(
|
|
2947
3258
|
(group) => clampChoiceGroup(cut, group)
|
|
2948
3259
|
);
|
|
@@ -2970,7 +3281,9 @@ var ComponentRegistryImpl = class {
|
|
|
2970
3281
|
*/
|
|
2971
3282
|
register(id, entry) {
|
|
2972
3283
|
this.components.set(id, entry);
|
|
2973
|
-
|
|
3284
|
+
appilotsDebugLog(
|
|
3285
|
+
`ComponentRegistry.register: id="${id}" kind="${entry.kind}" \u2014 total count: ${this.components.size}`
|
|
3286
|
+
);
|
|
2974
3287
|
this.notify(id, entry);
|
|
2975
3288
|
}
|
|
2976
3289
|
/**
|
|
@@ -2978,7 +3291,9 @@ var ComponentRegistryImpl = class {
|
|
|
2978
3291
|
*/
|
|
2979
3292
|
unregister(id) {
|
|
2980
3293
|
this.components.delete(id);
|
|
2981
|
-
|
|
3294
|
+
appilotsDebugLog(
|
|
3295
|
+
`ComponentRegistry.unregister: id="${id}" \u2014 total count: ${this.components.size}`
|
|
3296
|
+
);
|
|
2982
3297
|
this.notify(id, null);
|
|
2983
3298
|
}
|
|
2984
3299
|
/**
|
|
@@ -3082,14 +3397,14 @@ var ListRegistryImpl = class {
|
|
|
3082
3397
|
listeners = /* @__PURE__ */ new Set();
|
|
3083
3398
|
register(id, entry) {
|
|
3084
3399
|
this.lists.set(id, entry);
|
|
3085
|
-
|
|
3086
|
-
`
|
|
3400
|
+
appilotsDebugLog(
|
|
3401
|
+
`ListRegistry.register: id="${id}" component="${entry.component}" items=${entry.itemCount ?? "unknown"} \u2014 total count: ${this.lists.size}`
|
|
3087
3402
|
);
|
|
3088
3403
|
this.notify(id, entry);
|
|
3089
3404
|
}
|
|
3090
3405
|
unregister(id) {
|
|
3091
3406
|
this.lists.delete(id);
|
|
3092
|
-
|
|
3407
|
+
appilotsDebugLog(`ListRegistry.unregister: id="${id}" \u2014 total count: ${this.lists.size}`);
|
|
3093
3408
|
this.notify(id, null);
|
|
3094
3409
|
}
|
|
3095
3410
|
get(id) {
|
|
@@ -3135,7 +3450,7 @@ var ElementRegistryImpl = class {
|
|
|
3135
3450
|
next.set(element.id, element);
|
|
3136
3451
|
}
|
|
3137
3452
|
this.elements = next;
|
|
3138
|
-
|
|
3453
|
+
appilotsDebugLog(`ElementRegistry.replaceAll: elements=${this.elements.size}`);
|
|
3139
3454
|
}
|
|
3140
3455
|
register(id, entry) {
|
|
3141
3456
|
this.elements.set(id, entry);
|
|
@@ -3276,20 +3591,20 @@ function extractId(props) {
|
|
|
3276
3591
|
if (raw && typeof raw === "string") {
|
|
3277
3592
|
const normalized = normalizeId2(raw);
|
|
3278
3593
|
if (normalized && normalized.length > 0) {
|
|
3279
|
-
|
|
3594
|
+
appilotsDebugLog(`extractId: raw="${raw}" \u2192 normalized="${normalized}"`);
|
|
3280
3595
|
return normalized;
|
|
3281
3596
|
}
|
|
3282
|
-
|
|
3597
|
+
appilotsDebugLog(`extractId: raw="${raw}" normalized to empty string, falling back`);
|
|
3283
3598
|
}
|
|
3284
3599
|
const hint = deriveSemanticInputId(props);
|
|
3285
3600
|
if (hint) {
|
|
3286
|
-
|
|
3287
|
-
`
|
|
3601
|
+
appilotsDebugWarn(
|
|
3602
|
+
`extractId: no testID/nativeID/accessibilityLabel/name/placeholder/autoComplete on input \u2014 falling back to semantic hint "${hint}". Add testID to make this field reliably addressable.`
|
|
3288
3603
|
);
|
|
3289
3604
|
return hint;
|
|
3290
3605
|
}
|
|
3291
|
-
|
|
3292
|
-
"
|
|
3606
|
+
appilotsDebugLog(
|
|
3607
|
+
"extractId: no identifiable prop found (testID/nativeID/accessibilityLabel/name/placeholder/autoComplete missing); skipping registration"
|
|
3293
3608
|
);
|
|
3294
3609
|
return null;
|
|
3295
3610
|
}
|
|
@@ -3307,15 +3622,17 @@ var TrackedTextInput = React2__default.default.forwardRef(function TrackedTextIn
|
|
|
3307
3622
|
onChangeRef.current = props.onChangeText;
|
|
3308
3623
|
React2__default.default.useEffect(() => {
|
|
3309
3624
|
if (!id) {
|
|
3310
|
-
|
|
3625
|
+
appilotsDebugLog("TrackedTextInput useEffect: no id extracted, skipping registration");
|
|
3311
3626
|
return;
|
|
3312
3627
|
}
|
|
3313
|
-
|
|
3628
|
+
appilotsDebugLog(
|
|
3629
|
+
`TrackedTextInput useEffect: registering field id="${id}" label="${extractLabel(props)}"`
|
|
3630
|
+
);
|
|
3314
3631
|
const entry = {
|
|
3315
3632
|
kind: "field",
|
|
3316
3633
|
getValue: () => valueRef.current,
|
|
3317
3634
|
setValue: (v) => {
|
|
3318
|
-
|
|
3635
|
+
appilotsDebugLog(`TrackedTextInput setValue: id="${id}" value=${describeValue(v)}`);
|
|
3319
3636
|
onChangeRef.current?.(v);
|
|
3320
3637
|
inputRef.current?.setNativeProps?.({ text: v });
|
|
3321
3638
|
},
|
|
@@ -3325,15 +3642,18 @@ var TrackedTextInput = React2__default.default.forwardRef(function TrackedTextIn
|
|
|
3325
3642
|
};
|
|
3326
3643
|
registry.register(id, entry);
|
|
3327
3644
|
return () => {
|
|
3328
|
-
|
|
3645
|
+
appilotsDebugLog(`TrackedTextInput useEffect cleanup: unregistering field id="${id}"`);
|
|
3329
3646
|
registry.unregister(id);
|
|
3330
3647
|
};
|
|
3331
3648
|
}, [id]);
|
|
3332
|
-
const mergedRef = React2__default.default.useCallback(
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3649
|
+
const mergedRef = React2__default.default.useCallback(
|
|
3650
|
+
(instance) => {
|
|
3651
|
+
inputRef.current = instance;
|
|
3652
|
+
if (typeof forwardedRef === "function") forwardedRef(instance);
|
|
3653
|
+
else if (forwardedRef && typeof forwardedRef === "object") forwardedRef.current = instance;
|
|
3654
|
+
},
|
|
3655
|
+
[forwardedRef]
|
|
3656
|
+
);
|
|
3337
3657
|
return _originalCreateElement(reactNative.TextInput, { ...props, ref: mergedRef });
|
|
3338
3658
|
});
|
|
3339
3659
|
var TrackedSwitch = React2__default.default.forwardRef(function TrackedSwitch2(props, forwardedRef) {
|
|
@@ -3345,22 +3665,24 @@ var TrackedSwitch = React2__default.default.forwardRef(function TrackedSwitch2(p
|
|
|
3345
3665
|
onChangeRef.current = props.onValueChange;
|
|
3346
3666
|
React2__default.default.useEffect(() => {
|
|
3347
3667
|
if (!id) {
|
|
3348
|
-
|
|
3668
|
+
appilotsDebugLog("TrackedSwitch useEffect: no id extracted, skipping registration");
|
|
3349
3669
|
return;
|
|
3350
3670
|
}
|
|
3351
|
-
|
|
3671
|
+
appilotsDebugLog(
|
|
3672
|
+
`TrackedSwitch useEffect: registering toggle id="${id}" label="${extractLabel(props)}"`
|
|
3673
|
+
);
|
|
3352
3674
|
const entry = {
|
|
3353
3675
|
kind: "toggle",
|
|
3354
3676
|
getValue: () => valueRef.current,
|
|
3355
3677
|
setValue: (v) => {
|
|
3356
|
-
|
|
3678
|
+
appilotsDebugLog(`TrackedSwitch setValue called: id="${id}" value=${v}`);
|
|
3357
3679
|
onChangeRef.current?.(v);
|
|
3358
3680
|
},
|
|
3359
3681
|
label: extractLabel(props)
|
|
3360
3682
|
};
|
|
3361
3683
|
registry.register(id, entry);
|
|
3362
3684
|
return () => {
|
|
3363
|
-
|
|
3685
|
+
appilotsDebugLog(`TrackedSwitch useEffect cleanup: unregistering toggle id="${id}"`);
|
|
3364
3686
|
registry.unregister(id);
|
|
3365
3687
|
};
|
|
3366
3688
|
}, [id]);
|
|
@@ -3380,21 +3702,25 @@ function getTrackedPressable(OriginalComponent) {
|
|
|
3380
3702
|
return;
|
|
3381
3703
|
}
|
|
3382
3704
|
if (!id || !props.onPress) {
|
|
3383
|
-
|
|
3705
|
+
appilotsDebugLog(
|
|
3706
|
+
`TrackedPressable useEffect: skipping registration (id=${id}, hasOnPress=${!!props.onPress})`
|
|
3707
|
+
);
|
|
3384
3708
|
return;
|
|
3385
3709
|
}
|
|
3386
|
-
|
|
3710
|
+
appilotsDebugLog(
|
|
3711
|
+
`TrackedPressable useEffect: registering target id="${id}" label="${extractLabel(props)}"`
|
|
3712
|
+
);
|
|
3387
3713
|
const entry = {
|
|
3388
3714
|
kind: "target",
|
|
3389
3715
|
press: () => {
|
|
3390
|
-
|
|
3716
|
+
appilotsDebugLog(`TrackedPressable press called: id="${id}"`);
|
|
3391
3717
|
onPressRef.current?.();
|
|
3392
3718
|
},
|
|
3393
3719
|
label: extractLabel(props)
|
|
3394
3720
|
};
|
|
3395
3721
|
registry.register(id, entry);
|
|
3396
3722
|
return () => {
|
|
3397
|
-
|
|
3723
|
+
appilotsDebugLog(`TrackedPressable useEffect cleanup: unregistering target id="${id}"`);
|
|
3398
3724
|
registry.unregister(id);
|
|
3399
3725
|
};
|
|
3400
3726
|
}, [id, !!props.onPress]);
|
|
@@ -3403,12 +3729,7 @@ function getTrackedPressable(OriginalComponent) {
|
|
|
3403
3729
|
_pressableWrapperCache.set(OriginalComponent, cached);
|
|
3404
3730
|
return cached;
|
|
3405
3731
|
}
|
|
3406
|
-
var LIST_COMPONENT_NAMES = /* @__PURE__ */ new Set([
|
|
3407
|
-
"FlatList",
|
|
3408
|
-
"SectionList",
|
|
3409
|
-
"VirtualizedList",
|
|
3410
|
-
"FlashList"
|
|
3411
|
-
]);
|
|
3732
|
+
var LIST_COMPONENT_NAMES = /* @__PURE__ */ new Set(["FlatList", "SectionList", "VirtualizedList", "FlashList"]);
|
|
3412
3733
|
var _listWrapperCache = /* @__PURE__ */ new Map();
|
|
3413
3734
|
var _generatedListIdCounter = 0;
|
|
3414
3735
|
function componentDisplayName(type) {
|
|
@@ -3462,12 +3783,10 @@ var PREVIEW_TEXT_KEYS = [
|
|
|
3462
3783
|
"label",
|
|
3463
3784
|
"description",
|
|
3464
3785
|
"descricao",
|
|
3465
|
-
"plate",
|
|
3466
|
-
"placa",
|
|
3467
|
-
"model",
|
|
3468
|
-
"modelo",
|
|
3469
3786
|
"email",
|
|
3470
|
-
"username"
|
|
3787
|
+
"username",
|
|
3788
|
+
"code",
|
|
3789
|
+
"codigo"
|
|
3471
3790
|
];
|
|
3472
3791
|
function projectItemText(item) {
|
|
3473
3792
|
if (item == null) return "";
|
|
@@ -3563,10 +3882,7 @@ function getTrackedList(OriginalComponent, componentName) {
|
|
|
3563
3882
|
const itemCount = resolveItemCount(props);
|
|
3564
3883
|
const refreshing = props.refreshing === true;
|
|
3565
3884
|
const label = listLabel(props);
|
|
3566
|
-
const dataPreview = React2__default.default.useMemo(
|
|
3567
|
-
() => buildDataPreview(props),
|
|
3568
|
-
[props.data, props.sections]
|
|
3569
|
-
);
|
|
3885
|
+
const dataPreview = React2__default.default.useMemo(() => buildDataPreview(props), [props.data, props.sections]);
|
|
3570
3886
|
const mergedRef = React2__default.default.useCallback(
|
|
3571
3887
|
(instance) => {
|
|
3572
3888
|
instanceRef.current = instance;
|
|
@@ -3601,7 +3917,7 @@ function getTrackedList(OriginalComponent, componentName) {
|
|
|
3601
3917
|
}
|
|
3602
3918
|
return false;
|
|
3603
3919
|
} catch (err) {
|
|
3604
|
-
|
|
3920
|
+
appilotsDebugWarn(`TrackedList scrollToIndex failed for "${listId}":`, err);
|
|
3605
3921
|
return false;
|
|
3606
3922
|
}
|
|
3607
3923
|
},
|
|
@@ -3620,7 +3936,7 @@ function getTrackedList(OriginalComponent, componentName) {
|
|
|
3620
3936
|
}
|
|
3621
3937
|
return false;
|
|
3622
3938
|
} catch (err) {
|
|
3623
|
-
|
|
3939
|
+
appilotsDebugWarn(`TrackedList scrollToOffset failed for "${listId}":`, err);
|
|
3624
3940
|
return false;
|
|
3625
3941
|
}
|
|
3626
3942
|
},
|
|
@@ -3664,26 +3980,148 @@ function getTrackedList(OriginalComponent, componentName) {
|
|
|
3664
3980
|
_listWrapperCache.set(OriginalComponent, cached);
|
|
3665
3981
|
return cached;
|
|
3666
3982
|
}
|
|
3667
|
-
var
|
|
3983
|
+
var SCROLLABLE_COMPONENT_NAMES = /* @__PURE__ */ new Set(["ScrollView", "KeyboardAwareScrollView"]);
|
|
3984
|
+
var _scrollWrapperCache = /* @__PURE__ */ new Map();
|
|
3985
|
+
var _generatedScrollIdCounter = 0;
|
|
3986
|
+
function extractScrollId(props, componentName) {
|
|
3987
|
+
const raw = props?.appilotsScrollId ?? props?.testID ?? props?.accessibilityLabel;
|
|
3988
|
+
if (typeof raw === "string" && raw.trim().length > 0) return raw.trim();
|
|
3989
|
+
_generatedScrollIdCounter += 1;
|
|
3990
|
+
return `${componentName.toLowerCase()}-${_generatedScrollIdCounter}`;
|
|
3991
|
+
}
|
|
3992
|
+
function chain(appHandler, ours) {
|
|
3993
|
+
return ((...args) => {
|
|
3994
|
+
if (typeof appHandler === "function") {
|
|
3995
|
+
try {
|
|
3996
|
+
appHandler(...args);
|
|
3997
|
+
} catch (err) {
|
|
3998
|
+
appilotsDebugWarn("TrackedScrollView: app scroll handler threw:", err);
|
|
3999
|
+
}
|
|
4000
|
+
}
|
|
4001
|
+
ours(...args);
|
|
4002
|
+
});
|
|
4003
|
+
}
|
|
4004
|
+
function getTrackedScrollView(OriginalComponent, componentName) {
|
|
4005
|
+
let cached = _scrollWrapperCache.get(OriginalComponent);
|
|
4006
|
+
if (cached) return cached;
|
|
4007
|
+
cached = React2__default.default.forwardRef(function TrackedScrollView(props, forwardedRef) {
|
|
4008
|
+
const idRef = React2__default.default.useRef(null);
|
|
4009
|
+
if (!idRef.current) idRef.current = extractScrollId(props, componentName);
|
|
4010
|
+
const scrollId = idRef.current;
|
|
4011
|
+
const instanceRef = React2__default.default.useRef(null);
|
|
4012
|
+
const metricsRef = React2__default.default.useRef({
|
|
4013
|
+
offset: 0,
|
|
4014
|
+
visibleLength: 0,
|
|
4015
|
+
contentLength: 0
|
|
4016
|
+
});
|
|
4017
|
+
const horizontal = props.horizontal === true;
|
|
4018
|
+
const mergedRef = React2__default.default.useCallback(
|
|
4019
|
+
(instance) => {
|
|
4020
|
+
instanceRef.current = instance;
|
|
4021
|
+
if (typeof forwardedRef === "function") forwardedRef(instance);
|
|
4022
|
+
else if (forwardedRef && typeof forwardedRef === "object") forwardedRef.current = instance;
|
|
4023
|
+
},
|
|
4024
|
+
[forwardedRef]
|
|
4025
|
+
);
|
|
4026
|
+
const label = typeof props.appilotsScrollLabel === "string" ? props.appilotsScrollLabel : typeof props.accessibilityLabel === "string" ? props.accessibilityLabel : void 0;
|
|
4027
|
+
React2__default.default.useEffect(() => {
|
|
4028
|
+
listRegistry.register(scrollId, {
|
|
4029
|
+
kind: "scroll",
|
|
4030
|
+
id: scrollId,
|
|
4031
|
+
component: componentName,
|
|
4032
|
+
label,
|
|
4033
|
+
scrollToOffset: (offset) => {
|
|
4034
|
+
const instance = instanceRef.current;
|
|
4035
|
+
if (!instance) return false;
|
|
4036
|
+
try {
|
|
4037
|
+
const scrollTo = typeof instance.scrollTo === "function" ? instance.scrollTo.bind(instance) : typeof instance.getScrollResponder === "function" ? instance.getScrollResponder()?.scrollTo?.bind(instance.getScrollResponder()) : void 0;
|
|
4038
|
+
if (typeof scrollTo !== "function") return false;
|
|
4039
|
+
scrollTo(horizontal ? { x: offset, animated: true } : { y: offset, animated: true });
|
|
4040
|
+
metricsRef.current = { ...metricsRef.current, offset };
|
|
4041
|
+
return true;
|
|
4042
|
+
} catch (err) {
|
|
4043
|
+
appilotsDebugWarn(`TrackedScrollView scrollTo failed for "${scrollId}":`, err);
|
|
4044
|
+
return false;
|
|
4045
|
+
}
|
|
4046
|
+
},
|
|
4047
|
+
getScrollMetrics: () => {
|
|
4048
|
+
const m = metricsRef.current;
|
|
4049
|
+
return m.contentLength > 0 ? { ...m } : void 0;
|
|
4050
|
+
}
|
|
4051
|
+
});
|
|
4052
|
+
return () => {
|
|
4053
|
+
listRegistry.unregister(scrollId);
|
|
4054
|
+
};
|
|
4055
|
+
}, [scrollId, label, horizontal]);
|
|
4056
|
+
const onScroll = React2__default.default.useMemo(
|
|
4057
|
+
() => chain(props.onScroll, (event) => {
|
|
4058
|
+
const n = event?.nativeEvent;
|
|
4059
|
+
if (!n) return;
|
|
4060
|
+
const offset = horizontal ? n.contentOffset?.x : n.contentOffset?.y;
|
|
4061
|
+
const visible = horizontal ? n.layoutMeasurement?.width : n.layoutMeasurement?.height;
|
|
4062
|
+
const content = horizontal ? n.contentSize?.width : n.contentSize?.height;
|
|
4063
|
+
metricsRef.current = {
|
|
4064
|
+
offset: typeof offset === "number" ? offset : metricsRef.current.offset,
|
|
4065
|
+
visibleLength: typeof visible === "number" ? visible : metricsRef.current.visibleLength,
|
|
4066
|
+
contentLength: typeof content === "number" ? content : metricsRef.current.contentLength
|
|
4067
|
+
};
|
|
4068
|
+
}),
|
|
4069
|
+
[props.onScroll, horizontal]
|
|
4070
|
+
);
|
|
4071
|
+
const onLayout = React2__default.default.useMemo(
|
|
4072
|
+
() => chain(props.onLayout, (event) => {
|
|
4073
|
+
const size = horizontal ? event?.nativeEvent?.layout?.width : event?.nativeEvent?.layout?.height;
|
|
4074
|
+
if (typeof size === "number") {
|
|
4075
|
+
metricsRef.current = { ...metricsRef.current, visibleLength: size };
|
|
4076
|
+
}
|
|
4077
|
+
}),
|
|
4078
|
+
[props.onLayout, horizontal]
|
|
4079
|
+
);
|
|
4080
|
+
const onContentSizeChange = React2__default.default.useMemo(
|
|
4081
|
+
() => chain(props.onContentSizeChange, (w, h) => {
|
|
4082
|
+
const size = horizontal ? w : h;
|
|
4083
|
+
if (typeof size === "number") {
|
|
4084
|
+
metricsRef.current = { ...metricsRef.current, contentLength: size };
|
|
4085
|
+
}
|
|
4086
|
+
}),
|
|
4087
|
+
[props.onContentSizeChange, horizontal]
|
|
4088
|
+
);
|
|
4089
|
+
return _originalCreateElement(OriginalComponent, {
|
|
4090
|
+
...props,
|
|
4091
|
+
ref: mergedRef,
|
|
4092
|
+
// Without a throttle iOS fires `onScroll` once per gesture, which
|
|
4093
|
+
// is enough to stay roughly in sync but leaves the offset stale
|
|
4094
|
+
// mid-fling. 16ms is RN's own recommendation for live metrics.
|
|
4095
|
+
scrollEventThrottle: props.scrollEventThrottle ?? 16,
|
|
4096
|
+
onScroll,
|
|
4097
|
+
onLayout,
|
|
4098
|
+
onContentSizeChange,
|
|
4099
|
+
__appilotsScrollId: scrollId
|
|
4100
|
+
});
|
|
4101
|
+
});
|
|
4102
|
+
_scrollWrapperCache.set(OriginalComponent, cached);
|
|
4103
|
+
return cached;
|
|
4104
|
+
}
|
|
4105
|
+
var _enabled2 = false;
|
|
3668
4106
|
function enableAppilotsAutoTracking(options) {
|
|
3669
|
-
if (
|
|
3670
|
-
|
|
4107
|
+
if (_enabled2) return;
|
|
4108
|
+
_enabled2 = true;
|
|
3671
4109
|
const { trackPressable = true, debug = false } = options ?? {};
|
|
3672
4110
|
if (debug) {
|
|
3673
4111
|
componentRegistry.subscribe((id, entry) => {
|
|
3674
4112
|
if (entry) {
|
|
3675
|
-
|
|
4113
|
+
appilotsDebugLog(`Registered ${entry.kind}: "${id}" (${entry.label ?? "no label"})`);
|
|
3676
4114
|
} else {
|
|
3677
|
-
|
|
4115
|
+
appilotsDebugLog(`Unregistered: "${id}"`);
|
|
3678
4116
|
}
|
|
3679
4117
|
});
|
|
3680
4118
|
listRegistry.subscribe((id, entry) => {
|
|
3681
4119
|
if (entry) {
|
|
3682
|
-
|
|
3683
|
-
`
|
|
4120
|
+
appilotsDebugLog(
|
|
4121
|
+
`Registered list: "${id}" (${entry.component}, items=${entry.itemCount ?? "unknown"})`
|
|
3684
4122
|
);
|
|
3685
4123
|
} else {
|
|
3686
|
-
|
|
4124
|
+
appilotsDebugLog(`Unregistered list: "${id}"`);
|
|
3687
4125
|
}
|
|
3688
4126
|
});
|
|
3689
4127
|
}
|
|
@@ -3691,12 +4129,14 @@ function enableAppilotsAutoTracking(options) {
|
|
|
3691
4129
|
_originalCreateElement = originalCreateElement;
|
|
3692
4130
|
function isComponent(type, target, name) {
|
|
3693
4131
|
if (type === target) {
|
|
3694
|
-
|
|
4132
|
+
appilotsDebugLog(`isComponent: matched "${name}" by reference equality`);
|
|
3695
4133
|
return true;
|
|
3696
4134
|
}
|
|
3697
4135
|
const dn = type?.displayName || type?.name || "";
|
|
3698
4136
|
if (dn === name) {
|
|
3699
|
-
|
|
4137
|
+
appilotsDebugLog(
|
|
4138
|
+
`isComponent: matched "${name}" by displayName/name (reference equality failed \u2014 possible monorepo issue)`
|
|
4139
|
+
);
|
|
3700
4140
|
return true;
|
|
3701
4141
|
}
|
|
3702
4142
|
return false;
|
|
@@ -3705,24 +4145,36 @@ function enableAppilotsAutoTracking(options) {
|
|
|
3705
4145
|
if (!props || !type || props.__appilotsInternal) return null;
|
|
3706
4146
|
const displayName = componentDisplayName(type);
|
|
3707
4147
|
if (LIST_COMPONENT_NAMES.has(displayName)) {
|
|
3708
|
-
|
|
4148
|
+
appilotsDebugLog(`intercepted list component "${displayName}"`);
|
|
3709
4149
|
return { type: getTrackedList(type, displayName), props };
|
|
3710
4150
|
}
|
|
4151
|
+
if (SCROLLABLE_COMPONENT_NAMES.has(displayName)) {
|
|
4152
|
+
appilotsDebugLog(`intercepted scrollable "${displayName}"`);
|
|
4153
|
+
return { type: getTrackedScrollView(type, displayName), props };
|
|
4154
|
+
}
|
|
3711
4155
|
if (isComponent(type, reactNative.TextInput, "TextInput")) {
|
|
3712
4156
|
if (props.testID || props.accessibilityLabel || props.placeholder) {
|
|
3713
|
-
|
|
4157
|
+
appilotsDebugLog(
|
|
4158
|
+
// Ids, not the user-facing copy: a placeholder is the app's
|
|
4159
|
+
// own text and often the most identifying string on screen.
|
|
4160
|
+
`intercepted TextInput (testID="${props.testID ?? "?"}" hasLabel=${!!props.accessibilityLabel} hasPlaceholder=${!!props.placeholder})`
|
|
4161
|
+
);
|
|
3714
4162
|
return { type: TrackedTextInput, props };
|
|
3715
4163
|
}
|
|
3716
4164
|
}
|
|
3717
4165
|
if (isComponent(type, reactNative.Switch, "Switch")) {
|
|
3718
4166
|
if (props.testID || props.accessibilityLabel) {
|
|
3719
|
-
|
|
4167
|
+
appilotsDebugLog(
|
|
4168
|
+
`intercepted Switch (testID="${props.testID}", label="${props.accessibilityLabel}")`
|
|
4169
|
+
);
|
|
3720
4170
|
return { type: TrackedSwitch, props };
|
|
3721
4171
|
}
|
|
3722
4172
|
}
|
|
3723
4173
|
if (isComponent(type, reactNative.TouchableOpacity, "TouchableOpacity") || trackPressable && isComponent(type, reactNative.Pressable, "Pressable")) {
|
|
3724
4174
|
if ((props.testID || props.accessibilityLabel) && props.onPress) {
|
|
3725
|
-
|
|
4175
|
+
appilotsDebugLog(
|
|
4176
|
+
`intercepted Pressable/TouchableOpacity (testID="${props.testID}", label="${props.accessibilityLabel}")`
|
|
4177
|
+
);
|
|
3726
4178
|
return { type: getTrackedPressable(type), props };
|
|
3727
4179
|
}
|
|
3728
4180
|
}
|
|
@@ -3736,14 +4188,17 @@ function enableAppilotsAutoTracking(options) {
|
|
|
3736
4188
|
}
|
|
3737
4189
|
return originalCreateElement(type, props, ...children);
|
|
3738
4190
|
};
|
|
3739
|
-
|
|
4191
|
+
_createElementPatched = true;
|
|
4192
|
+
appilotsDebugLog("Auto-tracking: React.createElement patched");
|
|
3740
4193
|
try {
|
|
3741
4194
|
const jsxRuntime = __require("react/jsx-runtime");
|
|
3742
4195
|
if (jsxRuntime) {
|
|
3743
4196
|
_patchJsxRuntimeModule(jsxRuntime);
|
|
3744
4197
|
}
|
|
3745
4198
|
} catch (e) {
|
|
3746
|
-
|
|
4199
|
+
appilotsDebugLog(
|
|
4200
|
+
"Auto-tracking: react/jsx-runtime not available internally (will be patched by metro shim)"
|
|
4201
|
+
);
|
|
3747
4202
|
}
|
|
3748
4203
|
try {
|
|
3749
4204
|
const jsxDevRuntime = __require("react/jsx-dev-runtime");
|
|
@@ -3751,11 +4206,14 @@ function enableAppilotsAutoTracking(options) {
|
|
|
3751
4206
|
_patchJsxDevRuntimeModule(jsxDevRuntime);
|
|
3752
4207
|
}
|
|
3753
4208
|
} catch (e) {
|
|
3754
|
-
|
|
4209
|
+
appilotsDebugLog(
|
|
4210
|
+
"Auto-tracking: react/jsx-dev-runtime not available internally (will be patched by metro shim)"
|
|
4211
|
+
);
|
|
3755
4212
|
}
|
|
3756
4213
|
}
|
|
3757
4214
|
var _jsxRuntimePatched = false;
|
|
3758
4215
|
var _jsxDevRuntimePatched = false;
|
|
4216
|
+
var _createElementPatched = false;
|
|
3759
4217
|
function _patchJsxRuntimeModule(jsxRuntime) {
|
|
3760
4218
|
if (_jsxRuntimePatched || !isInterceptionActive() || !jsxRuntime) return;
|
|
3761
4219
|
_jsxRuntimePatched = true;
|
|
@@ -3769,7 +4227,7 @@ function _patchJsxRuntimeModule(jsxRuntime) {
|
|
|
3769
4227
|
}
|
|
3770
4228
|
return origJsx(type, props, key);
|
|
3771
4229
|
};
|
|
3772
|
-
|
|
4230
|
+
appilotsDebugLog("Auto-tracking: react/jsx-runtime jsx() patched");
|
|
3773
4231
|
}
|
|
3774
4232
|
if (origJsxs) {
|
|
3775
4233
|
jsxRuntime.jsxs = function(type, props, key) {
|
|
@@ -3779,7 +4237,7 @@ function _patchJsxRuntimeModule(jsxRuntime) {
|
|
|
3779
4237
|
}
|
|
3780
4238
|
return origJsxs(type, props, key);
|
|
3781
4239
|
};
|
|
3782
|
-
|
|
4240
|
+
appilotsDebugLog("Auto-tracking: react/jsx-runtime jsxs() patched");
|
|
3783
4241
|
}
|
|
3784
4242
|
}
|
|
3785
4243
|
function _patchJsxDevRuntimeModule(jsxDevRuntime) {
|
|
@@ -3794,58 +4252,75 @@ function _patchJsxDevRuntimeModule(jsxDevRuntime) {
|
|
|
3794
4252
|
}
|
|
3795
4253
|
return origJsxDEV(type, props, key, isStaticChildren, source, self);
|
|
3796
4254
|
};
|
|
3797
|
-
|
|
4255
|
+
appilotsDebugLog("Auto-tracking: react/jsx-dev-runtime jsxDEV() patched");
|
|
3798
4256
|
}
|
|
3799
4257
|
}
|
|
3800
4258
|
function _patchJsxRuntimes(jsxRuntime, jsxDevRuntime) {
|
|
3801
4259
|
if (!isInterceptionActive()) {
|
|
3802
|
-
|
|
4260
|
+
appilotsDebugWarn("_patchJsxRuntimes called but auto-tracking is not enabled");
|
|
3803
4261
|
return;
|
|
3804
4262
|
}
|
|
3805
|
-
|
|
4263
|
+
appilotsDebugLog("_patchJsxRuntimes: patching from app context (metro shim)");
|
|
3806
4264
|
if (jsxRuntime) _patchJsxRuntimeModule(jsxRuntime);
|
|
3807
4265
|
if (jsxDevRuntime) _patchJsxDevRuntimeModule(jsxDevRuntime);
|
|
3808
4266
|
}
|
|
3809
4267
|
function isAutoTrackingEnabled() {
|
|
3810
|
-
return
|
|
4268
|
+
return _enabled2;
|
|
4269
|
+
}
|
|
4270
|
+
function getAutoTrackingState() {
|
|
4271
|
+
return {
|
|
4272
|
+
enabled: _enabled2,
|
|
4273
|
+
createElementPatched: _createElementPatched,
|
|
4274
|
+
jsxRuntimePatched: _jsxRuntimePatched,
|
|
4275
|
+
jsxDevRuntimePatched: _jsxDevRuntimePatched,
|
|
4276
|
+
interceptionActive: isInterceptionActive()
|
|
4277
|
+
};
|
|
3811
4278
|
}
|
|
3812
4279
|
|
|
3813
4280
|
// src/core/initAppilots.ts
|
|
3814
4281
|
var _globalConfig = null;
|
|
3815
4282
|
var _autoConfigAttempted = false;
|
|
3816
4283
|
function initAppilots(config) {
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
4284
|
+
appilotsDebugLog(
|
|
4285
|
+
`initAppilots called with config: projectId="${config.projectId}", apiBaseUrl="${config.apiBaseUrl ?? config.apiUrl ?? "default"}", debug=${config.debug ?? false}, autoTracking=${JSON.stringify(config.autoTracking ?? {})}`
|
|
4286
|
+
);
|
|
4287
|
+
if (!config.apiBaseUrl) {
|
|
4288
|
+
config.apiBaseUrl = config.apiUrl ?? config.serverUrl;
|
|
3820
4289
|
}
|
|
3821
4290
|
_globalConfig = config;
|
|
3822
4291
|
const autoTrackingEnabled = config.autoTracking?.enabled !== false;
|
|
3823
4292
|
if (autoTrackingEnabled) {
|
|
3824
|
-
|
|
4293
|
+
appilotsDebugLog(
|
|
4294
|
+
"initAppilots: auto-tracking is enabled, calling enableAppilotsAutoTracking()"
|
|
4295
|
+
);
|
|
3825
4296
|
enableAppilotsAutoTracking({
|
|
3826
4297
|
trackPressable: config.autoTracking?.trackPressable ?? true,
|
|
3827
4298
|
debug: config.debug ?? false
|
|
3828
4299
|
});
|
|
3829
4300
|
} else {
|
|
3830
|
-
|
|
4301
|
+
appilotsDebugLog("initAppilots: auto-tracking is explicitly disabled");
|
|
3831
4302
|
}
|
|
3832
4303
|
}
|
|
3833
4304
|
function tryAutoConfig() {
|
|
3834
4305
|
if (_globalConfig || _autoConfigAttempted) {
|
|
3835
|
-
|
|
4306
|
+
appilotsDebugLog(
|
|
4307
|
+
`tryAutoConfig: skipping (alreadyConfigured=${!!_globalConfig}, alreadyAttempted=${_autoConfigAttempted})`
|
|
4308
|
+
);
|
|
3836
4309
|
return;
|
|
3837
4310
|
}
|
|
3838
4311
|
_autoConfigAttempted = true;
|
|
3839
4312
|
try {
|
|
3840
4313
|
const rc = globalThis.__APPILOTS_RC__;
|
|
3841
4314
|
if (rc && typeof rc === "object" && rc.projectId) {
|
|
3842
|
-
|
|
4315
|
+
appilotsDebugLog(
|
|
4316
|
+
`tryAutoConfig: found globalThis.__APPILOTS_RC__ with projectId="${rc.projectId}"`
|
|
4317
|
+
);
|
|
3843
4318
|
initAppilots(rc);
|
|
3844
4319
|
} else {
|
|
3845
|
-
|
|
4320
|
+
appilotsDebugLog("tryAutoConfig: globalThis.__APPILOTS_RC__ not found or missing projectId");
|
|
3846
4321
|
}
|
|
3847
4322
|
} catch {
|
|
3848
|
-
|
|
4323
|
+
appilotsDebugWarn("tryAutoConfig: error reading globalThis.__APPILOTS_RC__");
|
|
3849
4324
|
}
|
|
3850
4325
|
}
|
|
3851
4326
|
function getGlobalConfig() {
|
|
@@ -3862,7 +4337,7 @@ var _diagnostics = {
|
|
|
3862
4337
|
};
|
|
3863
4338
|
function setFiberRoot(fiber) {
|
|
3864
4339
|
if (_fiberRoot !== fiber) {
|
|
3865
|
-
|
|
4340
|
+
appilotsDebugLog(`Introspection: fiber root captured (type=${typeName(fiber)})`);
|
|
3866
4341
|
_fiberRoot = fiber;
|
|
3867
4342
|
}
|
|
3868
4343
|
_diagnostics.captured = true;
|
|
@@ -3899,262 +4374,976 @@ function typeName(fiber) {
|
|
|
3899
4374
|
if (!t) return "unknown";
|
|
3900
4375
|
if (typeof t === "string") return t;
|
|
3901
4376
|
if (typeof t === "function") return t.displayName ?? t.name ?? "anonymous";
|
|
3902
|
-
if (typeof t === "object")
|
|
4377
|
+
if (typeof t === "object")
|
|
4378
|
+
return t.displayName ?? t.render?.displayName ?? t.render?.name ?? "forwardRef/memo";
|
|
3903
4379
|
return String(t);
|
|
3904
4380
|
}
|
|
3905
4381
|
|
|
3906
|
-
// src/
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
4382
|
+
// src/introspection/textPolicy.ts
|
|
4383
|
+
function isReferenceable(text) {
|
|
4384
|
+
return typeof text === "string" && /[\p{L}\p{N}]/u.test(text);
|
|
4385
|
+
}
|
|
4386
|
+
function foldLatinDiacritics(text) {
|
|
4387
|
+
return text.normalize("NFD").replace(/[\u0300-\u036f]/g, "").normalize("NFC");
|
|
4388
|
+
}
|
|
4389
|
+
function foldForCompare(text) {
|
|
4390
|
+
if (!text) return "";
|
|
4391
|
+
return foldLatinDiacritics(text.toLowerCase()).replace(/[^\p{L}\p{N}]/gu, "");
|
|
4392
|
+
}
|
|
4393
|
+
function labelToId(label) {
|
|
4394
|
+
if (!label) return "";
|
|
4395
|
+
return foldLatinDiacritics(label.toLowerCase()).replace(/[^\p{L}\p{N}\s]/gu, "").trim().replace(/\s+(.)/gu, (_, c) => c.toUpperCase()).replace(/\s+/gu, "");
|
|
4396
|
+
}
|
|
4397
|
+
|
|
4398
|
+
// src/introspection/geometry.ts
|
|
4399
|
+
var _host = null;
|
|
4400
|
+
var _asked = 0;
|
|
4401
|
+
var _answered = 0;
|
|
4402
|
+
function setGeometryHost(host) {
|
|
4403
|
+
_host = host;
|
|
4404
|
+
_asked = 0;
|
|
4405
|
+
_answered = 0;
|
|
4406
|
+
}
|
|
4407
|
+
function geometryAvailability() {
|
|
4408
|
+
if (!_host) return "unavailable";
|
|
4409
|
+
if (_asked > 0 && _answered === 0) return "silent";
|
|
4410
|
+
return "available";
|
|
4411
|
+
}
|
|
4412
|
+
function geometryStats() {
|
|
4413
|
+
return { asked: _asked, answered: _answered };
|
|
4414
|
+
}
|
|
4415
|
+
function isUsableRect(rect) {
|
|
4416
|
+
return !!rect && Number.isFinite(rect.x) && Number.isFinite(rect.y) && Number.isFinite(rect.width) && Number.isFinite(rect.height);
|
|
4417
|
+
}
|
|
4418
|
+
var HOST_SEARCH_DEPTH = 6;
|
|
4419
|
+
function rectOfFiber(fiber) {
|
|
4420
|
+
const host = _host;
|
|
4421
|
+
if (!host || !fiber) return null;
|
|
4422
|
+
const stack = [{ node: fiber, depth: 0 }];
|
|
4423
|
+
let consulted = false;
|
|
4424
|
+
while (stack.length > 0) {
|
|
4425
|
+
const { node, depth } = stack.pop();
|
|
4426
|
+
const current = node;
|
|
4427
|
+
if (!current) continue;
|
|
4428
|
+
if (current.stateNode) {
|
|
4429
|
+
consulted = true;
|
|
4430
|
+
let rect = null;
|
|
4431
|
+
try {
|
|
4432
|
+
rect = host.rectOf(current.stateNode);
|
|
4433
|
+
} catch {
|
|
4434
|
+
rect = null;
|
|
4435
|
+
}
|
|
4436
|
+
if (isUsableRect(rect)) {
|
|
4437
|
+
_asked += 1;
|
|
4438
|
+
_answered += 1;
|
|
4439
|
+
return rect;
|
|
4440
|
+
}
|
|
4441
|
+
}
|
|
4442
|
+
if (depth < HOST_SEARCH_DEPTH && current.child) {
|
|
4443
|
+
stack.push({ node: current.child, depth: depth + 1 });
|
|
4444
|
+
const sibling = current.child.sibling;
|
|
4445
|
+
if (sibling) stack.push({ node: sibling, depth: depth + 1 });
|
|
3919
4446
|
}
|
|
3920
|
-
let top = fiber;
|
|
3921
|
-
while (top.return) top = top.return;
|
|
3922
|
-
setFiberRoot(top);
|
|
3923
|
-
}
|
|
3924
|
-
render() {
|
|
3925
|
-
return this.props.children ?? null;
|
|
3926
|
-
}
|
|
3927
|
-
};
|
|
3928
|
-
function AppilotsFiberRoot({
|
|
3929
|
-
children,
|
|
3930
|
-
onUnavailable
|
|
3931
|
-
}) {
|
|
3932
|
-
const Internals = React2__default.default.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED_IN_THIS_VERSION_OF_REACT;
|
|
3933
|
-
const ownerFiber = Internals?.ReactCurrentOwner?.current;
|
|
3934
|
-
if (ownerFiber && !getFiberRoot()) {
|
|
3935
|
-
setFiberRoot(ownerFiber);
|
|
3936
4447
|
}
|
|
3937
|
-
|
|
4448
|
+
if (consulted) _asked += 1;
|
|
4449
|
+
return null;
|
|
3938
4450
|
}
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
4451
|
+
function isRectOnScreen(rect, window) {
|
|
4452
|
+
if (rect.width <= 0 || rect.height <= 0) return false;
|
|
4453
|
+
if (rect.x >= window.width || rect.y >= window.height) return false;
|
|
4454
|
+
if (rect.x + rect.width <= 0 || rect.y + rect.height <= 0) return false;
|
|
4455
|
+
return true;
|
|
3944
4456
|
}
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
4457
|
+
var _rectByNode = /* @__PURE__ */ new WeakMap();
|
|
4458
|
+
function readGeometry(fiber) {
|
|
4459
|
+
const host = _host;
|
|
4460
|
+
if (!host) return { rect: null, fields: {} };
|
|
4461
|
+
const rect = rectOfFiber(fiber);
|
|
4462
|
+
if (!rect) return { rect: null, fields: {} };
|
|
4463
|
+
return { rect, fields: { onScreen: isRectOnScreen(rect, host.window) } };
|
|
3948
4464
|
}
|
|
3949
|
-
function
|
|
3950
|
-
if (
|
|
3951
|
-
|
|
4465
|
+
function withRect(node, reading) {
|
|
4466
|
+
if (reading.rect) _rectByNode.set(node, reading.rect);
|
|
4467
|
+
return node;
|
|
3952
4468
|
}
|
|
3953
|
-
function
|
|
3954
|
-
if (!
|
|
3955
|
-
|
|
4469
|
+
function rectForNode(node) {
|
|
4470
|
+
if (!node || typeof node !== "object") return void 0;
|
|
4471
|
+
return _rectByNode.get(node);
|
|
3956
4472
|
}
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
hasDegradedOnce = false;
|
|
3965
|
-
static getDerivedStateFromError() {
|
|
3966
|
-
return { degraded: true };
|
|
4473
|
+
|
|
4474
|
+
// src/introspection/walkFiber.ts
|
|
4475
|
+
function getTypeName(type) {
|
|
4476
|
+
if (!type) return null;
|
|
4477
|
+
if (typeof type === "string") return type;
|
|
4478
|
+
if (typeof type === "function") {
|
|
4479
|
+
return type.displayName ?? type.name ?? null;
|
|
3967
4480
|
}
|
|
3968
|
-
|
|
3969
|
-
if (
|
|
3970
|
-
|
|
3971
|
-
return;
|
|
3972
|
-
}
|
|
3973
|
-
this.hasDegradedOnce = true;
|
|
3974
|
-
console.error(
|
|
3975
|
-
`[Appilots] The Appilots ${this.props.surface} threw while rendering and has been disabled for the rest of this session. Your app keeps running \u2014 this is an Appilots bug, not a bug in your code. Please report it with the stack below: https://github.com/Axtern-Labs/Appilots/issues`,
|
|
3976
|
-
error
|
|
3977
|
-
);
|
|
3978
|
-
try {
|
|
3979
|
-
this.props.onError?.(error, info?.componentStack ?? null);
|
|
3980
|
-
} catch {
|
|
4481
|
+
if (typeof type === "object") {
|
|
4482
|
+
if (type.displayName) return type.displayName;
|
|
4483
|
+
if (type.render) {
|
|
4484
|
+
return type.render.displayName ?? type.render.name ?? null;
|
|
3981
4485
|
}
|
|
4486
|
+
if (type.type) return getTypeName(type.type);
|
|
3982
4487
|
}
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
4488
|
+
return null;
|
|
4489
|
+
}
|
|
4490
|
+
function matchesName(fiber, name) {
|
|
4491
|
+
return getTypeName(fiber.type) === name || getTypeName(fiber.elementType) === name;
|
|
4492
|
+
}
|
|
4493
|
+
function extractTextFromChildren(children) {
|
|
4494
|
+
if (children == null) return "";
|
|
4495
|
+
if (typeof children === "string") return children;
|
|
4496
|
+
if (typeof children === "number") return String(children);
|
|
4497
|
+
if (Array.isArray(children)) {
|
|
4498
|
+
return children.map((c) => extractTextFromChildren(c)).filter(Boolean).join("");
|
|
3987
4499
|
}
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
const
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4500
|
+
return "";
|
|
4501
|
+
}
|
|
4502
|
+
function findChildText(fiber) {
|
|
4503
|
+
const stack = [];
|
|
4504
|
+
if (fiber.child) stack.push(fiber.child);
|
|
4505
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
4506
|
+
const texts = [];
|
|
4507
|
+
const glyphs = [];
|
|
4508
|
+
while (stack.length > 0) {
|
|
4509
|
+
const node = stack.pop();
|
|
4510
|
+
if (!node || visited.has(node)) continue;
|
|
4511
|
+
visited.add(node);
|
|
4512
|
+
if (matchesName(node, "Text")) {
|
|
4513
|
+
const text = extractTextFromChildren(node.memoizedProps?.children);
|
|
4514
|
+
const trimmed = text.trim();
|
|
4515
|
+
if (isReferenceable(trimmed)) {
|
|
4516
|
+
texts.push(trimmed);
|
|
4517
|
+
if (texts.length >= 3) break;
|
|
4518
|
+
} else if (trimmed && glyphs.length < 3) {
|
|
4519
|
+
glyphs.push(trimmed);
|
|
4520
|
+
}
|
|
4521
|
+
}
|
|
4522
|
+
if (node.sibling) stack.push(node.sibling);
|
|
4523
|
+
if (node.child) stack.push(node.child);
|
|
4524
|
+
}
|
|
4525
|
+
if (texts.length > 0) return texts.join(" \xB7 ");
|
|
4526
|
+
return glyphs.length > 0 ? glyphs.join(" \xB7 ") : void 0;
|
|
4527
|
+
}
|
|
4528
|
+
var SELF_REFERENTIAL_COMPONENTS = /* @__PURE__ */ new Set([
|
|
4529
|
+
"AppilotsChat",
|
|
4530
|
+
"AppilotsChatInner",
|
|
4531
|
+
"ActionBreadcrumb",
|
|
4532
|
+
"ConfirmDialog"
|
|
4533
|
+
]);
|
|
4534
|
+
function isAppilotsSkipMarked(props) {
|
|
4535
|
+
if (!props) return false;
|
|
4536
|
+
return props.__appilotsSkip === true || props["data-appilots-skip"] === true || props.appilotsSkip === true;
|
|
4537
|
+
}
|
|
4538
|
+
function isAppilotsSensitiveMarked(props) {
|
|
4539
|
+
if (!props) return false;
|
|
4540
|
+
return props.__appilotsSensitive === true || props["data-appilots-sensitive"] === true || props.appilotsSensitive === true;
|
|
4541
|
+
}
|
|
4542
|
+
function stringProp(props, name) {
|
|
4543
|
+
const value = props?.[name];
|
|
4544
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
4545
|
+
}
|
|
4546
|
+
function numberProp(props, name) {
|
|
4547
|
+
const value = props?.[name];
|
|
4548
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
4549
|
+
}
|
|
4550
|
+
function shouldSkipSubtree(fiber) {
|
|
4551
|
+
const props = fiber.memoizedProps;
|
|
4552
|
+
if (!props) return false;
|
|
4553
|
+
const typeName2 = getTypeName(fiber.type) ?? getTypeName(fiber.elementType);
|
|
4554
|
+
if (typeName2 && SELF_REFERENTIAL_COMPONENTS.has(typeName2)) return true;
|
|
4555
|
+
if (isAppilotsSkipMarked(props)) return true;
|
|
4556
|
+
if (isModalFiber(fiber) && props.visible === false) return true;
|
|
4557
|
+
if (matchesName(fiber, "Screen") && props.activityState === 0) return true;
|
|
4558
|
+
const style = props.style;
|
|
4559
|
+
if (style) {
|
|
4560
|
+
const flat = Array.isArray(style) ? Object.assign({}, ...style.filter(Boolean)) : style;
|
|
4561
|
+
if (flat?.display === "none") return true;
|
|
4562
|
+
if (flat?.opacity === 0 && props.pointerEvents === "none") return true;
|
|
4563
|
+
}
|
|
4564
|
+
return false;
|
|
4565
|
+
}
|
|
4566
|
+
function inferInputType(props) {
|
|
4567
|
+
if (props.secureTextEntry || isAppilotsSensitiveMarked(props)) return "password";
|
|
4568
|
+
switch (props.keyboardType) {
|
|
4569
|
+
case "email-address":
|
|
4570
|
+
return "email";
|
|
4571
|
+
case "numeric":
|
|
4572
|
+
case "number-pad":
|
|
4573
|
+
case "decimal-pad":
|
|
4574
|
+
return "number";
|
|
4575
|
+
case "phone-pad":
|
|
4576
|
+
return "phone";
|
|
4577
|
+
default:
|
|
4578
|
+
return "text";
|
|
4579
|
+
}
|
|
4580
|
+
}
|
|
4581
|
+
function inferLabel(props) {
|
|
4582
|
+
return props.accessibilityLabel ?? props.label ?? props.placeholder ?? props.testID;
|
|
4583
|
+
}
|
|
4584
|
+
function resolveIdentity(props, label) {
|
|
4585
|
+
const declared = stringProp(props, "testID") ?? stringProp(props, "accessibilityLabel");
|
|
4586
|
+
if (declared) return { id: declared, provenance: "declared" };
|
|
4587
|
+
const derived = labelToId(label);
|
|
4588
|
+
if (derived) return { id: derived, provenance: "derived" };
|
|
4589
|
+
return { provenance: "positional" };
|
|
4590
|
+
}
|
|
4591
|
+
function isSwitchLike(fiber, props) {
|
|
4592
|
+
if (props?.accessibilityRole === "switch" || props?.role === "switch") return true;
|
|
4593
|
+
return matchesName(fiber, "Switch");
|
|
4594
|
+
}
|
|
4595
|
+
function switchValue(props) {
|
|
4596
|
+
if (typeof props?.value === "boolean") return props.value;
|
|
4597
|
+
const checked = props?.accessibilityState?.checked;
|
|
4598
|
+
return checked === true;
|
|
4599
|
+
}
|
|
4600
|
+
function nearbyLabelForSwitch(fiber) {
|
|
4601
|
+
let parent = fiber?.return;
|
|
4602
|
+
for (let depth = 0; parent && depth < 3; depth++, parent = parent.return) {
|
|
4603
|
+
const text = findChildText(parent);
|
|
4604
|
+
if (text && isReferenceable(text)) return text;
|
|
4605
|
+
}
|
|
4606
|
+
return void 0;
|
|
4607
|
+
}
|
|
4608
|
+
var ALWAYS_LIST_NAMES = /* @__PURE__ */ new Set([
|
|
4609
|
+
"FlatList",
|
|
4610
|
+
"SectionList",
|
|
4611
|
+
"VirtualizedList",
|
|
4612
|
+
// Shopify's high-perf FlatList replacement — same usage shape, same
|
|
4613
|
+
// virtualization, same per-item key.
|
|
4614
|
+
"FlashList"
|
|
4615
|
+
]);
|
|
4616
|
+
var HEURISTIC_LIST_NAMES = /* @__PURE__ */ new Set(["ScrollView"]);
|
|
4617
|
+
var LIST_CELL_NAMES = /* @__PURE__ */ new Set([
|
|
4618
|
+
"CellRenderer",
|
|
4619
|
+
"CellRendererComponent",
|
|
4620
|
+
"VirtualizedListCellContextProvider"
|
|
4621
|
+
]);
|
|
4622
|
+
function looksLikeListContainerByProps(props) {
|
|
4623
|
+
if (!props || typeof props !== "object") return false;
|
|
4624
|
+
if (typeof props.renderItem !== "function") return false;
|
|
4625
|
+
if (Array.isArray(props.sections)) return true;
|
|
4626
|
+
if (Array.isArray(props.data)) return true;
|
|
4627
|
+
return typeof props.getItemCount === "function" && typeof props.getItem === "function";
|
|
4628
|
+
}
|
|
4629
|
+
function isAlwaysListContainer(fiber) {
|
|
4630
|
+
for (const name of ALWAYS_LIST_NAMES) {
|
|
4631
|
+
if (matchesName(fiber, name)) return true;
|
|
4632
|
+
}
|
|
4633
|
+
return looksLikeListContainerByProps(fiber?.memoizedProps);
|
|
4634
|
+
}
|
|
4635
|
+
function isHeuristicListContainer(fiber) {
|
|
4636
|
+
for (const name of HEURISTIC_LIST_NAMES) {
|
|
4637
|
+
if (matchesName(fiber, name)) return true;
|
|
4638
|
+
}
|
|
4639
|
+
return false;
|
|
4640
|
+
}
|
|
4641
|
+
function isKnownListCell(fiber) {
|
|
4642
|
+
const typeName2 = getTypeName(fiber.type) ?? getTypeName(fiber.elementType);
|
|
4643
|
+
return !!typeName2 && LIST_CELL_NAMES.has(typeName2);
|
|
4644
|
+
}
|
|
4645
|
+
var MODAL_HOST_NAMES = /* @__PURE__ */ new Set(["RCTModalHostView", "ModalHostView"]);
|
|
4646
|
+
function isModalHostFiber(fiber) {
|
|
4647
|
+
const type = fiber?.type;
|
|
4648
|
+
return typeof type === "string" && MODAL_HOST_NAMES.has(type);
|
|
4649
|
+
}
|
|
4650
|
+
function isModalFiber(fiber) {
|
|
4651
|
+
return matchesName(fiber, "Modal") || isModalHostFiber(fiber);
|
|
4652
|
+
}
|
|
4653
|
+
function isVisibleModalFiber(fiber) {
|
|
4654
|
+
return isModalFiber(fiber) && fiber?.memoizedProps?.visible !== false;
|
|
4655
|
+
}
|
|
4656
|
+
function collectVisibleModalFibers(container, excludeRoots = []) {
|
|
4657
|
+
const excluded = /* @__PURE__ */ new WeakSet();
|
|
4658
|
+
for (const rootFiber of excludeRoots) {
|
|
4659
|
+
if (rootFiber) excluded.add(rootFiber);
|
|
4660
|
+
}
|
|
4661
|
+
const found = [];
|
|
4662
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
4663
|
+
const stack = [];
|
|
4664
|
+
if (container?.child) stack.push(container.child);
|
|
4665
|
+
while (stack.length > 0) {
|
|
4666
|
+
const node = stack.pop();
|
|
4667
|
+
if (!node || visited.has(node)) continue;
|
|
4668
|
+
visited.add(node);
|
|
4669
|
+
if (node.sibling) stack.push(node.sibling);
|
|
4670
|
+
if (excluded.has(node) || shouldSkipSubtree(node)) continue;
|
|
4671
|
+
if (isVisibleModalFiber(node)) {
|
|
4672
|
+
found.push(node);
|
|
4673
|
+
continue;
|
|
4674
|
+
}
|
|
4675
|
+
if (node.child) stack.push(node.child);
|
|
4676
|
+
}
|
|
4677
|
+
return found;
|
|
4678
|
+
}
|
|
4679
|
+
function isMarkedListItem(fiber, listId) {
|
|
4680
|
+
const props = fiber?.memoizedProps;
|
|
4681
|
+
if (!props || props.__appilotsListItem !== true) return false;
|
|
4682
|
+
if (!listId) return true;
|
|
4683
|
+
return props.__appilotsListId === listId;
|
|
4684
|
+
}
|
|
4685
|
+
function listIdFromProps(props) {
|
|
4686
|
+
return stringProp(props, "__appilotsListId") ?? stringProp(props, "appilotsListId") ?? // A ScrollView that turned out to hold keyed rows is BOTH: the
|
|
4687
|
+
// walker sees a list, auto-tracking registered a scrollable. Sharing
|
|
4688
|
+
// the id lets the two merge instead of describing one surface twice.
|
|
4689
|
+
stringProp(props, "__appilotsScrollId");
|
|
4690
|
+
}
|
|
4691
|
+
function explicitListIdFromProps(props) {
|
|
4692
|
+
return stringProp(props, "__appilotsListId") ?? stringProp(props, "appilotsListId");
|
|
4693
|
+
}
|
|
4694
|
+
function listMetadataFromProps(props) {
|
|
4695
|
+
const id = listIdFromProps(props);
|
|
4696
|
+
const itemCount = numberProp(props, "__appilotsItemCount");
|
|
4697
|
+
const label = stringProp(props, "__appilotsListLabel") ?? stringProp(props, "accessibilityLabel") ?? stringProp(props, "testID");
|
|
4698
|
+
const refreshing = props?.refreshing === true || props?.__appilotsRefreshing === true;
|
|
4699
|
+
const empty = props?.__appilotsEmpty === true || typeof itemCount === "number" && itemCount === 0;
|
|
4700
|
+
return {
|
|
4701
|
+
id,
|
|
4702
|
+
itemCount,
|
|
4703
|
+
refreshing,
|
|
4704
|
+
empty,
|
|
4705
|
+
label,
|
|
4706
|
+
source: id ? "auto-tracked" : void 0
|
|
4707
|
+
};
|
|
4708
|
+
}
|
|
4709
|
+
function hasRenderableContent(fiber) {
|
|
4710
|
+
const stack = [fiber];
|
|
4711
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
4712
|
+
while (stack.length > 0) {
|
|
4713
|
+
const node = stack.pop();
|
|
4714
|
+
if (!node || visited.has(node)) continue;
|
|
4715
|
+
visited.add(node);
|
|
4716
|
+
if (shouldSkipSubtree(node) || isModalFiber(node)) continue;
|
|
4717
|
+
const props = node.memoizedProps ?? {};
|
|
4718
|
+
if (matchesName(node, "Text")) {
|
|
4719
|
+
const text = extractTextFromChildren(props.children);
|
|
4720
|
+
if (text && text.trim().length > 0) return true;
|
|
4721
|
+
}
|
|
4722
|
+
if (matchesName(node, "TextInput") || matchesName(node, "Switch")) {
|
|
4723
|
+
return true;
|
|
4000
4724
|
}
|
|
4725
|
+
if (TOUCHABLE_NAMES.has(getTypeName(node.type) ?? "") || TOUCHABLE_NAMES.has(getTypeName(node.elementType) ?? "")) {
|
|
4726
|
+
return true;
|
|
4727
|
+
}
|
|
4728
|
+
if (node.sibling) stack.push(node.sibling);
|
|
4729
|
+
if (node.child) stack.push(node.child);
|
|
4730
|
+
}
|
|
4731
|
+
return false;
|
|
4732
|
+
}
|
|
4733
|
+
function findListCellsByType(container, minItems) {
|
|
4734
|
+
const cells = [];
|
|
4735
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
4736
|
+
const stack = [];
|
|
4737
|
+
if (container?.child) stack.push(container.child);
|
|
4738
|
+
while (stack.length > 0) {
|
|
4739
|
+
const node = stack.pop();
|
|
4740
|
+
if (!node || visited.has(node)) continue;
|
|
4741
|
+
visited.add(node);
|
|
4742
|
+
if (node.sibling) stack.push(node.sibling);
|
|
4743
|
+
if (shouldSkipSubtree(node) || isModalFiber(node)) continue;
|
|
4744
|
+
if (isAlwaysListContainer(node)) continue;
|
|
4745
|
+
if (isKnownListCell(node) && hasRenderableContent(node)) {
|
|
4746
|
+
cells.push(node);
|
|
4747
|
+
continue;
|
|
4748
|
+
}
|
|
4749
|
+
if (node.child) stack.push(node.child);
|
|
4750
|
+
}
|
|
4751
|
+
return cells.length >= minItems ? cells : null;
|
|
4752
|
+
}
|
|
4753
|
+
function findMarkedListItems(container, minItems, listId) {
|
|
4754
|
+
const items = [];
|
|
4755
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
4756
|
+
const stack = [];
|
|
4757
|
+
if (container?.child) stack.push(container.child);
|
|
4758
|
+
while (stack.length > 0) {
|
|
4759
|
+
const node = stack.pop();
|
|
4760
|
+
if (!node || visited.has(node)) continue;
|
|
4761
|
+
visited.add(node);
|
|
4762
|
+
if (node.sibling) stack.push(node.sibling);
|
|
4763
|
+
if (shouldSkipSubtree(node) || isModalFiber(node)) continue;
|
|
4764
|
+
if (isMarkedListItem(node, listId)) {
|
|
4765
|
+
items.push(node);
|
|
4766
|
+
continue;
|
|
4767
|
+
}
|
|
4768
|
+
if (node.child) stack.push(node.child);
|
|
4769
|
+
}
|
|
4770
|
+
if (items.length < minItems) return null;
|
|
4771
|
+
items.sort((a, b) => {
|
|
4772
|
+
const ai = numberProp(a.memoizedProps, "__appilotsItemIndex");
|
|
4773
|
+
const bi = numberProp(b.memoizedProps, "__appilotsItemIndex");
|
|
4774
|
+
if (ai === void 0 && bi === void 0) return 0;
|
|
4775
|
+
if (ai === void 0) return 1;
|
|
4776
|
+
if (bi === void 0) return -1;
|
|
4777
|
+
return ai - bi;
|
|
4001
4778
|
});
|
|
4779
|
+
return items;
|
|
4780
|
+
}
|
|
4781
|
+
function hasAuthoredReactKey(fiber) {
|
|
4782
|
+
const key = fiber?.key;
|
|
4783
|
+
if (key === null || key === void 0 || key === "") return false;
|
|
4784
|
+
const s = String(key);
|
|
4785
|
+
if (s.startsWith(".") && !s.startsWith(".$")) return false;
|
|
4786
|
+
return true;
|
|
4787
|
+
}
|
|
4788
|
+
function findKeyedSiblingItems(container, minItems) {
|
|
4789
|
+
if (!container) return null;
|
|
4790
|
+
let current = container;
|
|
4791
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
4792
|
+
while (current && !visited.has(current)) {
|
|
4793
|
+
visited.add(current);
|
|
4794
|
+
const siblings = [];
|
|
4795
|
+
let cur = current.child;
|
|
4796
|
+
while (cur) {
|
|
4797
|
+
if (!isModalFiber(cur)) siblings.push(cur);
|
|
4798
|
+
cur = cur.sibling;
|
|
4799
|
+
}
|
|
4800
|
+
if (siblings.length === 0) return null;
|
|
4801
|
+
const keyed = siblings.filter(hasAuthoredReactKey);
|
|
4802
|
+
if (keyed.length >= minItems) {
|
|
4803
|
+
return keyed;
|
|
4804
|
+
}
|
|
4805
|
+
if (siblings.length > 1) {
|
|
4806
|
+
return null;
|
|
4807
|
+
}
|
|
4808
|
+
current = siblings[0];
|
|
4809
|
+
}
|
|
4810
|
+
return null;
|
|
4002
4811
|
}
|
|
4003
|
-
function
|
|
4812
|
+
function findListItems(container, minItems = 2, preferCells = false) {
|
|
4813
|
+
if (!container) return null;
|
|
4814
|
+
const listId = listIdFromProps(container.memoizedProps);
|
|
4815
|
+
const markedItems = findMarkedListItems(container, minItems, listId);
|
|
4816
|
+
if (markedItems) return markedItems;
|
|
4817
|
+
if (preferCells) {
|
|
4818
|
+
const cells = findListCellsByType(container, minItems);
|
|
4819
|
+
if (cells) return cells;
|
|
4820
|
+
}
|
|
4821
|
+
if (minItems <= 1) {
|
|
4822
|
+
const multiItemLevel = findKeyedSiblingItems(container, 2);
|
|
4823
|
+
if (multiItemLevel) return multiItemLevel;
|
|
4824
|
+
}
|
|
4825
|
+
return findKeyedSiblingItems(container, minItems) ?? findListCellsByType(container, minItems);
|
|
4826
|
+
}
|
|
4827
|
+
var TOUCHABLE_NAMES = /* @__PURE__ */ new Set([
|
|
4828
|
+
"TouchableOpacity",
|
|
4829
|
+
"TouchableHighlight",
|
|
4830
|
+
"TouchableWithoutFeedback",
|
|
4831
|
+
"TouchableNativeFeedback",
|
|
4832
|
+
"Pressable"
|
|
4833
|
+
]);
|
|
4834
|
+
function hasPressHandler(fiber) {
|
|
4835
|
+
const props = fiber?.memoizedProps ?? {};
|
|
4836
|
+
return typeof props.onPress === "function" || typeof props.onPressIn === "function";
|
|
4837
|
+
}
|
|
4838
|
+
function isPressableTarget(fiber) {
|
|
4839
|
+
return TOUCHABLE_NAMES.has(getTypeName(fiber.type) ?? "") || TOUCHABLE_NAMES.has(getTypeName(fiber.elementType) ?? "") || hasPressHandler(fiber);
|
|
4840
|
+
}
|
|
4841
|
+
function emptyDetectorCounts() {
|
|
4004
4842
|
return {
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4843
|
+
Text: 0,
|
|
4844
|
+
TextInput: 0,
|
|
4845
|
+
Switch: 0,
|
|
4846
|
+
ActivityIndicator: 0,
|
|
4847
|
+
Modal: 0,
|
|
4848
|
+
adjustable: 0,
|
|
4849
|
+
pressable: 0,
|
|
4850
|
+
listContainers: 0
|
|
4013
4851
|
};
|
|
4014
4852
|
}
|
|
4015
|
-
function
|
|
4016
|
-
return
|
|
4017
|
-
AppilotsErrorBoundary,
|
|
4018
|
-
{
|
|
4019
|
-
surface: "provider",
|
|
4020
|
-
onError: reportProviderRenderFailure,
|
|
4021
|
-
fallback: /* @__PURE__ */ React2__default.default.createElement(AppilotsContext.Provider, { value: createDegradedContext(config ?? null) }, children)
|
|
4022
|
-
},
|
|
4023
|
-
/* @__PURE__ */ React2__default.default.createElement(AppilotsProviderInner, { config, client }, children)
|
|
4024
|
-
);
|
|
4853
|
+
function totalDetectorHits(counts) {
|
|
4854
|
+
return counts.Text + counts.TextInput + counts.Switch + counts.ActivityIndicator + counts.Modal + counts.adjustable + counts.pressable + counts.listContainers;
|
|
4025
4855
|
}
|
|
4026
|
-
function
|
|
4027
|
-
|
|
4856
|
+
function addDetectorCounts(into, from) {
|
|
4857
|
+
into.Text += from.Text;
|
|
4858
|
+
into.TextInput += from.TextInput;
|
|
4859
|
+
into.Switch += from.Switch;
|
|
4860
|
+
into.ActivityIndicator += from.ActivityIndicator;
|
|
4861
|
+
into.Modal += from.Modal;
|
|
4862
|
+
into.adjustable += from.adjustable;
|
|
4863
|
+
into.pressable += from.pressable;
|
|
4864
|
+
into.listContainers += from.listContainers;
|
|
4028
4865
|
}
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
return
|
|
4866
|
+
var _lastWalk = null;
|
|
4867
|
+
function getLastWalkDiagnostics() {
|
|
4868
|
+
return _lastWalk ? { ..._lastWalk, detectors: { ..._lastWalk.detectors } } : null;
|
|
4032
4869
|
}
|
|
4033
|
-
function
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
);
|
|
4870
|
+
function walkSubtree(root, detectLists, startInModal = false) {
|
|
4871
|
+
const result = {
|
|
4872
|
+
texts: [],
|
|
4873
|
+
inputs: [],
|
|
4874
|
+
buttons: [],
|
|
4875
|
+
toggles: [],
|
|
4876
|
+
sliders: [],
|
|
4877
|
+
visitedFibers: 0,
|
|
4878
|
+
skippedHidden: 0,
|
|
4879
|
+
loading: false,
|
|
4880
|
+
modalOpen: false,
|
|
4881
|
+
lists: [],
|
|
4882
|
+
detectors: emptyDetectorCounts()
|
|
4883
|
+
};
|
|
4884
|
+
if (!root) return result;
|
|
4885
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
4886
|
+
const stack = [];
|
|
4887
|
+
if (root.child) stack.push({ fiber: root.child, inModal: startInModal });
|
|
4888
|
+
while (stack.length > 0) {
|
|
4889
|
+
const { fiber, inModal, ancestorPress } = stack.pop();
|
|
4890
|
+
if (!fiber || visited.has(fiber)) continue;
|
|
4891
|
+
visited.add(fiber);
|
|
4892
|
+
result.visitedFibers++;
|
|
4893
|
+
if (fiber.sibling) stack.push({ fiber: fiber.sibling, inModal });
|
|
4894
|
+
if (shouldSkipSubtree(fiber)) {
|
|
4895
|
+
result.skippedHidden++;
|
|
4896
|
+
continue;
|
|
4897
|
+
}
|
|
4898
|
+
if (detectLists) {
|
|
4899
|
+
const isAlways = isAlwaysListContainer(fiber);
|
|
4900
|
+
const isHeuristic = !isAlways && isHeuristicListContainer(fiber);
|
|
4901
|
+
if (isAlways || isHeuristic) {
|
|
4902
|
+
result.detectors.listContainers++;
|
|
4903
|
+
const minItems = isAlways ? 1 : 2;
|
|
4904
|
+
const items = findListItems(fiber, minItems, isAlways);
|
|
4905
|
+
if (items && items.length >= minItems) {
|
|
4906
|
+
const containerType = getTypeName(fiber.type) ?? getTypeName(fiber.elementType) ?? "List";
|
|
4907
|
+
const listIndex = result.lists.length;
|
|
4908
|
+
const itemSnapshots = items.map((itemFiber, i) => {
|
|
4909
|
+
const itemResult = walkSubtree(itemFiber, false, inModal);
|
|
4910
|
+
result.visitedFibers += itemResult.visitedFibers;
|
|
4911
|
+
result.skippedHidden += itemResult.skippedHidden;
|
|
4912
|
+
addDetectorCounts(result.detectors, itemResult.detectors);
|
|
4913
|
+
if (itemResult.loading) result.loading = true;
|
|
4914
|
+
if (itemResult.modalOpen) result.modalOpen = true;
|
|
4915
|
+
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;
|
|
4916
|
+
const itemKey = typeof itemFiber.memoizedProps?.__appilotsItemKey === "string" || typeof itemFiber.memoizedProps?.__appilotsItemKey === "number" ? String(itemFiber.memoizedProps.__appilotsItemKey) : void 0;
|
|
4917
|
+
const dataIndex = numberProp(itemFiber.memoizedProps, "__appilotsItemIndex");
|
|
4918
|
+
const syntheticId = `list-${listIndex}-item-${i + 1}`;
|
|
4919
|
+
return {
|
|
4920
|
+
index: i + 1,
|
|
4921
|
+
dataIndex,
|
|
4922
|
+
reactKey,
|
|
4923
|
+
itemKey,
|
|
4924
|
+
syntheticId,
|
|
4925
|
+
texts: dedupeStringsInternal(itemResult.texts),
|
|
4926
|
+
// Scope the row's ordinals by its own synthetic id, so an
|
|
4927
|
+
// unnamed control in row 3 cannot collide with one in row 1
|
|
4928
|
+
// or with a screen-level one.
|
|
4929
|
+
buttons: dedupeButtonsInternal(itemResult.buttons, `${syntheticId}-`),
|
|
4930
|
+
inputs: dedupeInputsInternal(itemResult.inputs, `${syntheticId}-`),
|
|
4931
|
+
toggles: dedupeTogglesInternal(itemResult.toggles, `${syntheticId}-`)
|
|
4932
|
+
};
|
|
4933
|
+
});
|
|
4934
|
+
const meta2 = listMetadataFromProps(fiber.memoizedProps);
|
|
4935
|
+
result.lists.push({
|
|
4936
|
+
index: listIndex,
|
|
4937
|
+
id: meta2.id,
|
|
4938
|
+
containerType,
|
|
4939
|
+
source: meta2.source ?? "fiber",
|
|
4940
|
+
itemCount: meta2.itemCount,
|
|
4941
|
+
visibleItemCount: itemSnapshots.length,
|
|
4942
|
+
refreshing: meta2.refreshing,
|
|
4943
|
+
empty: meta2.empty,
|
|
4944
|
+
label: meta2.label,
|
|
4945
|
+
items: itemSnapshots
|
|
4946
|
+
});
|
|
4947
|
+
for (const modalFiber of collectVisibleModalFibers(fiber, items)) {
|
|
4948
|
+
result.modalOpen = true;
|
|
4949
|
+
if (modalFiber.child) stack.push({ fiber: modalFiber.child, inModal: true });
|
|
4950
|
+
}
|
|
4951
|
+
continue;
|
|
4952
|
+
}
|
|
4953
|
+
const meta = listMetadataFromProps(fiber.memoizedProps);
|
|
4954
|
+
const declaresList = meta.itemCount !== void 0 || meta.refreshing || meta.empty || !!explicitListIdFromProps(fiber.memoizedProps);
|
|
4955
|
+
if (declaresList) {
|
|
4956
|
+
const containerType = getTypeName(fiber.type) ?? getTypeName(fiber.elementType) ?? "List";
|
|
4957
|
+
result.lists.push({
|
|
4958
|
+
index: result.lists.length,
|
|
4959
|
+
id: meta.id,
|
|
4960
|
+
containerType,
|
|
4961
|
+
source: meta.source ?? "auto-tracked",
|
|
4962
|
+
itemCount: meta.itemCount,
|
|
4963
|
+
visibleItemCount: 0,
|
|
4964
|
+
refreshing: meta.refreshing,
|
|
4965
|
+
empty: meta.empty,
|
|
4966
|
+
label: meta.label,
|
|
4967
|
+
items: []
|
|
4968
|
+
});
|
|
4969
|
+
for (const modalFiber of collectVisibleModalFibers(fiber)) {
|
|
4970
|
+
result.modalOpen = true;
|
|
4971
|
+
if (modalFiber.child) stack.push({ fiber: modalFiber.child, inModal: true });
|
|
4972
|
+
}
|
|
4973
|
+
continue;
|
|
4974
|
+
}
|
|
4975
|
+
}
|
|
4976
|
+
}
|
|
4977
|
+
const props = fiber.memoizedProps ?? {};
|
|
4978
|
+
if (matchesName(fiber, "Text")) {
|
|
4979
|
+
result.detectors.Text++;
|
|
4980
|
+
const text = extractTextFromChildren(props.children);
|
|
4981
|
+
if (text && text.trim().length > 0) {
|
|
4982
|
+
result.texts.push(text.trim());
|
|
4983
|
+
}
|
|
4984
|
+
} else if (matchesName(fiber, "TextInput")) {
|
|
4985
|
+
result.detectors.TextInput++;
|
|
4986
|
+
if (props.__appilotsInternal !== true) {
|
|
4987
|
+
const isSecure = !!props.secureTextEntry || isAppilotsSensitiveMarked(props);
|
|
4988
|
+
const rawValue = typeof props.value === "string" ? props.value : void 0;
|
|
4989
|
+
const safeValue = isSecure ? rawValue && rawValue.length > 0 ? "<hidden>" : void 0 : rawValue;
|
|
4990
|
+
const identity = resolveIdentity(props, inferLabel(props));
|
|
4991
|
+
const geom = readGeometry(fiber);
|
|
4992
|
+
result.inputs.push(
|
|
4993
|
+
withRect(
|
|
4994
|
+
{
|
|
4995
|
+
id: identity.id,
|
|
4996
|
+
provenance: identity.provenance,
|
|
4997
|
+
label: inferLabel(props),
|
|
4998
|
+
value: safeValue,
|
|
4999
|
+
placeholder: props.placeholder,
|
|
5000
|
+
editable: props.editable !== false,
|
|
5001
|
+
secure: isSecure,
|
|
5002
|
+
type: inferInputType(props),
|
|
5003
|
+
// A field whose return key submits (#398). On a search box or
|
|
5004
|
+
// a one-field login this IS the submit, and without the flag
|
|
5005
|
+
// the screen looks like a form with no way to send it.
|
|
5006
|
+
...typeof props.onSubmitEditing === "function" ? { submitsOnReturn: true } : {},
|
|
5007
|
+
...inModal ? { inModal: true } : {},
|
|
5008
|
+
...geom.fields
|
|
5009
|
+
},
|
|
5010
|
+
geom
|
|
5011
|
+
)
|
|
5012
|
+
);
|
|
5013
|
+
}
|
|
5014
|
+
} else if (props.accessibilityRole === "adjustable") {
|
|
5015
|
+
result.detectors.adjustable++;
|
|
5016
|
+
if (props.__appilotsInternal !== true) {
|
|
5017
|
+
const av = props.accessibilityValue ?? {};
|
|
5018
|
+
const sliderLabel = props.accessibilityLabel ?? props.testID;
|
|
5019
|
+
const sliderIdentity = resolveIdentity(props, sliderLabel);
|
|
5020
|
+
const geom = readGeometry(fiber);
|
|
5021
|
+
result.sliders.push(
|
|
5022
|
+
withRect(
|
|
5023
|
+
{
|
|
5024
|
+
id: sliderIdentity.id,
|
|
5025
|
+
provenance: sliderIdentity.provenance,
|
|
5026
|
+
label: sliderLabel,
|
|
5027
|
+
value: typeof av.now === "number" ? av.now : void 0,
|
|
5028
|
+
min: typeof av.min === "number" ? av.min : void 0,
|
|
5029
|
+
max: typeof av.max === "number" ? av.max : void 0,
|
|
5030
|
+
...inModal ? { inModal: true } : {},
|
|
5031
|
+
...geom.fields
|
|
5032
|
+
},
|
|
5033
|
+
geom
|
|
5034
|
+
)
|
|
5035
|
+
);
|
|
5036
|
+
}
|
|
5037
|
+
} else if (isSwitchLike(fiber, props)) {
|
|
5038
|
+
result.detectors.Switch++;
|
|
5039
|
+
if (props.__appilotsInternal !== true) {
|
|
5040
|
+
const label = props.accessibilityLabel ?? props.testID ?? nearbyLabelForSwitch(fiber);
|
|
5041
|
+
const toggleIdentity = resolveIdentity(props, label);
|
|
5042
|
+
const geom = readGeometry(fiber);
|
|
5043
|
+
result.toggles.push(
|
|
5044
|
+
withRect(
|
|
5045
|
+
{
|
|
5046
|
+
// Same fallback the branch below has always had for buttons.
|
|
5047
|
+
// Without it every unnamed switch arrived as `id: undefined`
|
|
5048
|
+
// and dedupeToggles merged them all into one (#385).
|
|
5049
|
+
id: toggleIdentity.id,
|
|
5050
|
+
provenance: toggleIdentity.provenance,
|
|
5051
|
+
label,
|
|
5052
|
+
value: switchValue(props),
|
|
5053
|
+
...inModal ? { inModal: true } : {},
|
|
5054
|
+
...geom.fields
|
|
5055
|
+
},
|
|
5056
|
+
geom
|
|
5057
|
+
)
|
|
5058
|
+
);
|
|
5059
|
+
}
|
|
5060
|
+
continue;
|
|
5061
|
+
} else if (isPressableTarget(fiber)) {
|
|
5062
|
+
result.detectors.pressable++;
|
|
5063
|
+
const isRepeatOfAncestor = typeof props.onPress === "function" && props.onPress === ancestorPress;
|
|
5064
|
+
if (props.__appilotsInternal !== true && !isRepeatOfAncestor) {
|
|
5065
|
+
const label = findChildText(fiber);
|
|
5066
|
+
const state = props.accessibilityState ?? {};
|
|
5067
|
+
const on = state.checked === true || state.selected === true;
|
|
5068
|
+
const buttonIdentity = resolveIdentity(props, label);
|
|
5069
|
+
const geom = readGeometry(fiber);
|
|
5070
|
+
result.buttons.push(
|
|
5071
|
+
withRect(
|
|
5072
|
+
{
|
|
5073
|
+
id: buttonIdentity.id,
|
|
5074
|
+
provenance: buttonIdentity.provenance,
|
|
5075
|
+
label,
|
|
5076
|
+
disabled: !!props.disabled,
|
|
5077
|
+
...on ? { selected: true } : {},
|
|
5078
|
+
...inModal ? { inModal: true } : {},
|
|
5079
|
+
...geom.fields
|
|
5080
|
+
},
|
|
5081
|
+
geom
|
|
5082
|
+
)
|
|
5083
|
+
);
|
|
5084
|
+
}
|
|
5085
|
+
if (fiber.child) {
|
|
5086
|
+
stack.push({
|
|
5087
|
+
fiber: fiber.child,
|
|
5088
|
+
inModal,
|
|
5089
|
+
// Children of this pressable inherit its handler, so a nested
|
|
5090
|
+
// fiber forwarding the SAME `onPress` is recognized as a repeat.
|
|
5091
|
+
ancestorPress: typeof props.onPress === "function" ? props.onPress : ancestorPress
|
|
5092
|
+
});
|
|
5093
|
+
}
|
|
5094
|
+
continue;
|
|
5095
|
+
} else if (matchesName(fiber, "ActivityIndicator")) {
|
|
5096
|
+
result.detectors.ActivityIndicator++;
|
|
5097
|
+
result.loading = true;
|
|
5098
|
+
} else if (isModalFiber(fiber)) {
|
|
5099
|
+
result.detectors.Modal++;
|
|
5100
|
+
result.modalOpen = true;
|
|
5101
|
+
if (fiber.child) stack.push({ fiber: fiber.child, inModal: true });
|
|
5102
|
+
continue;
|
|
5103
|
+
}
|
|
5104
|
+
if (fiber.child) stack.push({ fiber: fiber.child, inModal });
|
|
4053
5105
|
}
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
const
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
);
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
5106
|
+
return result;
|
|
5107
|
+
}
|
|
5108
|
+
function walkFiber(root) {
|
|
5109
|
+
const snapshot = {
|
|
5110
|
+
route: getCurrentScreen(),
|
|
5111
|
+
texts: [],
|
|
5112
|
+
inputs: [],
|
|
5113
|
+
buttons: [],
|
|
5114
|
+
toggles: [],
|
|
5115
|
+
// Sliders come from the ComponentRegistry (useAppilotsSlider) —
|
|
5116
|
+
// captureSnapshot merges them so observation only ever advertises
|
|
5117
|
+
// sliders the executor can actually set (min/max/step + setValue).
|
|
5118
|
+
sliders: [],
|
|
5119
|
+
loading: false,
|
|
5120
|
+
modalOpen: false,
|
|
5121
|
+
lists: [],
|
|
5122
|
+
choiceGroups: [],
|
|
5123
|
+
elements: [],
|
|
5124
|
+
stats: { visitedFibers: 0, skippedHidden: 0 }
|
|
5125
|
+
};
|
|
5126
|
+
if (!root) return snapshot;
|
|
5127
|
+
const sub = walkSubtree(root, true);
|
|
5128
|
+
snapshot.texts = dedupeStringsInternal(sub.texts);
|
|
5129
|
+
snapshot.inputs = dedupeInputsInternal(sub.inputs);
|
|
5130
|
+
snapshot.buttons = dedupeButtonsInternal(sub.buttons);
|
|
5131
|
+
snapshot.toggles = dedupeTogglesInternal(sub.toggles);
|
|
5132
|
+
snapshot.sliders = dedupeSliders(sub.sliders);
|
|
5133
|
+
snapshot.loading = sub.loading;
|
|
5134
|
+
snapshot.modalOpen = sub.modalOpen;
|
|
5135
|
+
snapshot.lists = sub.lists;
|
|
5136
|
+
snapshot.choiceGroups = deriveChoiceGroups(snapshot);
|
|
5137
|
+
snapshot.stats.visitedFibers = sub.visitedFibers;
|
|
5138
|
+
snapshot.stats.skippedHidden = sub.skippedHidden;
|
|
5139
|
+
snapshot.stats.identity = tallyIdentity(snapshot);
|
|
5140
|
+
_lastWalk = {
|
|
5141
|
+
visitedFibers: sub.visitedFibers,
|
|
5142
|
+
skippedHidden: sub.skippedHidden,
|
|
5143
|
+
detectors: sub.detectors
|
|
5144
|
+
};
|
|
5145
|
+
return snapshot;
|
|
5146
|
+
}
|
|
5147
|
+
function tallyIdentity(snapshot) {
|
|
5148
|
+
const tally = { declared: 0, derived: 0, positional: 0 };
|
|
5149
|
+
const count = (entries2) => {
|
|
5150
|
+
for (const entry of entries2) {
|
|
5151
|
+
if (entry.provenance) tally[entry.provenance] += 1;
|
|
5152
|
+
}
|
|
5153
|
+
};
|
|
5154
|
+
count(snapshot.inputs);
|
|
5155
|
+
count(snapshot.buttons);
|
|
5156
|
+
count(snapshot.toggles);
|
|
5157
|
+
count(snapshot.sliders);
|
|
5158
|
+
for (const list of snapshot.lists) {
|
|
5159
|
+
for (const item of list.items) {
|
|
5160
|
+
count(item.buttons);
|
|
5161
|
+
count(item.inputs);
|
|
5162
|
+
count(item.toggles);
|
|
5163
|
+
}
|
|
5164
|
+
}
|
|
5165
|
+
return tally;
|
|
5166
|
+
}
|
|
5167
|
+
function dedupeButtonsInternal(buttons, scope = "") {
|
|
5168
|
+
return dedupeButtons(buttons, scope);
|
|
5169
|
+
}
|
|
5170
|
+
function dedupeInputsInternal(inputs, scope = "") {
|
|
5171
|
+
return dedupeInputs(inputs, scope);
|
|
5172
|
+
}
|
|
5173
|
+
function dedupeTogglesInternal(toggles, scope = "") {
|
|
5174
|
+
return dedupeToggles(toggles, scope);
|
|
5175
|
+
}
|
|
5176
|
+
function dedupeStringsInternal(strings) {
|
|
5177
|
+
return dedupeStrings(strings);
|
|
5178
|
+
}
|
|
5179
|
+
function isCommandLikeLabel(label) {
|
|
5180
|
+
if (!label) return true;
|
|
5181
|
+
const normalized = labelToId(label);
|
|
5182
|
+
if (!normalized) return true;
|
|
5183
|
+
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(
|
|
5184
|
+
normalized
|
|
4094
5185
|
);
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
5186
|
+
}
|
|
5187
|
+
function deriveChoiceGroups(snapshot) {
|
|
5188
|
+
const groups = [];
|
|
5189
|
+
for (const list of snapshot.lists) {
|
|
5190
|
+
const options = list.items.filter((item) => item.texts.length > 0 || item.buttons.length > 0).map((item, i) => {
|
|
5191
|
+
const texts = item.texts.length > 0 ? item.texts : item.buttons.map((b) => b.label ?? b.id ?? "").filter((text) => text.length > 0);
|
|
5192
|
+
return {
|
|
5193
|
+
index: i + 1,
|
|
5194
|
+
syntheticId: `${list.id ?? `list-${list.index}`}-choice-${i + 1}`,
|
|
5195
|
+
targetId: item.syntheticId,
|
|
5196
|
+
label: texts.slice(0, 2).join(" \xB7 "),
|
|
5197
|
+
texts,
|
|
5198
|
+
disabled: false
|
|
5199
|
+
};
|
|
4103
5200
|
});
|
|
4104
|
-
|
|
4105
|
-
|
|
5201
|
+
if (options.length > 0) {
|
|
5202
|
+
groups.push({
|
|
5203
|
+
index: groups.length,
|
|
5204
|
+
id: list.id,
|
|
5205
|
+
label: list.label,
|
|
5206
|
+
source: "list",
|
|
5207
|
+
options
|
|
5208
|
+
});
|
|
5209
|
+
}
|
|
5210
|
+
}
|
|
5211
|
+
const buttonOptions = snapshot.buttons.filter((button) => !button.disabled).filter((button) => isReferenceable(button.label ?? button.id)).filter((button) => !isCommandLikeLabel(button.label ?? button.id)).map((button, i) => {
|
|
5212
|
+
const label = button.label ?? button.id ?? "";
|
|
5213
|
+
return {
|
|
5214
|
+
index: i + 1,
|
|
5215
|
+
syntheticId: `choice-buttons-option-${i + 1}`,
|
|
5216
|
+
targetId: button.id ?? button.label,
|
|
5217
|
+
label,
|
|
5218
|
+
texts: [label],
|
|
5219
|
+
selected: !!button.selected,
|
|
5220
|
+
disabled: !!button.disabled
|
|
4106
5221
|
};
|
|
4107
|
-
}
|
|
4108
|
-
|
|
4109
|
-
(
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
5222
|
+
});
|
|
5223
|
+
if (buttonOptions.length >= 2) {
|
|
5224
|
+
groups.push({
|
|
5225
|
+
index: groups.length,
|
|
5226
|
+
id: "visible-options",
|
|
5227
|
+
label: "Visible options",
|
|
5228
|
+
source: "buttons",
|
|
5229
|
+
options: buttonOptions
|
|
5230
|
+
});
|
|
5231
|
+
}
|
|
5232
|
+
return groups;
|
|
4113
5233
|
}
|
|
4114
|
-
function
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
5234
|
+
function positionalId(scope, kind, ordinal) {
|
|
5235
|
+
return `${scope}${kind}-${ordinal}`;
|
|
5236
|
+
}
|
|
5237
|
+
function dedupeButtons(buttons, scope = "") {
|
|
5238
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5239
|
+
const out = [];
|
|
5240
|
+
let unnamed = 0;
|
|
5241
|
+
for (const b of buttons) {
|
|
5242
|
+
const idTrim = b.id?.trim();
|
|
5243
|
+
const labelTrim = b.label?.trim();
|
|
5244
|
+
if (!idTrim && !isReferenceable(labelTrim)) {
|
|
5245
|
+
unnamed += 1;
|
|
5246
|
+
out.push({ ...b, id: positionalId(scope, "btn", unnamed), provenance: "positional" });
|
|
5247
|
+
continue;
|
|
5248
|
+
}
|
|
5249
|
+
const key = `${idTrim ?? ""}|${labelTrim ?? ""}|${b.disabled ? 1 : 0}|${b.inModal ? 1 : 0}|${b.selected ? 1 : 0}`;
|
|
5250
|
+
if (seen.has(key)) continue;
|
|
5251
|
+
seen.add(key);
|
|
5252
|
+
out.push(b);
|
|
4118
5253
|
}
|
|
4119
|
-
return
|
|
5254
|
+
return out;
|
|
5255
|
+
}
|
|
5256
|
+
function dedupeInputs(inputs, scope = "") {
|
|
5257
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5258
|
+
const out = [];
|
|
5259
|
+
let unnamed = 0;
|
|
5260
|
+
for (const i of inputs) {
|
|
5261
|
+
if (!i.id?.trim() && !i.label?.trim() && !i.placeholder?.trim()) {
|
|
5262
|
+
unnamed += 1;
|
|
5263
|
+
out.push({ ...i, id: positionalId(scope, "input", unnamed), provenance: "positional" });
|
|
5264
|
+
continue;
|
|
5265
|
+
}
|
|
5266
|
+
const key = `${i.id ?? ""}|${i.label ?? ""}|${i.placeholder ?? ""}|${i.inModal ? 1 : 0}`;
|
|
5267
|
+
if (seen.has(key)) continue;
|
|
5268
|
+
seen.add(key);
|
|
5269
|
+
out.push(i);
|
|
5270
|
+
}
|
|
5271
|
+
return out;
|
|
5272
|
+
}
|
|
5273
|
+
function dedupeSliders(sliders, scope = "") {
|
|
5274
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5275
|
+
const out = [];
|
|
5276
|
+
let unnamed = 0;
|
|
5277
|
+
for (const s of sliders) {
|
|
5278
|
+
if (!s.id?.trim() && !s.label?.trim()) {
|
|
5279
|
+
unnamed += 1;
|
|
5280
|
+
out.push({ ...s, id: positionalId(scope, "slider", unnamed), provenance: "positional" });
|
|
5281
|
+
continue;
|
|
5282
|
+
}
|
|
5283
|
+
const key = `${s.id ?? ""}|${s.label ?? ""}|${s.inModal ? 1 : 0}`;
|
|
5284
|
+
if (seen.has(key)) continue;
|
|
5285
|
+
seen.add(key);
|
|
5286
|
+
out.push(s);
|
|
5287
|
+
}
|
|
5288
|
+
return out;
|
|
5289
|
+
}
|
|
5290
|
+
function dedupeToggles(toggles, scope = "") {
|
|
5291
|
+
let unnamed = 0;
|
|
5292
|
+
return toggles.map((t) => {
|
|
5293
|
+
if (t.id?.trim()) return t;
|
|
5294
|
+
unnamed += 1;
|
|
5295
|
+
return { ...t, id: positionalId(scope, "toggle", unnamed), provenance: "positional" };
|
|
5296
|
+
});
|
|
5297
|
+
}
|
|
5298
|
+
function dedupeStrings(strings) {
|
|
5299
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5300
|
+
const out = [];
|
|
5301
|
+
for (const s of strings) {
|
|
5302
|
+
const trimmed = s.trim();
|
|
5303
|
+
if (!trimmed) continue;
|
|
5304
|
+
if (seen.has(trimmed)) continue;
|
|
5305
|
+
seen.add(trimmed);
|
|
5306
|
+
out.push(trimmed);
|
|
5307
|
+
}
|
|
5308
|
+
return out;
|
|
4120
5309
|
}
|
|
4121
5310
|
|
|
4122
5311
|
// src/introspection/probeLoadingState.ts
|
|
4123
|
-
function
|
|
5312
|
+
function getTypeName2(type) {
|
|
4124
5313
|
if (!type) return null;
|
|
4125
5314
|
if (typeof type === "string") return type;
|
|
4126
5315
|
if (typeof type === "function") return type.displayName ?? type.name ?? null;
|
|
4127
5316
|
if (typeof type === "object") {
|
|
4128
5317
|
if (type.displayName) return type.displayName;
|
|
4129
5318
|
if (type.render) return type.render.displayName ?? type.render.name ?? null;
|
|
4130
|
-
if (type.type) return
|
|
5319
|
+
if (type.type) return getTypeName2(type.type);
|
|
4131
5320
|
}
|
|
4132
5321
|
return null;
|
|
4133
5322
|
}
|
|
4134
|
-
function
|
|
4135
|
-
return
|
|
5323
|
+
function matchesName2(fiber, name) {
|
|
5324
|
+
return getTypeName2(fiber.type) === name || getTypeName2(fiber.elementType) === name;
|
|
4136
5325
|
}
|
|
4137
5326
|
var SKELETON_NAME_RE = /skeleton|shimmer|contentloader/i;
|
|
4138
5327
|
function looksLikeSkeleton(fiber) {
|
|
4139
|
-
const name =
|
|
5328
|
+
const name = getTypeName2(fiber.type) ?? getTypeName2(fiber.elementType);
|
|
4140
5329
|
return !!name && SKELETON_NAME_RE.test(name);
|
|
4141
5330
|
}
|
|
4142
|
-
var
|
|
5331
|
+
var SELF_REFERENTIAL_COMPONENTS2 = /* @__PURE__ */ new Set([
|
|
4143
5332
|
"AppilotsChat",
|
|
4144
5333
|
"AppilotsChatInner",
|
|
4145
5334
|
"ActionBreadcrumb",
|
|
4146
5335
|
"ConfirmDialog"
|
|
4147
5336
|
]);
|
|
4148
|
-
function
|
|
5337
|
+
function shouldSkipSubtree2(fiber) {
|
|
4149
5338
|
const props = fiber.memoizedProps;
|
|
4150
5339
|
if (!props) return false;
|
|
4151
|
-
const typeName2 =
|
|
4152
|
-
if (typeName2 &&
|
|
5340
|
+
const typeName2 = getTypeName2(fiber.type) ?? getTypeName2(fiber.elementType);
|
|
5341
|
+
if (typeName2 && SELF_REFERENTIAL_COMPONENTS2.has(typeName2)) return true;
|
|
4153
5342
|
if (props.__appilotsSkip === true || props["data-appilots-skip"] === true || props.appilotsSkip === true) {
|
|
4154
5343
|
return true;
|
|
4155
5344
|
}
|
|
4156
|
-
if (
|
|
4157
|
-
if (
|
|
5345
|
+
if (isModalFiber(fiber) && props.visible === false) return true;
|
|
5346
|
+
if (matchesName2(fiber, "Screen") && props.activityState === 0) return true;
|
|
4158
5347
|
const style = props.style;
|
|
4159
5348
|
if (style) {
|
|
4160
5349
|
const flat = Array.isArray(style) ? Object.assign({}, ...style.filter(Boolean)) : style;
|
|
@@ -4163,7 +5352,7 @@ function shouldSkipSubtree(fiber) {
|
|
|
4163
5352
|
}
|
|
4164
5353
|
return false;
|
|
4165
5354
|
}
|
|
4166
|
-
var
|
|
5355
|
+
var TOUCHABLE_NAMES2 = /* @__PURE__ */ new Set([
|
|
4167
5356
|
"TouchableOpacity",
|
|
4168
5357
|
"TouchableHighlight",
|
|
4169
5358
|
"TouchableWithoutFeedback",
|
|
@@ -4171,7 +5360,7 @@ var TOUCHABLE_NAMES = /* @__PURE__ */ new Set([
|
|
|
4171
5360
|
"Pressable"
|
|
4172
5361
|
]);
|
|
4173
5362
|
function isTouchable(fiber) {
|
|
4174
|
-
return
|
|
5363
|
+
return TOUCHABLE_NAMES2.has(getTypeName2(fiber.type) ?? "") || TOUCHABLE_NAMES2.has(getTypeName2(fiber.elementType) ?? "");
|
|
4175
5364
|
}
|
|
4176
5365
|
function pickId(props) {
|
|
4177
5366
|
return props?.testID ?? props?.accessibilityLabel ?? void 0;
|
|
@@ -4207,31 +5396,34 @@ function probeLoadingState(pressedComponentId, route) {
|
|
|
4207
5396
|
visited.add(fiber);
|
|
4208
5397
|
result.visitedFibers++;
|
|
4209
5398
|
if (fiber.sibling) stack.push(fiber.sibling);
|
|
4210
|
-
if (
|
|
5399
|
+
if (shouldSkipSubtree2(fiber)) continue;
|
|
4211
5400
|
const props = fiber.memoizedProps ?? {};
|
|
4212
|
-
if (
|
|
5401
|
+
if (matchesName2(fiber, "ActivityIndicator") || looksLikeSkeleton(fiber)) {
|
|
4213
5402
|
result.loading = true;
|
|
4214
|
-
} else if (
|
|
5403
|
+
} else if (isModalFiber(fiber)) {
|
|
4215
5404
|
result.modalOpen = true;
|
|
5405
|
+
} else if (isSwitchLike(fiber, props)) {
|
|
5406
|
+
const id = pickId(props);
|
|
5407
|
+
toggleSigs.push(`${id ?? "?"}:${switchValue(props) ? 1 : 0}`);
|
|
4216
5408
|
} else if (isTouchable(fiber)) {
|
|
4217
5409
|
if (props.__appilotsInternal !== true) {
|
|
4218
5410
|
const id = pickId(props);
|
|
4219
5411
|
const disabled = !!props.disabled;
|
|
4220
|
-
|
|
5412
|
+
const state = props.accessibilityState ?? {};
|
|
5413
|
+
const on = state.checked === true || state.selected === true;
|
|
5414
|
+
buttonSigs.push(`${id ?? "?"}:${disabled ? 1 : 0}:${on ? 1 : 0}`);
|
|
4221
5415
|
if (pressedComponentId && idMatches(id, pressedComponentId)) {
|
|
4222
5416
|
result.pressedFound = true;
|
|
4223
5417
|
if (disabled) result.pressedDisabled = true;
|
|
4224
5418
|
}
|
|
4225
5419
|
}
|
|
4226
|
-
} else if (
|
|
5420
|
+
} else if (matchesName2(fiber, "TextInput")) {
|
|
4227
5421
|
if (props.__appilotsInternal !== true) {
|
|
4228
5422
|
const id = pickId(props);
|
|
4229
5423
|
const editable = props.editable !== false;
|
|
4230
|
-
|
|
5424
|
+
const filled = typeof props.value === "string" && props.value.length > 0;
|
|
5425
|
+
inputSigs.push(`${id ?? "?"}:${editable ? 1 : 0}:${filled ? 1 : 0}`);
|
|
4231
5426
|
}
|
|
4232
|
-
} else if (matchesName(fiber, "Switch")) {
|
|
4233
|
-
const id = pickId(props);
|
|
4234
|
-
toggleSigs.push(`${id ?? "?"}:${props.value ? 1 : 0}`);
|
|
4235
5427
|
}
|
|
4236
5428
|
if (fiber.child) stack.push(fiber.child);
|
|
4237
5429
|
}
|
|
@@ -4242,11 +5434,48 @@ function probeLoadingState(pressedComponentId, route) {
|
|
|
4242
5434
|
return result;
|
|
4243
5435
|
}
|
|
4244
5436
|
|
|
5437
|
+
// ../shared/dist/routes/index.mjs
|
|
5438
|
+
var CONTAINER_SUFFIXES = [
|
|
5439
|
+
"screen",
|
|
5440
|
+
"route",
|
|
5441
|
+
"page",
|
|
5442
|
+
"view",
|
|
5443
|
+
"tab",
|
|
5444
|
+
"stack",
|
|
5445
|
+
"drawer",
|
|
5446
|
+
"navigator"
|
|
5447
|
+
];
|
|
5448
|
+
var CONTENT_SUFFIXES = ["list", "details", "detail", "create", "edit", "new", "form", "index"];
|
|
5449
|
+
var MIN_STEM_LENGTH = 3;
|
|
5450
|
+
function fold(name) {
|
|
5451
|
+
return name.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "");
|
|
5452
|
+
}
|
|
5453
|
+
function stripSuffixes(folded, suffixes) {
|
|
5454
|
+
for (const suffix of suffixes) {
|
|
5455
|
+
if (!folded.endsWith(suffix)) continue;
|
|
5456
|
+
const stem = folded.slice(0, -suffix.length);
|
|
5457
|
+
if (stem.length >= MIN_STEM_LENGTH) return stem;
|
|
5458
|
+
}
|
|
5459
|
+
return folded;
|
|
5460
|
+
}
|
|
5461
|
+
function normalizeRouteFamily(name) {
|
|
5462
|
+
const all = [...CONTAINER_SUFFIXES, ...CONTENT_SUFFIXES];
|
|
5463
|
+
let stem = stripSuffixes(stripSuffixes(fold(name), all), all);
|
|
5464
|
+
if (stem.endsWith("s") && stem.length - 1 >= MIN_STEM_LENGTH) stem = stem.slice(0, -1);
|
|
5465
|
+
return stem;
|
|
5466
|
+
}
|
|
5467
|
+
function routesBelongToSameFeature(a, b) {
|
|
5468
|
+
const na = normalizeRouteFamily(a);
|
|
5469
|
+
const nb = normalizeRouteFamily(b);
|
|
5470
|
+
if (!na || !nb) return false;
|
|
5471
|
+
return na === nb;
|
|
5472
|
+
}
|
|
5473
|
+
|
|
4245
5474
|
// src/navigation/navigationState.ts
|
|
4246
5475
|
var _currentScreen = null;
|
|
4247
5476
|
var _navigationRef = null;
|
|
4248
5477
|
function setCurrentScreen(screen) {
|
|
4249
|
-
|
|
5478
|
+
appilotsDebugLog(`setCurrentScreen: "${_currentScreen}" \u2192 "${screen}"`);
|
|
4250
5479
|
_currentScreen = screen;
|
|
4251
5480
|
}
|
|
4252
5481
|
function getCurrentScreen() {
|
|
@@ -4255,8 +5484,8 @@ function getCurrentScreen() {
|
|
|
4255
5484
|
const deepest = activePath[activePath.length - 1] ?? null;
|
|
4256
5485
|
if (deepest && deepest !== _currentScreen) {
|
|
4257
5486
|
if (_currentScreen) {
|
|
4258
|
-
|
|
4259
|
-
`
|
|
5487
|
+
appilotsDebugLog(
|
|
5488
|
+
`getCurrentScreen: active path differs from cached \u2014 deepest="${deepest}", cached="${_currentScreen}". Updating cache.`
|
|
4260
5489
|
);
|
|
4261
5490
|
}
|
|
4262
5491
|
_currentScreen = deepest;
|
|
@@ -4267,7 +5496,9 @@ function getCurrentScreen() {
|
|
|
4267
5496
|
const liveScreen = getActiveRouteFromRef(_navigationRef);
|
|
4268
5497
|
if (liveScreen) {
|
|
4269
5498
|
if (liveScreen !== _currentScreen) {
|
|
4270
|
-
|
|
5499
|
+
appilotsDebugLog(
|
|
5500
|
+
`getCurrentScreen: live reading differs from cached \u2014 live="${liveScreen}", cached="${_currentScreen}". Updating cache.`
|
|
5501
|
+
);
|
|
4271
5502
|
_currentScreen = liveScreen;
|
|
4272
5503
|
}
|
|
4273
5504
|
return liveScreen;
|
|
@@ -4311,7 +5542,9 @@ function getActiveRouteNames() {
|
|
|
4311
5542
|
function routeNamesAtState(state) {
|
|
4312
5543
|
if (!state) return [];
|
|
4313
5544
|
if (Array.isArray(state.routeNames)) {
|
|
4314
|
-
return state.routeNames.filter(
|
|
5545
|
+
return state.routeNames.filter(
|
|
5546
|
+
(name) => typeof name === "string" && name.length > 0
|
|
5547
|
+
);
|
|
4315
5548
|
}
|
|
4316
5549
|
if (Array.isArray(state.routes)) {
|
|
4317
5550
|
return state.routes.map((route) => route?.name).filter((name) => typeof name === "string" && name.length > 0);
|
|
@@ -4428,16 +5661,6 @@ function getActiveRouteFromRef(navRef) {
|
|
|
4428
5661
|
}
|
|
4429
5662
|
}
|
|
4430
5663
|
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
4431
|
-
function normalizeRouteFamily(name) {
|
|
4432
|
-
return name.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/(tab|list|screen|details?|navigator)$/i, "");
|
|
4433
|
-
}
|
|
4434
|
-
function routesBelongToSameFeature(a, b) {
|
|
4435
|
-
const na = normalizeRouteFamily(a);
|
|
4436
|
-
const nb = normalizeRouteFamily(b);
|
|
4437
|
-
if (!na || !nb) return false;
|
|
4438
|
-
if (na === nb) return true;
|
|
4439
|
-
return na.startsWith(nb) || nb.startsWith(na);
|
|
4440
|
-
}
|
|
4441
5664
|
function navigationTargetReached(target, fromScreen) {
|
|
4442
5665
|
const cur = getCurrentScreen();
|
|
4443
5666
|
const path = getActiveRouteNames();
|
|
@@ -4613,6 +5836,365 @@ async function waitForLoadingSettle(opts = {}) {
|
|
|
4613
5836
|
};
|
|
4614
5837
|
}
|
|
4615
5838
|
|
|
5839
|
+
// src/version.ts
|
|
5840
|
+
var SDK_VERSION2 = "0.11.0";
|
|
5841
|
+
var FiberSentinel = class extends React2__default.default.Component {
|
|
5842
|
+
componentDidMount() {
|
|
5843
|
+
const fiber = this._reactInternals ?? this._reactInternalFiber ?? null;
|
|
5844
|
+
if (!fiber) {
|
|
5845
|
+
const reactVersion = React2__default.default.version ?? null;
|
|
5846
|
+
appilotsDebugWarn(
|
|
5847
|
+
`FiberSentinel: this._reactInternals is undefined; snapshot capture will fall back to render-time owner. React version may be incompatible (react=${reactVersion}).`
|
|
5848
|
+
);
|
|
5849
|
+
recordIntrospectionFailure("sentinel-missing-internals", reactVersion);
|
|
5850
|
+
this.props.onUnavailable?.({ reactVersion });
|
|
5851
|
+
return;
|
|
5852
|
+
}
|
|
5853
|
+
let top = fiber;
|
|
5854
|
+
while (top.return) top = top.return;
|
|
5855
|
+
setFiberRoot(top);
|
|
5856
|
+
}
|
|
5857
|
+
render() {
|
|
5858
|
+
return this.props.children ?? null;
|
|
5859
|
+
}
|
|
5860
|
+
};
|
|
5861
|
+
function AppilotsFiberRoot({
|
|
5862
|
+
children,
|
|
5863
|
+
onUnavailable
|
|
5864
|
+
}) {
|
|
5865
|
+
const Internals = React2__default.default.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED_IN_THIS_VERSION_OF_REACT;
|
|
5866
|
+
const ownerFiber = Internals?.ReactCurrentOwner?.current;
|
|
5867
|
+
if (ownerFiber && !getFiberRoot()) {
|
|
5868
|
+
setFiberRoot(ownerFiber);
|
|
5869
|
+
}
|
|
5870
|
+
return /* @__PURE__ */ React2__default.default.createElement(FiberSentinel, { onUnavailable }, children);
|
|
5871
|
+
}
|
|
5872
|
+
|
|
5873
|
+
// src/debug/logger.ts
|
|
5874
|
+
setAppilotsDebugResolver(() => getGlobalConfig()?.debug === true);
|
|
5875
|
+
function setAppilotsDebugEnabled2(enabled) {
|
|
5876
|
+
setAppilotsDebugEnabled(enabled);
|
|
5877
|
+
}
|
|
5878
|
+
|
|
5879
|
+
// src/platform/nativeDialogTracking.ts
|
|
5880
|
+
var DEFAULT_BUTTON_LABEL = "OK";
|
|
5881
|
+
var ANSWERED_DIALOG_MEMORY_MS = 15e3;
|
|
5882
|
+
var _open = null;
|
|
5883
|
+
var _lastAnswered = null;
|
|
5884
|
+
var _counter = 0;
|
|
5885
|
+
var _installed = null;
|
|
5886
|
+
function getOpenNativeDialog() {
|
|
5887
|
+
return _open;
|
|
5888
|
+
}
|
|
5889
|
+
function getLastAnsweredNativeDialog() {
|
|
5890
|
+
if (!_lastAnswered) return null;
|
|
5891
|
+
if (Date.now() - _lastAnswered.at > ANSWERED_DIALOG_MEMORY_MS) return null;
|
|
5892
|
+
return _lastAnswered;
|
|
5893
|
+
}
|
|
5894
|
+
function labelOf(button, index) {
|
|
5895
|
+
const text = typeof button?.text === "string" ? button.text.trim() : "";
|
|
5896
|
+
if (text.length > 0) return text;
|
|
5897
|
+
return index === 0 ? DEFAULT_BUTTON_LABEL : `Button ${index + 1}`;
|
|
5898
|
+
}
|
|
5899
|
+
function installNativeDialogTracking(host) {
|
|
5900
|
+
if (_installed) return;
|
|
5901
|
+
const original = host.alert;
|
|
5902
|
+
const patched = (title, message, buttons, options) => {
|
|
5903
|
+
const id = `native-dialog-${_counter += 1}`;
|
|
5904
|
+
const source = Array.isArray(buttons) && buttons.length > 0 ? buttons : [{ text: DEFAULT_BUTTON_LABEL }];
|
|
5905
|
+
const close = (dialogId, answeredWith) => {
|
|
5906
|
+
if (_open?.id !== dialogId) return;
|
|
5907
|
+
_lastAnswered = {
|
|
5908
|
+
id: dialogId,
|
|
5909
|
+
...tracked.title ? { title: tracked.title } : {},
|
|
5910
|
+
buttons: tracked.buttons.map((button) => button.label),
|
|
5911
|
+
...answeredWith ? { answeredWith } : {},
|
|
5912
|
+
at: Date.now()
|
|
5913
|
+
};
|
|
5914
|
+
_open = null;
|
|
5915
|
+
};
|
|
5916
|
+
const tracked = {
|
|
5917
|
+
id,
|
|
5918
|
+
title: typeof title === "string" && title.trim().length > 0 ? title.trim() : void 0,
|
|
5919
|
+
message: typeof message === "string" && message.trim().length > 0 ? message.trim() : void 0,
|
|
5920
|
+
buttons: []
|
|
5921
|
+
};
|
|
5922
|
+
const wrapped = source.map((button, index) => ({
|
|
5923
|
+
...button,
|
|
5924
|
+
onPress: (value) => {
|
|
5925
|
+
close(id, labelOf(button, index));
|
|
5926
|
+
button.onPress?.(value);
|
|
5927
|
+
}
|
|
5928
|
+
}));
|
|
5929
|
+
tracked.buttons = source.map((button, index) => ({
|
|
5930
|
+
label: labelOf(button, index),
|
|
5931
|
+
...button.style ? { style: button.style } : {},
|
|
5932
|
+
press: () => {
|
|
5933
|
+
wrapped[index]?.onPress?.();
|
|
5934
|
+
}
|
|
5935
|
+
}));
|
|
5936
|
+
_open = tracked;
|
|
5937
|
+
const opts = options;
|
|
5938
|
+
const patchedOptions = opts && typeof opts === "object" ? {
|
|
5939
|
+
...opts,
|
|
5940
|
+
onDismiss: () => {
|
|
5941
|
+
close(id);
|
|
5942
|
+
opts.onDismiss?.();
|
|
5943
|
+
}
|
|
5944
|
+
} : options;
|
|
5945
|
+
return original(title, message, wrapped, patchedOptions);
|
|
5946
|
+
};
|
|
5947
|
+
host.alert = patched;
|
|
5948
|
+
_installed = { host, original, patched };
|
|
5949
|
+
}
|
|
5950
|
+
function uninstallNativeDialogTracking() {
|
|
5951
|
+
if (!_installed) return;
|
|
5952
|
+
if (_installed.host.alert === _installed.patched) {
|
|
5953
|
+
_installed.host.alert = _installed.original;
|
|
5954
|
+
}
|
|
5955
|
+
_installed = null;
|
|
5956
|
+
_open = null;
|
|
5957
|
+
_lastAnswered = null;
|
|
5958
|
+
}
|
|
5959
|
+
|
|
5960
|
+
// src/introspection/nameMangling.ts
|
|
5961
|
+
var _lastProbe = null;
|
|
5962
|
+
function getNameManglingProbe() {
|
|
5963
|
+
return _lastProbe;
|
|
5964
|
+
}
|
|
5965
|
+
function probeNameMangling(components) {
|
|
5966
|
+
const observed = {};
|
|
5967
|
+
let mangled = false;
|
|
5968
|
+
for (const [expected, component] of Object.entries(components)) {
|
|
5969
|
+
if (component === void 0) continue;
|
|
5970
|
+
const actual = getTypeName(component) ?? null;
|
|
5971
|
+
observed[expected] = actual;
|
|
5972
|
+
if (actual !== expected) mangled = true;
|
|
5973
|
+
}
|
|
5974
|
+
_lastProbe = { mangled, observed };
|
|
5975
|
+
if (mangled) {
|
|
5976
|
+
recordIntrospectionFailure("names-mangled", null);
|
|
5977
|
+
console.warn(
|
|
5978
|
+
"[Appilots] This bundle renamed React Native components: " + Object.entries(observed).filter(([expectedName, actual]) => actual !== expectedName).map(([expectedName, actual]) => `${expectedName} \u2192 ${actual ?? "unknown"}`).join(", ") + ". Detection falls back to accessibility roles and component shape, which covers switches, modals and lists but is less precise. To restore names, keep `keep_fnames`/`keep_classnames` in your Metro minifierConfig \u2014 `withAppilots()` sets them for you."
|
|
5979
|
+
);
|
|
5980
|
+
}
|
|
5981
|
+
return _lastProbe;
|
|
5982
|
+
}
|
|
5983
|
+
|
|
5984
|
+
// src/platform/fabricGeometry.ts
|
|
5985
|
+
function readRect(instance) {
|
|
5986
|
+
const candidate = instance;
|
|
5987
|
+
const read = candidate?.getBoundingClientRect ?? candidate?.unstable_getBoundingClientRect;
|
|
5988
|
+
if (typeof read !== "function") return null;
|
|
5989
|
+
const rect = read.call(candidate);
|
|
5990
|
+
if (!rect) return null;
|
|
5991
|
+
return { x: rect.x, y: rect.y, width: rect.width, height: rect.height };
|
|
5992
|
+
}
|
|
5993
|
+
function createFabricGeometryHost(dimensions) {
|
|
5994
|
+
const fabric = globalThis.nativeFabricUIManager;
|
|
5995
|
+
if (!fabric) return null;
|
|
5996
|
+
return {
|
|
5997
|
+
get window() {
|
|
5998
|
+
return dimensions.get("window");
|
|
5999
|
+
},
|
|
6000
|
+
rectOf: readRect
|
|
6001
|
+
};
|
|
6002
|
+
}
|
|
6003
|
+
var AppilotsErrorBoundary = class extends React2__default.default.Component {
|
|
6004
|
+
state = { degraded: false, escalate: null };
|
|
6005
|
+
/**
|
|
6006
|
+
* Instance field rather than state: `componentDidCatch` needs to know
|
|
6007
|
+
* whether THIS is the first failure, and by the time it runs
|
|
6008
|
+
* `getDerivedStateFromError` has already flipped `state.degraded`.
|
|
6009
|
+
*/
|
|
6010
|
+
hasDegradedOnce = false;
|
|
6011
|
+
static getDerivedStateFromError() {
|
|
6012
|
+
return { degraded: true };
|
|
6013
|
+
}
|
|
6014
|
+
componentDidCatch(error, info) {
|
|
6015
|
+
if (this.hasDegradedOnce) {
|
|
6016
|
+
this.setState({ escalate: error ?? new Error("Appilots: re-thrown host render error") });
|
|
6017
|
+
return;
|
|
6018
|
+
}
|
|
6019
|
+
this.hasDegradedOnce = true;
|
|
6020
|
+
console.error(
|
|
6021
|
+
`[Appilots] The Appilots ${this.props.surface} threw while rendering and has been disabled for the rest of this session. Your app keeps running \u2014 this is an Appilots bug, not a bug in your code. Please report it with the stack below: https://github.com/Axtern-Labs/Appilots/issues`,
|
|
6022
|
+
error
|
|
6023
|
+
);
|
|
6024
|
+
try {
|
|
6025
|
+
this.props.onError?.(error, info?.componentStack ?? null);
|
|
6026
|
+
} catch {
|
|
6027
|
+
}
|
|
6028
|
+
}
|
|
6029
|
+
render() {
|
|
6030
|
+
if (this.state.escalate !== null) throw this.state.escalate;
|
|
6031
|
+
if (this.state.degraded) return this.props.fallback;
|
|
6032
|
+
return this.props.children;
|
|
6033
|
+
}
|
|
6034
|
+
};
|
|
6035
|
+
|
|
6036
|
+
// src/context/AppilotsProvider.tsx
|
|
6037
|
+
var AppilotsContext = React2.createContext(null);
|
|
6038
|
+
function createInertClient() {
|
|
6039
|
+
const unavailable = () => Promise.reject(new Error("Appilots is unavailable: the SDK degraded after a render error."));
|
|
6040
|
+
return new Proxy({}, {
|
|
6041
|
+
get: (_target, prop) => {
|
|
6042
|
+
if (prop === "then" || typeof prop === "symbol") return void 0;
|
|
6043
|
+
return unavailable;
|
|
6044
|
+
}
|
|
6045
|
+
});
|
|
6046
|
+
}
|
|
6047
|
+
function createDegradedContext(config) {
|
|
6048
|
+
return {
|
|
6049
|
+
config: config ?? { projectId: "" },
|
|
6050
|
+
client: createInertClient(),
|
|
6051
|
+
subscribe: () => () => {
|
|
6052
|
+
},
|
|
6053
|
+
emit: () => {
|
|
6054
|
+
},
|
|
6055
|
+
remotePersonalization: null,
|
|
6056
|
+
degraded: true
|
|
6057
|
+
};
|
|
6058
|
+
}
|
|
6059
|
+
function AppilotsProvider({ config, children, client }) {
|
|
6060
|
+
return /* @__PURE__ */ React2__default.default.createElement(
|
|
6061
|
+
AppilotsErrorBoundary,
|
|
6062
|
+
{
|
|
6063
|
+
surface: "provider",
|
|
6064
|
+
onError: reportProviderRenderFailure,
|
|
6065
|
+
fallback: /* @__PURE__ */ React2__default.default.createElement(AppilotsContext.Provider, { value: createDegradedContext(config ?? null) }, children)
|
|
6066
|
+
},
|
|
6067
|
+
/* @__PURE__ */ React2__default.default.createElement(AppilotsProviderInner, { config, client }, children)
|
|
6068
|
+
);
|
|
6069
|
+
}
|
|
6070
|
+
function reportProviderRenderFailure() {
|
|
6071
|
+
recordRenderFailure(readReactVersion());
|
|
6072
|
+
}
|
|
6073
|
+
function readReactVersion() {
|
|
6074
|
+
const version = React2__default.default.version;
|
|
6075
|
+
return typeof version === "string" ? version : null;
|
|
6076
|
+
}
|
|
6077
|
+
function AppilotsProviderInner({
|
|
6078
|
+
config: configProp,
|
|
6079
|
+
children,
|
|
6080
|
+
client: externalClient
|
|
6081
|
+
}) {
|
|
6082
|
+
appilotsDebugLog(
|
|
6083
|
+
`AppilotsProvider initializing \u2014 config source: ${configProp ? "prop" : "auto (globalThis.__APPILOTS_RC__)"}`
|
|
6084
|
+
);
|
|
6085
|
+
tryAutoConfig();
|
|
6086
|
+
const globalConfig = getGlobalConfig();
|
|
6087
|
+
appilotsDebugLog(`AppilotsProvider: configProp=${!!configProp}, globalConfig=${!!globalConfig}`);
|
|
6088
|
+
const config = configProp ?? (globalConfig ? {
|
|
6089
|
+
projectId: globalConfig.projectId,
|
|
6090
|
+
apiBaseUrl: globalConfig.apiBaseUrl,
|
|
6091
|
+
apiKey: globalConfig.apiKey,
|
|
6092
|
+
permissions: globalConfig.permissions,
|
|
6093
|
+
debug: globalConfig.debug,
|
|
6094
|
+
appVersion: globalConfig.appVersion,
|
|
6095
|
+
mcpVersion: globalConfig.mcpVersion,
|
|
6096
|
+
fetchPersonalization: globalConfig.fetchPersonalization,
|
|
6097
|
+
suppressNativeConfirm: globalConfig.suppressNativeConfirm
|
|
6098
|
+
} : null);
|
|
6099
|
+
if (!config?.projectId) {
|
|
6100
|
+
throw new Error(
|
|
6101
|
+
"AppilotsProvider: No config found. Add withAppilots() to your metro.config.js and create a .appilotsrc file, or pass a config prop directly."
|
|
6102
|
+
);
|
|
6103
|
+
}
|
|
6104
|
+
React2.useEffect(() => {
|
|
6105
|
+
setAppilotsDebugEnabled2(config.debug === true);
|
|
6106
|
+
}, [config.debug]);
|
|
6107
|
+
React2.useEffect(() => {
|
|
6108
|
+
probeNameMangling({ Switch: reactNative.Switch, Modal: reactNative.Modal, Text: reactNative.Text });
|
|
6109
|
+
}, []);
|
|
6110
|
+
React2.useEffect(() => {
|
|
6111
|
+
setGeometryHost(createFabricGeometryHost(reactNative.Dimensions));
|
|
6112
|
+
return () => setGeometryHost(null);
|
|
6113
|
+
}, []);
|
|
6114
|
+
const trackNativeDialogs = config.trackNativeDialogs !== false;
|
|
6115
|
+
React2.useEffect(() => {
|
|
6116
|
+
if (!trackNativeDialogs) return;
|
|
6117
|
+
installNativeDialogTracking(reactNative.Alert);
|
|
6118
|
+
return () => {
|
|
6119
|
+
uninstallNativeDialogTracking();
|
|
6120
|
+
};
|
|
6121
|
+
}, [trackNativeDialogs]);
|
|
6122
|
+
const listenersRef = React2.useRef(/* @__PURE__ */ new Set());
|
|
6123
|
+
const subscribe = React2.useCallback((handler) => {
|
|
6124
|
+
listenersRef.current.add(handler);
|
|
6125
|
+
return () => {
|
|
6126
|
+
listenersRef.current.delete(handler);
|
|
6127
|
+
};
|
|
6128
|
+
}, []);
|
|
6129
|
+
const emit = React2.useCallback((event) => {
|
|
6130
|
+
recordAppilotsEventTrace(event);
|
|
6131
|
+
listenersRef.current.forEach((handler) => handler(event));
|
|
6132
|
+
}, []);
|
|
6133
|
+
const handleIntrospectionUnavailable = React2.useCallback(
|
|
6134
|
+
({ reactVersion }) => {
|
|
6135
|
+
emit({
|
|
6136
|
+
type: "sdk:introspection:unavailable",
|
|
6137
|
+
timestamp: Date.now(),
|
|
6138
|
+
data: { reason: "sentinel-missing-internals", reactVersion }
|
|
6139
|
+
});
|
|
6140
|
+
},
|
|
6141
|
+
[emit]
|
|
6142
|
+
);
|
|
6143
|
+
const client = React2.useMemo(
|
|
6144
|
+
() => externalClient ?? new AppilotsClient({
|
|
6145
|
+
projectId: config.projectId,
|
|
6146
|
+
apiBaseUrl: config.apiBaseUrl,
|
|
6147
|
+
apiKey: config.apiKey,
|
|
6148
|
+
debug: config.debug,
|
|
6149
|
+
appVersion: config.appVersion,
|
|
6150
|
+
mcpVersion: config.mcpVersion,
|
|
6151
|
+
// This package's published version, so the server knows which
|
|
6152
|
+
// SDK is actually in the field (issue #312).
|
|
6153
|
+
sdkVersion: SDK_VERSION2,
|
|
6154
|
+
user: config.user,
|
|
6155
|
+
// Only reports a FAILED reading; the happy path sends nothing.
|
|
6156
|
+
introspectionReporter: getIntrospectionDiagnostics
|
|
6157
|
+
}),
|
|
6158
|
+
[
|
|
6159
|
+
config.projectId,
|
|
6160
|
+
config.apiBaseUrl,
|
|
6161
|
+
config.apiKey,
|
|
6162
|
+
config.debug,
|
|
6163
|
+
config.appVersion,
|
|
6164
|
+
config.mcpVersion,
|
|
6165
|
+
config.user,
|
|
6166
|
+
externalClient
|
|
6167
|
+
]
|
|
6168
|
+
);
|
|
6169
|
+
const fetchPersonalizationEnabled = config.fetchPersonalization !== false;
|
|
6170
|
+
const [remotePersonalization, setRemotePersonalization] = React2.useState(
|
|
6171
|
+
null
|
|
6172
|
+
);
|
|
6173
|
+
React2.useEffect(() => {
|
|
6174
|
+
if (!fetchPersonalizationEnabled) return;
|
|
6175
|
+
let cancelled = false;
|
|
6176
|
+
client.getPersonalization().then((data) => {
|
|
6177
|
+
if (!cancelled) setRemotePersonalization(data);
|
|
6178
|
+
}).catch(() => {
|
|
6179
|
+
});
|
|
6180
|
+
return () => {
|
|
6181
|
+
cancelled = true;
|
|
6182
|
+
};
|
|
6183
|
+
}, [client, fetchPersonalizationEnabled]);
|
|
6184
|
+
const value = React2.useMemo(
|
|
6185
|
+
() => ({ config, client, subscribe, emit, remotePersonalization }),
|
|
6186
|
+
[config, client, subscribe, emit, remotePersonalization]
|
|
6187
|
+
);
|
|
6188
|
+
return /* @__PURE__ */ React2__default.default.createElement(AppilotsContext.Provider, { value }, /* @__PURE__ */ React2__default.default.createElement(AppilotsFiberRoot, { onUnavailable: handleIntrospectionUnavailable }, children));
|
|
6189
|
+
}
|
|
6190
|
+
function useAppilotsContext() {
|
|
6191
|
+
const context = React2.useContext(AppilotsContext);
|
|
6192
|
+
if (!context) {
|
|
6193
|
+
throw new Error("useAppilotsContext must be used within an <AppilotsProvider>");
|
|
6194
|
+
}
|
|
6195
|
+
return context;
|
|
6196
|
+
}
|
|
6197
|
+
|
|
4616
6198
|
// src/navigation/registerScreen.ts
|
|
4617
6199
|
var screenRegistry = /* @__PURE__ */ new Map();
|
|
4618
6200
|
function registerScreen(metadata) {
|
|
@@ -4634,9 +6216,12 @@ exports.AppilotsErrorBoundary = AppilotsErrorBoundary;
|
|
|
4634
6216
|
exports.AppilotsProvider = AppilotsProvider;
|
|
4635
6217
|
exports.AppilotsRegistryProvider = AppilotsRegistryProvider;
|
|
4636
6218
|
exports.ChatSessionMachine = ChatSessionMachine;
|
|
6219
|
+
exports.FORM_VALIDATION_TEXT_RE = FORM_VALIDATION_TEXT_RE;
|
|
6220
|
+
exports.FORM_WRITE_SUCCESS_TEXT_RE = FORM_WRITE_SUCCESS_TEXT_RE;
|
|
4637
6221
|
exports.OPTIONAL_STEP_AUTOMATION_HINT = OPTIONAL_STEP_AUTOMATION_HINT;
|
|
4638
6222
|
exports.RateLimitedError = RateLimitedError;
|
|
4639
6223
|
exports.SDK_VERSION = SDK_VERSION2;
|
|
6224
|
+
exports.TOUCHABLE_NAMES = TOUCHABLE_NAMES;
|
|
4640
6225
|
exports._patchJsxRuntimes = _patchJsxRuntimes;
|
|
4641
6226
|
exports.actionPressTargetId = actionPressTargetId;
|
|
4642
6227
|
exports.appilotsDebugLog = appilotsDebugLog;
|
|
@@ -4653,27 +6238,44 @@ exports.defaultDarkTheme = defaultDarkTheme;
|
|
|
4653
6238
|
exports.defaultLightTheme = defaultLightTheme;
|
|
4654
6239
|
exports.deriveInteractionElements = deriveInteractionElements;
|
|
4655
6240
|
exports.describeAction = describeAction;
|
|
6241
|
+
exports.describeValue = describeValue;
|
|
4656
6242
|
exports.elementRegistry = elementRegistry;
|
|
6243
|
+
exports.emptyDetectorCounts = emptyDetectorCounts;
|
|
4657
6244
|
exports.enableAppilotsAutoTracking = enableAppilotsAutoTracking;
|
|
6245
|
+
exports.findListItems = findListItems;
|
|
6246
|
+
exports.foldForCompare = foldForCompare;
|
|
6247
|
+
exports.geometryAvailability = geometryAvailability;
|
|
6248
|
+
exports.geometryStats = geometryStats;
|
|
4658
6249
|
exports.getActiveRouteNames = getActiveRouteNames;
|
|
4659
6250
|
exports.getAllScreens = getAllScreens;
|
|
4660
6251
|
exports.getAppilotsDebugTraces = getAppilotsDebugTraces;
|
|
6252
|
+
exports.getAutoTrackingState = getAutoTrackingState;
|
|
4661
6253
|
exports.getCurrentScreen = getCurrentScreen;
|
|
4662
6254
|
exports.getCurrentScreenSignature = getCurrentScreenSignature;
|
|
4663
6255
|
exports.getDefaultRegistry = getDefaultRegistry;
|
|
4664
6256
|
exports.getFiberRoot = getFiberRoot;
|
|
4665
6257
|
exports.getGlobalConfig = getGlobalConfig;
|
|
4666
6258
|
exports.getIntrospectionDiagnostics = getIntrospectionDiagnostics;
|
|
6259
|
+
exports.getLastAnsweredNativeDialog = getLastAnsweredNativeDialog;
|
|
6260
|
+
exports.getLastWalkDiagnostics = getLastWalkDiagnostics;
|
|
6261
|
+
exports.getNameManglingProbe = getNameManglingProbe;
|
|
4667
6262
|
exports.getNavigationRef = getNavigationRef;
|
|
4668
6263
|
exports.getNavigationStateSnapshot = getNavigationStateSnapshot;
|
|
6264
|
+
exports.getOpenNativeDialog = getOpenNativeDialog;
|
|
4669
6265
|
exports.getScreenMetadata = getScreenMetadata;
|
|
6266
|
+
exports.getTypeName = getTypeName;
|
|
4670
6267
|
exports.humanizeError = humanizeError;
|
|
4671
6268
|
exports.idLooselyMatches = idLooselyMatches;
|
|
4672
6269
|
exports.initAppilots = initAppilots;
|
|
6270
|
+
exports.isAlwaysListContainer = isAlwaysListContainer;
|
|
4673
6271
|
exports.isAutoTrackingEnabled = isAutoTrackingEnabled;
|
|
4674
6272
|
exports.isGenericSelectValue = isGenericSelectValue;
|
|
6273
|
+
exports.isHeuristicListContainer = isHeuristicListContainer;
|
|
4675
6274
|
exports.isListItemPressTarget = isListItemPressTarget;
|
|
6275
|
+
exports.isModalFiber = isModalFiber;
|
|
4676
6276
|
exports.isOptionalStepAutomationFailure = isOptionalStepAutomationFailure;
|
|
6277
|
+
exports.isReferenceable = isReferenceable;
|
|
6278
|
+
exports.isSwitchLike = isSwitchLike;
|
|
4677
6279
|
exports.listRegistry = listRegistry;
|
|
4678
6280
|
exports.looksDestructiveActionLabel = looksDestructiveActionLabel;
|
|
4679
6281
|
exports.matchScore = matchScore;
|
|
@@ -4683,15 +6285,21 @@ exports.parseStableElementId = parseStableElementId;
|
|
|
4683
6285
|
exports.probeLoadingState = probeLoadingState;
|
|
4684
6286
|
exports.recordAppilotsDebugTrace = recordAppilotsDebugTrace;
|
|
4685
6287
|
exports.recordIntrospectionFailure = recordIntrospectionFailure;
|
|
6288
|
+
exports.rectForNode = rectForNode;
|
|
4686
6289
|
exports.registerScreen = registerScreen;
|
|
4687
6290
|
exports.resolveBaseTheme = resolveBaseTheme;
|
|
4688
6291
|
exports.routesBelongToSameFeature = routesBelongToSameFeature;
|
|
4689
6292
|
exports.screenDepartedBaseline = screenDepartedBaseline;
|
|
4690
6293
|
exports.setCurrentScreen = setCurrentScreen;
|
|
4691
6294
|
exports.setNavigationRef = setNavigationRef;
|
|
6295
|
+
exports.shouldSkipSubtree = shouldSkipSubtree;
|
|
4692
6296
|
exports.snapshotShowsOpenCreateForm = snapshotShowsOpenCreateForm;
|
|
4693
6297
|
exports.subscribeAppilotsDebugTraces = subscribeAppilotsDebugTraces;
|
|
6298
|
+
exports.switchValue = switchValue;
|
|
6299
|
+
exports.toWireElement = toWireElement;
|
|
6300
|
+
exports.totalDetectorHits = totalDetectorHits;
|
|
4694
6301
|
exports.useAppilotsContext = useAppilotsContext;
|
|
4695
6302
|
exports.useResolvedRegistry = useResolvedRegistry;
|
|
4696
6303
|
exports.waitForLoadingSettle = waitForLoadingSettle;
|
|
4697
6304
|
exports.waitForScreenSettle = waitForScreenSettle;
|
|
6305
|
+
exports.walkFiber = walkFiber;
|