@appilots/sdk 0.11.3 → 0.14.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/control-transformer.js +69 -0
- package/dist/.build-meta.json +3 -3
- package/dist/{chunk-2ZDELL54.mjs → chunk-6JWU3NBT.mjs} +860 -208
- package/dist/{chunk-ROXXCDIG.mjs → chunk-AKAMWKO6.mjs} +5795 -546
- package/dist/{chunk-5UVMNKPT.js → chunk-GDCBLSYT.js} +8 -8
- package/dist/{chunk-UFMTRGML.js → chunk-JGUDXRXN.js} +1143 -477
- package/dist/{chunk-JKLE5SLN.mjs → chunk-N66DUP54.mjs} +1 -1
- package/dist/{chunk-SUMIABJK.js → chunk-QAZ4TN3Z.js} +5817 -544
- 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-BR-33WMN.d.mts → index-wMMetyrj.d.mts} +169 -660
- package/dist/{index-BR-33WMN.d.ts → index-wMMetyrj.d.ts} +169 -660
- package/dist/index.d.mts +1500 -76
- package/dist/index.d.ts +1500 -76
- package/dist/index.js +1442 -720
- package/dist/index.mjs +1271 -612
- package/dist/navigation/index.d.mts +22 -1
- package/dist/navigation/index.d.ts +22 -1
- package/dist/navigation/index.js +13 -13
- package/dist/navigation/index.mjs +2 -2
- package/metro.d.ts +3 -5
- package/metro.js +46 -5
- package/package.json +16 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkQAZ4TN3Z_js = require('./chunk-QAZ4TN3Z.js');
|
|
4
4
|
var React = require('react');
|
|
5
5
|
var reactNative = require('react-native');
|
|
6
6
|
|
|
@@ -8,6 +8,277 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
8
8
|
|
|
9
9
|
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
10
10
|
|
|
11
|
+
// src/i18n/bundles/pt-BR.ts
|
|
12
|
+
var ptBR = {
|
|
13
|
+
chatTitle: "Assistente Appilots",
|
|
14
|
+
clearButton: "Limpar",
|
|
15
|
+
inputPlaceholder: "Digite uma mensagem...",
|
|
16
|
+
emptyTitle: "Como posso ajudar?",
|
|
17
|
+
emptySubtitle: "Navego, preencho formul\xE1rios e executo a\xE7\xF5es neste app.",
|
|
18
|
+
thinking: "Pensando...",
|
|
19
|
+
statusAnalyzing: "Analisando a tela...",
|
|
20
|
+
statusWaitingApp: "Aguardando o app responder...",
|
|
21
|
+
statusAdjusting: "Ajustando o plano...",
|
|
22
|
+
stillWorking: "Ainda trabalhando\u2026 {seconds} s",
|
|
23
|
+
poweredBy: "Powered by Appilots",
|
|
24
|
+
approve: "Aprovar",
|
|
25
|
+
reject: "Rejeitar",
|
|
26
|
+
cancelledByUser: "Cancelado pelo usu\xE1rio",
|
|
27
|
+
confirmDestructiveTitle: "A\xE7\xE3o destrutiva",
|
|
28
|
+
confirmTitle: "Confirma\xE7\xE3o necess\xE1ria",
|
|
29
|
+
confirmMessage: 'Tem certeza que deseja "{action}"?',
|
|
30
|
+
confirmDestructiveApprove: "Sim, executar",
|
|
31
|
+
confirmApprove: "Confirmar",
|
|
32
|
+
confirmCancel: "Cancelar",
|
|
33
|
+
confirmThisAction: "esta a\xE7\xE3o",
|
|
34
|
+
confirmExpired: "Esta confirma\xE7\xE3o expirou. Pe\xE7a de novo ao assistente para continuar.",
|
|
35
|
+
unknownAction: "A\xE7\xE3o desconhecida",
|
|
36
|
+
somethingWentWrong: "Algo deu errado",
|
|
37
|
+
openChatA11y: "Abrir chat do assistente",
|
|
38
|
+
closeChatA11y: "Fechar chat do assistente",
|
|
39
|
+
stopGeneratingA11y: "Parar gera\xE7\xE3o",
|
|
40
|
+
talkToHumanA11y: "Falar com um atendente humano",
|
|
41
|
+
humanAgentLabel: "Atendente",
|
|
42
|
+
escalationRequested: "Certo! Chamei um atendente humano. Voc\xEA pode continuar usando o app normalmente enquanto isso.",
|
|
43
|
+
escalationConnected: "Um atendente entrou na conversa.",
|
|
44
|
+
escalationResolved: "O atendimento humano foi encerrado. Voltei a te ajudar por aqui.",
|
|
45
|
+
escalationOffer: "Se preferir, posso chamar uma pessoa para ajudar.",
|
|
46
|
+
escalationOfferChip: "Falar com um atendente",
|
|
47
|
+
escalationPendingBanner: "Aguardando um atendente...",
|
|
48
|
+
escalationActiveBanner: "Voc\xEA est\xE1 falando com um atendente",
|
|
49
|
+
pillWorking: "Trabalhando...",
|
|
50
|
+
pillExpandA11y: "Abrir a conversa do assistente",
|
|
51
|
+
pillStopA11y: "Parar o assistente",
|
|
52
|
+
missionPause: "Pausar",
|
|
53
|
+
missionResume: "Retomar tarefa",
|
|
54
|
+
missionCancel: "Cancelar tarefa",
|
|
55
|
+
missionPaused: "Pausada",
|
|
56
|
+
pillDone: "Pronto \u2014 toque para ver",
|
|
57
|
+
a11yAwaitingApproval: "O assistente precisa da sua confirma\xE7\xE3o para continuar.",
|
|
58
|
+
a11yTurnDone: "O assistente terminou.",
|
|
59
|
+
micStartA11y: "Segurar para falar",
|
|
60
|
+
micStopA11y: "Soltar para enviar",
|
|
61
|
+
micListening: "Ouvindo..."
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// src/i18n/bundles/en.ts
|
|
65
|
+
var en = {
|
|
66
|
+
chatTitle: "Appilots Assistant",
|
|
67
|
+
clearButton: "Clear",
|
|
68
|
+
inputPlaceholder: "Type a message...",
|
|
69
|
+
emptyTitle: "How can I help?",
|
|
70
|
+
emptySubtitle: "I navigate, fill forms, and run actions in this app.",
|
|
71
|
+
thinking: "Thinking...",
|
|
72
|
+
statusAnalyzing: "Reading the screen...",
|
|
73
|
+
statusWaitingApp: "Waiting for the app...",
|
|
74
|
+
statusAdjusting: "Adjusting the plan...",
|
|
75
|
+
stillWorking: "Still working\u2026 {seconds} s",
|
|
76
|
+
poweredBy: "Powered by Appilots",
|
|
77
|
+
approve: "Approve",
|
|
78
|
+
reject: "Reject",
|
|
79
|
+
cancelledByUser: "Cancelled by user",
|
|
80
|
+
confirmDestructiveTitle: "Destructive action",
|
|
81
|
+
confirmTitle: "Confirmation needed",
|
|
82
|
+
confirmMessage: 'Are you sure you want to "{action}"?',
|
|
83
|
+
confirmDestructiveApprove: "Yes, do it",
|
|
84
|
+
confirmApprove: "Confirm",
|
|
85
|
+
confirmCancel: "Cancel",
|
|
86
|
+
confirmThisAction: "this action",
|
|
87
|
+
confirmExpired: "This confirmation expired. Ask the assistant again to continue.",
|
|
88
|
+
unknownAction: "Unknown action",
|
|
89
|
+
somethingWentWrong: "Something went wrong",
|
|
90
|
+
openChatA11y: "Open assistant chat",
|
|
91
|
+
closeChatA11y: "Close assistant chat",
|
|
92
|
+
stopGeneratingA11y: "Stop generating",
|
|
93
|
+
talkToHumanA11y: "Talk to a human agent",
|
|
94
|
+
humanAgentLabel: "Agent",
|
|
95
|
+
escalationRequested: "Done! I've called a human agent. You can keep using the app normally in the meantime.",
|
|
96
|
+
escalationConnected: "A human agent joined the conversation.",
|
|
97
|
+
escalationResolved: "The human handoff has ended. I'm back to help you here.",
|
|
98
|
+
escalationOffer: "If you prefer, I can bring in a person to help.",
|
|
99
|
+
escalationOfferChip: "Talk to a human",
|
|
100
|
+
escalationPendingBanner: "Waiting for a human agent...",
|
|
101
|
+
escalationActiveBanner: "You're talking to a human agent",
|
|
102
|
+
pillWorking: "Working...",
|
|
103
|
+
pillExpandA11y: "Open the assistant conversation",
|
|
104
|
+
pillStopA11y: "Stop the assistant",
|
|
105
|
+
missionPause: "Pause",
|
|
106
|
+
missionResume: "Resume task",
|
|
107
|
+
missionCancel: "Cancel task",
|
|
108
|
+
missionPaused: "Paused",
|
|
109
|
+
pillDone: "Done \u2014 tap to read",
|
|
110
|
+
a11yAwaitingApproval: "The assistant needs your confirmation to continue.",
|
|
111
|
+
a11yTurnDone: "The assistant finished.",
|
|
112
|
+
micStartA11y: "Hold to talk",
|
|
113
|
+
micStopA11y: "Release to send",
|
|
114
|
+
micListening: "Listening..."
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// src/i18n/bundles/es.ts
|
|
118
|
+
var es = {
|
|
119
|
+
chatTitle: "Asistente Appilots",
|
|
120
|
+
clearButton: "Limpiar",
|
|
121
|
+
inputPlaceholder: "Escribe un mensaje...",
|
|
122
|
+
emptyTitle: "\xBFEn qu\xE9 puedo ayudarte?",
|
|
123
|
+
emptySubtitle: "Navego, relleno formularios y ejecuto acciones en esta app.",
|
|
124
|
+
thinking: "Pensando...",
|
|
125
|
+
statusAnalyzing: "Analizando la pantalla...",
|
|
126
|
+
statusWaitingApp: "Esperando a la app...",
|
|
127
|
+
statusAdjusting: "Ajustando el plan...",
|
|
128
|
+
stillWorking: "Sigo trabajando\u2026 {seconds} s",
|
|
129
|
+
poweredBy: "Hecho con Appilots",
|
|
130
|
+
approve: "Aprobar",
|
|
131
|
+
reject: "Rechazar",
|
|
132
|
+
cancelledByUser: "Cancelado por el usuario",
|
|
133
|
+
confirmDestructiveTitle: "Acci\xF3n destructiva",
|
|
134
|
+
confirmTitle: "Confirmaci\xF3n necesaria",
|
|
135
|
+
confirmMessage: '\xBFSeguro que quieres "{action}"?',
|
|
136
|
+
confirmDestructiveApprove: "S\xED, ejecutar",
|
|
137
|
+
confirmApprove: "Confirmar",
|
|
138
|
+
confirmCancel: "Cancelar",
|
|
139
|
+
confirmThisAction: "esta acci\xF3n",
|
|
140
|
+
confirmExpired: "Esta confirmaci\xF3n expir\xF3. Pide de nuevo al asistente para continuar.",
|
|
141
|
+
unknownAction: "Acci\xF3n desconocida",
|
|
142
|
+
somethingWentWrong: "Algo sali\xF3 mal",
|
|
143
|
+
openChatA11y: "Abrir chat del asistente",
|
|
144
|
+
closeChatA11y: "Cerrar chat del asistente",
|
|
145
|
+
stopGeneratingA11y: "Detener generaci\xF3n",
|
|
146
|
+
talkToHumanA11y: "Hablar con un agente humano",
|
|
147
|
+
humanAgentLabel: "Agente",
|
|
148
|
+
escalationRequested: "\xA1Listo! Llam\xE9 a un agente humano. Mientras tanto puedes seguir usando la app con normalidad.",
|
|
149
|
+
escalationConnected: "Un agente humano se uni\xF3 a la conversaci\xF3n.",
|
|
150
|
+
escalationResolved: "La atenci\xF3n humana termin\xF3. Vuelvo a ayudarte por aqu\xED.",
|
|
151
|
+
escalationOffer: "Si prefieres, puedo llamar a una persona para ayudarte.",
|
|
152
|
+
escalationOfferChip: "Hablar con un agente",
|
|
153
|
+
escalationPendingBanner: "Esperando a un agente...",
|
|
154
|
+
escalationActiveBanner: "Est\xE1s hablando con un agente humano",
|
|
155
|
+
pillWorking: "Trabajando...",
|
|
156
|
+
pillExpandA11y: "Abrir la conversaci\xF3n del asistente",
|
|
157
|
+
pillStopA11y: "Detener el asistente",
|
|
158
|
+
missionPause: "Pausar",
|
|
159
|
+
missionResume: "Reanudar tarea",
|
|
160
|
+
missionCancel: "Cancelar tarea",
|
|
161
|
+
missionPaused: "Pausada",
|
|
162
|
+
pillDone: "Listo \u2014 toca para ver",
|
|
163
|
+
a11yAwaitingApproval: "El asistente necesita tu confirmaci\xF3n para continuar.",
|
|
164
|
+
a11yTurnDone: "El asistente termin\xF3.",
|
|
165
|
+
micStartA11y: "Mantener para hablar",
|
|
166
|
+
micStopA11y: "Soltar para enviar",
|
|
167
|
+
micListening: "Escuchando..."
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// src/i18n/bundles/fr.ts
|
|
171
|
+
var fr = {
|
|
172
|
+
chatTitle: "Assistant Appilots",
|
|
173
|
+
clearButton: "Effacer",
|
|
174
|
+
inputPlaceholder: "\xC9crivez un message\u2026",
|
|
175
|
+
emptyTitle: "Comment puis-je vous aider ?",
|
|
176
|
+
emptySubtitle: "Je navigue, remplis les formulaires et effectue des actions dans cette application.",
|
|
177
|
+
thinking: "R\xE9flexion en cours\u2026",
|
|
178
|
+
statusAnalyzing: "Lecture de l\u2019\xE9cran\u2026",
|
|
179
|
+
statusWaitingApp: "En attente de l\u2019application\u2026",
|
|
180
|
+
statusAdjusting: "Ajustement du plan\u2026",
|
|
181
|
+
stillWorking: "Toujours en cours\u2026 {seconds} s",
|
|
182
|
+
poweredBy: "Propuls\xE9 par Appilots",
|
|
183
|
+
approve: "Approuver",
|
|
184
|
+
reject: "Refuser",
|
|
185
|
+
cancelledByUser: "Annul\xE9 par l\u2019utilisateur",
|
|
186
|
+
confirmDestructiveTitle: "Action destructive",
|
|
187
|
+
confirmTitle: "Confirmation requise",
|
|
188
|
+
confirmMessage: "Voulez-vous vraiment \xAB {action} \xBB ?",
|
|
189
|
+
confirmDestructiveApprove: "Oui, ex\xE9cuter",
|
|
190
|
+
confirmApprove: "Confirmer",
|
|
191
|
+
confirmCancel: "Annuler",
|
|
192
|
+
confirmThisAction: "cette action",
|
|
193
|
+
confirmExpired: "Cette confirmation a expir\xE9. Redemandez \xE0 l\u2019assistant pour continuer.",
|
|
194
|
+
unknownAction: "Action inconnue",
|
|
195
|
+
somethingWentWrong: "Une erreur est survenue",
|
|
196
|
+
openChatA11y: "Ouvrir la conversation avec l\u2019assistant",
|
|
197
|
+
closeChatA11y: "Fermer la conversation",
|
|
198
|
+
stopGeneratingA11y: "Arr\xEAter la g\xE9n\xE9ration",
|
|
199
|
+
talkToHumanA11y: "Parler \xE0 un conseiller",
|
|
200
|
+
humanAgentLabel: "Conseiller",
|
|
201
|
+
escalationRequested: "J\u2019ai contact\xE9 un conseiller. Vous pouvez continuer \xE0 utiliser l\u2019application en attendant.",
|
|
202
|
+
escalationConnected: "Un conseiller a rejoint la conversation.",
|
|
203
|
+
escalationResolved: "L\u2019intervention du conseiller est termin\xE9e. Je peux \xE0 nouveau vous aider.",
|
|
204
|
+
escalationOffer: "Si vous pr\xE9f\xE9rez, je peux faire appel \xE0 un conseiller.",
|
|
205
|
+
escalationOfferChip: "Parler \xE0 un conseiller",
|
|
206
|
+
escalationPendingBanner: "En attente d\u2019un conseiller\u2026",
|
|
207
|
+
escalationActiveBanner: "Vous discutez avec un conseiller",
|
|
208
|
+
pillWorking: "En cours\u2026",
|
|
209
|
+
pillExpandA11y: "Ouvrir la conversation avec l\u2019assistant",
|
|
210
|
+
pillStopA11y: "Arr\xEAter l\u2019assistant",
|
|
211
|
+
missionPause: "Mettre en pause",
|
|
212
|
+
missionResume: "Reprendre la t\xE2che",
|
|
213
|
+
missionCancel: "Annuler la t\xE2che",
|
|
214
|
+
missionPaused: "En pause",
|
|
215
|
+
pillDone: "Termin\xE9 \u2014 touchez pour lire",
|
|
216
|
+
a11yAwaitingApproval: "L\u2019assistant a besoin de votre confirmation pour continuer.",
|
|
217
|
+
a11yTurnDone: "L\u2019assistant a termin\xE9.",
|
|
218
|
+
micStartA11y: "Maintenez pour parler",
|
|
219
|
+
micStopA11y: "Rel\xE2chez pour envoyer",
|
|
220
|
+
micListening: "\xC9coute en cours\u2026"
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
// src/i18n/I18nProvider.tsx
|
|
224
|
+
var BUNDLES = {
|
|
225
|
+
"pt-BR": ptBR,
|
|
226
|
+
en,
|
|
227
|
+
es,
|
|
228
|
+
fr
|
|
229
|
+
};
|
|
230
|
+
var DEFAULT_LOCALE = "en";
|
|
231
|
+
function detectDeviceLocale() {
|
|
232
|
+
try {
|
|
233
|
+
let raw;
|
|
234
|
+
if (reactNative.Platform.OS === "ios") {
|
|
235
|
+
const manager = reactNative.NativeModules?.SettingsManager;
|
|
236
|
+
const settings = manager?.getConstants?.()?.settings ?? manager?.settings;
|
|
237
|
+
const languages = Array.isArray(settings?.AppleLanguages) ? settings.AppleLanguages : [];
|
|
238
|
+
for (const language of languages) {
|
|
239
|
+
const locale = chunkQAZ4TN3Z_js.normalizeAppilotsLocale(language);
|
|
240
|
+
if (locale) return locale;
|
|
241
|
+
}
|
|
242
|
+
raw = settings?.AppleLocale;
|
|
243
|
+
} else if (reactNative.Platform.OS === "android") {
|
|
244
|
+
const manager = reactNative.NativeModules?.I18nManager;
|
|
245
|
+
raw = manager?.getConstants?.()?.localeIdentifier ?? manager?.localeIdentifier;
|
|
246
|
+
}
|
|
247
|
+
if (!raw || typeof raw !== "string") return null;
|
|
248
|
+
return chunkQAZ4TN3Z_js.normalizeAppilotsLocale(raw) ?? null;
|
|
249
|
+
} catch {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function resolveLocale(prop) {
|
|
254
|
+
if (prop && BUNDLES[prop]) return prop;
|
|
255
|
+
const detected = detectDeviceLocale();
|
|
256
|
+
if (detected && BUNDLES[detected]) return detected;
|
|
257
|
+
return DEFAULT_LOCALE;
|
|
258
|
+
}
|
|
259
|
+
var I18nContext = React.createContext(null);
|
|
260
|
+
function AppilotsI18nProvider({ locale, overrides, children }) {
|
|
261
|
+
const value = React.useMemo(() => {
|
|
262
|
+
const resolved = resolveLocale(locale ?? null);
|
|
263
|
+
const merged = overrides ? { ...BUNDLES[resolved], ...overrides } : BUNDLES[resolved];
|
|
264
|
+
return {
|
|
265
|
+
locale: resolved,
|
|
266
|
+
strings: merged,
|
|
267
|
+
t: (key) => merged[key]
|
|
268
|
+
};
|
|
269
|
+
}, [locale, overrides]);
|
|
270
|
+
return /* @__PURE__ */ React__default.default.createElement(I18nContext.Provider, { value }, children);
|
|
271
|
+
}
|
|
272
|
+
function useAppilotsI18n() {
|
|
273
|
+
const ctx = React.useContext(I18nContext);
|
|
274
|
+
if (ctx) return ctx;
|
|
275
|
+
return {
|
|
276
|
+
locale: DEFAULT_LOCALE,
|
|
277
|
+
strings: BUNDLES[DEFAULT_LOCALE],
|
|
278
|
+
t: (key) => BUNDLES[DEFAULT_LOCALE][key]
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
11
282
|
// src/introspection/captureSnapshot.ts
|
|
12
283
|
function normalizeSliderKey(value) {
|
|
13
284
|
return (value ?? "").toLowerCase().replace(/^slider[-_]/, "");
|
|
@@ -23,9 +294,9 @@ function fiberSliderMatches(fiber, registryId, registryLabel) {
|
|
|
23
294
|
function reconcileSliders(snapshot) {
|
|
24
295
|
const fiberSliders = snapshot.sliders;
|
|
25
296
|
const out = [];
|
|
26
|
-
for (const { id, kind } of
|
|
297
|
+
for (const { id, kind } of chunkQAZ4TN3Z_js.componentRegistry.snapshot()) {
|
|
27
298
|
if (kind !== "slider") continue;
|
|
28
|
-
const entry =
|
|
299
|
+
const entry = chunkQAZ4TN3Z_js.componentRegistry.getSlider(id);
|
|
29
300
|
if (!entry) continue;
|
|
30
301
|
const fiber = fiberSliders.find((s) => fiberSliderMatches(s, id, entry.label));
|
|
31
302
|
const visible = !!fiber || typeof entry.screen === "string" && entry.screen === snapshot.route;
|
|
@@ -53,7 +324,7 @@ function normalizeFieldKey(value) {
|
|
|
53
324
|
}
|
|
54
325
|
function canonicalizeRegisteredFields(snapshot) {
|
|
55
326
|
const claimed = /* @__PURE__ */ new Set();
|
|
56
|
-
for (const { id, kind, label } of
|
|
327
|
+
for (const { id, kind, label } of chunkQAZ4TN3Z_js.componentRegistry.snapshot()) {
|
|
57
328
|
if (kind !== "field") continue;
|
|
58
329
|
if (snapshot.inputs.some((input) => input.id === id)) continue;
|
|
59
330
|
const registryLabel = (label ?? "").toLowerCase();
|
|
@@ -72,7 +343,7 @@ function canonicalizeRegisteredFields(snapshot) {
|
|
|
72
343
|
}
|
|
73
344
|
}
|
|
74
345
|
function mergeRegisteredLists(snapshot) {
|
|
75
|
-
const registered =
|
|
346
|
+
const registered = chunkQAZ4TN3Z_js.listRegistry.snapshot();
|
|
76
347
|
if (registered.length === 0) return;
|
|
77
348
|
const byId = /* @__PURE__ */ new Map();
|
|
78
349
|
for (const list of snapshot.lists) {
|
|
@@ -80,20 +351,35 @@ function mergeRegisteredLists(snapshot) {
|
|
|
80
351
|
}
|
|
81
352
|
for (const entry of registered) {
|
|
82
353
|
if (entry.kind === "scroll") continue;
|
|
354
|
+
const existing = byId.get(entry.id);
|
|
355
|
+
if (!existing && !(entry.screen && entry.screen === snapshot.route)) continue;
|
|
83
356
|
const metrics = entry.getScrollMetrics?.();
|
|
84
357
|
const scrollFacts = metrics ? {
|
|
85
358
|
scrollOffsetY: Math.max(0, Math.round(metrics.offset)),
|
|
86
359
|
canScrollUp: metrics.offset > 8,
|
|
87
360
|
canScrollDown: metrics.offset + metrics.visibleLength < metrics.contentLength - 8
|
|
88
361
|
} : void 0;
|
|
89
|
-
const existing = byId.get(entry.id);
|
|
90
362
|
if (existing) {
|
|
91
363
|
existing.itemCount = existing.itemCount ?? entry.itemCount;
|
|
364
|
+
existing.totalItemCount = existing.totalItemCount ?? entry.totalItemCount;
|
|
92
365
|
existing.refreshing = existing.refreshing ?? entry.refreshing;
|
|
93
366
|
existing.empty = existing.empty ?? entry.empty;
|
|
94
367
|
existing.label = existing.label ?? entry.label;
|
|
95
368
|
existing.source = existing.source ?? "auto-tracked";
|
|
96
369
|
existing.visibleItemCount = existing.items.length;
|
|
370
|
+
const viewport = entry.measureViewport?.();
|
|
371
|
+
if (viewport && viewport.width > 0 && viewport.height > 0) {
|
|
372
|
+
let measured = 0;
|
|
373
|
+
let inViewport = 0;
|
|
374
|
+
for (const item of existing.items) {
|
|
375
|
+
const rect = chunkQAZ4TN3Z_js.rectForNode(item);
|
|
376
|
+
if (!rect) continue;
|
|
377
|
+
measured++;
|
|
378
|
+
item.onScreen = rect.width > 0 && rect.height > 0 && rect.x < viewport.x + viewport.width && rect.x + rect.width > viewport.x && rect.y < viewport.y + viewport.height && rect.y + rect.height > viewport.y;
|
|
379
|
+
if (item.onScreen) inViewport++;
|
|
380
|
+
}
|
|
381
|
+
if (measured === existing.items.length) existing.viewportItemCount = inViewport;
|
|
382
|
+
}
|
|
97
383
|
if (entry.dataPreview && entry.dataPreview.length > 0) {
|
|
98
384
|
existing.dataPreview = entry.dataPreview;
|
|
99
385
|
}
|
|
@@ -110,6 +396,7 @@ function mergeRegisteredLists(snapshot) {
|
|
|
110
396
|
containerType: entry.component,
|
|
111
397
|
source: "registry",
|
|
112
398
|
itemCount: entry.itemCount,
|
|
399
|
+
totalItemCount: entry.totalItemCount,
|
|
113
400
|
visibleItemCount: 0,
|
|
114
401
|
refreshing: entry.refreshing,
|
|
115
402
|
empty: entry.empty,
|
|
@@ -121,7 +408,7 @@ function mergeRegisteredLists(snapshot) {
|
|
|
121
408
|
}
|
|
122
409
|
}
|
|
123
410
|
function mergeRegisteredScrollables(snapshot) {
|
|
124
|
-
const registered =
|
|
411
|
+
const registered = chunkQAZ4TN3Z_js.listRegistry.snapshot().filter((e) => e.kind === "scroll");
|
|
125
412
|
if (registered.length === 0) return;
|
|
126
413
|
const listsById = /* @__PURE__ */ new Map();
|
|
127
414
|
for (const list of snapshot.lists) {
|
|
@@ -154,7 +441,7 @@ function mergeRegisteredScrollables(snapshot) {
|
|
|
154
441
|
if (out.length > 0) snapshot.scrollables = out;
|
|
155
442
|
}
|
|
156
443
|
function mergeNativeDialog(snapshot) {
|
|
157
|
-
const dialog =
|
|
444
|
+
const dialog = chunkQAZ4TN3Z_js.getOpenNativeDialog();
|
|
158
445
|
if (!dialog) return;
|
|
159
446
|
snapshot.nativeDialog = {
|
|
160
447
|
id: dialog.id,
|
|
@@ -169,21 +456,58 @@ function mergeNativeDialog(snapshot) {
|
|
|
169
456
|
}
|
|
170
457
|
var MIN_FIBERS_FOR_BLINDNESS = 200;
|
|
171
458
|
function recordBlindWalk() {
|
|
172
|
-
const walk =
|
|
459
|
+
const walk = chunkQAZ4TN3Z_js.getLastWalkDiagnostics();
|
|
173
460
|
if (!walk) return;
|
|
174
461
|
if (walk.visitedFibers < MIN_FIBERS_FOR_BLINDNESS) return;
|
|
175
|
-
if (
|
|
176
|
-
|
|
462
|
+
if (chunkQAZ4TN3Z_js.totalDetectorHits(walk.detectors) > 0) return;
|
|
463
|
+
chunkQAZ4TN3Z_js.recordIntrospectionFailure("walk-recognized-nothing", null);
|
|
464
|
+
}
|
|
465
|
+
function mergeRegisteredFieldValues(snapshot) {
|
|
466
|
+
const present = new Set(snapshot.inputs.map((i) => normalizeFieldKey(i.id)));
|
|
467
|
+
const onScreenIds = [
|
|
468
|
+
...snapshot.buttons.map((b) => (b.id ?? "").toLowerCase()),
|
|
469
|
+
...snapshot.toggles.map((t) => (t.id ?? "").toLowerCase())
|
|
470
|
+
].filter(Boolean);
|
|
471
|
+
const onScreenLabels = new Set(
|
|
472
|
+
[...snapshot.buttons.map((b) => b.label), ...snapshot.texts].filter((l) => !!l).map((l) => l.toLowerCase())
|
|
473
|
+
);
|
|
474
|
+
for (const { id, kind, screen, label } of chunkQAZ4TN3Z_js.componentRegistry.snapshot()) {
|
|
475
|
+
if (kind !== "field") continue;
|
|
476
|
+
const key = normalizeFieldKey(id);
|
|
477
|
+
if (!key || present.has(key)) continue;
|
|
478
|
+
const entry = chunkQAZ4TN3Z_js.componentRegistry.getField(id);
|
|
479
|
+
if (!entry) continue;
|
|
480
|
+
const fieldType = entry.fieldType ?? "";
|
|
481
|
+
if (fieldType === "text" || fieldType === "") continue;
|
|
482
|
+
const declaresRoute = typeof screen === "string" && screen === snapshot.route;
|
|
483
|
+
if (screen && !declaresRoute && !chunkQAZ4TN3Z_js.getActiveRouteNames().includes(screen)) continue;
|
|
484
|
+
const idEvidence = onScreenIds.some((candidate) => candidate.split(/[^a-z0-9]+/).includes(key));
|
|
485
|
+
const labelEvidence = !!entry.label && onScreenLabels.has(entry.label.toLowerCase());
|
|
486
|
+
if (!declaresRoute && !idEvidence && !labelEvidence) continue;
|
|
487
|
+
let value;
|
|
488
|
+
try {
|
|
489
|
+
value = String(entry.getValue() ?? "");
|
|
490
|
+
} catch {
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
snapshot.inputs.push({
|
|
494
|
+
id,
|
|
495
|
+
label: entry.label ?? label,
|
|
496
|
+
value,
|
|
497
|
+
type: fieldType
|
|
498
|
+
});
|
|
499
|
+
present.add(key);
|
|
500
|
+
}
|
|
177
501
|
}
|
|
178
502
|
function captureSnapshot() {
|
|
179
|
-
const root =
|
|
503
|
+
const root = chunkQAZ4TN3Z_js.getFiberRoot();
|
|
180
504
|
if (!root) {
|
|
181
|
-
|
|
505
|
+
chunkQAZ4TN3Z_js.appilotsDebugWarn(
|
|
182
506
|
"captureSnapshot: fiber root not captured yet. Ensure <AppilotsProvider> has rendered before calling this."
|
|
183
507
|
);
|
|
184
|
-
|
|
508
|
+
chunkQAZ4TN3Z_js.recordIntrospectionFailure("never-mounted", null);
|
|
185
509
|
return {
|
|
186
|
-
route:
|
|
510
|
+
route: chunkQAZ4TN3Z_js.getCurrentScreen(),
|
|
187
511
|
texts: [],
|
|
188
512
|
inputs: [],
|
|
189
513
|
buttons: [],
|
|
@@ -197,9 +521,9 @@ function captureSnapshot() {
|
|
|
197
521
|
};
|
|
198
522
|
}
|
|
199
523
|
const start = Date.now();
|
|
200
|
-
const snapshot =
|
|
524
|
+
const snapshot = chunkQAZ4TN3Z_js.walkFiber(root);
|
|
201
525
|
recordBlindWalk();
|
|
202
|
-
const activePath =
|
|
526
|
+
const activePath = chunkQAZ4TN3Z_js.getActiveRouteNames();
|
|
203
527
|
const deepestRoute = activePath[activePath.length - 1];
|
|
204
528
|
if (deepestRoute) snapshot.route = deepestRoute;
|
|
205
529
|
mergeRegisteredLists(snapshot);
|
|
@@ -207,15 +531,16 @@ function captureSnapshot() {
|
|
|
207
531
|
mergeNativeDialog(snapshot);
|
|
208
532
|
reconcileSliders(snapshot);
|
|
209
533
|
canonicalizeRegisteredFields(snapshot);
|
|
210
|
-
|
|
211
|
-
|
|
534
|
+
mergeRegisteredFieldValues(snapshot);
|
|
535
|
+
chunkQAZ4TN3Z_js.clampSnapshotToWireLimits(snapshot);
|
|
536
|
+
const entries = chunkQAZ4TN3Z_js.deriveInteractionElements(snapshot, { rectOf: chunkQAZ4TN3Z_js.rectForNode });
|
|
212
537
|
const rectById = new Map(
|
|
213
538
|
entries.flatMap((entry) => entry.rect ? [[entry.id, entry.rect]] : [])
|
|
214
539
|
);
|
|
215
|
-
snapshot.elements = entries.map(
|
|
216
|
-
snapshot.choiceGroups =
|
|
217
|
-
|
|
218
|
-
|
|
540
|
+
snapshot.elements = entries.map(chunkQAZ4TN3Z_js.toWireElement);
|
|
541
|
+
snapshot.choiceGroups = chunkQAZ4TN3Z_js.attachElementIdsToChoiceGroups(snapshot.choiceGroups, snapshot.elements);
|
|
542
|
+
chunkQAZ4TN3Z_js.clampSnapshotToWireLimits(snapshot);
|
|
543
|
+
chunkQAZ4TN3Z_js.elementRegistry.replaceAll(
|
|
219
544
|
snapshot.elements.map((element) => {
|
|
220
545
|
const rect = rectById.get(element.id);
|
|
221
546
|
return rect ? { ...element, rect } : element;
|
|
@@ -227,10 +552,10 @@ function captureSnapshot() {
|
|
|
227
552
|
(acc, l) => acc + (typeof l.itemCount === "number" ? l.itemCount : 0),
|
|
228
553
|
0
|
|
229
554
|
);
|
|
230
|
-
|
|
555
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
231
556
|
`captureSnapshot: route="${snapshot.route}" texts=${snapshot.texts.length} inputs=${snapshot.inputs.length} buttons=${snapshot.buttons.length} toggles=${snapshot.toggles.length} sliders=${snapshot.sliders.length} loading=${snapshot.loading} modal=${snapshot.modalOpen} lists=${snapshot.lists.length}(visibleItems=${totalListItems}, dataItems=${totalListDataItems}) choices=${snapshot.choiceGroups.length} elements=${snapshot.elements.length} ` + (snapshot.truncated ? "truncated=true " : "") + `(walked ${snapshot.stats?.visitedFibers ?? 0} fibers, skipped ${snapshot.stats?.skippedHidden ?? 0} hidden, ${elapsed}ms)`
|
|
232
557
|
);
|
|
233
|
-
|
|
558
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
234
559
|
`captureSnapshot detail: lists=[${snapshot.lists.map((l) => `${l.containerType}:${l.id ?? l.label ?? "?"}(rows=${l.items.length})`).join(", ")}] inputs=[${snapshot.inputs.map((i) => i.id ?? i.label ?? "?").slice(0, 12).join(", ")}] buttons=[${snapshot.buttons.map((b) => b.id ?? b.label ?? "?").slice(0, 15).join(", ")}]`
|
|
235
560
|
);
|
|
236
561
|
return snapshot;
|
|
@@ -241,10 +566,10 @@ function registryCounts() {
|
|
|
241
566
|
toggles: 0,
|
|
242
567
|
sliders: 0,
|
|
243
568
|
targets: 0,
|
|
244
|
-
lists:
|
|
245
|
-
elements:
|
|
569
|
+
lists: chunkQAZ4TN3Z_js.listRegistry.snapshot().length,
|
|
570
|
+
elements: chunkQAZ4TN3Z_js.elementRegistry.size
|
|
246
571
|
};
|
|
247
|
-
for (const { kind } of
|
|
572
|
+
for (const { kind } of chunkQAZ4TN3Z_js.componentRegistry.snapshot()) {
|
|
248
573
|
if (kind === "field") counts.fields++;
|
|
249
574
|
else if (kind === "toggle") counts.toggles++;
|
|
250
575
|
else if (kind === "slider") counts.sliders++;
|
|
@@ -253,26 +578,26 @@ function registryCounts() {
|
|
|
253
578
|
return counts;
|
|
254
579
|
}
|
|
255
580
|
function appilotsSelfCheck() {
|
|
256
|
-
const root =
|
|
581
|
+
const root = chunkQAZ4TN3Z_js.getFiberRoot();
|
|
257
582
|
const start = Date.now();
|
|
258
|
-
if (root)
|
|
583
|
+
if (root) chunkQAZ4TN3Z_js.walkFiber(root);
|
|
259
584
|
const elapsedMs = Date.now() - start;
|
|
260
|
-
const walk =
|
|
585
|
+
const walk = chunkQAZ4TN3Z_js.getLastWalkDiagnostics();
|
|
261
586
|
return {
|
|
262
|
-
sdkVersion:
|
|
587
|
+
sdkVersion: chunkQAZ4TN3Z_js.SDK_VERSION,
|
|
263
588
|
reactVersion: React__default.default.version ?? null,
|
|
264
|
-
route:
|
|
265
|
-
introspection:
|
|
266
|
-
autoTracking:
|
|
589
|
+
route: chunkQAZ4TN3Z_js.getCurrentScreen() || null,
|
|
590
|
+
introspection: chunkQAZ4TN3Z_js.getIntrospectionDiagnostics(),
|
|
591
|
+
autoTracking: chunkQAZ4TN3Z_js.getAutoTrackingState(),
|
|
267
592
|
walk: {
|
|
268
593
|
visitedFibers: root ? walk?.visitedFibers ?? 0 : 0,
|
|
269
594
|
skippedHidden: root ? walk?.skippedHidden ?? 0 : 0,
|
|
270
595
|
elapsedMs
|
|
271
596
|
},
|
|
272
|
-
detectors: root ? walk?.detectors ??
|
|
597
|
+
detectors: root ? walk?.detectors ?? chunkQAZ4TN3Z_js.emptyDetectorCounts() : chunkQAZ4TN3Z_js.emptyDetectorCounts(),
|
|
273
598
|
registry: registryCounts(),
|
|
274
|
-
nameMangling:
|
|
275
|
-
geometry: { availability:
|
|
599
|
+
nameMangling: chunkQAZ4TN3Z_js.getNameManglingProbe(),
|
|
600
|
+
geometry: { availability: chunkQAZ4TN3Z_js.geometryAvailability(), ...chunkQAZ4TN3Z_js.geometryStats() }
|
|
276
601
|
};
|
|
277
602
|
}
|
|
278
603
|
|
|
@@ -285,7 +610,7 @@ function declaredState(props) {
|
|
|
285
610
|
return typeof checked === "boolean" ? checked : void 0;
|
|
286
611
|
}
|
|
287
612
|
function isReactNativeSwitch(fiber) {
|
|
288
|
-
return
|
|
613
|
+
return chunkQAZ4TN3Z_js.getTypeName(fiber?.type) === "Switch" || chunkQAZ4TN3Z_js.getTypeName(fiber?.elementType) === "Switch";
|
|
289
614
|
}
|
|
290
615
|
var SWITCH_FLIP_HANDLERS = ["onValueChange", "onChange", "onPress"];
|
|
291
616
|
function flipSwitchFiber(fiber, next) {
|
|
@@ -309,6 +634,11 @@ function flipSwitchFiber(fiber, next) {
|
|
|
309
634
|
return { ok: true, via: handler.via };
|
|
310
635
|
}
|
|
311
636
|
|
|
637
|
+
// src/introspection/positionalIdentity.ts
|
|
638
|
+
function isPositionalControlId(value) {
|
|
639
|
+
return /^(?:list-\d+-item-\d+-)?(?:btn|input|slider|toggle)-\d+$/i.test(value.trim());
|
|
640
|
+
}
|
|
641
|
+
|
|
312
642
|
// src/introspection/findInteractive.ts
|
|
313
643
|
function getTypeName2(type) {
|
|
314
644
|
if (!type) return null;
|
|
@@ -383,7 +713,7 @@ function shouldSkipSubtree2(fiber) {
|
|
|
383
713
|
const typeName = getTypeName2(fiber.type) ?? getTypeName2(fiber.elementType);
|
|
384
714
|
if (typeName && SELF_REFERENTIAL_COMPONENTS.has(typeName)) return true;
|
|
385
715
|
if (isAppilotsSkipMarked(props)) return true;
|
|
386
|
-
if (
|
|
716
|
+
if (chunkQAZ4TN3Z_js.isModalFiber(fiber) && props.visible === false) return true;
|
|
387
717
|
if (matchesName(fiber, "Screen") && props.activityState === 0) return true;
|
|
388
718
|
const style = props.style;
|
|
389
719
|
if (style) {
|
|
@@ -393,9 +723,17 @@ function shouldSkipSubtree2(fiber) {
|
|
|
393
723
|
}
|
|
394
724
|
return false;
|
|
395
725
|
}
|
|
396
|
-
|
|
726
|
+
function isSecureInput(props) {
|
|
727
|
+
return !!props.secureTextEntry || chunkQAZ4TN3Z_js.isAppilotsSensitiveMarked(props);
|
|
728
|
+
}
|
|
729
|
+
var normalize = chunkQAZ4TN3Z_js.foldForCompare;
|
|
397
730
|
function scoreMatchDetail(fiber, queryNorm, queryRaw) {
|
|
398
731
|
const props = fiber.memoizedProps ?? {};
|
|
732
|
+
if (chunkQAZ4TN3Z_js.isSourceControlId(queryRaw)) {
|
|
733
|
+
const matches = chunkQAZ4TN3Z_js.sourceControlId(fiber) === queryRaw;
|
|
734
|
+
const disabled = props.disabled === true || props.accessibilityState?.disabled === true;
|
|
735
|
+
return { score: matches ? disabled ? 60 : 120 : 0, named: matches, disabled };
|
|
736
|
+
}
|
|
399
737
|
const candidates = [];
|
|
400
738
|
if (typeof props.testID === "string") candidates.push({ val: props.testID, weight: 100 });
|
|
401
739
|
if (typeof props.accessibilityLabel === "string")
|
|
@@ -409,16 +747,22 @@ function scoreMatchDetail(fiber, queryNorm, queryRaw) {
|
|
|
409
747
|
if (childText) candidates.push({ val: childText, weight: 80 });
|
|
410
748
|
}
|
|
411
749
|
let best = 0;
|
|
750
|
+
let exact = false;
|
|
412
751
|
for (const { val, weight } of candidates) {
|
|
413
752
|
const vNorm = normalize(val);
|
|
414
753
|
if (!vNorm) continue;
|
|
415
|
-
if (val === queryRaw)
|
|
416
|
-
|
|
417
|
-
|
|
754
|
+
if (val === queryRaw) {
|
|
755
|
+
best = Math.max(best, weight + 20);
|
|
756
|
+
exact = true;
|
|
757
|
+
} else if (vNorm === queryNorm) {
|
|
758
|
+
best = Math.max(best, weight + 10);
|
|
759
|
+
exact = true;
|
|
760
|
+
} else if (!isPositionalControlId(queryRaw) && queryNorm && (vNorm.includes(queryNorm) || queryNorm.includes(vNorm)))
|
|
418
761
|
best = Math.max(best, weight - 20);
|
|
419
762
|
}
|
|
763
|
+
if (!exact && isSecureInput(props)) best = 0;
|
|
420
764
|
const named = best >= IDENTITY_MATCH_SCORE;
|
|
421
|
-
const disabledProp = props.disabled === true;
|
|
765
|
+
const disabledProp = props.disabled === true || props.editable === false || props.readOnly === true;
|
|
422
766
|
const disabledA11y = typeof props.accessibilityState === "object" && props.accessibilityState !== null && props.accessibilityState.disabled === true;
|
|
423
767
|
if (best > 0 && disabledProp) {
|
|
424
768
|
best = Math.max(1, best - 60);
|
|
@@ -428,12 +772,18 @@ function scoreMatchDetail(fiber, queryNorm, queryRaw) {
|
|
|
428
772
|
}
|
|
429
773
|
return { score: best, named, disabled: disabledProp || disabledA11y };
|
|
430
774
|
}
|
|
775
|
+
var inputIdentities = /* @__PURE__ */ new WeakMap();
|
|
431
776
|
function wrapTextInput(fiber) {
|
|
777
|
+
const identity = inputIdentities.get(fiber) ?? (fiber.alternate && inputIdentities.get(fiber.alternate)) ?? {};
|
|
778
|
+
inputIdentities.set(fiber, identity);
|
|
779
|
+
if (fiber.alternate) inputIdentities.set(fiber.alternate, identity);
|
|
432
780
|
const getProps = () => fiber.memoizedProps ?? {};
|
|
433
781
|
return {
|
|
434
782
|
kind: "field",
|
|
783
|
+
controlIdentity: identity,
|
|
435
784
|
label: getProps().accessibilityLabel ?? getProps().label ?? getProps().placeholder ?? getProps().testID,
|
|
436
785
|
getValue: () => getProps().value,
|
|
786
|
+
finishEditing: () => chunkQAZ4TN3Z_js.endTextInputEditing(getProps()),
|
|
437
787
|
setValue: (value) => {
|
|
438
788
|
const { onChangeText, onChange } = getProps();
|
|
439
789
|
if (typeof onChangeText === "function") {
|
|
@@ -468,7 +818,7 @@ function wrapSwitch(fiber) {
|
|
|
468
818
|
// `accessibilityRole="switch"`) has only the former, and reporting
|
|
469
819
|
// `false` for a control that is on is worse than reporting nothing:
|
|
470
820
|
// the caller inverts this to decide where to move.
|
|
471
|
-
getValue: () =>
|
|
821
|
+
getValue: () => chunkQAZ4TN3Z_js.switchValue(getProps()),
|
|
472
822
|
setValue: (value) => {
|
|
473
823
|
const boolVal = typeof value === "boolean" ? value : value === "true" || value === true;
|
|
474
824
|
const flipped = flipSwitchFiber(fiber, boolVal);
|
|
@@ -514,18 +864,18 @@ function describeCandidate(fiber, kind) {
|
|
|
514
864
|
const props = fiber?.memoizedProps ?? {};
|
|
515
865
|
return props.testID ?? props.accessibilityLabel ?? props.placeholder ?? (kind === "target" ? findChildText(fiber) : void 0);
|
|
516
866
|
}
|
|
517
|
-
function isDescendantOf(fiber, ancestor) {
|
|
867
|
+
function isDescendantOf(fiber, ancestor, parents) {
|
|
518
868
|
if (!fiber || !ancestor) return false;
|
|
519
|
-
let node = fiber
|
|
520
|
-
for (let depth = 0; node && depth < 200; depth++, node = node
|
|
869
|
+
let node = parents.get(fiber);
|
|
870
|
+
for (let depth = 0; node && depth < 200; depth++, node = parents.get(node)) {
|
|
521
871
|
if (node === ancestor) return true;
|
|
522
872
|
}
|
|
523
873
|
return false;
|
|
524
874
|
}
|
|
525
875
|
function findInteractiveByIdentifier(query, options = {}) {
|
|
526
|
-
const root =
|
|
876
|
+
const root = chunkQAZ4TN3Z_js.getFiberRoot();
|
|
527
877
|
if (!root) {
|
|
528
|
-
|
|
878
|
+
chunkQAZ4TN3Z_js.appilotsDebugWarn("findInteractiveByIdentifier: fiber root not captured yet");
|
|
529
879
|
return null;
|
|
530
880
|
}
|
|
531
881
|
const queryNorm = normalize(query);
|
|
@@ -538,18 +888,20 @@ function findInteractiveByIdentifier(query, options = {}) {
|
|
|
538
888
|
let bestDisabled = false;
|
|
539
889
|
let tied = [];
|
|
540
890
|
const visited = /* @__PURE__ */ new WeakSet();
|
|
891
|
+
const parents = /* @__PURE__ */ new WeakMap();
|
|
541
892
|
const stack = [];
|
|
542
|
-
if (root.child) stack.push(root.child);
|
|
893
|
+
if (root.child) stack.push({ fiber: root.child, parent: root });
|
|
543
894
|
while (stack.length > 0) {
|
|
544
|
-
const fiber = stack.pop();
|
|
895
|
+
const { fiber, parent } = stack.pop();
|
|
545
896
|
if (!fiber || visited.has(fiber)) continue;
|
|
546
897
|
visited.add(fiber);
|
|
547
|
-
|
|
898
|
+
parents.set(fiber, parent);
|
|
899
|
+
if (fiber.sibling) stack.push({ fiber: fiber.sibling, parent });
|
|
548
900
|
if (shouldSkipSubtree2(fiber)) continue;
|
|
549
901
|
const props = fiber.memoizedProps ?? {};
|
|
550
902
|
let kind = null;
|
|
551
903
|
if (matchesName(fiber, "TextInput")) kind = "field";
|
|
552
|
-
else if (
|
|
904
|
+
else if (chunkQAZ4TN3Z_js.isSwitchLike(fiber, props)) kind = "toggle";
|
|
553
905
|
else if (isPressableTarget(fiber)) kind = "target";
|
|
554
906
|
if (kind && (!options.kind || options.kind === kind)) {
|
|
555
907
|
const detail = scoreMatchDetail(fiber, queryNorm, queryRaw);
|
|
@@ -558,7 +910,7 @@ function findInteractiveByIdentifier(query, options = {}) {
|
|
|
558
910
|
if (score > bestScore) tied = [{ fiber, kind }];
|
|
559
911
|
else if (score === bestScore) tied.push({ fiber, kind });
|
|
560
912
|
}
|
|
561
|
-
const beatsBest = score > bestScore || score > 0 && score === bestScore && isDescendantOf(fiber, bestFiber);
|
|
913
|
+
const beatsBest = score > bestScore || score > 0 && score === bestScore && isDescendantOf(fiber, bestFiber, parents);
|
|
562
914
|
if (beatsBest) {
|
|
563
915
|
bestScore = score;
|
|
564
916
|
bestFiber = fiber;
|
|
@@ -567,14 +919,18 @@ function findInteractiveByIdentifier(query, options = {}) {
|
|
|
567
919
|
bestId = describeCandidate(fiber, kind);
|
|
568
920
|
if (kind === "field") bestHandle = wrapTextInput(fiber);
|
|
569
921
|
else if (kind === "toggle") bestHandle = wrapSwitch(fiber);
|
|
570
|
-
else
|
|
922
|
+
else if (chunkQAZ4TN3Z_js.isSourceControlId(queryRaw)) {
|
|
923
|
+
const bound = chunkQAZ4TN3Z_js.sourceControlTarget(fiber);
|
|
924
|
+
if (!bound || bound.disabled) bestHandle = null;
|
|
925
|
+
else bestHandle = wrapTouchable(bound.fiber, findChildText(fiber));
|
|
926
|
+
} else bestHandle = wrapTouchable(fiber, findChildText(fiber));
|
|
571
927
|
}
|
|
572
928
|
}
|
|
573
929
|
if (kind === "toggle") continue;
|
|
574
|
-
if (fiber.child) stack.push(fiber.child);
|
|
930
|
+
if (fiber.child) stack.push({ fiber: fiber.child, parent: fiber });
|
|
575
931
|
}
|
|
576
932
|
if (bestHandle && bestScore < (options.minScore ?? 0)) {
|
|
577
|
-
|
|
933
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
578
934
|
`findInteractiveByIdentifier: query="${query}" \u2192 best match scored ${bestScore}, below the requested floor of ${options.minScore} \u2014 refusing it`
|
|
579
935
|
);
|
|
580
936
|
return null;
|
|
@@ -582,23 +938,146 @@ function findInteractiveByIdentifier(query, options = {}) {
|
|
|
582
938
|
if (bestHandle) {
|
|
583
939
|
const independent = tied.filter(
|
|
584
940
|
(candidate) => !tied.some(
|
|
585
|
-
(other) => other.fiber !== candidate.fiber && isDescendantOf(other.fiber, candidate.fiber)
|
|
941
|
+
(other) => other.fiber !== candidate.fiber && isDescendantOf(other.fiber, candidate.fiber, parents)
|
|
586
942
|
)
|
|
587
943
|
);
|
|
588
944
|
bestHandle.matchCount = independent.length;
|
|
589
945
|
bestHandle.named = bestNamed;
|
|
590
946
|
bestHandle.disabled = bestDisabled;
|
|
947
|
+
const measured = bestFiber;
|
|
948
|
+
bestHandle.measure = () => chunkQAZ4TN3Z_js.rectOfFiber(measured);
|
|
591
949
|
const candidates = independent.map(({ fiber, kind }) => describeCandidate(fiber, kind)).filter((id) => typeof id === "string" && id.length > 0).slice(0, 8);
|
|
592
950
|
if (candidates.length > 0) bestHandle.matchCandidates = candidates;
|
|
593
|
-
|
|
951
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
594
952
|
`findInteractiveByIdentifier: query="${query}" \u2192 kind=${bestHandle.kind} label="${bestHandle.label ?? bestId}" score=${bestScore} named=${bestNamed} disabled=${bestDisabled} tied=${independent.length}`
|
|
595
953
|
);
|
|
596
954
|
} else {
|
|
597
|
-
|
|
955
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(`findInteractiveByIdentifier: query="${query}" \u2192 no match`);
|
|
598
956
|
}
|
|
599
957
|
return bestHandle;
|
|
600
958
|
}
|
|
601
959
|
|
|
960
|
+
// src/introspection/spotlightTarget.ts
|
|
961
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
962
|
+
var announcementListeners = /* @__PURE__ */ new Set();
|
|
963
|
+
var current = null;
|
|
964
|
+
var seq = 0;
|
|
965
|
+
var expiry = null;
|
|
966
|
+
var SPOTLIGHT_TTL_MS = 1200;
|
|
967
|
+
var mode = "off";
|
|
968
|
+
function setSpotlightMode(next) {
|
|
969
|
+
mode = next;
|
|
970
|
+
}
|
|
971
|
+
function getSpotlightMode() {
|
|
972
|
+
return mode;
|
|
973
|
+
}
|
|
974
|
+
function emit() {
|
|
975
|
+
for (const listener of listeners) listener(current);
|
|
976
|
+
}
|
|
977
|
+
function setSpotlightTarget(rect, label, verb) {
|
|
978
|
+
if (label && verb) for (const listener of announcementListeners) listener(label, verb);
|
|
979
|
+
if (expiry) {
|
|
980
|
+
clearTimeout(expiry);
|
|
981
|
+
expiry = null;
|
|
982
|
+
}
|
|
983
|
+
if (!rect) {
|
|
984
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
985
|
+
`setSpotlightTarget: cleared${label ? ` (was about to mark "${label}")` : ""}`
|
|
986
|
+
);
|
|
987
|
+
if (current === null) return;
|
|
988
|
+
current = null;
|
|
989
|
+
emit();
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
992
|
+
current = { rect, label, seq: ++seq };
|
|
993
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
994
|
+
`setSpotlightTarget: seq=${current.seq} label="${label ?? ""}" rect=${Math.round(rect.x)},${Math.round(rect.y)} ${Math.round(rect.width)}x${Math.round(rect.height)}`
|
|
995
|
+
);
|
|
996
|
+
emit();
|
|
997
|
+
expiry = setTimeout(() => {
|
|
998
|
+
expiry = null;
|
|
999
|
+
current = null;
|
|
1000
|
+
emit();
|
|
1001
|
+
}, SPOTLIGHT_TTL_MS);
|
|
1002
|
+
}
|
|
1003
|
+
function getSpotlightTarget() {
|
|
1004
|
+
return current;
|
|
1005
|
+
}
|
|
1006
|
+
function subscribeSpotlight(listener) {
|
|
1007
|
+
listeners.add(listener);
|
|
1008
|
+
return () => {
|
|
1009
|
+
listeners.delete(listener);
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
function subscribeSpotlightAnnouncement(listener) {
|
|
1013
|
+
announcementListeners.add(listener);
|
|
1014
|
+
return () => {
|
|
1015
|
+
announcementListeners.delete(listener);
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
// src/introspection/scrollIntoView.ts
|
|
1020
|
+
var REVEAL_MARGIN = 24;
|
|
1021
|
+
function offsetToReveal({ rect, viewport, metrics }) {
|
|
1022
|
+
const maxOffset = Math.max(0, metrics.contentLength - metrics.visibleLength);
|
|
1023
|
+
const viewTop = viewport.top + REVEAL_MARGIN;
|
|
1024
|
+
const viewBottom = viewport.top + viewport.height - REVEAL_MARGIN;
|
|
1025
|
+
const tallerThanViewport = rect.height > viewport.height - REVEAL_MARGIN * 2;
|
|
1026
|
+
let delta;
|
|
1027
|
+
if (tallerThanViewport) {
|
|
1028
|
+
if (rect.y >= viewTop && rect.y <= viewBottom) return null;
|
|
1029
|
+
delta = rect.y - viewTop;
|
|
1030
|
+
} else if (rect.y < viewTop) {
|
|
1031
|
+
delta = rect.y - viewTop;
|
|
1032
|
+
} else if (rect.y + rect.height > viewBottom) {
|
|
1033
|
+
delta = rect.y + rect.height - viewBottom;
|
|
1034
|
+
} else {
|
|
1035
|
+
return null;
|
|
1036
|
+
}
|
|
1037
|
+
const target = clamp(metrics.offset + delta, 0, maxOffset);
|
|
1038
|
+
if (Math.abs(target - metrics.offset) < 1) return null;
|
|
1039
|
+
return target;
|
|
1040
|
+
}
|
|
1041
|
+
function clamp(value, min, max) {
|
|
1042
|
+
return Math.min(max, Math.max(min, value));
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
// src/introspection/revealTarget.ts
|
|
1046
|
+
function revealTarget(rect) {
|
|
1047
|
+
const host = chunkQAZ4TN3Z_js.getGeometryHost();
|
|
1048
|
+
if (!host) return { rect, scrolled: false };
|
|
1049
|
+
if (chunkQAZ4TN3Z_js.isRectOnScreen(rect, host.window)) return { rect, scrolled: false };
|
|
1050
|
+
const scrollable = resolveScrollable();
|
|
1051
|
+
if (!scrollable) return { rect, scrolled: false };
|
|
1052
|
+
const metrics = scrollable.getScrollMetrics?.();
|
|
1053
|
+
if (!metrics) return { rect, scrolled: false };
|
|
1054
|
+
const box = scrollable.measureViewport?.();
|
|
1055
|
+
const viewport = box ? { top: box.y, height: box.height } : { top: 0, height: host.window.height };
|
|
1056
|
+
const target = offsetToReveal({ rect, viewport, metrics });
|
|
1057
|
+
if (target === null) return { rect, scrolled: false };
|
|
1058
|
+
const moved = scrollable.scrollToOffset?.(target) ?? false;
|
|
1059
|
+
if (!moved) {
|
|
1060
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(`revealTarget: "${scrollable.id}" refused scrollToOffset(${target})`);
|
|
1061
|
+
return { rect, scrolled: false };
|
|
1062
|
+
}
|
|
1063
|
+
const delta = target - metrics.offset;
|
|
1064
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
1065
|
+
`revealTarget: scrolled "${scrollable.id}" by ${Math.round(delta)}px (${Math.round(metrics.offset)} \u2192 ${Math.round(target)})`
|
|
1066
|
+
);
|
|
1067
|
+
return { rect: { ...rect, y: rect.y - delta }, scrolled: true };
|
|
1068
|
+
}
|
|
1069
|
+
function resolveScrollable() {
|
|
1070
|
+
const screen = chunkQAZ4TN3Z_js.getCurrentScreen();
|
|
1071
|
+
const candidates = chunkQAZ4TN3Z_js.listRegistry.snapshot().filter((entry) => entry.scrollToOffset && entry.getScrollMetrics).filter((entry) => !screen || !entry.screen || entry.screen === screen);
|
|
1072
|
+
if (candidates.length === 1) return candidates[0];
|
|
1073
|
+
if (candidates.length > 1) {
|
|
1074
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
1075
|
+
`revealTarget: ${candidates.length} scrollables on "${screen ?? "?"}" \u2014 cannot tell which holds the target, so not scrolling.`
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
return null;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
602
1081
|
// src/executor/handlers/navigateHandler.ts
|
|
603
1082
|
var _reportedMissingNavRef = false;
|
|
604
1083
|
function reportMissingNavigationRef() {
|
|
@@ -641,43 +1120,52 @@ function screenExistsAnywhere(state, screenName) {
|
|
|
641
1120
|
return false;
|
|
642
1121
|
}
|
|
643
1122
|
function safeNavigate(nav, screenName, params, path) {
|
|
1123
|
+
const state = nav.getState?.();
|
|
1124
|
+
const rootState = nav.getRootState?.() ?? state;
|
|
644
1125
|
if (path && path.length > 0) {
|
|
1126
|
+
if (Array.isArray(rootState?.routeNames) && !screenExistsAnywhere(rootState, path[0]) && !state?.routeNames?.includes(path[0])) {
|
|
1127
|
+
if (state?.routeNames?.includes(screenName)) {
|
|
1128
|
+
nav.navigate(screenName, params);
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1131
|
+
throw new Error(
|
|
1132
|
+
`Route "${path[0]}" is not registered in any navigator. Cannot resolve the supplied path to "${screenName}".`
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
645
1135
|
const { root, nestedParams } = buildNestedParams(path, screenName, params);
|
|
646
|
-
|
|
1136
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
647
1137
|
`safeNavigate: using path-based navigation \u2014 root="${root}", nested=${JSON.stringify(nestedParams)}`
|
|
648
1138
|
);
|
|
649
1139
|
nav.navigate(root, nestedParams);
|
|
650
1140
|
return;
|
|
651
1141
|
}
|
|
652
|
-
const state = nav.getState?.();
|
|
653
1142
|
if (state?.routeNames?.includes(screenName)) {
|
|
654
1143
|
nav.navigate(screenName, params);
|
|
655
1144
|
return;
|
|
656
1145
|
}
|
|
657
|
-
const rootState = nav.getRootState?.() ?? state;
|
|
658
1146
|
if (!screenExistsAnywhere(rootState, screenName)) {
|
|
659
1147
|
throw new Error(
|
|
660
1148
|
`Screen "${screenName}" is not registered in any navigator. The screen may have been removed, may live inside a flow that is not currently mounted (e.g. Auth stack after login), or the MCP doc is stale.`
|
|
661
1149
|
);
|
|
662
1150
|
}
|
|
663
|
-
|
|
1151
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
664
1152
|
`safeNavigate: screen exists in nested navigator, attempting direct navigation to "${screenName}"`
|
|
665
1153
|
);
|
|
666
1154
|
nav.navigate(screenName, params);
|
|
667
1155
|
}
|
|
668
1156
|
function navigateHandler(payload, context) {
|
|
669
|
-
|
|
1157
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
670
1158
|
// Params carry record ids and, on some screens, the user's own
|
|
671
1159
|
// data — the count answers "were params passed?" and nothing else.
|
|
672
|
-
`navigateHandler called: screenName="${payload.screenName}" action="${payload.navigationAction}" params=${
|
|
1160
|
+
`navigateHandler called: screenName="${payload.screenName}" action="${payload.navigationAction}" params=${chunkQAZ4TN3Z_js.describeValue(payload.params)}`
|
|
673
1161
|
);
|
|
674
1162
|
const { navigationRef, permissions } = context;
|
|
675
1163
|
const nav = navigationRef.current;
|
|
676
1164
|
if (!permissions.canNavigate) {
|
|
677
1165
|
return {
|
|
678
1166
|
success: false,
|
|
679
|
-
error: "Navigation
|
|
680
|
-
diagnose: { category: "unknown", screen: payload.screenName }
|
|
1167
|
+
error: chunkQAZ4TN3Z_js.permissionDeniedMessage("Navigation", "canNavigate"),
|
|
1168
|
+
diagnose: { category: "unknown", screen: payload.screenName, recoverable: false }
|
|
681
1169
|
};
|
|
682
1170
|
}
|
|
683
1171
|
const isGoBack = payload.navigationAction === "goBack";
|
|
@@ -762,12 +1250,12 @@ function navigateHandler(payload, context) {
|
|
|
762
1250
|
diagnose: { category: "unknown", screen: payload.screenName }
|
|
763
1251
|
};
|
|
764
1252
|
}
|
|
765
|
-
|
|
1253
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
766
1254
|
`navigateHandler: navigation succeeded for "${payload.screenName}" (action="${payload.navigationAction}")`
|
|
767
1255
|
);
|
|
768
1256
|
return { success: true };
|
|
769
1257
|
} catch (err) {
|
|
770
|
-
|
|
1258
|
+
chunkQAZ4TN3Z_js.appilotsDebugWarn(
|
|
771
1259
|
`navigateHandler: navigation failed for "${payload.screenName}": ${err?.message}`
|
|
772
1260
|
);
|
|
773
1261
|
const msg = String(err?.message ?? "Navigation failed");
|
|
@@ -815,18 +1303,18 @@ function markedItemIndexFromFiber(fiber) {
|
|
|
815
1303
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
816
1304
|
}
|
|
817
1305
|
function normalize2(value) {
|
|
818
|
-
return
|
|
1306
|
+
return chunkQAZ4TN3Z_js.foldForCompare(String(value ?? ""));
|
|
819
1307
|
}
|
|
820
1308
|
function hasPressHandler2(fiber) {
|
|
821
1309
|
const props = fiber?.memoizedProps ?? {};
|
|
822
1310
|
return typeof props.onPress === "function" || typeof props.onPressIn === "function";
|
|
823
1311
|
}
|
|
824
1312
|
function isPressableFiber(fiber) {
|
|
825
|
-
const typeName =
|
|
826
|
-
return
|
|
1313
|
+
const typeName = chunkQAZ4TN3Z_js.getTypeName(fiber.type) ?? chunkQAZ4TN3Z_js.getTypeName(fiber.elementType) ?? "";
|
|
1314
|
+
return chunkQAZ4TN3Z_js.TOUCHABLE_NAMES.has(typeName) || hasPressHandler2(fiber);
|
|
827
1315
|
}
|
|
828
1316
|
function findListContainers(options = {}) {
|
|
829
|
-
const root =
|
|
1317
|
+
const root = chunkQAZ4TN3Z_js.getFiberRoot();
|
|
830
1318
|
if (!root) return [];
|
|
831
1319
|
const containers = [];
|
|
832
1320
|
const visited = /* @__PURE__ */ new WeakSet();
|
|
@@ -837,17 +1325,17 @@ function findListContainers(options = {}) {
|
|
|
837
1325
|
if (!fiber || visited.has(fiber)) continue;
|
|
838
1326
|
visited.add(fiber);
|
|
839
1327
|
if (fiber.sibling) stack.push(fiber.sibling);
|
|
840
|
-
if (
|
|
841
|
-
if (
|
|
842
|
-
const minItems =
|
|
843
|
-
const items =
|
|
1328
|
+
if (chunkQAZ4TN3Z_js.shouldSkipSubtree(fiber)) continue;
|
|
1329
|
+
if (chunkQAZ4TN3Z_js.isAlwaysListContainer(fiber) || chunkQAZ4TN3Z_js.isHeuristicListContainer(fiber)) {
|
|
1330
|
+
const minItems = chunkQAZ4TN3Z_js.isAlwaysListContainer(fiber) || options.allowSingleHeuristic ? 1 : 2;
|
|
1331
|
+
const items = chunkQAZ4TN3Z_js.findListItems(fiber, minItems);
|
|
844
1332
|
if (items && items.length >= minItems) {
|
|
845
1333
|
containers.push({
|
|
846
1334
|
container: fiber,
|
|
847
1335
|
items,
|
|
848
1336
|
listId: listIdFromContainer(fiber),
|
|
849
1337
|
listLabel: listLabelFromContainer(fiber),
|
|
850
|
-
containerType:
|
|
1338
|
+
containerType: chunkQAZ4TN3Z_js.getTypeName(fiber.type) ?? chunkQAZ4TN3Z_js.getTypeName(fiber.elementType) ?? "List"
|
|
851
1339
|
});
|
|
852
1340
|
continue;
|
|
853
1341
|
}
|
|
@@ -866,7 +1354,7 @@ function findFirstTouchable(item) {
|
|
|
866
1354
|
const { fiber, includeSibling } = stack.pop();
|
|
867
1355
|
if (!fiber || visited.has(fiber)) continue;
|
|
868
1356
|
visited.add(fiber);
|
|
869
|
-
if (
|
|
1357
|
+
if (chunkQAZ4TN3Z_js.shouldSkipSubtree(fiber)) continue;
|
|
870
1358
|
if (isPressableFiber(fiber)) {
|
|
871
1359
|
const props = fiber.memoizedProps ?? {};
|
|
872
1360
|
if (typeof props.onPress === "function" || typeof props.onPressIn === "function") {
|
|
@@ -893,7 +1381,7 @@ function findTouchableFibers(item) {
|
|
|
893
1381
|
const { fiber, includeSibling } = stack.pop();
|
|
894
1382
|
if (!fiber || visited.has(fiber)) continue;
|
|
895
1383
|
visited.add(fiber);
|
|
896
|
-
if (
|
|
1384
|
+
if (chunkQAZ4TN3Z_js.shouldSkipSubtree(fiber)) continue;
|
|
897
1385
|
const props = fiber.memoizedProps ?? {};
|
|
898
1386
|
if (isPressableFiber(fiber) && (typeof props.onPress === "function" || typeof props.onPressIn === "function")) {
|
|
899
1387
|
found.push(fiber);
|
|
@@ -937,7 +1425,7 @@ function findFirstText(fiber) {
|
|
|
937
1425
|
const node = stack.pop();
|
|
938
1426
|
if (!node || visited.has(node)) continue;
|
|
939
1427
|
visited.add(node);
|
|
940
|
-
const typeName =
|
|
1428
|
+
const typeName = chunkQAZ4TN3Z_js.getTypeName(node.type) ?? chunkQAZ4TN3Z_js.getTypeName(node.elementType) ?? "";
|
|
941
1429
|
if (typeName === "Text") {
|
|
942
1430
|
const text = textFromChildren(node.memoizedProps?.children).trim();
|
|
943
1431
|
if (text) return text;
|
|
@@ -956,7 +1444,7 @@ function collectTexts(fiber) {
|
|
|
956
1444
|
const node = stack.pop();
|
|
957
1445
|
if (!node || visited.has(node)) continue;
|
|
958
1446
|
visited.add(node);
|
|
959
|
-
const typeName =
|
|
1447
|
+
const typeName = chunkQAZ4TN3Z_js.getTypeName(node.type) ?? chunkQAZ4TN3Z_js.getTypeName(node.elementType) ?? "";
|
|
960
1448
|
if (typeName === "Text") {
|
|
961
1449
|
const text = textFromChildren(node.memoizedProps?.children).trim();
|
|
962
1450
|
if (text) out.push(text);
|
|
@@ -968,10 +1456,10 @@ function collectTexts(fiber) {
|
|
|
968
1456
|
}
|
|
969
1457
|
function hasUsefulTouchableIdentity(fiber) {
|
|
970
1458
|
const props = fiber?.memoizedProps ?? {};
|
|
971
|
-
if (
|
|
972
|
-
if (
|
|
973
|
-
if (
|
|
974
|
-
return
|
|
1459
|
+
if (chunkQAZ4TN3Z_js.isReferenceable(props.testID)) return true;
|
|
1460
|
+
if (chunkQAZ4TN3Z_js.isReferenceable(props.accessibilityLabel)) return true;
|
|
1461
|
+
if (chunkQAZ4TN3Z_js.isReferenceable(props.label)) return true;
|
|
1462
|
+
return chunkQAZ4TN3Z_js.isReferenceable(findFirstText(fiber));
|
|
975
1463
|
}
|
|
976
1464
|
function describeTouchable(fiber) {
|
|
977
1465
|
const props = fiber?.memoizedProps ?? {};
|
|
@@ -982,10 +1470,10 @@ function describeTouchable(fiber) {
|
|
|
982
1470
|
}
|
|
983
1471
|
function touchableLooksDestructive(fiber) {
|
|
984
1472
|
const descriptor = describeTouchable(fiber);
|
|
985
|
-
if (descriptor &&
|
|
1473
|
+
if (descriptor && chunkQAZ4TN3Z_js.looksDestructiveActionLabel(descriptor)) return true;
|
|
986
1474
|
const props = fiber?.memoizedProps ?? {};
|
|
987
1475
|
const haystack = [props.testID, props.accessibilityLabel, props.accessibilityHint, props.label].filter((value) => typeof value === "string").join(" ");
|
|
988
|
-
return
|
|
1476
|
+
return chunkQAZ4TN3Z_js.looksDestructiveActionLabel(haystack);
|
|
989
1477
|
}
|
|
990
1478
|
function describeItemCandidate(listIndex, zeroBasedIndex, item) {
|
|
991
1479
|
const syntheticId = `list-${listIndex}-item-${zeroBasedIndex + 1}`;
|
|
@@ -1034,8 +1522,10 @@ function pressResolvedListItem(list, itemFiber, listIndex, itemIndex) {
|
|
|
1034
1522
|
(candidate) => candidate !== touchable && containsFiber(touchable, candidate)
|
|
1035
1523
|
);
|
|
1036
1524
|
if (primaryWrapsNestedTargets) {
|
|
1037
|
-
|
|
1038
|
-
|
|
1525
|
+
const outer = describeTouchable(touchable) ?? "?";
|
|
1526
|
+
const nested = safeIdentifiableTouchables.filter((candidate) => candidate !== touchable && containsFiber(touchable, candidate)).map((candidate) => describeTouchable(candidate) ?? "?").slice(0, 6);
|
|
1527
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
1528
|
+
`listItemDispatch: item "list-${listIndex}-item-${itemIndex}" has nested pressables; pressing outer row target [outer=${outer}] [nested=${nested.join(", ")}] [outerHasOnPress=${typeof touchable?.memoizedProps?.onPress === "function"}]`
|
|
1039
1529
|
);
|
|
1040
1530
|
} else {
|
|
1041
1531
|
const candidates = safeIdentifiableTouchables.map(describeTouchable).filter((d) => !!d).slice(0, 8);
|
|
@@ -1069,14 +1559,14 @@ function pressResolvedListItem(list, itemFiber, listIndex, itemIndex) {
|
|
|
1069
1559
|
}
|
|
1070
1560
|
return {
|
|
1071
1561
|
ok: true,
|
|
1072
|
-
containerType:
|
|
1562
|
+
containerType: chunkQAZ4TN3Z_js.getTypeName(container.type) ?? chunkQAZ4TN3Z_js.getTypeName(container.elementType) ?? list.containerType
|
|
1073
1563
|
};
|
|
1074
1564
|
} catch (err) {
|
|
1075
1565
|
return {
|
|
1076
1566
|
ok: false,
|
|
1077
1567
|
reason: "press-threw",
|
|
1078
1568
|
error: err?.message ?? "press handler threw",
|
|
1079
|
-
containerType:
|
|
1569
|
+
containerType: chunkQAZ4TN3Z_js.getTypeName(container.type) ?? chunkQAZ4TN3Z_js.getTypeName(container.elementType) ?? list.containerType
|
|
1080
1570
|
};
|
|
1081
1571
|
}
|
|
1082
1572
|
}
|
|
@@ -1102,10 +1592,12 @@ function scoreItemCandidate(item, zeroBasedIndex, locator) {
|
|
|
1102
1592
|
if (locator.itemKey) {
|
|
1103
1593
|
if (itemKey === locator.itemKey) score += 1e3;
|
|
1104
1594
|
else if (itemKey && normalize2(itemKey) === normalize2(locator.itemKey)) score += 950;
|
|
1595
|
+
else return 0;
|
|
1105
1596
|
}
|
|
1106
1597
|
if (locator.reactKey) {
|
|
1107
1598
|
if (reactKey === locator.reactKey) score += 900;
|
|
1108
1599
|
else if (reactKey && normalize2(reactKey) === normalize2(locator.reactKey)) score += 850;
|
|
1600
|
+
else if (!locator.itemKey) return 0;
|
|
1109
1601
|
}
|
|
1110
1602
|
if (locator.itemIndex && zeroBasedIndex === locator.itemIndex - 1) score += 750;
|
|
1111
1603
|
if (locator.itemIndex && markedIndex !== void 0 && (markedIndex === locator.itemIndex || markedIndex === locator.itemIndex - 1)) {
|
|
@@ -1132,7 +1624,7 @@ function candidateLists(containers, locator) {
|
|
|
1132
1624
|
return containers.map((list, listIndex) => ({ list, listIndex }));
|
|
1133
1625
|
}
|
|
1134
1626
|
function pressListItemAtOrdinal(listIndex, itemIndex) {
|
|
1135
|
-
if (!
|
|
1627
|
+
if (!chunkQAZ4TN3Z_js.getFiberRoot()) return { ok: false, reason: "no-fiber-root" };
|
|
1136
1628
|
const containers = findListContainers({ allowSingleHeuristic: true });
|
|
1137
1629
|
if (listIndex < 0 || listIndex >= containers.length) {
|
|
1138
1630
|
return { ok: false, reason: "list-not-found" };
|
|
@@ -1146,7 +1638,7 @@ function pressListItemAtOrdinal(listIndex, itemIndex) {
|
|
|
1146
1638
|
return pressResolvedListItem(list, items[zeroBased], listIndex, itemIndex);
|
|
1147
1639
|
}
|
|
1148
1640
|
function resolveListItemByIdentity(locator) {
|
|
1149
|
-
if (!
|
|
1641
|
+
if (!chunkQAZ4TN3Z_js.getFiberRoot()) return { ok: false, result: { ok: false, reason: "no-fiber-root" } };
|
|
1150
1642
|
const parsed = locator.syntheticId ? parseSyntheticListItemId(locator.syntheticId) : null;
|
|
1151
1643
|
const effective = parsed ? { ...locator, listIndex: parsed.listIndex, itemIndex: parsed.itemIndex } : locator;
|
|
1152
1644
|
const containers = findListContainers({ allowSingleHeuristic: true });
|
|
@@ -1175,7 +1667,7 @@ function resolveListItemByIdentity(locator) {
|
|
|
1175
1667
|
scoredCandidates.sort((a, b) => b.score - a.score);
|
|
1176
1668
|
const best = scoredCandidates[0];
|
|
1177
1669
|
const tiedCandidates = scoredCandidates.filter((c) => c.score === best.score);
|
|
1178
|
-
if (tiedCandidates.length > 1 && best.score < 750) {
|
|
1670
|
+
if (tiedCandidates.length > 1 && (best.score < 750 || Boolean(effective.itemKey || effective.reactKey))) {
|
|
1179
1671
|
const candidates = tiedCandidates.map((c) => describeItemCandidate(c.listIndex, c.itemIndex - 1, c.item)).slice(0, 8);
|
|
1180
1672
|
return {
|
|
1181
1673
|
ok: false,
|
|
@@ -1207,9 +1699,9 @@ function findSwitchFibers(item) {
|
|
|
1207
1699
|
const { fiber, includeSibling } = stack.pop();
|
|
1208
1700
|
if (!fiber || visited.has(fiber)) continue;
|
|
1209
1701
|
visited.add(fiber);
|
|
1210
|
-
if (
|
|
1702
|
+
if (chunkQAZ4TN3Z_js.shouldSkipSubtree(fiber)) continue;
|
|
1211
1703
|
const props = fiber.memoizedProps ?? {};
|
|
1212
|
-
if (
|
|
1704
|
+
if (chunkQAZ4TN3Z_js.isSwitchLike(fiber, props)) {
|
|
1213
1705
|
if (props.__appilotsInternal !== true) found.push(fiber);
|
|
1214
1706
|
if (includeSibling && fiber.sibling) {
|
|
1215
1707
|
stack.push({ fiber: fiber.sibling, includeSibling: true });
|
|
@@ -1243,11 +1735,11 @@ function toggleListItemByIdentity(locator, options) {
|
|
|
1243
1735
|
}
|
|
1244
1736
|
const target = switches[0];
|
|
1245
1737
|
const props = target?.memoizedProps ?? {};
|
|
1246
|
-
const
|
|
1247
|
-
if (options?.expected !== void 0 &&
|
|
1248
|
-
return { ok: true, containerType: list.containerType, value:
|
|
1738
|
+
const current2 = chunkQAZ4TN3Z_js.switchValue(props);
|
|
1739
|
+
if (options?.expected !== void 0 && current2 === options.expected) {
|
|
1740
|
+
return { ok: true, containerType: list.containerType, value: current2, noop: true };
|
|
1249
1741
|
}
|
|
1250
|
-
const flipped = flipSwitchFiber(target, !
|
|
1742
|
+
const flipped = flipSwitchFiber(target, !current2);
|
|
1251
1743
|
if (!flipped.ok) {
|
|
1252
1744
|
if (flipped.reason === "no-handler") {
|
|
1253
1745
|
return {
|
|
@@ -1264,7 +1756,7 @@ function toggleListItemByIdentity(locator, options) {
|
|
|
1264
1756
|
containerType: list.containerType
|
|
1265
1757
|
};
|
|
1266
1758
|
}
|
|
1267
|
-
return { ok: true, containerType: list.containerType, value: !
|
|
1759
|
+
return { ok: true, containerType: list.containerType, value: !current2 };
|
|
1268
1760
|
}
|
|
1269
1761
|
function pressListItemByIdentity(locator) {
|
|
1270
1762
|
const resolved = resolveListItemByIdentity(locator);
|
|
@@ -1282,7 +1774,7 @@ function screenDiagnose(targetId, category = "component-not-found") {
|
|
|
1282
1774
|
return {
|
|
1283
1775
|
category,
|
|
1284
1776
|
targetId,
|
|
1285
|
-
screen:
|
|
1777
|
+
screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0
|
|
1286
1778
|
};
|
|
1287
1779
|
}
|
|
1288
1780
|
function isPressLike(action) {
|
|
@@ -1302,10 +1794,10 @@ function elementLookupKey(value) {
|
|
|
1302
1794
|
return canonicalElementId(value).toLowerCase().replace(/[\s_]+/g, "-");
|
|
1303
1795
|
}
|
|
1304
1796
|
function findRegisteredElement(elementId) {
|
|
1305
|
-
const direct =
|
|
1797
|
+
const direct = chunkQAZ4TN3Z_js.elementRegistry.get(elementId) ?? chunkQAZ4TN3Z_js.elementRegistry.get(canonicalElementId(elementId));
|
|
1306
1798
|
if (direct) return direct;
|
|
1307
1799
|
const wanted = elementLookupKey(elementId);
|
|
1308
|
-
return
|
|
1800
|
+
return chunkQAZ4TN3Z_js.elementRegistry.snapshot().find((element) => elementLookupKey(element.id) === wanted);
|
|
1309
1801
|
}
|
|
1310
1802
|
function resolveInteractionElement(elementId) {
|
|
1311
1803
|
return getLatestElement(elementId);
|
|
@@ -1425,7 +1917,7 @@ function dispatchIdentifiedToggle(targetId, action) {
|
|
|
1425
1917
|
diagnose: { ...screenDiagnose(targetId, "unknown"), recoverable: true }
|
|
1426
1918
|
};
|
|
1427
1919
|
}
|
|
1428
|
-
|
|
1920
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
1429
1921
|
`elementDispatch: "${action}" on "${targetId}" names a switch \u2014 flipping it instead of pressing, so the verb cannot land on an ancestor`
|
|
1430
1922
|
);
|
|
1431
1923
|
try {
|
|
@@ -1459,6 +1951,13 @@ function dispatchFiberTarget(targetId, action) {
|
|
|
1459
1951
|
diagnose: screenDiagnose(targetId)
|
|
1460
1952
|
};
|
|
1461
1953
|
}
|
|
1954
|
+
const measured = handle.measure?.() ?? null;
|
|
1955
|
+
const verb = action === "scroll" ? void 0 : action === "toggle" || action === "focus" ? action : "press";
|
|
1956
|
+
if (measured && getSpotlightMode() === "guided") {
|
|
1957
|
+
setSpotlightTarget(revealTarget(measured).rect, handle.label, verb);
|
|
1958
|
+
} else {
|
|
1959
|
+
setSpotlightTarget(measured, handle.label, verb);
|
|
1960
|
+
}
|
|
1462
1961
|
try {
|
|
1463
1962
|
if (isPressLike(action) && handle.kind === "target" && handle.press) {
|
|
1464
1963
|
handle.press();
|
|
@@ -1509,6 +2008,13 @@ function dispatchLegacyTarget(targetId, registry, action) {
|
|
|
1509
2008
|
};
|
|
1510
2009
|
}
|
|
1511
2010
|
function dispatchElement(element, registry, action) {
|
|
2011
|
+
if (element.dispatchable === false) {
|
|
2012
|
+
return {
|
|
2013
|
+
success: false,
|
|
2014
|
+
error: `Element "${element.id}" is observation-only and has no exact live control binding.`,
|
|
2015
|
+
diagnose: { ...screenDiagnose(element.id, "ambiguous-target"), recoverable: false }
|
|
2016
|
+
};
|
|
2017
|
+
}
|
|
1512
2018
|
if (element.disabled === true) {
|
|
1513
2019
|
return {
|
|
1514
2020
|
success: false,
|
|
@@ -1527,6 +2033,13 @@ function dispatchElement(element, registry, action) {
|
|
|
1527
2033
|
texts: element.texts
|
|
1528
2034
|
});
|
|
1529
2035
|
if (pressed.ok) return { success: true };
|
|
2036
|
+
if (!pressed.refusal && (element.listContext.itemKey || element.listContext.reactKey)) {
|
|
2037
|
+
return {
|
|
2038
|
+
success: false,
|
|
2039
|
+
error: pressed.error ?? `The observed list entity "${element.label ?? element.id}" could not be resolved. Reobserve; do not substitute its old position.`,
|
|
2040
|
+
diagnose: { ...screenDiagnose(element.id, "ambiguous-target"), recoverable: true }
|
|
2041
|
+
};
|
|
2042
|
+
}
|
|
1530
2043
|
if (pressed.refusal) {
|
|
1531
2044
|
return {
|
|
1532
2045
|
success: false,
|
|
@@ -1634,7 +2147,7 @@ function dispatchToggleElement(element, registry) {
|
|
|
1634
2147
|
}
|
|
1635
2148
|
function dispatchStructuredElementId(identifier, action) {
|
|
1636
2149
|
if (!isElementIdentifier(identifier) || !isPressLike(action)) return null;
|
|
1637
|
-
const parsed =
|
|
2150
|
+
const parsed = chunkQAZ4TN3Z_js.parseStableElementId(identifier);
|
|
1638
2151
|
if (!parsed || parsed.role !== "option") return null;
|
|
1639
2152
|
if (!parsed.itemKey && !parsed.listId) return null;
|
|
1640
2153
|
const pressed = pressListItemByIdentity({
|
|
@@ -1644,7 +2157,7 @@ function dispatchStructuredElementId(identifier, action) {
|
|
|
1644
2157
|
texts: parsed.itemKey ? [parsed.itemKey] : void 0
|
|
1645
2158
|
});
|
|
1646
2159
|
if (pressed.ok) {
|
|
1647
|
-
|
|
2160
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
1648
2161
|
`elementDispatch: resolved stale el id "${identifier}" via structural identity (listId="${parsed.listId}", itemKey="${parsed.itemKey}")`
|
|
1649
2162
|
);
|
|
1650
2163
|
return { success: true };
|
|
@@ -1675,20 +2188,20 @@ function normalize4(value) {
|
|
|
1675
2188
|
return value.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
|
|
1676
2189
|
}
|
|
1677
2190
|
function resolveScreenForFormFields() {
|
|
1678
|
-
const activePath =
|
|
2191
|
+
const activePath = chunkQAZ4TN3Z_js.getActiveRouteNames();
|
|
1679
2192
|
for (let i = activePath.length - 1; i >= 0; i--) {
|
|
1680
2193
|
const name = activePath[i];
|
|
1681
|
-
const meta = name ?
|
|
2194
|
+
const meta = name ? chunkQAZ4TN3Z_js.getScreenMetadata(name) : void 0;
|
|
1682
2195
|
if (name && Array.isArray(meta?.fields) && meta.fields.length > 0) return name;
|
|
1683
2196
|
}
|
|
1684
|
-
return
|
|
2197
|
+
return chunkQAZ4TN3Z_js.getCurrentScreen();
|
|
1685
2198
|
}
|
|
1686
2199
|
function collectKnownFormFields(registry) {
|
|
1687
2200
|
const registryFields = registry.snapshot().filter((entry) => entry.kind === "field" || entry.kind === "slider").map((entry) => ({ id: entry.id, label: entry.label }));
|
|
1688
2201
|
if (registryFields.length >= 2) return registryFields;
|
|
1689
2202
|
const screen = resolveScreenForFormFields();
|
|
1690
2203
|
if (screen) {
|
|
1691
|
-
const metaFields =
|
|
2204
|
+
const metaFields = chunkQAZ4TN3Z_js.getScreenMetadata(screen)?.fields;
|
|
1692
2205
|
if (Array.isArray(metaFields) && metaFields.length > 0) {
|
|
1693
2206
|
return metaFields.filter((field) => !!field && typeof field.id === "string").map((field) => ({
|
|
1694
2207
|
id: field.id,
|
|
@@ -1698,7 +2211,7 @@ function collectKnownFormFields(registry) {
|
|
|
1698
2211
|
}));
|
|
1699
2212
|
}
|
|
1700
2213
|
}
|
|
1701
|
-
for (const meta of
|
|
2214
|
+
for (const meta of chunkQAZ4TN3Z_js.getAllScreens()) {
|
|
1702
2215
|
if (Array.isArray(meta.fields) && meta.fields.length > 0) {
|
|
1703
2216
|
return meta.fields.filter((field) => !!field && typeof field.id === "string").map((field) => ({
|
|
1704
2217
|
id: field.id,
|
|
@@ -1710,19 +2223,9 @@ function collectKnownFormFields(registry) {
|
|
|
1710
2223
|
}
|
|
1711
2224
|
return registryFields;
|
|
1712
2225
|
}
|
|
1713
|
-
function isMisplacedFieldId(fieldId
|
|
2226
|
+
function isMisplacedFieldId(fieldId) {
|
|
1714
2227
|
const trimmed = fieldId.trim();
|
|
1715
|
-
|
|
1716
|
-
if (LIST_ORDINAL_RE.test(trimmed)) return true;
|
|
1717
|
-
if (/^\d+$/.test(trimmed)) return true;
|
|
1718
|
-
const normalized = normalize4(trimmed);
|
|
1719
|
-
if (knownIds.has(normalized)) return false;
|
|
1720
|
-
for (const known of knownIds) {
|
|
1721
|
-
if (known.length >= 4 && (known.includes(normalized) || normalized.includes(known))) {
|
|
1722
|
-
return false;
|
|
1723
|
-
}
|
|
1724
|
-
}
|
|
1725
|
-
return true;
|
|
2228
|
+
return !trimmed || LIST_ORDINAL_RE.test(trimmed) || /^\d+$/.test(trimmed);
|
|
1726
2229
|
}
|
|
1727
2230
|
function valueMatchesOption(field, rawValue) {
|
|
1728
2231
|
const value = normalize4(String(rawValue ?? ""));
|
|
@@ -1779,6 +2282,7 @@ function fieldTypeMatchesShape(field, shape) {
|
|
|
1779
2282
|
function fieldAcceptsFreeText(field, shape) {
|
|
1780
2283
|
const type = normalize4(field.type ?? "text");
|
|
1781
2284
|
if (CHOICE_FIELD_TYPES.has(type)) return false;
|
|
2285
|
+
if (type === "password") return false;
|
|
1782
2286
|
if (NUMERIC_FIELD_TYPES.has(type)) return shape === "number";
|
|
1783
2287
|
if (DATE_FIELD_TYPES.has(type)) return shape === "date";
|
|
1784
2288
|
if (EMAIL_FIELD_TYPES.has(type)) return shape === "email";
|
|
@@ -1799,19 +2303,18 @@ function inferFieldIdForValue(rawValue, fields, used) {
|
|
|
1799
2303
|
function rewriteMisplacedFormFillFields(fields, registry) {
|
|
1800
2304
|
const knownFields = collectKnownFormFields(registry);
|
|
1801
2305
|
if (knownFields.length === 0) return fields;
|
|
1802
|
-
const
|
|
1803
|
-
const needsRewrite = fields.some((field) => isMisplacedFieldId(field.fieldId, knownIds));
|
|
2306
|
+
const needsRewrite = fields.some((field) => isMisplacedFieldId(field.fieldId));
|
|
1804
2307
|
if (!needsRewrite) return fields;
|
|
1805
2308
|
const used = /* @__PURE__ */ new Set();
|
|
1806
2309
|
return fields.map((field) => {
|
|
1807
|
-
if (!isMisplacedFieldId(field.fieldId
|
|
2310
|
+
if (!isMisplacedFieldId(field.fieldId)) {
|
|
1808
2311
|
used.add(field.fieldId);
|
|
1809
2312
|
return field;
|
|
1810
2313
|
}
|
|
1811
2314
|
const inferred = inferFieldIdForValue(String(field.value ?? ""), knownFields, used);
|
|
1812
2315
|
if (!inferred) return field;
|
|
1813
2316
|
used.add(inferred);
|
|
1814
|
-
|
|
2317
|
+
chunkQAZ4TN3Z_js.appilotsDebugWarn(
|
|
1815
2318
|
`formFieldRewrite: ${field.fieldId} \u2192 ${inferred} (value=${JSON.stringify(field.value)})`
|
|
1816
2319
|
);
|
|
1817
2320
|
return { ...field, fieldId: inferred };
|
|
@@ -1819,8 +2322,8 @@ function rewriteMisplacedFormFillFields(fields, registry) {
|
|
|
1819
2322
|
}
|
|
1820
2323
|
|
|
1821
2324
|
// src/executor/formValidation.ts
|
|
1822
|
-
var FORM_VALIDATION_TEXT_RE2 =
|
|
1823
|
-
var FORM_SUCCESS_TEXT_RE =
|
|
2325
|
+
var FORM_VALIDATION_TEXT_RE2 = chunkQAZ4TN3Z_js.FORM_VALIDATION_TEXT_RE;
|
|
2326
|
+
var FORM_SUCCESS_TEXT_RE = chunkQAZ4TN3Z_js.FORM_WRITE_SUCCESS_TEXT_RE;
|
|
1824
2327
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1825
2328
|
function inferValidationFieldId(message, inputs) {
|
|
1826
2329
|
const haystack = normalizeText(message);
|
|
@@ -1844,12 +2347,18 @@ function normalizeText(value) {
|
|
|
1844
2347
|
function containsWord(haystack, needle) {
|
|
1845
2348
|
return ` ${haystack} `.includes(` ${needle} `);
|
|
1846
2349
|
}
|
|
1847
|
-
function readVisibleFormValidation(snap) {
|
|
2350
|
+
function readVisibleFormValidation(snap, beforeTexts) {
|
|
1848
2351
|
if (!snap) return void 0;
|
|
2352
|
+
const invalid = snap.inputs?.find((input) => input.invalid === true);
|
|
2353
|
+
const hasSubmitControl = snap.buttons?.some(
|
|
2354
|
+
(button) => chunkQAZ4TN3Z_js.SUBMIT_CONTROL_RE.test(button.label ?? button.id ?? "")
|
|
2355
|
+
);
|
|
1849
2356
|
for (const text of snap.texts ?? []) {
|
|
1850
|
-
if (!text?.trim() || !
|
|
2357
|
+
if (!text?.trim() || !chunkQAZ4TN3Z_js.isVisibleValidationText(text, { invalid: !!invalid, hasSubmitControl, beforeTexts }))
|
|
2358
|
+
continue;
|
|
1851
2359
|
return { fieldId: inferValidationFieldId(text, snap.inputs), message: text };
|
|
1852
2360
|
}
|
|
2361
|
+
if (invalid) return { fieldId: invalid.id, message: "The app marks this field as invalid." };
|
|
1853
2362
|
return void 0;
|
|
1854
2363
|
}
|
|
1855
2364
|
function readVisibleFormSuccess(snap) {
|
|
@@ -1857,20 +2366,23 @@ function readVisibleFormSuccess(snap) {
|
|
|
1857
2366
|
return (snap.texts ?? []).find((text) => text?.trim() && FORM_SUCCESS_TEXT_RE.test(text));
|
|
1858
2367
|
}
|
|
1859
2368
|
function submitAsyncStillPending(submitTargetId) {
|
|
1860
|
-
const probe =
|
|
2369
|
+
const probe = chunkQAZ4TN3Z_js.probeLoadingState(submitTargetId ?? null, chunkQAZ4TN3Z_js.getCurrentScreen());
|
|
1861
2370
|
if (probe.loading) return true;
|
|
1862
2371
|
if (submitTargetId && probe.pressedFound && probe.pressedDisabled) return true;
|
|
1863
2372
|
return false;
|
|
1864
2373
|
}
|
|
1865
|
-
function evaluatePostSubmitSnapshot(snap, activePath) {
|
|
1866
|
-
const validation = readVisibleFormValidation(snap);
|
|
2374
|
+
function evaluatePostSubmitSnapshot(snap, activePath, beforeTexts) {
|
|
2375
|
+
const validation = readVisibleFormValidation(snap, beforeTexts);
|
|
1867
2376
|
if (validation) {
|
|
1868
2377
|
return { status: "failure", fieldId: validation.fieldId, message: validation.message };
|
|
1869
2378
|
}
|
|
1870
2379
|
const successText = readVisibleFormSuccess(snap);
|
|
1871
2380
|
if (successText) return { status: "success", message: successText };
|
|
1872
|
-
if (!
|
|
1873
|
-
return {
|
|
2381
|
+
if (!chunkQAZ4TN3Z_js.snapshotShowsOpenCreateForm(snap, activePath)) {
|
|
2382
|
+
return {
|
|
2383
|
+
status: "unverified",
|
|
2384
|
+
message: "The form closed without a visible success receipt. Inspect the resulting record before claiming the goal is complete."
|
|
2385
|
+
};
|
|
1874
2386
|
}
|
|
1875
2387
|
return void 0;
|
|
1876
2388
|
}
|
|
@@ -1885,8 +2397,8 @@ async function waitForPostSubmitOutcome(options) {
|
|
|
1885
2397
|
continue;
|
|
1886
2398
|
}
|
|
1887
2399
|
const snap2 = captureSnapshot();
|
|
1888
|
-
const activePath2 =
|
|
1889
|
-
const outcome2 = evaluatePostSubmitSnapshot(snap2, activePath2);
|
|
2400
|
+
const activePath2 = chunkQAZ4TN3Z_js.getActiveRouteNames();
|
|
2401
|
+
const outcome2 = evaluatePostSubmitSnapshot(snap2, activePath2, options?.beforeTexts);
|
|
1890
2402
|
if (outcome2) return outcome2;
|
|
1891
2403
|
await sleep(pollMs);
|
|
1892
2404
|
}
|
|
@@ -1897,8 +2409,8 @@ async function waitForPostSubmitOutcome(options) {
|
|
|
1897
2409
|
};
|
|
1898
2410
|
}
|
|
1899
2411
|
const snap = captureSnapshot();
|
|
1900
|
-
const activePath =
|
|
1901
|
-
const outcome = evaluatePostSubmitSnapshot(snap, activePath);
|
|
2412
|
+
const activePath = chunkQAZ4TN3Z_js.getActiveRouteNames();
|
|
2413
|
+
const outcome = evaluatePostSubmitSnapshot(snap, activePath, options?.beforeTexts);
|
|
1902
2414
|
if (outcome) return outcome;
|
|
1903
2415
|
return {
|
|
1904
2416
|
status: "failure",
|
|
@@ -1906,91 +2418,6 @@ async function waitForPostSubmitOutcome(options) {
|
|
|
1906
2418
|
};
|
|
1907
2419
|
}
|
|
1908
2420
|
|
|
1909
|
-
// ../shared/dist/chunk-ERITSWKE.mjs
|
|
1910
|
-
var DEFAULT_FUZZY_FLOOR = 4;
|
|
1911
|
-
function normalizeId(value) {
|
|
1912
|
-
return String(value ?? "").normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1913
|
-
}
|
|
1914
|
-
var KIND_PREFIX_WORDS = "button|switch|toggle|input|field|link|btn|slider";
|
|
1915
|
-
var KEBAB_SNAKE_PREFIX_RE = new RegExp(`^(?:${KIND_PREFIX_WORDS})[-_]`, "i");
|
|
1916
|
-
var CAMEL_PREFIX_RE = new RegExp(`^(?:${KIND_PREFIX_WORDS})(?=[A-Z])`, "");
|
|
1917
|
-
function stripKindPrefix(id) {
|
|
1918
|
-
const raw = String(id ?? "");
|
|
1919
|
-
if (KEBAB_SNAKE_PREFIX_RE.test(raw)) return raw.replace(KEBAB_SNAKE_PREFIX_RE, "");
|
|
1920
|
-
if (CAMEL_PREFIX_RE.test(raw)) return raw.replace(CAMEL_PREFIX_RE, "");
|
|
1921
|
-
return raw;
|
|
1922
|
-
}
|
|
1923
|
-
function actionAllowsKind(action, kind) {
|
|
1924
|
-
if (!action || !kind) return true;
|
|
1925
|
-
switch (action) {
|
|
1926
|
-
case "press":
|
|
1927
|
-
case "longPress":
|
|
1928
|
-
return kind !== "field" && kind !== "input" && kind !== "slider";
|
|
1929
|
-
case "set_value":
|
|
1930
|
-
return kind === "slider" || kind === "field" || kind === "input";
|
|
1931
|
-
case "focus":
|
|
1932
|
-
return kind === "field" || kind === "input";
|
|
1933
|
-
case "toggle":
|
|
1934
|
-
return kind === "toggle";
|
|
1935
|
-
default:
|
|
1936
|
-
return true;
|
|
1937
|
-
}
|
|
1938
|
-
}
|
|
1939
|
-
function distinctIds(candidates) {
|
|
1940
|
-
return [...new Set(candidates.map((c) => c.id))];
|
|
1941
|
-
}
|
|
1942
|
-
function resolveTarget(requested, candidates, opts = {}) {
|
|
1943
|
-
const floor = opts.fuzzyFloor ?? DEFAULT_FUZZY_FLOOR;
|
|
1944
|
-
const nReq = normalizeId(requested);
|
|
1945
|
-
if (!nReq || candidates.length === 0) {
|
|
1946
|
-
return { status: "unverified", reason: "not-found" };
|
|
1947
|
-
}
|
|
1948
|
-
for (const c of candidates) {
|
|
1949
|
-
if (normalizeId(c.id) === nReq) {
|
|
1950
|
-
return { status: "matched", id: c.id, tier: "exact" };
|
|
1951
|
-
}
|
|
1952
|
-
}
|
|
1953
|
-
const labelExact = distinctIds(
|
|
1954
|
-
candidates.filter((c) => c.label && normalizeId(c.label) === nReq)
|
|
1955
|
-
);
|
|
1956
|
-
if (labelExact.length === 1) return { status: "matched", id: labelExact[0], tier: "exact" };
|
|
1957
|
-
if (labelExact.length > 1) return { status: "unverified", reason: "ambiguous" };
|
|
1958
|
-
const nReqStripped = normalizeId(stripKindPrefix(requested));
|
|
1959
|
-
for (const c of candidates) {
|
|
1960
|
-
const nId = normalizeId(c.id);
|
|
1961
|
-
const nIdStripped = normalizeId(stripKindPrefix(c.id));
|
|
1962
|
-
if (nReqStripped && (nReqStripped === nId || nReqStripped === nIdStripped) || nIdStripped && nIdStripped === nReq) {
|
|
1963
|
-
return { status: "matched", id: c.id, tier: "prefix" };
|
|
1964
|
-
}
|
|
1965
|
-
}
|
|
1966
|
-
if (opts.destructive) {
|
|
1967
|
-
return { status: "unverified", reason: "destructive-inexact" };
|
|
1968
|
-
}
|
|
1969
|
-
if (nReq.length < floor) {
|
|
1970
|
-
return { status: "unverified", reason: "not-found" };
|
|
1971
|
-
}
|
|
1972
|
-
const fuzzy = candidates.filter((c) => {
|
|
1973
|
-
for (const s of [c.id, c.label]) {
|
|
1974
|
-
if (!s) continue;
|
|
1975
|
-
const ns = normalizeId(s);
|
|
1976
|
-
if (ns.length >= floor && (ns.includes(nReq) || nReq.includes(ns))) return true;
|
|
1977
|
-
}
|
|
1978
|
-
return false;
|
|
1979
|
-
});
|
|
1980
|
-
if (fuzzy.length === 0) {
|
|
1981
|
-
return { status: "unverified", reason: "not-found" };
|
|
1982
|
-
}
|
|
1983
|
-
const typed = fuzzy.filter((c) => actionAllowsKind(opts.action, c.kind));
|
|
1984
|
-
if (typed.length === 0) {
|
|
1985
|
-
return { status: "unverified", reason: "type-mismatch" };
|
|
1986
|
-
}
|
|
1987
|
-
const ids = distinctIds(typed);
|
|
1988
|
-
if (ids.length > 1) {
|
|
1989
|
-
return { status: "unverified", reason: "ambiguous" };
|
|
1990
|
-
}
|
|
1991
|
-
return { status: "matched", id: ids[0], tier: "fuzzy" };
|
|
1992
|
-
}
|
|
1993
|
-
|
|
1994
2421
|
// src/executor/handlers/uiInteractionHandler.ts
|
|
1995
2422
|
function findSnapshotButton(targetId) {
|
|
1996
2423
|
try {
|
|
@@ -2003,16 +2430,16 @@ function findSnapshotButton(targetId) {
|
|
|
2003
2430
|
}
|
|
2004
2431
|
}
|
|
2005
2432
|
function buildUiDiagnose(targetId, cause) {
|
|
2006
|
-
const activePath =
|
|
2007
|
-
const screen = activePath[activePath.length - 1] ??
|
|
2433
|
+
const activePath = chunkQAZ4TN3Z_js.getActiveRouteNames();
|
|
2434
|
+
const screen = activePath[activePath.length - 1] ?? chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0;
|
|
2008
2435
|
const screenPath = activePath.length > 1 ? activePath.join("/") : screen;
|
|
2009
2436
|
const diagnose = {
|
|
2010
2437
|
category: cause === "not-found" ? "component-not-found" : cause === "disabled" ? "disabled" : "unknown",
|
|
2011
2438
|
targetId,
|
|
2012
2439
|
screen: screenPath
|
|
2013
2440
|
};
|
|
2014
|
-
if (
|
|
2015
|
-
diagnose.visibleMessage =
|
|
2441
|
+
if (chunkQAZ4TN3Z_js.isOptionalStepAutomationFailure(targetId, screenPath, activePath)) {
|
|
2442
|
+
diagnose.visibleMessage = chunkQAZ4TN3Z_js.OPTIONAL_STEP_AUTOMATION_HINT;
|
|
2016
2443
|
diagnose.recoverable = true;
|
|
2017
2444
|
}
|
|
2018
2445
|
return diagnose;
|
|
@@ -2063,6 +2490,7 @@ function stripComponentPrefix(componentId) {
|
|
|
2063
2490
|
return null;
|
|
2064
2491
|
}
|
|
2065
2492
|
function resolveComponentId(componentId, registry, action) {
|
|
2493
|
+
if (chunkQAZ4TN3Z_js.isSourceControlId(componentId)) return componentId;
|
|
2066
2494
|
if (registry.getTarget(componentId) || registry.getToggle(componentId) || registry.getField(componentId) || registry.getSlider(componentId)) {
|
|
2067
2495
|
return componentId;
|
|
2068
2496
|
}
|
|
@@ -2070,15 +2498,16 @@ function resolveComponentId(componentId, registry, action) {
|
|
|
2070
2498
|
const snapshot = registry.snapshot();
|
|
2071
2499
|
for (const comp of snapshot) {
|
|
2072
2500
|
if (comp.id.toLowerCase() === lower) {
|
|
2073
|
-
|
|
2501
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
2074
2502
|
`resolveComponentId: case-insensitive match "${componentId}" \u2192 "${comp.id}"`
|
|
2075
2503
|
);
|
|
2076
2504
|
return comp.id;
|
|
2077
2505
|
}
|
|
2078
2506
|
}
|
|
2079
|
-
|
|
2507
|
+
if (isPositionalControlId(componentId)) return componentId;
|
|
2508
|
+
const currentScreen = chunkQAZ4TN3Z_js.getCurrentScreen();
|
|
2080
2509
|
if (currentScreen) {
|
|
2081
|
-
const screenMeta =
|
|
2510
|
+
const screenMeta = chunkQAZ4TN3Z_js.getScreenMetadata(currentScreen);
|
|
2082
2511
|
const actions = screenMeta?.actions;
|
|
2083
2512
|
if (actions && Array.isArray(actions)) {
|
|
2084
2513
|
const metaAction = actions.find(
|
|
@@ -2087,14 +2516,14 @@ function resolveComponentId(componentId, registry, action) {
|
|
|
2087
2516
|
if (metaAction && typeof metaAction === "object" && metaAction.label) {
|
|
2088
2517
|
const metaLabel = metaAction.label;
|
|
2089
2518
|
const normalizedMetaLabel = metaLabel.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
|
|
2090
|
-
|
|
2519
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
2091
2520
|
`resolveComponentId: found screen metadata for "${componentId}" \u2192 label="${metaLabel}"`
|
|
2092
2521
|
);
|
|
2093
2522
|
for (const comp of snapshot) {
|
|
2094
2523
|
if (!comp.label) continue;
|
|
2095
2524
|
const compLabel = comp.label.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
|
|
2096
2525
|
if (compLabel === normalizedMetaLabel || compLabel.includes(normalizedMetaLabel) || normalizedMetaLabel.includes(compLabel)) {
|
|
2097
|
-
|
|
2526
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
2098
2527
|
`resolveComponentId: FOUND via metadata: "${componentId}" \u2192 "${comp.id}" (label="${comp.label}")`
|
|
2099
2528
|
);
|
|
2100
2529
|
return comp.id;
|
|
@@ -2109,9 +2538,9 @@ function resolveComponentId(componentId, registry, action) {
|
|
|
2109
2538
|
label: c.label,
|
|
2110
2539
|
kind: c.kind
|
|
2111
2540
|
}));
|
|
2112
|
-
const match = resolveTarget(componentId, candidates, { action });
|
|
2541
|
+
const match = chunkQAZ4TN3Z_js.resolveTarget(componentId, candidates, { action });
|
|
2113
2542
|
if (match.status === "matched") {
|
|
2114
|
-
|
|
2543
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
2115
2544
|
`resolveComponentId: matched "${componentId}" -> "${match.id}" (tier=${match.tier})`
|
|
2116
2545
|
);
|
|
2117
2546
|
return match.id;
|
|
@@ -2201,7 +2630,7 @@ function setValueHandler(rawComponentId, requested, registry) {
|
|
|
2201
2630
|
try {
|
|
2202
2631
|
slider.setValue(applied);
|
|
2203
2632
|
if (applied !== requestedValue) {
|
|
2204
|
-
|
|
2633
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
2205
2634
|
`uiInteractionHandler: set_value snapped ${requestedValue} \u2192 ${applied} for "${componentId}" (step=${step})`
|
|
2206
2635
|
);
|
|
2207
2636
|
}
|
|
@@ -2236,7 +2665,7 @@ function checkModalOcclusion(rawComponentId, action) {
|
|
|
2236
2665
|
return null;
|
|
2237
2666
|
}
|
|
2238
2667
|
if (typeof rawComponentId !== "string" || rawComponentId.trim().length === 0) return null;
|
|
2239
|
-
const dialog =
|
|
2668
|
+
const dialog = chunkQAZ4TN3Z_js.getOpenNativeDialog();
|
|
2240
2669
|
if (dialog) {
|
|
2241
2670
|
const needle = normalizeIdent(rawComponentId);
|
|
2242
2671
|
if (dialog.buttons.some((b) => normalizeIdent(b.label) === needle)) return null;
|
|
@@ -2246,16 +2675,16 @@ function checkModalOcclusion(rawComponentId, action) {
|
|
|
2246
2675
|
diagnose: {
|
|
2247
2676
|
category: "ambiguous-target",
|
|
2248
2677
|
targetId: rawComponentId,
|
|
2249
|
-
screen:
|
|
2678
|
+
screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0,
|
|
2250
2679
|
candidates: dialog.buttons.map((b) => b.label).slice(0, 8)
|
|
2251
2680
|
}
|
|
2252
2681
|
};
|
|
2253
2682
|
}
|
|
2254
|
-
const fiberRoot =
|
|
2683
|
+
const fiberRoot = chunkQAZ4TN3Z_js.getFiberRoot();
|
|
2255
2684
|
if (!fiberRoot) return null;
|
|
2256
2685
|
let snap;
|
|
2257
2686
|
try {
|
|
2258
|
-
snap =
|
|
2687
|
+
snap = chunkQAZ4TN3Z_js.walkFiber(fiberRoot);
|
|
2259
2688
|
} catch {
|
|
2260
2689
|
return null;
|
|
2261
2690
|
}
|
|
@@ -2317,15 +2746,18 @@ function checkModalOcclusion(rawComponentId, action) {
|
|
|
2317
2746
|
}
|
|
2318
2747
|
function uiInteractionHandler(payload, context) {
|
|
2319
2748
|
const { permissions } = context;
|
|
2320
|
-
const registry = context.registry ??
|
|
2749
|
+
const registry = context.registry ?? chunkQAZ4TN3Z_js.componentRegistry;
|
|
2321
2750
|
if (!permissions.canInteractUI) {
|
|
2322
2751
|
return {
|
|
2323
2752
|
success: false,
|
|
2324
|
-
error: "UI interaction
|
|
2325
|
-
diagnose:
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2753
|
+
error: chunkQAZ4TN3Z_js.permissionDeniedMessage("UI interaction", "canInteractUI"),
|
|
2754
|
+
diagnose: {
|
|
2755
|
+
...buildUiDiagnose(
|
|
2756
|
+
payload.componentId ?? payload.targetId ?? "",
|
|
2757
|
+
"unknown"
|
|
2758
|
+
),
|
|
2759
|
+
recoverable: false
|
|
2760
|
+
}
|
|
2329
2761
|
};
|
|
2330
2762
|
}
|
|
2331
2763
|
const { action } = payload;
|
|
@@ -2339,7 +2771,7 @@ function uiInteractionHandler(payload, context) {
|
|
|
2339
2771
|
if (sliderId) {
|
|
2340
2772
|
const smuggled = payload.value ?? payload.params?.value;
|
|
2341
2773
|
if (smuggled !== void 0) {
|
|
2342
|
-
|
|
2774
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
2343
2775
|
`uiInteractionHandler: "${actionStr}" on slider "${sliderId}" carried value=${JSON.stringify(smuggled)} \u2014 routing to set_value`
|
|
2344
2776
|
);
|
|
2345
2777
|
return setValueHandler(rawComponentId, smuggled, registry);
|
|
@@ -2350,23 +2782,23 @@ function uiInteractionHandler(payload, context) {
|
|
|
2350
2782
|
diagnose: { ...buildUiDiagnose(sliderId, "unknown"), recoverable: true }
|
|
2351
2783
|
};
|
|
2352
2784
|
}
|
|
2353
|
-
const openDialog =
|
|
2785
|
+
const openDialog = chunkQAZ4TN3Z_js.getOpenNativeDialog();
|
|
2354
2786
|
const isPressVerb = actionStr === "press" || actionStr === "tap" || actionStr === "click";
|
|
2355
2787
|
if (openDialog && isPressVerb) {
|
|
2356
2788
|
const needle = normalizeIdent(rawComponentId);
|
|
2357
2789
|
const button = openDialog.buttons.find((b) => normalizeIdent(b.label) === needle);
|
|
2358
2790
|
if (button) {
|
|
2359
2791
|
button.press();
|
|
2360
|
-
|
|
2792
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(`uiInteractionHandler: pressed native dialog button "${button.label}"`);
|
|
2361
2793
|
return { success: true, effect: "changed" };
|
|
2362
2794
|
}
|
|
2363
2795
|
}
|
|
2364
2796
|
if (!openDialog && isPressVerb) {
|
|
2365
|
-
const answered =
|
|
2797
|
+
const answered = chunkQAZ4TN3Z_js.getLastAnsweredNativeDialog();
|
|
2366
2798
|
const needle = normalizeIdent(rawComponentId);
|
|
2367
2799
|
if (answered && needle) {
|
|
2368
2800
|
if (answered.answeredWith && normalizeIdent(answered.answeredWith) === needle) {
|
|
2369
|
-
|
|
2801
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
2370
2802
|
`uiInteractionHandler: native dialog button "${answered.answeredWith}" was already pressed and the dialog is closed \u2014 treating the repeat as done`
|
|
2371
2803
|
);
|
|
2372
2804
|
return { success: true, effect: "completed" };
|
|
@@ -2378,7 +2810,7 @@ function uiInteractionHandler(payload, context) {
|
|
|
2378
2810
|
diagnose: {
|
|
2379
2811
|
category: "component-not-found",
|
|
2380
2812
|
targetId: rawComponentId,
|
|
2381
|
-
screen:
|
|
2813
|
+
screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0,
|
|
2382
2814
|
recoverable: false
|
|
2383
2815
|
}
|
|
2384
2816
|
};
|
|
@@ -2387,7 +2819,7 @@ function uiInteractionHandler(payload, context) {
|
|
|
2387
2819
|
}
|
|
2388
2820
|
const occluded = checkModalOcclusion(rawComponentId, actionStr);
|
|
2389
2821
|
if (occluded) {
|
|
2390
|
-
|
|
2822
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
2391
2823
|
`uiInteractionHandler: blocked "${actionStr}" on "${rawComponentId}" \u2014 target is behind an open modal`
|
|
2392
2824
|
);
|
|
2393
2825
|
return occluded;
|
|
@@ -2395,7 +2827,7 @@ function uiInteractionHandler(payload, context) {
|
|
|
2395
2827
|
if (typeof rawComponentId === "string" && rawComponentId.trim().toLowerCase().startsWith("el:")) {
|
|
2396
2828
|
const result = dispatchElementOrTarget(rawComponentId, registry, actionStr);
|
|
2397
2829
|
if (result.success) {
|
|
2398
|
-
|
|
2830
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
2399
2831
|
`uiInteractionHandler: interaction element dispatch succeeded for "${rawComponentId}"`
|
|
2400
2832
|
);
|
|
2401
2833
|
}
|
|
@@ -2403,17 +2835,17 @@ function uiInteractionHandler(payload, context) {
|
|
|
2403
2835
|
}
|
|
2404
2836
|
const ordinal = parseSyntheticListItemId(rawComponentId);
|
|
2405
2837
|
if (ordinal && (action === "press" || actionStr === "tap" || actionStr === "click" || actionStr === "longPress")) {
|
|
2406
|
-
|
|
2838
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
2407
2839
|
`uiInteractionHandler: dispatching synthetic list ordinal \u2014 componentId="${rawComponentId}" list=${ordinal.listIndex} item=${ordinal.itemIndex}`
|
|
2408
2840
|
);
|
|
2409
2841
|
const result = pressListItemAtOrdinal(ordinal.listIndex, ordinal.itemIndex);
|
|
2410
2842
|
if (result.ok) {
|
|
2411
|
-
|
|
2843
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
2412
2844
|
`uiInteractionHandler: synthetic ordinal press succeeded (container=${result.containerType ?? "List"})`
|
|
2413
2845
|
);
|
|
2414
2846
|
return { success: true };
|
|
2415
2847
|
}
|
|
2416
|
-
const screen =
|
|
2848
|
+
const screen = chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0;
|
|
2417
2849
|
if (result.reason === "list-not-found" || result.reason === "item-not-found") {
|
|
2418
2850
|
return {
|
|
2419
2851
|
success: false,
|
|
@@ -2454,7 +2886,7 @@ function uiInteractionHandler(payload, context) {
|
|
|
2454
2886
|
};
|
|
2455
2887
|
}
|
|
2456
2888
|
const componentId = resolveComponentId(rawComponentId, registry, actionStr);
|
|
2457
|
-
|
|
2889
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
2458
2890
|
`uiInteractionHandler: resolved componentId="${payload.componentId}" \u2192 "${componentId}"`
|
|
2459
2891
|
);
|
|
2460
2892
|
const target = registry.getTarget(componentId);
|
|
@@ -2507,7 +2939,7 @@ function uiInteractionHandler(payload, context) {
|
|
|
2507
2939
|
return { success: false, error: err?.message ?? "Focus failed" };
|
|
2508
2940
|
}
|
|
2509
2941
|
}
|
|
2510
|
-
|
|
2942
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
2511
2943
|
`uiInteractionHandler: registry miss for "${componentId}", falling back to fiber tree`
|
|
2512
2944
|
);
|
|
2513
2945
|
const namedToggle = dispatchIdentifiedToggle(componentId, actionStr);
|
|
@@ -2519,7 +2951,7 @@ function uiInteractionHandler(payload, context) {
|
|
|
2519
2951
|
try {
|
|
2520
2952
|
if (actionStr === "press" && handle.kind === "target" && handle.press) {
|
|
2521
2953
|
handle.press();
|
|
2522
|
-
|
|
2954
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
2523
2955
|
`uiInteractionHandler: fiber fallback press succeeded for "${componentId}"`
|
|
2524
2956
|
);
|
|
2525
2957
|
return { success: true };
|
|
@@ -2555,6 +2987,28 @@ function uiInteractionHandler(payload, context) {
|
|
|
2555
2987
|
};
|
|
2556
2988
|
}
|
|
2557
2989
|
|
|
2990
|
+
// src/executor/completeTextEdit.ts
|
|
2991
|
+
var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
2992
|
+
async function completeTextEdit(fieldId, expected, registered, origin, resolveRegistered) {
|
|
2993
|
+
await sleep2(80);
|
|
2994
|
+
const current2 = findInteractiveByIdentifier(fieldId, { kind: "field" });
|
|
2995
|
+
if (origin?.controlIdentity && current2?.controlIdentity !== origin.controlIdentity) return false;
|
|
2996
|
+
if (registered && resolveRegistered && resolveRegistered() !== registered) return false;
|
|
2997
|
+
if (registered?.finishEditing) registered.finishEditing();
|
|
2998
|
+
else if (current2 && (current2.matchCount ?? 1) === 1 && !current2.disabled)
|
|
2999
|
+
current2.finishEditing?.();
|
|
3000
|
+
const started = Date.now();
|
|
3001
|
+
do {
|
|
3002
|
+
await sleep2(80);
|
|
3003
|
+
const live = findInteractiveByIdentifier(fieldId, { kind: "field" });
|
|
3004
|
+
if (origin?.controlIdentity && live?.controlIdentity !== origin.controlIdentity) return false;
|
|
3005
|
+
if (registered && resolveRegistered && resolveRegistered() !== registered) return false;
|
|
3006
|
+
const value = registered ? registered.getValue() : live?.getValue?.();
|
|
3007
|
+
if (value !== void 0 && value !== null && String(value) === String(expected)) return true;
|
|
3008
|
+
} while (Date.now() - started < 480);
|
|
3009
|
+
return false;
|
|
3010
|
+
}
|
|
3011
|
+
|
|
2558
3012
|
// src/executor/formSubmitResolve.ts
|
|
2559
3013
|
var SUBMIT_LABEL_HINT_RE = /\b(submit|save|send|continue|next|sign\s*in|log\s*in|register|salvar|enviar|entrar|cadastrar|continuar|proximo|próximo|avancar|avançar|confirmar|guardar|registrarse|iniciar\s+sesi[óo]n|enregistrer|envoyer|valider|soumettre|confirmer|se\s+connecter|s['e]\s*inscrire)\b/i;
|
|
2560
3014
|
var AGENT_CHROME_TARGET_RE = /\b(fechar|close|dismiss|cancelar|cancel|limpar|clear|chat\s+do\s+assistente|assistant\s+chat)\b/i;
|
|
@@ -2582,7 +3036,7 @@ function submitLabelHintsSubmit(label) {
|
|
|
2582
3036
|
return SUBMIT_LABEL_HINT_RE.test(trimmed);
|
|
2583
3037
|
}
|
|
2584
3038
|
function screenDeclaresSubmitAction(screenName) {
|
|
2585
|
-
const meta =
|
|
3039
|
+
const meta = chunkQAZ4TN3Z_js.getScreenMetadata(screenName);
|
|
2586
3040
|
return Array.isArray(meta?.actions) && meta.actions.some(
|
|
2587
3041
|
(action) => typeof action === "object" && action !== null && action.type === "submit"
|
|
2588
3042
|
);
|
|
@@ -2615,7 +3069,7 @@ function resolveFormScreensForSubmit(screen, activePath, registry) {
|
|
|
2615
3069
|
} else {
|
|
2616
3070
|
push(screen);
|
|
2617
3071
|
}
|
|
2618
|
-
push(
|
|
3072
|
+
push(chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0);
|
|
2619
3073
|
const withSubmit = [];
|
|
2620
3074
|
const rest = [];
|
|
2621
3075
|
for (const name of ordered) {
|
|
@@ -2633,7 +3087,7 @@ function collectSubmitTargetCandidates(screens, registry) {
|
|
|
2633
3087
|
candidates.push(id);
|
|
2634
3088
|
};
|
|
2635
3089
|
for (const screenName of screens) {
|
|
2636
|
-
const meta =
|
|
3090
|
+
const meta = chunkQAZ4TN3Z_js.getScreenMetadata(screenName);
|
|
2637
3091
|
const submitMeta = Array.isArray(meta?.actions) ? meta.actions.find(
|
|
2638
3092
|
(action) => typeof action === "object" && action !== null && action.type === "submit"
|
|
2639
3093
|
) : void 0;
|
|
@@ -2677,8 +3131,8 @@ function readVisibleValidation(fieldId, label) {
|
|
|
2677
3131
|
return void 0;
|
|
2678
3132
|
}
|
|
2679
3133
|
function resolveScreenContext() {
|
|
2680
|
-
const activePath =
|
|
2681
|
-
const screen = activePath[activePath.length - 1] ??
|
|
3134
|
+
const activePath = chunkQAZ4TN3Z_js.getActiveRouteNames();
|
|
3135
|
+
const screen = activePath[activePath.length - 1] ?? chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0;
|
|
2682
3136
|
return { screen, activePath };
|
|
2683
3137
|
}
|
|
2684
3138
|
function selectValueApplied(fieldId, requestedValue, currentValue, registry) {
|
|
@@ -2686,36 +3140,36 @@ function selectValueApplied(fieldId, requestedValue, currentValue, registry) {
|
|
|
2686
3140
|
if (!requested) return false;
|
|
2687
3141
|
const meta = getMetadataField(fieldId, registry);
|
|
2688
3142
|
const options = Array.isArray(meta?.options) ? meta.options : [];
|
|
2689
|
-
const requestedNorm =
|
|
2690
|
-
const currentNorm =
|
|
3143
|
+
const requestedNorm = chunkQAZ4TN3Z_js.normalize3(requested);
|
|
3144
|
+
const currentNorm = chunkQAZ4TN3Z_js.normalize3(currentValue);
|
|
2691
3145
|
if (currentNorm === requestedNorm) return true;
|
|
2692
3146
|
for (const option of options) {
|
|
2693
3147
|
const value = typeof option?.value === "string" ? option.value : "";
|
|
2694
3148
|
const label = typeof option?.label === "string" ? option.label : "";
|
|
2695
|
-
if (
|
|
2696
|
-
if (
|
|
2697
|
-
if (
|
|
3149
|
+
if (chunkQAZ4TN3Z_js.normalize3(value) === requestedNorm && chunkQAZ4TN3Z_js.normalize3(label) === currentNorm) return true;
|
|
3150
|
+
if (chunkQAZ4TN3Z_js.normalize3(label) === requestedNorm && chunkQAZ4TN3Z_js.normalize3(label) === currentNorm) return true;
|
|
3151
|
+
if (chunkQAZ4TN3Z_js.normalize3(value) === requestedNorm && chunkQAZ4TN3Z_js.normalize3(value) === currentNorm) return true;
|
|
2698
3152
|
}
|
|
2699
3153
|
return false;
|
|
2700
3154
|
}
|
|
2701
3155
|
function getMetadataField(fieldId, registry) {
|
|
2702
3156
|
const screens = /* @__PURE__ */ new Set();
|
|
2703
|
-
for (const name of
|
|
2704
|
-
const
|
|
2705
|
-
if (
|
|
3157
|
+
for (const name of chunkQAZ4TN3Z_js.getActiveRouteNames()) screens.add(name);
|
|
3158
|
+
const current2 = chunkQAZ4TN3Z_js.getCurrentScreen();
|
|
3159
|
+
if (current2) screens.add(current2);
|
|
2706
3160
|
if (registry) {
|
|
2707
3161
|
for (const comp of registry.snapshot()) {
|
|
2708
3162
|
if (comp.kind === "field" && comp.screen) screens.add(comp.screen);
|
|
2709
3163
|
}
|
|
2710
3164
|
}
|
|
2711
|
-
const needle =
|
|
3165
|
+
const needle = chunkQAZ4TN3Z_js.normalize3(fieldId);
|
|
2712
3166
|
for (const screenName of screens) {
|
|
2713
|
-
const screenMeta =
|
|
3167
|
+
const screenMeta = chunkQAZ4TN3Z_js.getScreenMetadata(screenName);
|
|
2714
3168
|
const fields = Array.isArray(screenMeta?.fields) ? screenMeta.fields : [];
|
|
2715
3169
|
const match = fields.find((field) => {
|
|
2716
3170
|
if (!field || typeof field !== "object") return false;
|
|
2717
|
-
const id = typeof field.id === "string" ?
|
|
2718
|
-
const label = typeof field.label === "string" ?
|
|
3171
|
+
const id = typeof field.id === "string" ? chunkQAZ4TN3Z_js.normalize3(field.id) : "";
|
|
3172
|
+
const label = typeof field.label === "string" ? chunkQAZ4TN3Z_js.normalize3(field.label) : "";
|
|
2719
3173
|
return id === needle || label === needle;
|
|
2720
3174
|
});
|
|
2721
3175
|
if (match) return match;
|
|
@@ -2727,11 +3181,11 @@ function resolveSelectOption(fieldId, value, registry) {
|
|
|
2727
3181
|
if (!requested) return void 0;
|
|
2728
3182
|
const meta = getMetadataField(fieldId, registry);
|
|
2729
3183
|
const options = Array.isArray(meta?.options) ? meta.options : [];
|
|
2730
|
-
const requestedNorm =
|
|
3184
|
+
const requestedNorm = chunkQAZ4TN3Z_js.normalize3(requested);
|
|
2731
3185
|
for (const option of options) {
|
|
2732
3186
|
const optionValue = typeof option?.value === "string" ? option.value : "";
|
|
2733
3187
|
const optionLabel = typeof option?.label === "string" ? option.label : "";
|
|
2734
|
-
if (
|
|
3188
|
+
if (chunkQAZ4TN3Z_js.normalize3(optionValue) === requestedNorm || chunkQAZ4TN3Z_js.normalize3(optionLabel) === requestedNorm) {
|
|
2735
3189
|
return { value: optionValue, label: optionLabel };
|
|
2736
3190
|
}
|
|
2737
3191
|
}
|
|
@@ -2743,7 +3197,7 @@ async function tryOpenSelectModal(fieldId, registry) {
|
|
|
2743
3197
|
if (!target) continue;
|
|
2744
3198
|
try {
|
|
2745
3199
|
target.press();
|
|
2746
|
-
await
|
|
3200
|
+
await sleep3(180);
|
|
2747
3201
|
return true;
|
|
2748
3202
|
} catch {
|
|
2749
3203
|
}
|
|
@@ -2781,12 +3235,12 @@ async function tryPressSelectOption(fieldId, value, registry, options = {}) {
|
|
|
2781
3235
|
return {
|
|
2782
3236
|
success: false,
|
|
2783
3237
|
error: `No pressable option found for select field "${fieldId}"`,
|
|
2784
|
-
diagnose: { category: "component-not-found", fieldId, screen:
|
|
3238
|
+
diagnose: { category: "component-not-found", fieldId, screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0 }
|
|
2785
3239
|
};
|
|
2786
3240
|
}
|
|
2787
3241
|
function normalizeFieldType(type) {
|
|
2788
3242
|
if (typeof type !== "string") return void 0;
|
|
2789
|
-
const normalized =
|
|
3243
|
+
const normalized = chunkQAZ4TN3Z_js.normalize3(type);
|
|
2790
3244
|
if (normalized === "select" || normalized === "picker" || normalized === "dropdown")
|
|
2791
3245
|
return "select";
|
|
2792
3246
|
if (normalized === "toggle" || normalized === "switch" || normalized === "checkbox")
|
|
@@ -2816,7 +3270,7 @@ function fieldCueTerms(fieldId, label) {
|
|
|
2816
3270
|
);
|
|
2817
3271
|
const terms = /* @__PURE__ */ new Set();
|
|
2818
3272
|
for (const value of raw) {
|
|
2819
|
-
const normalized =
|
|
3273
|
+
const normalized = chunkQAZ4TN3Z_js.normalize3(value);
|
|
2820
3274
|
if (normalized.length >= 3 && normalized !== "id") terms.add(normalized);
|
|
2821
3275
|
}
|
|
2822
3276
|
return [...terms];
|
|
@@ -2824,17 +3278,17 @@ function fieldCueTerms(fieldId, label) {
|
|
|
2824
3278
|
function snapshotHasFieldCue(snap, fieldId, label) {
|
|
2825
3279
|
const terms = fieldCueTerms(fieldId, label);
|
|
2826
3280
|
if (terms.length === 0) return false;
|
|
2827
|
-
const visible = [...snap.texts ?? [], ...(snap.buttons ?? []).map((b) => b.label ?? b.id ?? "")].map((text) =>
|
|
3281
|
+
const visible = [...snap.texts ?? [], ...(snap.buttons ?? []).map((b) => b.label ?? b.id ?? "")].map((text) => chunkQAZ4TN3Z_js.normalize3(text)).filter(Boolean);
|
|
2828
3282
|
return visible.some((text) => terms.some((term) => text.includes(term) || term.includes(text)));
|
|
2829
3283
|
}
|
|
2830
3284
|
function scoreCandidateText(value, texts) {
|
|
2831
|
-
const valueNorm =
|
|
3285
|
+
const valueNorm = chunkQAZ4TN3Z_js.normalize3(String(value ?? ""));
|
|
2832
3286
|
if (!valueNorm) return 0;
|
|
2833
3287
|
let best = 0;
|
|
2834
3288
|
for (const text of texts) {
|
|
2835
|
-
const textNorm =
|
|
3289
|
+
const textNorm = chunkQAZ4TN3Z_js.normalize3(text);
|
|
2836
3290
|
if (!textNorm) continue;
|
|
2837
|
-
best = Math.max(best,
|
|
3291
|
+
best = Math.max(best, chunkQAZ4TN3Z_js.matchScore(valueNorm, textNorm));
|
|
2838
3292
|
}
|
|
2839
3293
|
return best;
|
|
2840
3294
|
}
|
|
@@ -2848,7 +3302,7 @@ function optionTexts(option) {
|
|
|
2848
3302
|
function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue, registry) {
|
|
2849
3303
|
const fieldLabel = getFieldLabel(fieldId, registry);
|
|
2850
3304
|
const fieldCueVisible = snapshotHasFieldCue(snap, fieldId, fieldLabel);
|
|
2851
|
-
const genericValue =
|
|
3305
|
+
const genericValue = chunkQAZ4TN3Z_js.isGenericSelectValue(value);
|
|
2852
3306
|
const candidates = [];
|
|
2853
3307
|
let order = 0;
|
|
2854
3308
|
const choiceGroups = snap.choiceGroups ?? [];
|
|
@@ -2860,7 +3314,7 @@ function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue,
|
|
|
2860
3314
|
const groupCueScore = Math.max(
|
|
2861
3315
|
globalCueScore,
|
|
2862
3316
|
...groupTexts.map((text) => {
|
|
2863
|
-
const normalized =
|
|
3317
|
+
const normalized = chunkQAZ4TN3Z_js.normalize3(text);
|
|
2864
3318
|
return fieldCueTerms(fieldId, fieldLabel).some(
|
|
2865
3319
|
(term) => normalized.includes(term) || term.includes(normalized)
|
|
2866
3320
|
) ? 80 : 0;
|
|
@@ -2897,7 +3351,7 @@ function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue,
|
|
|
2897
3351
|
const elementCueScore = Math.max(
|
|
2898
3352
|
fieldCueVisible && elements.length <= 12 ? 50 : 0,
|
|
2899
3353
|
...cueTexts.map((text) => {
|
|
2900
|
-
const normalized =
|
|
3354
|
+
const normalized = chunkQAZ4TN3Z_js.normalize3(text);
|
|
2901
3355
|
return fieldTerms.some((term) => normalized.includes(term) || term.includes(normalized)) ? 80 : 0;
|
|
2902
3356
|
})
|
|
2903
3357
|
);
|
|
@@ -2955,7 +3409,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
|
|
|
2955
3409
|
return {
|
|
2956
3410
|
success: false,
|
|
2957
3411
|
error: err?.message ?? "Could not capture visible choices",
|
|
2958
|
-
diagnose: { category: "unknown", fieldId, screen:
|
|
3412
|
+
diagnose: { category: "unknown", fieldId, screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0 }
|
|
2959
3413
|
};
|
|
2960
3414
|
}
|
|
2961
3415
|
const candidates = buildChoiceCandidates(
|
|
@@ -2973,7 +3427,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
|
|
|
2973
3427
|
diagnose: {
|
|
2974
3428
|
category: "component-not-found",
|
|
2975
3429
|
fieldId,
|
|
2976
|
-
screen:
|
|
3430
|
+
screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0
|
|
2977
3431
|
}
|
|
2978
3432
|
};
|
|
2979
3433
|
}
|
|
@@ -2987,7 +3441,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
|
|
|
2987
3441
|
}
|
|
2988
3442
|
function isContinuationButton(label) {
|
|
2989
3443
|
if (!label) return false;
|
|
2990
|
-
return /^(next|continue|proximo|prox|continuar|avancar|avançar)$/i.test(
|
|
3444
|
+
return /^(next|continue|proximo|prox|continuar|avancar|avançar)$/i.test(chunkQAZ4TN3Z_js.normalize3(label));
|
|
2991
3445
|
}
|
|
2992
3446
|
function pressContinuationButton(registry) {
|
|
2993
3447
|
const snap = captureSnapshot();
|
|
@@ -3000,40 +3454,44 @@ function pressContinuationButton(registry) {
|
|
|
3000
3454
|
return {
|
|
3001
3455
|
success: false,
|
|
3002
3456
|
error: "No enabled continuation button is visible",
|
|
3003
|
-
diagnose: { category: "component-not-found", screen:
|
|
3457
|
+
diagnose: { category: "component-not-found", screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0 }
|
|
3004
3458
|
};
|
|
3005
3459
|
}
|
|
3006
3460
|
return pressTargetByIdOrLabel(id, registry);
|
|
3007
3461
|
}
|
|
3008
3462
|
function findField(fieldId, registry) {
|
|
3009
|
-
|
|
3463
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(`findField: searching for fieldId="${fieldId}"`);
|
|
3010
3464
|
const exact = registry.getField(fieldId);
|
|
3011
3465
|
if (exact) {
|
|
3012
|
-
|
|
3466
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(`findField: FOUND exact match for fieldId="${fieldId}"`);
|
|
3013
3467
|
return exact;
|
|
3014
3468
|
}
|
|
3015
3469
|
const lower = fieldId.toLowerCase();
|
|
3016
3470
|
const snapshot = registry.snapshot();
|
|
3017
3471
|
for (const comp of snapshot) {
|
|
3018
3472
|
if (comp.kind === "field" && comp.id.toLowerCase() === lower) {
|
|
3019
|
-
|
|
3473
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
3020
3474
|
`findField: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
|
|
3021
3475
|
);
|
|
3022
3476
|
return registry.getField(comp.id);
|
|
3023
3477
|
}
|
|
3024
3478
|
}
|
|
3025
|
-
|
|
3026
|
-
|
|
3479
|
+
if (findInteractiveByIdentifier(fieldId, { kind: "field", minScore: IDENTITY_MATCH_SCORE })) {
|
|
3480
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(`findField: "${fieldId}" names a live input \u2014 not guessing in the registry`);
|
|
3481
|
+
return void 0;
|
|
3482
|
+
}
|
|
3483
|
+
const currentScreenForTieBreak = chunkQAZ4TN3Z_js.getCurrentScreen();
|
|
3484
|
+
const needle = chunkQAZ4TN3Z_js.normalize3(fieldId);
|
|
3027
3485
|
let bestComp;
|
|
3028
3486
|
let bestScore = 0;
|
|
3029
3487
|
let bestOnCurrentScreen = false;
|
|
3030
3488
|
for (const comp of snapshot) {
|
|
3031
3489
|
if (comp.kind !== "field") continue;
|
|
3032
|
-
const candidates = [
|
|
3033
|
-
if (comp.label) candidates.push(
|
|
3490
|
+
const candidates = [chunkQAZ4TN3Z_js.normalize3(comp.id)];
|
|
3491
|
+
if (comp.label) candidates.push(chunkQAZ4TN3Z_js.normalize3(comp.label));
|
|
3034
3492
|
let candidateScore = 0;
|
|
3035
3493
|
for (const cand of candidates) {
|
|
3036
|
-
const s =
|
|
3494
|
+
const s = chunkQAZ4TN3Z_js.matchScore(needle, cand);
|
|
3037
3495
|
if (s > candidateScore) candidateScore = s;
|
|
3038
3496
|
}
|
|
3039
3497
|
if (candidateScore === 0) continue;
|
|
@@ -3046,14 +3504,14 @@ function findField(fieldId, registry) {
|
|
|
3046
3504
|
}
|
|
3047
3505
|
}
|
|
3048
3506
|
if (bestComp && bestScore >= 75) {
|
|
3049
|
-
|
|
3507
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
3050
3508
|
`findField: scored match "${fieldId}" -> "${bestComp.id}" (label="${bestComp.label}", score=${bestScore})`
|
|
3051
3509
|
);
|
|
3052
3510
|
return registry.getField(bestComp.id);
|
|
3053
3511
|
}
|
|
3054
|
-
const currentScreen =
|
|
3512
|
+
const currentScreen = chunkQAZ4TN3Z_js.getCurrentScreen();
|
|
3055
3513
|
if (currentScreen) {
|
|
3056
|
-
const screenMeta =
|
|
3514
|
+
const screenMeta = chunkQAZ4TN3Z_js.getScreenMetadata(currentScreen);
|
|
3057
3515
|
const fields = screenMeta?.fields;
|
|
3058
3516
|
if (fields && Array.isArray(fields)) {
|
|
3059
3517
|
const metaField = fields.find(
|
|
@@ -3061,19 +3519,19 @@ function findField(fieldId, registry) {
|
|
|
3061
3519
|
);
|
|
3062
3520
|
if (metaField && typeof metaField === "object" && metaField.label) {
|
|
3063
3521
|
const metaLabel = metaField.label;
|
|
3064
|
-
const metaNeedle =
|
|
3522
|
+
const metaNeedle = chunkQAZ4TN3Z_js.normalize3(metaLabel);
|
|
3065
3523
|
let mBest;
|
|
3066
3524
|
let mBestScore = 0;
|
|
3067
3525
|
for (const comp of snapshot) {
|
|
3068
3526
|
if (comp.kind !== "field" || !comp.label) continue;
|
|
3069
|
-
const score =
|
|
3527
|
+
const score = chunkQAZ4TN3Z_js.matchScore(metaNeedle, chunkQAZ4TN3Z_js.normalize3(comp.label));
|
|
3070
3528
|
if (score > mBestScore) {
|
|
3071
3529
|
mBestScore = score;
|
|
3072
3530
|
mBest = comp;
|
|
3073
3531
|
}
|
|
3074
3532
|
}
|
|
3075
3533
|
if (mBest && mBestScore >= 60) {
|
|
3076
|
-
|
|
3534
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
3077
3535
|
`findField: FOUND via screen metadata translation: fieldId="${fieldId}" -> metaLabel="${metaLabel}" -> registered="${mBest.id}" (score=${mBestScore})`
|
|
3078
3536
|
);
|
|
3079
3537
|
return registry.getField(mBest.id);
|
|
@@ -3082,34 +3540,34 @@ function findField(fieldId, registry) {
|
|
|
3082
3540
|
}
|
|
3083
3541
|
}
|
|
3084
3542
|
if (bestComp && bestScore >= 40) {
|
|
3085
|
-
|
|
3543
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
3086
3544
|
`findField: weak substring match "${fieldId}" -> "${bestComp.id}" (label="${bestComp.label}", score=${bestScore})`
|
|
3087
3545
|
);
|
|
3088
3546
|
return registry.getField(bestComp.id);
|
|
3089
3547
|
}
|
|
3090
|
-
|
|
3548
|
+
chunkQAZ4TN3Z_js.appilotsDebugWarn(
|
|
3091
3549
|
`findField: NOT FOUND \u2014 fieldId="${fieldId}" not in registry. Available fields: ${snapshot.filter((c) => c.kind === "field").map((c) => `"${c.id}" (label: ${c.label})`).join(", ") || "none"}`
|
|
3092
3550
|
);
|
|
3093
3551
|
return void 0;
|
|
3094
3552
|
}
|
|
3095
3553
|
function findToggle(fieldId, registry) {
|
|
3096
|
-
|
|
3554
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(`findToggle: searching for fieldId="${fieldId}"`);
|
|
3097
3555
|
const exact = registry.getToggle(fieldId);
|
|
3098
3556
|
if (exact) {
|
|
3099
|
-
|
|
3557
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(`findToggle: FOUND exact match for "${fieldId}"`);
|
|
3100
3558
|
return exact;
|
|
3101
3559
|
}
|
|
3102
3560
|
const lower = fieldId.toLowerCase();
|
|
3103
3561
|
const snapshot = registry.snapshot();
|
|
3104
3562
|
for (const comp of snapshot) {
|
|
3105
3563
|
if (comp.kind === "toggle" && comp.id.toLowerCase() === lower) {
|
|
3106
|
-
|
|
3564
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
3107
3565
|
`findToggle: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
|
|
3108
3566
|
);
|
|
3109
3567
|
return registry.getToggle(comp.id);
|
|
3110
3568
|
}
|
|
3111
3569
|
}
|
|
3112
|
-
|
|
3570
|
+
chunkQAZ4TN3Z_js.appilotsDebugWarn(
|
|
3113
3571
|
`findToggle: NOT FOUND \u2014 fieldId="${fieldId}" not in registry. Available toggles: ${snapshot.filter((c) => c.kind === "toggle").map((c) => `"${c.id}"`).join(", ") || "none"}`
|
|
3114
3572
|
);
|
|
3115
3573
|
return void 0;
|
|
@@ -3120,7 +3578,7 @@ function findSlider(fieldId, registry) {
|
|
|
3120
3578
|
const lower = fieldId.toLowerCase();
|
|
3121
3579
|
for (const comp of registry.snapshot()) {
|
|
3122
3580
|
if (comp.kind === "slider" && comp.id.toLowerCase() === lower) {
|
|
3123
|
-
|
|
3581
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
3124
3582
|
`findSlider: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
|
|
3125
3583
|
);
|
|
3126
3584
|
return registry.getSlider(comp.id);
|
|
@@ -3128,17 +3586,17 @@ function findSlider(fieldId, registry) {
|
|
|
3128
3586
|
}
|
|
3129
3587
|
return void 0;
|
|
3130
3588
|
}
|
|
3131
|
-
var
|
|
3589
|
+
var sleep3 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
3132
3590
|
async function formFillHandler(payload, context) {
|
|
3133
3591
|
const { permissions } = context;
|
|
3134
|
-
const registry = context.registry ??
|
|
3592
|
+
const registry = context.registry ?? chunkQAZ4TN3Z_js.componentRegistry;
|
|
3135
3593
|
const { screen, activePath } = resolveScreenContext();
|
|
3136
3594
|
const screenPath = activePath.length > 1 ? activePath.join("/") : screen;
|
|
3137
3595
|
if (!permissions.canFillForms) {
|
|
3138
3596
|
return {
|
|
3139
3597
|
success: false,
|
|
3140
|
-
error: "Form filling
|
|
3141
|
-
diagnose: { category: "unknown", screen: screenPath }
|
|
3598
|
+
error: chunkQAZ4TN3Z_js.permissionDeniedMessage("Form filling", "canFillForms"),
|
|
3599
|
+
diagnose: { category: "unknown", screen: screenPath, recoverable: false }
|
|
3142
3600
|
};
|
|
3143
3601
|
}
|
|
3144
3602
|
if (!payload.fields || payload.fields.length === 0) {
|
|
@@ -3150,11 +3608,11 @@ async function formFillHandler(payload, context) {
|
|
|
3150
3608
|
}
|
|
3151
3609
|
const registrySnapshot = registry.snapshot();
|
|
3152
3610
|
if (registrySnapshot.length === 0) {
|
|
3153
|
-
|
|
3611
|
+
chunkQAZ4TN3Z_js.appilotsDebugWarn(
|
|
3154
3612
|
"formFillHandler: registry is EMPTY \u2014 auto-tracking may not be active. Ensure enableAppilotsAutoTracking() runs before components mount."
|
|
3155
3613
|
);
|
|
3156
3614
|
} else {
|
|
3157
|
-
|
|
3615
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
3158
3616
|
`[Appilots formFillHandler] Registry has ${registrySnapshot.length} components:`,
|
|
3159
3617
|
registrySnapshot.map((c) => `${c.kind}:${c.id}`).join(", ")
|
|
3160
3618
|
);
|
|
@@ -3162,7 +3620,7 @@ async function formFillHandler(payload, context) {
|
|
|
3162
3620
|
const fieldResults = [];
|
|
3163
3621
|
let allSuccess = true;
|
|
3164
3622
|
let selectedChoiceThisBatch = false;
|
|
3165
|
-
|
|
3623
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(`formFillHandler: processing ${payload.fields.length} fields`);
|
|
3166
3624
|
const availableFieldIds = () => registry.snapshot().filter((comp) => comp.kind === "field").map((comp) => `${comp.id}${comp.label ? ` (${comp.label})` : ""}`).slice(0, 8);
|
|
3167
3625
|
const isElementIdField = (field) => typeof field.fieldId === "string" && field.fieldId.trim().toLowerCase().startsWith("el:");
|
|
3168
3626
|
for (const field of payload.fields.filter(isElementIdField)) {
|
|
@@ -3189,20 +3647,57 @@ async function formFillHandler(payload, context) {
|
|
|
3189
3647
|
const { fieldId, fieldType, value } = field;
|
|
3190
3648
|
const effectiveFieldType = getEffectiveFieldType(fieldId, fieldType, registry);
|
|
3191
3649
|
let selectFailure;
|
|
3192
|
-
|
|
3193
|
-
`formFillHandler: looking up fieldId="${fieldId}" fieldType="${fieldType}" effectiveFieldType="${effectiveFieldType}" value=${
|
|
3650
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
3651
|
+
`formFillHandler: looking up fieldId="${fieldId}" fieldType="${fieldType}" effectiveFieldType="${effectiveFieldType}" value=${chunkQAZ4TN3Z_js.describeValue(value)}`
|
|
3194
3652
|
);
|
|
3195
3653
|
const fieldEntry = findField(fieldId, registry);
|
|
3196
3654
|
if (fieldEntry) {
|
|
3197
3655
|
try {
|
|
3198
|
-
|
|
3656
|
+
const nativeField = findInteractiveByIdentifier(fieldId, { kind: "field" });
|
|
3657
|
+
if (nativeField?.disabled || (nativeField?.matchCount ?? 1) > 1) {
|
|
3658
|
+
fieldResults.push({
|
|
3659
|
+
fieldId,
|
|
3660
|
+
success: false,
|
|
3661
|
+
error: nativeField?.disabled ? "The field is disabled" : "The field identifier matches multiple controls",
|
|
3662
|
+
diagnose: {
|
|
3663
|
+
category: nativeField?.disabled ? "disabled" : "ambiguous-target",
|
|
3664
|
+
fieldId,
|
|
3665
|
+
screen: screenPath
|
|
3666
|
+
}
|
|
3667
|
+
});
|
|
3668
|
+
allSuccess = false;
|
|
3669
|
+
continue;
|
|
3670
|
+
}
|
|
3671
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
3199
3672
|
`formFillHandler: found field "${fieldId}" via registry, calling setValue(<${String(value).length} chars>)`
|
|
3200
3673
|
);
|
|
3201
3674
|
const beforeValue = effectiveFieldType === "date" ? fieldEntry.getValue?.() ?? "" : void 0;
|
|
3202
3675
|
fieldEntry.focus?.();
|
|
3203
3676
|
fieldEntry.setValue(String(value));
|
|
3677
|
+
if (effectiveFieldType === "text" || effectiveFieldType === "number") {
|
|
3678
|
+
if (!await completeTextEdit(
|
|
3679
|
+
fieldId,
|
|
3680
|
+
value,
|
|
3681
|
+
fieldEntry,
|
|
3682
|
+
nativeField,
|
|
3683
|
+
() => findField(fieldId, registry)
|
|
3684
|
+
)) {
|
|
3685
|
+
fieldResults.push({
|
|
3686
|
+
fieldId,
|
|
3687
|
+
success: false,
|
|
3688
|
+
error: "The field did not retain the requested value after editing ended. Inspect its current value before retrying.",
|
|
3689
|
+
diagnose: { category: "validation", fieldId, screen: screenPath }
|
|
3690
|
+
});
|
|
3691
|
+
allSuccess = false;
|
|
3692
|
+
continue;
|
|
3693
|
+
}
|
|
3694
|
+
}
|
|
3204
3695
|
if (effectiveFieldType === "date") {
|
|
3205
|
-
|
|
3696
|
+
let afterValue = fieldEntry.getValue?.() ?? "";
|
|
3697
|
+
if (afterValue === beforeValue) {
|
|
3698
|
+
await sleep3(80);
|
|
3699
|
+
afterValue = fieldEntry.getValue?.() ?? "";
|
|
3700
|
+
}
|
|
3206
3701
|
if (afterValue === beforeValue) {
|
|
3207
3702
|
fieldResults.push({
|
|
3208
3703
|
fieldId,
|
|
@@ -3222,11 +3717,11 @@ async function formFillHandler(payload, context) {
|
|
|
3222
3717
|
if (effectiveFieldType === "select") {
|
|
3223
3718
|
let after = fieldEntry.getValue?.() ?? "";
|
|
3224
3719
|
if (!selectValueApplied(fieldId, value, after, registry)) {
|
|
3225
|
-
await
|
|
3720
|
+
await sleep3(80);
|
|
3226
3721
|
after = fieldEntry.getValue?.() ?? "";
|
|
3227
3722
|
}
|
|
3228
3723
|
if (!selectValueApplied(fieldId, value, after, registry)) {
|
|
3229
|
-
|
|
3724
|
+
chunkQAZ4TN3Z_js.appilotsDebugWarn(
|
|
3230
3725
|
`formFillHandler: select field "${fieldId}" setValue did not stick (wrote <${String(value).length} chars>, current is <${String(after ?? "").length} chars>), trying visible choice fallback`
|
|
3231
3726
|
);
|
|
3232
3727
|
const selectResult = await selectVisibleChoice(fieldId, value, registry, {
|
|
@@ -3343,7 +3838,7 @@ async function formFillHandler(payload, context) {
|
|
|
3343
3838
|
if (!selectResult.success && selectedChoiceThisBatch) {
|
|
3344
3839
|
const nextResult = pressContinuationButton(registry);
|
|
3345
3840
|
if (nextResult.success) {
|
|
3346
|
-
await
|
|
3841
|
+
await sleep3(180);
|
|
3347
3842
|
selectResult = await selectVisibleChoice(fieldId, value, registry, {
|
|
3348
3843
|
allowFirstVisibleWhenNoCue: true
|
|
3349
3844
|
});
|
|
@@ -3351,24 +3846,50 @@ async function formFillHandler(payload, context) {
|
|
|
3351
3846
|
}
|
|
3352
3847
|
if (selectResult.success) {
|
|
3353
3848
|
selectedChoiceThisBatch = true;
|
|
3354
|
-
|
|
3849
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
3355
3850
|
`formFillHandler: selected visible option for "${fieldId}"` + (selectResult.selectedLabel ? ` \u2192 "${selectResult.selectedLabel}"` : "")
|
|
3356
3851
|
);
|
|
3357
|
-
await
|
|
3852
|
+
await sleep3(120);
|
|
3358
3853
|
fieldResults.push({ fieldId, success: true });
|
|
3359
3854
|
continue;
|
|
3360
3855
|
}
|
|
3361
3856
|
selectFailure = selectResult;
|
|
3362
3857
|
}
|
|
3363
|
-
|
|
3858
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(`formFillHandler: registry miss for "${fieldId}", falling back to fiber tree`);
|
|
3364
3859
|
const handle = findInteractiveByIdentifier(fieldId, {
|
|
3365
3860
|
kind: effectiveFieldType === "toggle" ? "toggle" : "field"
|
|
3366
3861
|
});
|
|
3367
3862
|
if (handle?.setValue) {
|
|
3368
3863
|
try {
|
|
3864
|
+
if (handle.disabled || (handle.matchCount ?? 1) > 1) {
|
|
3865
|
+
fieldResults.push({
|
|
3866
|
+
fieldId,
|
|
3867
|
+
success: false,
|
|
3868
|
+
error: handle.disabled ? "The field is disabled" : "The field identifier matches multiple controls",
|
|
3869
|
+
diagnose: {
|
|
3870
|
+
category: handle.disabled ? "disabled" : "ambiguous-target",
|
|
3871
|
+
fieldId,
|
|
3872
|
+
screen: screenPath,
|
|
3873
|
+
candidates: handle.matchCandidates
|
|
3874
|
+
}
|
|
3875
|
+
});
|
|
3876
|
+
allSuccess = false;
|
|
3877
|
+
continue;
|
|
3878
|
+
}
|
|
3879
|
+
setSpotlightTarget(handle.measure?.() ?? null, handle.label, "fill");
|
|
3369
3880
|
handle.focus?.();
|
|
3370
3881
|
handle.setValue(value);
|
|
3371
|
-
|
|
3882
|
+
if (handle.kind === "field" && !await completeTextEdit(fieldId, value, void 0, handle)) {
|
|
3883
|
+
fieldResults.push({
|
|
3884
|
+
fieldId,
|
|
3885
|
+
success: false,
|
|
3886
|
+
error: "The field did not retain the requested value after editing ended. Inspect its current value before retrying.",
|
|
3887
|
+
diagnose: { category: "validation", fieldId, screen: screenPath }
|
|
3888
|
+
});
|
|
3889
|
+
allSuccess = false;
|
|
3890
|
+
continue;
|
|
3891
|
+
}
|
|
3892
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
3372
3893
|
`formFillHandler: fiber fallback succeeded for "${fieldId}" \u2192 label="${handle.label}"`
|
|
3373
3894
|
);
|
|
3374
3895
|
fieldResults.push({ fieldId, success: true });
|
|
@@ -3415,14 +3936,15 @@ async function formFillHandler(payload, context) {
|
|
|
3415
3936
|
}
|
|
3416
3937
|
if (!allSuccess) {
|
|
3417
3938
|
const failedIds = fieldResults.filter((result) => !result.success).map((result) => result.fieldId);
|
|
3418
|
-
|
|
3939
|
+
chunkQAZ4TN3Z_js.appilotsDebugWarn(
|
|
3419
3940
|
"formFillHandler: submitAfterFill=true requested but some fields failed; NOT submitting" + (failedIds.length > 0 ? ` (failed: ${failedIds.join(", ")})` : "")
|
|
3420
3941
|
);
|
|
3421
3942
|
} else {
|
|
3422
|
-
await
|
|
3943
|
+
await sleep3(120);
|
|
3423
3944
|
if (!permissions.canSubmitForms) {
|
|
3424
3945
|
return { success: false, error: "Form submission is not permitted", fieldResults };
|
|
3425
3946
|
}
|
|
3947
|
+
const beforeSubmitTexts = captureSnapshot().texts;
|
|
3426
3948
|
const submitResult = pressSubmitButton(
|
|
3427
3949
|
{
|
|
3428
3950
|
screen,
|
|
@@ -3433,7 +3955,7 @@ async function formFillHandler(payload, context) {
|
|
|
3433
3955
|
registry
|
|
3434
3956
|
);
|
|
3435
3957
|
if (!submitResult.success) {
|
|
3436
|
-
|
|
3958
|
+
chunkQAZ4TN3Z_js.appilotsDebugWarn(`formFillHandler: submitAfterFill failed \u2014 ${submitResult.error}`);
|
|
3437
3959
|
return {
|
|
3438
3960
|
success: false,
|
|
3439
3961
|
error: submitResult.error,
|
|
@@ -3442,10 +3964,11 @@ async function formFillHandler(payload, context) {
|
|
|
3442
3964
|
};
|
|
3443
3965
|
}
|
|
3444
3966
|
const postSubmit = await waitForPostSubmitOutcome({
|
|
3445
|
-
submitTargetId: submitResult.pressedTargetId
|
|
3967
|
+
submitTargetId: submitResult.pressedTargetId,
|
|
3968
|
+
beforeTexts: beforeSubmitTexts
|
|
3446
3969
|
});
|
|
3447
3970
|
if (postSubmit.status === "pending") {
|
|
3448
|
-
|
|
3971
|
+
chunkQAZ4TN3Z_js.appilotsDebugWarn(`formFillHandler: submit still pending \u2014 ${postSubmit.message}`);
|
|
3449
3972
|
return {
|
|
3450
3973
|
success: false,
|
|
3451
3974
|
error: postSubmit.message,
|
|
@@ -3454,7 +3977,7 @@ async function formFillHandler(payload, context) {
|
|
|
3454
3977
|
};
|
|
3455
3978
|
}
|
|
3456
3979
|
if (postSubmit.status === "failure") {
|
|
3457
|
-
|
|
3980
|
+
chunkQAZ4TN3Z_js.appilotsDebugWarn(
|
|
3458
3981
|
`formFillHandler: submit rejected by visible validation \u2014 ${postSubmit.message}`
|
|
3459
3982
|
);
|
|
3460
3983
|
return {
|
|
@@ -3469,7 +3992,10 @@ async function formFillHandler(payload, context) {
|
|
|
3469
3992
|
}
|
|
3470
3993
|
};
|
|
3471
3994
|
}
|
|
3472
|
-
|
|
3995
|
+
if (postSubmit.status === "unverified") {
|
|
3996
|
+
return { success: true, fieldResults, effect: "unknown" };
|
|
3997
|
+
}
|
|
3998
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog("formFillHandler: submitAfterFill \u2014 submit completed");
|
|
3473
3999
|
}
|
|
3474
4000
|
}
|
|
3475
4001
|
const aggregatedDiagnose = aggregateFieldDiagnoses(fieldResults, screenPath);
|
|
@@ -3481,17 +4007,17 @@ async function formFillHandler(payload, context) {
|
|
|
3481
4007
|
};
|
|
3482
4008
|
}
|
|
3483
4009
|
function pressSubmitButton(context, registry) {
|
|
3484
|
-
const activePath = context.activePath ??
|
|
4010
|
+
const activePath = context.activePath ?? chunkQAZ4TN3Z_js.getActiveRouteNames();
|
|
3485
4011
|
const hintScreen = context.screen ?? context.screenPath;
|
|
3486
4012
|
const formScreens = resolveFormScreensForSubmit(hintScreen, activePath, registry);
|
|
3487
|
-
const resolvedScreen = formScreens.find((name) => screenDeclaresSubmit(name)) ?? formScreens[0] ?? hintScreen ??
|
|
4013
|
+
const resolvedScreen = formScreens.find((name) => screenDeclaresSubmit(name)) ?? formScreens[0] ?? hintScreen ?? chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0;
|
|
3488
4014
|
const candidates = collectSubmitTargetCandidates(formScreens, registry);
|
|
3489
4015
|
for (const candidate of candidates) {
|
|
3490
4016
|
const target = registry.getTarget(candidate);
|
|
3491
4017
|
if (target) {
|
|
3492
4018
|
try {
|
|
3493
4019
|
target.press();
|
|
3494
|
-
|
|
4020
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
3495
4021
|
`formFillHandler: submitAfterFill \u2014 pressed registry target "${candidate}"` + (resolvedScreen ? ` on screen "${resolvedScreen}"` : "")
|
|
3496
4022
|
);
|
|
3497
4023
|
return { success: true, pressedTargetId: candidate };
|
|
@@ -3505,7 +4031,7 @@ function pressSubmitButton(context, registry) {
|
|
|
3505
4031
|
}
|
|
3506
4032
|
}
|
|
3507
4033
|
for (const screenName of formScreens) {
|
|
3508
|
-
const screenMeta =
|
|
4034
|
+
const screenMeta = chunkQAZ4TN3Z_js.getScreenMetadata(screenName);
|
|
3509
4035
|
const submitMeta = Array.isArray(screenMeta?.actions) ? screenMeta.actions.find(
|
|
3510
4036
|
(action) => typeof action === "object" && action !== null && action.type === "submit"
|
|
3511
4037
|
) : void 0;
|
|
@@ -3516,7 +4042,7 @@ function pressSubmitButton(context, registry) {
|
|
|
3516
4042
|
if (handle?.press) {
|
|
3517
4043
|
try {
|
|
3518
4044
|
handle.press();
|
|
3519
|
-
|
|
4045
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 fiber fallback "${submitLabel}"`);
|
|
3520
4046
|
return { success: true, pressedTargetId: submitId ?? submitLabel };
|
|
3521
4047
|
} catch (err) {
|
|
3522
4048
|
return {
|
|
@@ -3538,7 +4064,7 @@ function pressSubmitButton(context, registry) {
|
|
|
3538
4064
|
if (id) {
|
|
3539
4065
|
const pressed = pressTargetByIdOrLabel(id, registry);
|
|
3540
4066
|
if (pressed.success) {
|
|
3541
|
-
|
|
4067
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 pressed visible heuristic "${id}"`);
|
|
3542
4068
|
return { success: true, pressedTargetId: id };
|
|
3543
4069
|
}
|
|
3544
4070
|
}
|
|
@@ -3552,7 +4078,7 @@ function pressSubmitButton(context, registry) {
|
|
|
3552
4078
|
if (target) {
|
|
3553
4079
|
try {
|
|
3554
4080
|
target.press();
|
|
3555
|
-
|
|
4081
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
3556
4082
|
`formFillHandler: submitAfterFill \u2014 pressed by label heuristic "${comp.label}"`
|
|
3557
4083
|
);
|
|
3558
4084
|
return { success: true, pressedTargetId: comp.id };
|
|
@@ -3568,7 +4094,7 @@ function pressSubmitButton(context, registry) {
|
|
|
3568
4094
|
for (const fieldId of [...context.filledFieldIds ?? []].reverse()) {
|
|
3569
4095
|
const handle = findInteractiveByIdentifier(fieldId, { kind: "field" });
|
|
3570
4096
|
if (handle?.submitFromKeyboard?.()) {
|
|
3571
|
-
|
|
4097
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 return key on "${fieldId}"`);
|
|
3572
4098
|
return { success: true, pressedTargetId: fieldId };
|
|
3573
4099
|
}
|
|
3574
4100
|
}
|
|
@@ -3606,7 +4132,21 @@ function aggregateFieldDiagnoses(results, screen) {
|
|
|
3606
4132
|
var FALLBACK_PAGE_PX = 600;
|
|
3607
4133
|
var PAGE_FRACTION = 0.85;
|
|
3608
4134
|
var POST_SCROLL_MOUNT_MS = 400;
|
|
3609
|
-
var
|
|
4135
|
+
var PAGINATION_MAX_WAIT_MS = 4e3;
|
|
4136
|
+
var PAGINATION_POLL_MS = 150;
|
|
4137
|
+
var sleep4 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
4138
|
+
async function settleAfterScroll() {
|
|
4139
|
+
await sleep4(POST_SCROLL_MOUNT_MS);
|
|
4140
|
+
if (!chunkQAZ4TN3Z_js.probeLoadingState(void 0, chunkQAZ4TN3Z_js.getCurrentScreen()).loading) return;
|
|
4141
|
+
const deadline = Date.now() + PAGINATION_MAX_WAIT_MS;
|
|
4142
|
+
while (Date.now() < deadline) {
|
|
4143
|
+
await sleep4(PAGINATION_POLL_MS);
|
|
4144
|
+
if (!chunkQAZ4TN3Z_js.probeLoadingState(void 0, chunkQAZ4TN3Z_js.getCurrentScreen()).loading) {
|
|
4145
|
+
await sleep4(POST_SCROLL_MOUNT_MS);
|
|
4146
|
+
return;
|
|
4147
|
+
}
|
|
4148
|
+
}
|
|
4149
|
+
}
|
|
3610
4150
|
function normalizeId2(value) {
|
|
3611
4151
|
return String(value ?? "").toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "");
|
|
3612
4152
|
}
|
|
@@ -3614,12 +4154,12 @@ function buildDiagnose(category, targetId, candidates) {
|
|
|
3614
4154
|
return {
|
|
3615
4155
|
category,
|
|
3616
4156
|
targetId,
|
|
3617
|
-
screen:
|
|
4157
|
+
screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0,
|
|
3618
4158
|
...candidates && candidates.length > 0 ? { candidates: candidates.slice(0, 8) } : {}
|
|
3619
4159
|
};
|
|
3620
4160
|
}
|
|
3621
4161
|
function resolveListEntry(listId) {
|
|
3622
|
-
const entries =
|
|
4162
|
+
const entries = chunkQAZ4TN3Z_js.listRegistry.snapshot();
|
|
3623
4163
|
if (entries.length === 0) return {};
|
|
3624
4164
|
if (listId) {
|
|
3625
4165
|
const wanted = normalizeId2(listId);
|
|
@@ -3642,13 +4182,26 @@ function pageOffset(metrics, direction) {
|
|
|
3642
4182
|
}
|
|
3643
4183
|
return next;
|
|
3644
4184
|
}
|
|
4185
|
+
async function finishScroll(entry, before) {
|
|
4186
|
+
await settleAfterScroll();
|
|
4187
|
+
const current2 = chunkQAZ4TN3Z_js.listRegistry.get(entry.id) ?? entry;
|
|
4188
|
+
const after = current2.getScrollMetrics?.();
|
|
4189
|
+
const grew = typeof entry.itemCount === "number" && typeof current2.itemCount === "number" && current2.itemCount > entry.itemCount;
|
|
4190
|
+
const moved = grew || !!(before && after && (Math.abs(after.offset - before.offset) > 2 || after.contentLength > before.contentLength + 2));
|
|
4191
|
+
const outcome = moved ? "moved" : before && after ? "no-progress" : "unverified";
|
|
4192
|
+
current2.exploration?.recordScroll(outcome);
|
|
4193
|
+
return {
|
|
4194
|
+
success: true,
|
|
4195
|
+
effect: moved ? "changed" : outcome === "no-progress" ? "none" : "unknown"
|
|
4196
|
+
};
|
|
4197
|
+
}
|
|
3645
4198
|
async function scrollListHandler(payload, context) {
|
|
3646
4199
|
const { permissions } = context;
|
|
3647
4200
|
if (!permissions.canInteractUI) {
|
|
3648
4201
|
return {
|
|
3649
4202
|
success: false,
|
|
3650
|
-
error: "UI interaction
|
|
3651
|
-
diagnose: buildDiagnose("unknown", payload.listId)
|
|
4203
|
+
error: chunkQAZ4TN3Z_js.permissionDeniedMessage("UI interaction", "canInteractUI"),
|
|
4204
|
+
diagnose: { ...buildDiagnose("unknown", payload.listId), recoverable: false }
|
|
3652
4205
|
};
|
|
3653
4206
|
}
|
|
3654
4207
|
const toIndex = typeof payload.toIndex === "number" ? payload.toIndex : void 0;
|
|
@@ -3676,6 +4229,15 @@ async function scrollListHandler(payload, context) {
|
|
|
3676
4229
|
diagnose: buildDiagnose("component-not-found", payload.listId, candidates)
|
|
3677
4230
|
};
|
|
3678
4231
|
}
|
|
4232
|
+
const exploration = entry.exploration?.snapshot();
|
|
4233
|
+
if (exploration && (exploration.remainingScrollSteps === 0 || exploration.consecutiveNoProgress >= 2)) {
|
|
4234
|
+
return {
|
|
4235
|
+
success: false,
|
|
4236
|
+
effect: "none",
|
|
4237
|
+
error: "List exploration stopped: scroll budget exhausted or repeated no progress. Use the current loaded count/coverage and report any remaining uncertainty; do not repeat this scroll.",
|
|
4238
|
+
diagnose: { ...buildDiagnose("validation", entry.id), recoverable: false }
|
|
4239
|
+
};
|
|
4240
|
+
}
|
|
3679
4241
|
if (toIndex !== void 0) {
|
|
3680
4242
|
if (entry.kind === "scroll") {
|
|
3681
4243
|
return {
|
|
@@ -3691,17 +4253,16 @@ async function scrollListHandler(payload, context) {
|
|
|
3691
4253
|
diagnose: buildDiagnose("validation", entry.id)
|
|
3692
4254
|
};
|
|
3693
4255
|
}
|
|
4256
|
+
const before = entry.getScrollMetrics?.();
|
|
3694
4257
|
const zeroBased = toIndex - 1;
|
|
3695
4258
|
if (entry.scrollToIndex?.(zeroBased)) {
|
|
3696
|
-
|
|
3697
|
-
return { success: true };
|
|
4259
|
+
return finishScroll(entry, before);
|
|
3698
4260
|
}
|
|
3699
4261
|
const metrics2 = entry.getScrollMetrics?.();
|
|
3700
4262
|
if (metrics2 && metrics2.contentLength > 0 && typeof entry.itemCount === "number" && entry.itemCount > 0) {
|
|
3701
4263
|
const estimated = zeroBased / entry.itemCount * metrics2.contentLength;
|
|
3702
4264
|
if (entry.scrollToOffset?.(Math.max(0, estimated))) {
|
|
3703
|
-
|
|
3704
|
-
return { success: true };
|
|
4265
|
+
return finishScroll(entry, before);
|
|
3705
4266
|
}
|
|
3706
4267
|
}
|
|
3707
4268
|
return {
|
|
@@ -3711,10 +4272,21 @@ async function scrollListHandler(payload, context) {
|
|
|
3711
4272
|
};
|
|
3712
4273
|
}
|
|
3713
4274
|
const metrics = entry.getScrollMetrics?.();
|
|
4275
|
+
if (!metrics && exploration?.lastScroll === "unverified") {
|
|
4276
|
+
return {
|
|
4277
|
+
success: false,
|
|
4278
|
+
effect: "unknown",
|
|
4279
|
+
error: "Scroll offset is still unavailable after one probe. Cannot safely page again; do not infer the end or repeat the same absolute offset.",
|
|
4280
|
+
diagnose: { ...buildDiagnose("validation", entry.id), recoverable: false }
|
|
4281
|
+
};
|
|
4282
|
+
}
|
|
3714
4283
|
const target = pageOffset(metrics, direction);
|
|
4284
|
+
if (metrics && Math.abs(target - metrics.offset) <= 2) {
|
|
4285
|
+
entry.exploration?.recordScroll("boundary");
|
|
4286
|
+
return { success: true, effect: "none" };
|
|
4287
|
+
}
|
|
3715
4288
|
if (entry.scrollToOffset?.(target)) {
|
|
3716
|
-
|
|
3717
|
-
return { success: true };
|
|
4289
|
+
return finishScroll(entry, metrics);
|
|
3718
4290
|
}
|
|
3719
4291
|
return {
|
|
3720
4292
|
success: false,
|
|
@@ -3763,12 +4335,12 @@ function resolveActionHints(screen, pressedComponentId, actionPayload) {
|
|
|
3763
4335
|
if (typeof declared === "number") return { asyncBudgetMs: declared };
|
|
3764
4336
|
}
|
|
3765
4337
|
if (!screen || !pressedComponentId) return void 0;
|
|
3766
|
-
const meta =
|
|
4338
|
+
const meta = chunkQAZ4TN3Z_js.getScreenMetadata(screen);
|
|
3767
4339
|
const actions = meta?.actions;
|
|
3768
4340
|
if (!actions || actions.length === 0) return void 0;
|
|
3769
4341
|
for (const a of actions) {
|
|
3770
4342
|
if (typeof a === "string") continue;
|
|
3771
|
-
if (
|
|
4343
|
+
if (chunkQAZ4TN3Z_js.idLooselyMatches(a.id, pressedComponentId)) {
|
|
3772
4344
|
const inferred = a.appilotsInferred;
|
|
3773
4345
|
const declared = a.asyncBudgetMs;
|
|
3774
4346
|
const hints = {
|
|
@@ -3798,12 +4370,12 @@ function hashFieldValue(value) {
|
|
|
3798
4370
|
}
|
|
3799
4371
|
return (hash >>> 0).toString(36);
|
|
3800
4372
|
}
|
|
3801
|
-
var DISCRETE_FIELD_TYPES = /* @__PURE__ */ new Set(["select", "date"]);
|
|
4373
|
+
var DISCRETE_FIELD_TYPES = /* @__PURE__ */ new Set(["select", "date", "number"]);
|
|
3802
4374
|
function discreteFieldSignature() {
|
|
3803
4375
|
const sigs = [];
|
|
3804
|
-
for (const { id, kind } of
|
|
4376
|
+
for (const { id, kind } of chunkQAZ4TN3Z_js.componentRegistry.snapshot()) {
|
|
3805
4377
|
if (kind !== "field") continue;
|
|
3806
|
-
const entry =
|
|
4378
|
+
const entry = chunkQAZ4TN3Z_js.componentRegistry.getField(id);
|
|
3807
4379
|
if (!entry || !DISCRETE_FIELD_TYPES.has(entry.fieldType ?? "")) continue;
|
|
3808
4380
|
try {
|
|
3809
4381
|
sigs.push(`${id}:${hashFieldValue(String(entry.getValue() ?? ""))}`);
|
|
@@ -3812,35 +4384,46 @@ function discreteFieldSignature() {
|
|
|
3812
4384
|
}
|
|
3813
4385
|
return sigs.sort().join(",");
|
|
3814
4386
|
}
|
|
3815
|
-
|
|
4387
|
+
function capturePreInteractionBaseline(payload) {
|
|
3816
4388
|
const targetId = targetIdFromPayload(payload);
|
|
3817
|
-
const
|
|
3818
|
-
const
|
|
3819
|
-
|
|
3820
|
-
|
|
4389
|
+
const screen = chunkQAZ4TN3Z_js.getCurrentScreen();
|
|
4390
|
+
const probe = chunkQAZ4TN3Z_js.probeLoadingState(targetId || null, screen);
|
|
4391
|
+
return {
|
|
4392
|
+
fingerprint: probe.fingerprint,
|
|
4393
|
+
fields: discreteFieldSignature(),
|
|
4394
|
+
screen,
|
|
4395
|
+
readable: probe.fingerprint !== ""
|
|
4396
|
+
};
|
|
4397
|
+
}
|
|
4398
|
+
async function waitForPostInteractionSettle(payload, preBaseline) {
|
|
4399
|
+
const targetId = targetIdFromPayload(payload);
|
|
4400
|
+
const baseline = preBaseline ?? capturePreInteractionBaseline(payload);
|
|
4401
|
+
const fromScreen = baseline.screen;
|
|
4402
|
+
const baselineFields = baseline.fields;
|
|
4403
|
+
const readable = baseline.readable;
|
|
3821
4404
|
await sleepMs(100);
|
|
3822
|
-
const afterPress =
|
|
4405
|
+
const afterPress = chunkQAZ4TN3Z_js.probeLoadingState(targetId || null, chunkQAZ4TN3Z_js.getCurrentScreen());
|
|
3823
4406
|
const modalOrLoading = afterPress.modalOpen || afterPress.loading || afterPress.pressedDisabled;
|
|
3824
4407
|
const fingerprintChanged = afterPress.fingerprint !== baseline.fingerprint;
|
|
3825
4408
|
const verdict = () => {
|
|
3826
4409
|
if (!readable) return { effect: "unknown" };
|
|
3827
|
-
const settled =
|
|
4410
|
+
const settled = chunkQAZ4TN3Z_js.probeLoadingState(targetId || null, chunkQAZ4TN3Z_js.getCurrentScreen());
|
|
3828
4411
|
if (settled.fingerprint === "") return { effect: "unknown" };
|
|
3829
4412
|
if (discreteFieldSignature() !== baselineFields) return { effect: "changed" };
|
|
3830
4413
|
return { effect: settled.fingerprint !== baseline.fingerprint ? "changed" : "none" };
|
|
3831
4414
|
};
|
|
3832
4415
|
const declared = declaredBudgetMs(resolveActionHints(fromScreen, targetId || null, payload));
|
|
3833
|
-
const capMs = declared ?? (
|
|
4416
|
+
const capMs = declared ?? (chunkQAZ4TN3Z_js.isListItemPressTarget(targetId) ? 5e3 : 1e4);
|
|
3834
4417
|
if (modalOrLoading || fingerprintChanged) {
|
|
3835
|
-
await
|
|
4418
|
+
await chunkQAZ4TN3Z_js.waitForLoadingSettle({
|
|
3836
4419
|
pressedComponentId: targetId || null,
|
|
3837
4420
|
fromScreen,
|
|
3838
4421
|
maxMs: capMs
|
|
3839
4422
|
});
|
|
3840
4423
|
return verdict();
|
|
3841
4424
|
}
|
|
3842
|
-
if (
|
|
3843
|
-
await
|
|
4425
|
+
if (chunkQAZ4TN3Z_js.isListItemPressTarget(targetId)) {
|
|
4426
|
+
await chunkQAZ4TN3Z_js.waitForLoadingSettle({
|
|
3844
4427
|
fromScreen,
|
|
3845
4428
|
maxMs: 3e3
|
|
3846
4429
|
});
|
|
@@ -3849,19 +4432,13 @@ async function waitForPostInteractionSettle(payload) {
|
|
|
3849
4432
|
}
|
|
3850
4433
|
|
|
3851
4434
|
// src/executor/ActionExecutor.ts
|
|
3852
|
-
var DEFAULT_PERMISSIONS = {
|
|
3853
|
-
canNavigate: true,
|
|
3854
|
-
canFillForms: true,
|
|
3855
|
-
canInteractUI: true,
|
|
3856
|
-
canSubmitForms: true
|
|
3857
|
-
};
|
|
3858
4435
|
function validateActionPayload(action) {
|
|
3859
4436
|
const invalid = (message, ids) => ({
|
|
3860
4437
|
success: false,
|
|
3861
4438
|
error: message,
|
|
3862
4439
|
diagnose: {
|
|
3863
4440
|
category: "validation",
|
|
3864
|
-
screen:
|
|
4441
|
+
screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0,
|
|
3865
4442
|
...ids ?? {}
|
|
3866
4443
|
}
|
|
3867
4444
|
});
|
|
@@ -3922,10 +4499,10 @@ function isDestructivePayload(payload) {
|
|
|
3922
4499
|
return !!params && typeof params === "object" && params.destructive === true;
|
|
3923
4500
|
}
|
|
3924
4501
|
async function executeAction(action, context) {
|
|
3925
|
-
|
|
4502
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
3926
4503
|
`executeAction called: type="${action.type}", id="${action.id}", payload=${JSON.stringify(action.payload)}`
|
|
3927
4504
|
);
|
|
3928
|
-
const permissions = context.permissions
|
|
4505
|
+
const permissions = chunkQAZ4TN3Z_js.resolveAgentPermissions(context.permissions);
|
|
3929
4506
|
context.emit({
|
|
3930
4507
|
type: "agent:action:start",
|
|
3931
4508
|
timestamp: Date.now(),
|
|
@@ -3951,7 +4528,7 @@ async function executeAction(action, context) {
|
|
|
3951
4528
|
let result;
|
|
3952
4529
|
const validationFailure = validateActionPayload(action);
|
|
3953
4530
|
if (validationFailure) {
|
|
3954
|
-
|
|
4531
|
+
chunkQAZ4TN3Z_js.appilotsDebugWarn(
|
|
3955
4532
|
`executeAction: payload validation failed for type="${action.type}" id="${action.id}": ${validationFailure.error}`
|
|
3956
4533
|
);
|
|
3957
4534
|
context.emit({
|
|
@@ -3978,17 +4555,18 @@ async function executeAction(action, context) {
|
|
|
3978
4555
|
case "form_fill":
|
|
3979
4556
|
result = await formFillHandler(action.payload, {
|
|
3980
4557
|
permissions,
|
|
3981
|
-
registry: context.registry ??
|
|
4558
|
+
registry: context.registry ?? chunkQAZ4TN3Z_js.getDefaultRegistry()
|
|
3982
4559
|
});
|
|
3983
4560
|
break;
|
|
3984
4561
|
case "ui_interaction": {
|
|
3985
4562
|
const payload = action.payload;
|
|
4563
|
+
const baseline = capturePreInteractionBaseline(payload);
|
|
3986
4564
|
result = uiInteractionHandler(payload, {
|
|
3987
4565
|
permissions,
|
|
3988
|
-
registry: context.registry ??
|
|
4566
|
+
registry: context.registry ?? chunkQAZ4TN3Z_js.getDefaultRegistry()
|
|
3989
4567
|
});
|
|
3990
4568
|
if (result.success) {
|
|
3991
|
-
const settle = await waitForPostInteractionSettle(payload);
|
|
4569
|
+
const settle = await waitForPostInteractionSettle(payload, baseline);
|
|
3992
4570
|
result.effect = result.effect ?? effectFor(payload, settle.effect);
|
|
3993
4571
|
}
|
|
3994
4572
|
break;
|
|
@@ -4014,7 +4592,7 @@ async function executeAction(action, context) {
|
|
|
4014
4592
|
};
|
|
4015
4593
|
}
|
|
4016
4594
|
} catch (err) {
|
|
4017
|
-
|
|
4595
|
+
chunkQAZ4TN3Z_js.appilotsDebugWarn(
|
|
4018
4596
|
`executeAction: exception during action type="${action.type}" id="${action.id}": ${err?.message}`
|
|
4019
4597
|
);
|
|
4020
4598
|
result = {
|
|
@@ -4022,7 +4600,7 @@ async function executeAction(action, context) {
|
|
|
4022
4600
|
error: err?.message ?? "Action execution failed unexpectedly"
|
|
4023
4601
|
};
|
|
4024
4602
|
}
|
|
4025
|
-
|
|
4603
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
4026
4604
|
`executeAction result: type="${action.type}", id="${action.id}", success=${result.success}, error=${result.error ?? "none"}`
|
|
4027
4605
|
);
|
|
4028
4606
|
context.emit({
|
|
@@ -4076,18 +4654,28 @@ var _patchedAlert = (title, message, buttons, options) => {
|
|
|
4076
4654
|
return suppression.originalAlert(title, message, buttons, options);
|
|
4077
4655
|
}
|
|
4078
4656
|
suppression.consumed = true;
|
|
4079
|
-
|
|
4657
|
+
const report = (handlerCompleted) => suppression.onHandled?.({
|
|
4658
|
+
title: title.slice(0, 300),
|
|
4659
|
+
message: message?.slice(0, 1e3),
|
|
4660
|
+
buttonLabel: button.text?.slice(0, 160),
|
|
4661
|
+
handlerCompleted
|
|
4662
|
+
});
|
|
4663
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog("Suppressing native Alert during already-confirmed destructive agent action");
|
|
4080
4664
|
try {
|
|
4081
|
-
suppression.pending = Promise.resolve(button.onPress()).then(() =>
|
|
4665
|
+
suppression.pending = Promise.resolve(button.onPress()).then(() => report(true)).catch((err) => {
|
|
4666
|
+
reportHandlerFailure(err);
|
|
4667
|
+
report(false);
|
|
4668
|
+
});
|
|
4082
4669
|
} catch (err) {
|
|
4083
4670
|
reportHandlerFailure(err);
|
|
4084
4671
|
suppression.pending = null;
|
|
4672
|
+
report(false);
|
|
4085
4673
|
}
|
|
4086
4674
|
};
|
|
4087
4675
|
function reportHandlerFailure(err) {
|
|
4088
4676
|
console.error("[Appilots] The app\u2019s Alert handler threw while being auto-confirmed", err);
|
|
4089
4677
|
}
|
|
4090
|
-
async function runWithConfirmedDestructiveContext(enabled, host, fn) {
|
|
4678
|
+
async function runWithConfirmedDestructiveContext(enabled, host, fn, onHandled) {
|
|
4091
4679
|
if (!enabled) return fn();
|
|
4092
4680
|
if (_active) {
|
|
4093
4681
|
_active.depth += 1;
|
|
@@ -4108,6 +4696,7 @@ async function runWithConfirmedDestructiveContext(enabled, host, fn) {
|
|
|
4108
4696
|
depth: 1,
|
|
4109
4697
|
consumed: false,
|
|
4110
4698
|
pending: null,
|
|
4699
|
+
onHandled,
|
|
4111
4700
|
timer: null
|
|
4112
4701
|
};
|
|
4113
4702
|
_active = suppression;
|
|
@@ -4127,45 +4716,67 @@ async function runWithConfirmedDestructiveContext(enabled, host, fn) {
|
|
|
4127
4716
|
}
|
|
4128
4717
|
|
|
4129
4718
|
// src/platform/reactNativeAdapter.ts
|
|
4130
|
-
var deltaTracker =
|
|
4719
|
+
var deltaTracker = chunkQAZ4TN3Z_js.createSnapshotDeltaTracker();
|
|
4131
4720
|
function resolveScreenMetadata() {
|
|
4132
|
-
const activePath =
|
|
4721
|
+
const activePath = chunkQAZ4TN3Z_js.getActiveRouteNames();
|
|
4133
4722
|
for (let i = activePath.length - 1; i >= 0; i--) {
|
|
4134
4723
|
const name = activePath[i];
|
|
4135
|
-
const meta = name ?
|
|
4724
|
+
const meta = name ? chunkQAZ4TN3Z_js.getScreenMetadata(name) : void 0;
|
|
4136
4725
|
if (meta && (Array.isArray(meta.fields) && meta.fields.length > 0 || Array.isArray(meta.actions) && meta.actions.length > 0)) {
|
|
4137
4726
|
return meta;
|
|
4138
4727
|
}
|
|
4139
4728
|
}
|
|
4140
|
-
const screen =
|
|
4141
|
-
return screen ?
|
|
4729
|
+
const screen = chunkQAZ4TN3Z_js.getCurrentScreen();
|
|
4730
|
+
return screen ? chunkQAZ4TN3Z_js.getScreenMetadata(screen) : void 0;
|
|
4142
4731
|
}
|
|
4143
4732
|
function buildAgentContext(extras = {}) {
|
|
4144
|
-
if (extras.newMission === true)
|
|
4733
|
+
if (extras.newMission === true) {
|
|
4734
|
+
deltaTracker.reset();
|
|
4735
|
+
for (const entry of chunkQAZ4TN3Z_js.listRegistry.snapshot()) entry.exploration?.reset();
|
|
4736
|
+
}
|
|
4145
4737
|
const context = {};
|
|
4146
4738
|
context.platform = "react-native";
|
|
4147
|
-
|
|
4739
|
+
context.missionProtocol = 1;
|
|
4740
|
+
context.deviceLocale = detectDeviceLocale() ?? "en";
|
|
4741
|
+
const screen = chunkQAZ4TN3Z_js.getCurrentScreen();
|
|
4148
4742
|
if (screen) context.currentScreen = screen;
|
|
4149
|
-
const navigationState =
|
|
4743
|
+
const navigationState = chunkQAZ4TN3Z_js.getNavigationStateSnapshot();
|
|
4150
4744
|
if (navigationState) context.navigationState = navigationState;
|
|
4151
4745
|
const screenMeta = resolveScreenMetadata();
|
|
4152
4746
|
if (screenMeta) context.screenMetadata = screenMeta;
|
|
4153
4747
|
try {
|
|
4154
4748
|
const snapshot = captureSnapshot();
|
|
4749
|
+
for (const list of snapshot.lists) {
|
|
4750
|
+
const memory = list.id ? chunkQAZ4TN3Z_js.listRegistry.get(list.id)?.exploration : void 0;
|
|
4751
|
+
if (!memory) continue;
|
|
4752
|
+
memory.observe(list.items);
|
|
4753
|
+
list.exploration = memory.snapshot();
|
|
4754
|
+
}
|
|
4155
4755
|
const delta = deltaTracker.observe(snapshot);
|
|
4156
4756
|
if (delta) snapshot.delta = delta;
|
|
4157
4757
|
context.snapshot = snapshot;
|
|
4158
4758
|
} catch (err) {
|
|
4159
|
-
|
|
4759
|
+
chunkQAZ4TN3Z_js.appilotsDebugWarn("buildAgentContext: captureSnapshot failed", err);
|
|
4160
4760
|
}
|
|
4161
|
-
const registry =
|
|
4761
|
+
const registry = chunkQAZ4TN3Z_js.componentRegistry.snapshot();
|
|
4162
4762
|
const filtered = screen ? registry.filter((c) => !c.screen || c.screen === screen) : registry;
|
|
4163
4763
|
if (filtered.length > 0) context.registeredComponents = filtered;
|
|
4164
|
-
const registeredLists =
|
|
4764
|
+
const registeredLists = chunkQAZ4TN3Z_js.listRegistry.snapshot();
|
|
4165
4765
|
if (registeredLists.length > 0) {
|
|
4166
|
-
|
|
4167
|
-
|
|
4766
|
+
const snapshot = context.snapshot;
|
|
4767
|
+
const activeIds = new Set(
|
|
4768
|
+
[...snapshot?.lists ?? [], ...snapshot?.scrollables ?? []].map((l) => l.id)
|
|
4168
4769
|
);
|
|
4770
|
+
context.registeredLists = registeredLists.filter((entry) => activeIds.has(entry.id)).map(({ id, kind, component, itemCount, totalItemCount, label, refreshing, empty }) => ({
|
|
4771
|
+
id,
|
|
4772
|
+
kind,
|
|
4773
|
+
component,
|
|
4774
|
+
itemCount,
|
|
4775
|
+
totalItemCount,
|
|
4776
|
+
label,
|
|
4777
|
+
refreshing,
|
|
4778
|
+
empty
|
|
4779
|
+
}));
|
|
4169
4780
|
}
|
|
4170
4781
|
if (extras.loadingPending === true) context.loadingPending = true;
|
|
4171
4782
|
return context;
|
|
@@ -4175,30 +4786,31 @@ async function settleTurn(input) {
|
|
|
4175
4786
|
let loadingPending = false;
|
|
4176
4787
|
const { turnActions, pressedComponentId: pressedId, navigateTargetScreen } = input;
|
|
4177
4788
|
const successById = new Map(input.results.map((r) => [r.actionId, r.success]));
|
|
4789
|
+
const effectById = new Map(input.results.map((r) => [r.actionId, r.effect]));
|
|
4178
4790
|
const typeById = new Map(input.results.map((r) => [r.actionId, r.type]));
|
|
4179
4791
|
const pressedAction = turnActions.find(
|
|
4180
4792
|
(a) => a.type === "ui_interaction" && a.payload?.componentId === pressedId
|
|
4181
4793
|
);
|
|
4182
4794
|
const hints = resolveActionHints(
|
|
4183
|
-
|
|
4795
|
+
chunkQAZ4TN3Z_js.getCurrentScreen(),
|
|
4184
4796
|
pressedId,
|
|
4185
4797
|
pressedAction?.payload
|
|
4186
4798
|
);
|
|
4187
4799
|
const capSource = typeof hints?.asyncBudgetMs === "number" && hints.asyncBudgetMs > 0 ? " (app-declared)" : hints?.isAsyncTrigger ? " (mcp-inferred)" : "";
|
|
4188
4800
|
if (input.hadNavigate) {
|
|
4189
|
-
const settle = await
|
|
4801
|
+
const settle = await chunkQAZ4TN3Z_js.waitForScreenSettle({
|
|
4190
4802
|
expectingChange: true,
|
|
4191
4803
|
fromScreen: input.preNavigateScreen ?? null,
|
|
4192
4804
|
fromSignature: input.preNavigateSignature ?? null,
|
|
4193
4805
|
targetScreen: navigateTargetScreen,
|
|
4194
4806
|
maxMs: 3500
|
|
4195
4807
|
});
|
|
4196
|
-
|
|
4808
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
4197
4809
|
`settleTurn: post-navigate settle done \u2014 screen="${settle.screen}" transitioned=${settle.transitioned} timedOut=${settle.timedOut} waitedMs=${settle.waitedMs}`
|
|
4198
4810
|
);
|
|
4199
|
-
const navigationMoved = settle.transitioned ||
|
|
4811
|
+
const navigationMoved = settle.transitioned || chunkQAZ4TN3Z_js.screenDepartedBaseline(input.preNavigateScreen ?? null, input.preNavigateSignature ?? null) || !!navigateTargetScreen && !!settle.screen && chunkQAZ4TN3Z_js.routesBelongToSameFeature(settle.screen, navigateTargetScreen);
|
|
4200
4812
|
if (!navigationMoved) {
|
|
4201
|
-
|
|
4813
|
+
chunkQAZ4TN3Z_js.appilotsDebugWarn(
|
|
4202
4814
|
`tool-without-effect: navigate emitted but screen did not change (stayed at "${input.preNavigateScreen ?? "unknown"}", waitedMs=${settle.waitedMs}). Likely causes: target screenName missing from MCP doc, nested-nav path absent, or React Navigation rejected the route.`
|
|
4203
4815
|
);
|
|
4204
4816
|
for (const [actionId, type] of typeById) {
|
|
@@ -4206,50 +4818,51 @@ async function settleTurn(input) {
|
|
|
4206
4818
|
}
|
|
4207
4819
|
}
|
|
4208
4820
|
const postNavigateCapMs = resolvePostNavigateCapMs(hints);
|
|
4209
|
-
const loadSettle = await
|
|
4821
|
+
const loadSettle = await chunkQAZ4TN3Z_js.waitForLoadingSettle({
|
|
4210
4822
|
fromScreen: settle.screen ?? null,
|
|
4211
4823
|
maxMs: postNavigateCapMs
|
|
4212
4824
|
});
|
|
4213
|
-
|
|
4825
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
4214
4826
|
`settleTurn: post-navigate loading settle \u2014 settled=${loadSettle.settled} loadingPending=${loadSettle.loadingPending} probes=${loadSettle.probeCount} waitedMs=${loadSettle.waitedMs} cap=${postNavigateCapMs}${capSource}`
|
|
4215
4827
|
);
|
|
4216
4828
|
if (loadSettle.loadingPending) loadingPending = true;
|
|
4217
4829
|
} else {
|
|
4218
4830
|
const settleCapMs = resolveSettleCapMs(hints);
|
|
4219
4831
|
const busyMaxMs = resolveBusyCeilingMs(hints);
|
|
4220
|
-
const loadSettle = await
|
|
4832
|
+
const loadSettle = await chunkQAZ4TN3Z_js.waitForLoadingSettle({
|
|
4221
4833
|
pressedComponentId: pressedId,
|
|
4222
|
-
fromScreen:
|
|
4834
|
+
fromScreen: chunkQAZ4TN3Z_js.getCurrentScreen(),
|
|
4223
4835
|
maxMs: settleCapMs,
|
|
4224
4836
|
...busyMaxMs !== void 0 ? { busyMaxMs } : {}
|
|
4225
4837
|
});
|
|
4226
|
-
|
|
4838
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
4227
4839
|
`settleTurn: post-action loading settle \u2014 pressedId="${pressedId ?? ""}" settled=${loadSettle.settled} transitioned=${loadSettle.transitioned} loadingPending=${loadSettle.loadingPending} probes=${loadSettle.probeCount} waitedMs=${loadSettle.waitedMs} cap=${settleCapMs}${capSource}${busyMaxMs !== void 0 ? ` busyCap=${busyMaxMs}` : ""}`
|
|
4228
4840
|
);
|
|
4229
4841
|
if (loadSettle.loadingPending) loadingPending = true;
|
|
4230
4842
|
const listPressActions = turnActions.filter((action) => {
|
|
4231
|
-
const target =
|
|
4232
|
-
return target ?
|
|
4843
|
+
const target = chunkQAZ4TN3Z_js.actionPressTargetId(action);
|
|
4844
|
+
return target ? chunkQAZ4TN3Z_js.isListItemPressTarget(target) : false;
|
|
4233
4845
|
});
|
|
4234
4846
|
if (listPressActions.length > 0) {
|
|
4235
|
-
const baselineFingerprint =
|
|
4236
|
-
const postPressSettle = await
|
|
4847
|
+
const baselineFingerprint = chunkQAZ4TN3Z_js.probeLoadingState(pressedId, chunkQAZ4TN3Z_js.getCurrentScreen()).fingerprint;
|
|
4848
|
+
const postPressSettle = await chunkQAZ4TN3Z_js.waitForScreenSettle({
|
|
4237
4849
|
expectingChange: true,
|
|
4238
4850
|
fromScreen: input.preNavigateScreen ?? null,
|
|
4239
4851
|
fromSignature: input.preNavigateSignature ?? null,
|
|
4240
4852
|
maxMs: 2500
|
|
4241
4853
|
});
|
|
4242
|
-
await
|
|
4854
|
+
await chunkQAZ4TN3Z_js.waitForLoadingSettle({
|
|
4243
4855
|
pressedComponentId: pressedId,
|
|
4244
|
-
fromScreen:
|
|
4856
|
+
fromScreen: chunkQAZ4TN3Z_js.getCurrentScreen(),
|
|
4245
4857
|
maxMs: 4e3
|
|
4246
4858
|
});
|
|
4247
|
-
const afterFingerprint =
|
|
4248
|
-
|
|
4859
|
+
const afterFingerprint = chunkQAZ4TN3Z_js.probeLoadingState(pressedId, chunkQAZ4TN3Z_js.getCurrentScreen()).fingerprint;
|
|
4860
|
+
chunkQAZ4TN3Z_js.appilotsDebugLog(
|
|
4249
4861
|
`settleTurn: post-list-press settle \u2014 screen="${postPressSettle.screen}" transitioned=${postPressSettle.transitioned} timedOut=${postPressSettle.timedOut} waitedMs=${postPressSettle.waitedMs}`
|
|
4250
4862
|
);
|
|
4251
4863
|
if (!postPressSettle.transitioned && baselineFingerprint === afterFingerprint) {
|
|
4252
4864
|
for (const action of listPressActions) {
|
|
4865
|
+
if (effectById.get(action.id) === "changed") continue;
|
|
4253
4866
|
if (successById.get(action.id)) {
|
|
4254
4867
|
toolWithoutEffectIds.add(action.id);
|
|
4255
4868
|
}
|
|
@@ -4261,46 +4874,68 @@ async function settleTurn(input) {
|
|
|
4261
4874
|
}
|
|
4262
4875
|
var reactNativeChatAdapter = {
|
|
4263
4876
|
buildContext: buildAgentContext,
|
|
4264
|
-
getCurrentScreen:
|
|
4265
|
-
getCurrentScreenSignature:
|
|
4877
|
+
getCurrentScreen: chunkQAZ4TN3Z_js.getCurrentScreen,
|
|
4878
|
+
getCurrentScreenSignature: chunkQAZ4TN3Z_js.getCurrentScreenSignature,
|
|
4266
4879
|
settleTurn
|
|
4267
4880
|
};
|
|
4268
4881
|
function createReactNativeActionRunner(getOptions) {
|
|
4269
4882
|
return {
|
|
4883
|
+
buildMissionContext: () => reactNativeChatAdapter.buildContext(),
|
|
4270
4884
|
async execute(action, { confirmedDestructive }) {
|
|
4271
|
-
const { permissions, emit, navigationRef, suppressNativeConfirm } = getOptions();
|
|
4272
|
-
const navRef = navigationRef?.current ? navigationRef : { current:
|
|
4273
|
-
|
|
4885
|
+
const { permissions, emit: emit2, navigationRef, suppressNativeConfirm } = getOptions();
|
|
4886
|
+
const navRef = navigationRef?.current ? navigationRef : { current: chunkQAZ4TN3Z_js.getNavigationRef() };
|
|
4887
|
+
let receipt;
|
|
4888
|
+
let terminal;
|
|
4889
|
+
const result = await runWithConfirmedDestructiveContext(
|
|
4274
4890
|
confirmedDestructive && suppressNativeConfirm !== false,
|
|
4275
4891
|
reactNative.Alert,
|
|
4276
4892
|
() => executeAction(action, {
|
|
4277
4893
|
navigationRef: navRef,
|
|
4278
4894
|
permissions,
|
|
4279
|
-
emit
|
|
4280
|
-
|
|
4895
|
+
emit: (event) => {
|
|
4896
|
+
if (confirmedDestructive && (event.type === "agent:action:complete" || event.type === "agent:action:error"))
|
|
4897
|
+
terminal = event;
|
|
4898
|
+
else emit2(event);
|
|
4899
|
+
}
|
|
4900
|
+
}),
|
|
4901
|
+
(handled) => {
|
|
4902
|
+
receipt = handled;
|
|
4903
|
+
}
|
|
4281
4904
|
);
|
|
4905
|
+
const failed = receipt?.handlerCompleted === false;
|
|
4906
|
+
if (terminal)
|
|
4907
|
+
emit2({
|
|
4908
|
+
...terminal,
|
|
4909
|
+
type: failed ? "agent:action:error" : terminal.type,
|
|
4910
|
+
data: {
|
|
4911
|
+
...terminal.data,
|
|
4912
|
+
...receipt ? { nativeConfirmation: receipt } : {},
|
|
4913
|
+
...failed ? { success: false, error: "Native confirmation callback failed" } : {}
|
|
4914
|
+
}
|
|
4915
|
+
});
|
|
4916
|
+
return failed ? { ...result, success: false, error: "Native confirmation callback failed" } : result;
|
|
4282
4917
|
},
|
|
4283
|
-
getCurrentScreen:
|
|
4284
|
-
getCurrentScreenSignature:
|
|
4918
|
+
getCurrentScreen: chunkQAZ4TN3Z_js.getCurrentScreen,
|
|
4919
|
+
getCurrentScreenSignature: chunkQAZ4TN3Z_js.getCurrentScreenSignature,
|
|
4285
4920
|
getScreenActionsMetadata(screen) {
|
|
4286
|
-
return
|
|
4921
|
+
return chunkQAZ4TN3Z_js.getScreenMetadata(screen)?.actions;
|
|
4287
4922
|
},
|
|
4288
|
-
waitForScreenSettle:
|
|
4923
|
+
waitForScreenSettle: chunkQAZ4TN3Z_js.waitForScreenSettle
|
|
4289
4924
|
};
|
|
4290
4925
|
}
|
|
4291
4926
|
|
|
4292
4927
|
// src/hooks/useAppilotsChat.ts
|
|
4293
4928
|
function useAppilotsChat(options = {}) {
|
|
4294
|
-
const { client, emit, subscribe } =
|
|
4929
|
+
const { client, emit: emit2, subscribe } = chunkQAZ4TN3Z_js.useAppilotsContext();
|
|
4295
4930
|
const machine = React.useMemo(
|
|
4296
|
-
() => new
|
|
4297
|
-
{ client, adapter: reactNativeChatAdapter, emit, warn:
|
|
4931
|
+
() => new chunkQAZ4TN3Z_js.ChatSessionMachine(
|
|
4932
|
+
{ client, adapter: reactNativeChatAdapter, emit: emit2, warn: chunkQAZ4TN3Z_js.appilotsDebugWarn },
|
|
4298
4933
|
options
|
|
4299
4934
|
),
|
|
4300
4935
|
// A new machine per client/provider instance — options are pushed in
|
|
4301
4936
|
// below so changing copy never resets the transcript.
|
|
4302
4937
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
4303
|
-
[client,
|
|
4938
|
+
[client, emit2]
|
|
4304
4939
|
);
|
|
4305
4940
|
const optionsRef = React.useRef(options);
|
|
4306
4941
|
optionsRef.current = options;
|
|
@@ -4308,6 +4943,14 @@ function useAppilotsChat(options = {}) {
|
|
|
4308
4943
|
const state = React.useSyncExternalStore(machine.subscribeState, machine.getState, machine.getState);
|
|
4309
4944
|
React.useEffect(() => subscribe(machine.handleEvent), [subscribe, machine]);
|
|
4310
4945
|
React.useEffect(() => () => machine.dispose(), [machine]);
|
|
4946
|
+
React.useEffect(() => {
|
|
4947
|
+
void machine.restoreMission();
|
|
4948
|
+
const subscription = reactNative.AppState?.addEventListener?.("change", (next) => {
|
|
4949
|
+
if (next !== "active" && machine.getState().mission?.status === "running")
|
|
4950
|
+
void machine.pauseMission();
|
|
4951
|
+
});
|
|
4952
|
+
return () => subscription?.remove();
|
|
4953
|
+
}, [machine]);
|
|
4311
4954
|
const requestHuman = React.useCallback(
|
|
4312
4955
|
(reason) => machine.requestHuman(reason),
|
|
4313
4956
|
[machine]
|
|
@@ -4317,7 +4960,13 @@ function useAppilotsChat(options = {}) {
|
|
|
4317
4960
|
const clearMessages = React.useCallback(() => machine.clearMessages(), [machine]);
|
|
4318
4961
|
const clearError = React.useCallback(() => machine.clearError(), [machine]);
|
|
4319
4962
|
return {
|
|
4963
|
+
mission: state.mission,
|
|
4964
|
+
pauseMission: () => machine.pauseMission(),
|
|
4965
|
+
resumeMission: () => machine.resumeMission(),
|
|
4966
|
+
cancelMission: () => machine.cancelMission(),
|
|
4967
|
+
hasStartedActing: state.hasStartedActing,
|
|
4320
4968
|
messages: state.messages,
|
|
4969
|
+
replyLocale: state.replyLocale,
|
|
4321
4970
|
isLoading: state.isLoading,
|
|
4322
4971
|
loadingStatusKey: state.loadingStatusKey,
|
|
4323
4972
|
error: state.error,
|
|
@@ -4330,39 +4979,33 @@ function useAppilotsChat(options = {}) {
|
|
|
4330
4979
|
clearError
|
|
4331
4980
|
};
|
|
4332
4981
|
}
|
|
4333
|
-
var DEFAULT_PERMISSIONS2 = {
|
|
4334
|
-
canNavigate: true,
|
|
4335
|
-
canFillForms: true,
|
|
4336
|
-
canInteractUI: true,
|
|
4337
|
-
canSubmitForms: true
|
|
4338
|
-
};
|
|
4339
4982
|
function useAppilotsActions(options = {}) {
|
|
4340
|
-
const { client, subscribe, config, emit } =
|
|
4983
|
+
const { client, subscribe, config, emit: emit2 } = chunkQAZ4TN3Z_js.useAppilotsContext();
|
|
4341
4984
|
const { navigationRef, autoExecute = false } = options;
|
|
4342
4985
|
const runnerOptionsRef = React.useRef({
|
|
4343
|
-
permissions: config.permissions
|
|
4344
|
-
emit,
|
|
4986
|
+
permissions: chunkQAZ4TN3Z_js.resolveAgentPermissions(config.permissions),
|
|
4987
|
+
emit: emit2,
|
|
4345
4988
|
navigationRef,
|
|
4346
4989
|
suppressNativeConfirm: config.suppressNativeConfirm
|
|
4347
4990
|
});
|
|
4348
4991
|
runnerOptionsRef.current = {
|
|
4349
|
-
permissions: config.permissions
|
|
4350
|
-
emit,
|
|
4992
|
+
permissions: chunkQAZ4TN3Z_js.resolveAgentPermissions(config.permissions),
|
|
4993
|
+
emit: emit2,
|
|
4351
4994
|
navigationRef,
|
|
4352
4995
|
suppressNativeConfirm: config.suppressNativeConfirm
|
|
4353
4996
|
};
|
|
4354
4997
|
const machine = React.useMemo(
|
|
4355
|
-
() => new
|
|
4998
|
+
() => new chunkQAZ4TN3Z_js.ActionQueueMachine(
|
|
4356
4999
|
{
|
|
4357
5000
|
client,
|
|
4358
5001
|
adapter: createReactNativeActionRunner(() => runnerOptionsRef.current),
|
|
4359
|
-
emit,
|
|
4360
|
-
warn:
|
|
5002
|
+
emit: emit2,
|
|
5003
|
+
warn: chunkQAZ4TN3Z_js.appilotsDebugWarn
|
|
4361
5004
|
},
|
|
4362
5005
|
{ autoExecute }
|
|
4363
5006
|
),
|
|
4364
5007
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
4365
|
-
[client,
|
|
5008
|
+
[client, emit2]
|
|
4366
5009
|
);
|
|
4367
5010
|
machine.setOptions({ autoExecute });
|
|
4368
5011
|
const state = React.useSyncExternalStore(machine.subscribeState, machine.getState, machine.getState);
|
|
@@ -4414,7 +5057,7 @@ function shouldShowSuggestedPrompts(args) {
|
|
|
4414
5057
|
|
|
4415
5058
|
// src/hooks/useSuggestedPrompts.ts
|
|
4416
5059
|
function useSuggestedPrompts(options) {
|
|
4417
|
-
const { client } =
|
|
5060
|
+
const { client } = chunkQAZ4TN3Z_js.useAppilotsContext();
|
|
4418
5061
|
const { enabled, limit = 4 } = options;
|
|
4419
5062
|
const [prompts, setPrompts] = React.useState([]);
|
|
4420
5063
|
const [isLoading, setIsLoading] = React.useState(false);
|
|
@@ -4424,8 +5067,8 @@ function useSuggestedPrompts(options) {
|
|
|
4424
5067
|
if (!enabled) return;
|
|
4425
5068
|
const requestId = ++requestIdRef.current;
|
|
4426
5069
|
let cancelled = false;
|
|
4427
|
-
const screen =
|
|
4428
|
-
const localDev = screen ? (
|
|
5070
|
+
const screen = chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0;
|
|
5071
|
+
const localDev = screen ? (chunkQAZ4TN3Z_js.getScreenMetadata(screen)?.suggestedPrompts ?? []).map((text) => ({
|
|
4429
5072
|
text,
|
|
4430
5073
|
source: "dev-defined"
|
|
4431
5074
|
})) : [];
|
|
@@ -4439,7 +5082,7 @@ function useSuggestedPrompts(options) {
|
|
|
4439
5082
|
if (cancelled || requestIdRef.current !== requestId) return;
|
|
4440
5083
|
setPrompts(mergePromptSources(localDev, data, limit));
|
|
4441
5084
|
}).catch((err) => {
|
|
4442
|
-
|
|
5085
|
+
chunkQAZ4TN3Z_js.appilotsDebugWarn("useSuggestedPrompts: fetch failed", err);
|
|
4443
5086
|
}).finally(() => {
|
|
4444
5087
|
if (cancelled || requestIdRef.current !== requestId) return;
|
|
4445
5088
|
setIsLoading(false);
|
|
@@ -4450,11 +5093,11 @@ function useSuggestedPrompts(options) {
|
|
|
4450
5093
|
}, [client, enabled, limit, refreshTick]);
|
|
4451
5094
|
React.useEffect(() => {
|
|
4452
5095
|
if (!enabled) return;
|
|
4453
|
-
let lastScreen =
|
|
5096
|
+
let lastScreen = chunkQAZ4TN3Z_js.getCurrentScreen();
|
|
4454
5097
|
const interval = setInterval(() => {
|
|
4455
|
-
const
|
|
4456
|
-
if (
|
|
4457
|
-
lastScreen =
|
|
5098
|
+
const current2 = chunkQAZ4TN3Z_js.getCurrentScreen();
|
|
5099
|
+
if (current2 !== lastScreen) {
|
|
5100
|
+
lastScreen = current2;
|
|
4458
5101
|
setRefreshTick((t) => t + 1);
|
|
4459
5102
|
}
|
|
4460
5103
|
}, 800);
|
|
@@ -4467,22 +5110,22 @@ function useSuggestedPrompts(options) {
|
|
|
4467
5110
|
};
|
|
4468
5111
|
}
|
|
4469
5112
|
function useAppilotsNavigation() {
|
|
4470
|
-
const { emit } =
|
|
5113
|
+
const { emit: emit2 } = chunkQAZ4TN3Z_js.useAppilotsContext();
|
|
4471
5114
|
const [currentScreen, setCurrentScreenState] = React.useState(null);
|
|
4472
5115
|
const [navigationHistory, setNavigationHistory] = React.useState([]);
|
|
4473
5116
|
const navigationRef = React.useRef(null);
|
|
4474
5117
|
const setCurrentScreen2 = React.useCallback(
|
|
4475
5118
|
(screenName) => {
|
|
4476
5119
|
setCurrentScreenState(screenName);
|
|
4477
|
-
|
|
5120
|
+
chunkQAZ4TN3Z_js.setCurrentScreen(screenName);
|
|
4478
5121
|
setNavigationHistory((prev) => [...prev, screenName]);
|
|
4479
|
-
|
|
5122
|
+
emit2({
|
|
4480
5123
|
type: "navigation:change",
|
|
4481
5124
|
timestamp: Date.now(),
|
|
4482
5125
|
data: { screenName }
|
|
4483
5126
|
});
|
|
4484
5127
|
},
|
|
4485
|
-
[
|
|
5128
|
+
[emit2]
|
|
4486
5129
|
);
|
|
4487
5130
|
React.useEffect(() => {
|
|
4488
5131
|
const nav = navigationRef.current;
|
|
@@ -4505,7 +5148,7 @@ function useAppilotsNavigation() {
|
|
|
4505
5148
|
|
|
4506
5149
|
// src/hooks/useAppilots.ts
|
|
4507
5150
|
function useAppilots() {
|
|
4508
|
-
const { config, client } =
|
|
5151
|
+
const { config, client } = chunkQAZ4TN3Z_js.useAppilotsContext();
|
|
4509
5152
|
const chat = useAppilotsChat();
|
|
4510
5153
|
const navigation = useAppilotsNavigation();
|
|
4511
5154
|
const actions = useAppilotsActions();
|
|
@@ -4532,9 +5175,14 @@ function useAppilots() {
|
|
|
4532
5175
|
rejectAction: actions.rejectAction
|
|
4533
5176
|
};
|
|
4534
5177
|
}
|
|
5178
|
+
function useAppilotsElementProps(id) {
|
|
5179
|
+
return React.useMemo(() => ({ testID: id }), [id]);
|
|
5180
|
+
}
|
|
5181
|
+
|
|
5182
|
+
// src/hooks/useAppilotsField.ts
|
|
4535
5183
|
function useAppilotsField(id, options) {
|
|
4536
5184
|
const { value, onChangeText, ref, fieldType, label, screen } = options;
|
|
4537
|
-
const registry =
|
|
5185
|
+
const registry = chunkQAZ4TN3Z_js.useResolvedRegistry();
|
|
4538
5186
|
const valueRef = React.useRef(value);
|
|
4539
5187
|
const onChangeRef = React.useRef(onChangeText);
|
|
4540
5188
|
valueRef.current = value;
|
|
@@ -4559,10 +5207,11 @@ function useAppilotsField(id, options) {
|
|
|
4559
5207
|
registry.unregister(id);
|
|
4560
5208
|
};
|
|
4561
5209
|
}, [id, registry, getValue, setValue, focus, ref, fieldType, label, screen]);
|
|
5210
|
+
return useAppilotsElementProps(id);
|
|
4562
5211
|
}
|
|
4563
5212
|
function useAppilotsTarget(id, options) {
|
|
4564
5213
|
const { onPress, onLongPress, onScrollTo, label, screen } = options;
|
|
4565
|
-
const registry =
|
|
5214
|
+
const registry = chunkQAZ4TN3Z_js.useResolvedRegistry();
|
|
4566
5215
|
const onPressRef = React.useRef(onPress);
|
|
4567
5216
|
const onLongPressRef = React.useRef(onLongPress);
|
|
4568
5217
|
const onScrollToRef = React.useRef(onScrollTo);
|
|
@@ -4586,10 +5235,11 @@ function useAppilotsTarget(id, options) {
|
|
|
4586
5235
|
registry.unregister(id);
|
|
4587
5236
|
};
|
|
4588
5237
|
}, [id, registry, press, longPress, scrollTo, onLongPress, onScrollTo, label, screen]);
|
|
5238
|
+
return useAppilotsElementProps(id);
|
|
4589
5239
|
}
|
|
4590
5240
|
function useAppilotsToggle(id, options) {
|
|
4591
5241
|
const { value, onValueChange, label, screen } = options;
|
|
4592
|
-
const registry =
|
|
5242
|
+
const registry = chunkQAZ4TN3Z_js.useResolvedRegistry();
|
|
4593
5243
|
const valueRef = React.useRef(value);
|
|
4594
5244
|
const onChangeRef = React.useRef(onValueChange);
|
|
4595
5245
|
valueRef.current = value;
|
|
@@ -4609,10 +5259,11 @@ function useAppilotsToggle(id, options) {
|
|
|
4609
5259
|
registry.unregister(id);
|
|
4610
5260
|
};
|
|
4611
5261
|
}, [id, registry, getValue, setValue, label, screen]);
|
|
5262
|
+
return useAppilotsElementProps(id);
|
|
4612
5263
|
}
|
|
4613
5264
|
function useAppilotsSlider(id, options) {
|
|
4614
5265
|
const { value, onValueChange, min, max, step, label, screen } = options;
|
|
4615
|
-
const registry =
|
|
5266
|
+
const registry = chunkQAZ4TN3Z_js.useResolvedRegistry();
|
|
4616
5267
|
const valueRef = React.useRef(value);
|
|
4617
5268
|
const onChangeRef = React.useRef(onValueChange);
|
|
4618
5269
|
valueRef.current = value;
|
|
@@ -4635,16 +5286,31 @@ function useAppilotsSlider(id, options) {
|
|
|
4635
5286
|
registry.unregister(id);
|
|
4636
5287
|
};
|
|
4637
5288
|
}, [id, registry, getValue, setValue, min, max, step, label, screen]);
|
|
5289
|
+
return useAppilotsElementProps(id);
|
|
4638
5290
|
}
|
|
4639
5291
|
|
|
5292
|
+
exports.AppilotsI18nProvider = AppilotsI18nProvider;
|
|
5293
|
+
exports.REVEAL_MARGIN = REVEAL_MARGIN;
|
|
5294
|
+
exports.SPOTLIGHT_TTL_MS = SPOTLIGHT_TTL_MS;
|
|
4640
5295
|
exports.appilotsSelfCheck = appilotsSelfCheck;
|
|
4641
5296
|
exports.captureSnapshot = captureSnapshot;
|
|
5297
|
+
exports.detectDeviceLocale = detectDeviceLocale;
|
|
4642
5298
|
exports.executeAction = executeAction;
|
|
5299
|
+
exports.getSpotlightMode = getSpotlightMode;
|
|
5300
|
+
exports.getSpotlightTarget = getSpotlightTarget;
|
|
5301
|
+
exports.offsetToReveal = offsetToReveal;
|
|
5302
|
+
exports.resolveLocale = resolveLocale;
|
|
5303
|
+
exports.revealTarget = revealTarget;
|
|
5304
|
+
exports.setSpotlightMode = setSpotlightMode;
|
|
5305
|
+
exports.setSpotlightTarget = setSpotlightTarget;
|
|
4643
5306
|
exports.shouldShowSuggestedPrompts = shouldShowSuggestedPrompts;
|
|
5307
|
+
exports.subscribeSpotlight = subscribeSpotlight;
|
|
5308
|
+
exports.subscribeSpotlightAnnouncement = subscribeSpotlightAnnouncement;
|
|
4644
5309
|
exports.useAppilots = useAppilots;
|
|
4645
5310
|
exports.useAppilotsActions = useAppilotsActions;
|
|
4646
5311
|
exports.useAppilotsChat = useAppilotsChat;
|
|
4647
5312
|
exports.useAppilotsField = useAppilotsField;
|
|
5313
|
+
exports.useAppilotsI18n = useAppilotsI18n;
|
|
4648
5314
|
exports.useAppilotsNavigation = useAppilotsNavigation;
|
|
4649
5315
|
exports.useAppilotsSlider = useAppilotsSlider;
|
|
4650
5316
|
exports.useAppilotsTarget = useAppilotsTarget;
|