@enricai/barnacle 1.12.81 → 1.12.82
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/dist/lib/llm/judges/verify-step-advanced.d.ts +1 -1
- package/dist/lib/llm/judges/verify-step-advanced.d.ts.map +1 -1
- package/dist/lib/llm/judges/verify-step-advanced.js +2 -1
- package/dist/lib/llm/judges/verify-step-advanced.js.map +1 -1
- package/dist/plugins/config-plugin.d.ts +1 -0
- package/dist/plugins/config-plugin.d.ts.map +1 -1
- package/dist/plugins/config-plugin.js +7 -1
- package/dist/plugins/config-plugin.js.map +1 -1
- package/dist/plugins/loader.d.ts +2 -2
- package/dist/plugins/loader.d.ts.map +1 -1
- package/dist/plugins/loader.js +6 -3
- package/dist/plugins/loader.js.map +1 -1
- package/dist/scraper/click-settle.d.ts +8 -2
- package/dist/scraper/click-settle.d.ts.map +1 -1
- package/dist/scraper/click-settle.js +27 -28
- package/dist/scraper/click-settle.js.map +1 -1
- package/dist/scraper/errors.d.ts +23 -2
- package/dist/scraper/errors.d.ts.map +1 -1
- package/dist/scraper/errors.js +32 -4
- package/dist/scraper/errors.js.map +1 -1
- package/dist/scraper/flow-runner.d.ts +38 -29
- package/dist/scraper/flow-runner.d.ts.map +1 -1
- package/dist/scraper/flow-runner.js +132 -74
- package/dist/scraper/flow-runner.js.map +1 -1
- package/dist/scraper/http-client.d.ts +7 -2
- package/dist/scraper/http-client.d.ts.map +1 -1
- package/dist/scraper/http-client.js +132 -19
- package/dist/scraper/http-client.js.map +1 -1
- package/dist/scraper/metrics.d.ts +2 -2
- package/dist/scraper/metrics.js +2 -2
- package/dist/scraper/phantom-click.d.ts +6 -0
- package/dist/scraper/phantom-click.d.ts.map +1 -1
- package/dist/scraper/phantom-click.js +62 -15
- package/dist/scraper/phantom-click.js.map +1 -1
- package/dist/site-plugin.d.ts +7 -4
- package/dist/site-plugin.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -78,6 +78,7 @@ exports.verifyFillReadback = verifyFillReadback;
|
|
|
78
78
|
exports.verifyPromptSelectorCommitted = verifyPromptSelectorCommitted;
|
|
79
79
|
exports.tailRetargetPhrasesForStep = tailRetargetPhrasesForStep;
|
|
80
80
|
exports.stepQuotesValueNotControlName = stepQuotesValueNotControlName;
|
|
81
|
+
exports.waitForUploadNetworkSignal = waitForUploadNetworkSignal;
|
|
81
82
|
exports.isUploadAffordanceLabel = isUploadAffordanceLabel;
|
|
82
83
|
exports.writeFixtureToTempFile = writeFixtureToTempFile;
|
|
83
84
|
exports.attachToSurfacedInput = attachToSurfacedInput;
|
|
@@ -393,6 +394,8 @@ function wireSignalCapture(page, params) {
|
|
|
393
394
|
method: capture.method,
|
|
394
395
|
status: capture.status,
|
|
395
396
|
url: capture.url,
|
|
397
|
+
hasBody: (req.requestPostData ?? "").length > 0,
|
|
398
|
+
multipart: /^multipart\//i.test(requestContentType(req.requestHeaders)),
|
|
396
399
|
});
|
|
397
400
|
if (recentCaptureMeta.length > RECENT_CAPTURES_WINDOW) {
|
|
398
401
|
recentCaptureMeta.splice(0, recentCaptureMeta.length - RECENT_CAPTURES_WINDOW);
|
|
@@ -1156,13 +1159,60 @@ function fieldValuesAtFailureExpr() {
|
|
|
1156
1159
|
return out;
|
|
1157
1160
|
})()`;
|
|
1158
1161
|
}
|
|
1162
|
+
/**
|
|
1163
|
+
* Reads the in-page quiescence probe as a typed, non-null value. A detached
|
|
1164
|
+
* frame or malformed probe result reads as idle so settle consumes the reader
|
|
1165
|
+
* directly and needs no guard of its own.
|
|
1166
|
+
*/
|
|
1167
|
+
async function readPageQuiescence(target) {
|
|
1168
|
+
const idle = { pending: 0, mutations: 0 };
|
|
1169
|
+
const result = await Promise.resolve(target.evaluate(click_settle_1.QUIESCENCE_PROBE_EXPR)).catch(() => idle);
|
|
1170
|
+
if (result === null || typeof result !== "object")
|
|
1171
|
+
return idle;
|
|
1172
|
+
const { pending, mutations } = result;
|
|
1173
|
+
return typeof pending === "number" && typeof mutations === "number"
|
|
1174
|
+
? { pending, mutations }
|
|
1175
|
+
: idle;
|
|
1176
|
+
}
|
|
1177
|
+
/**
|
|
1178
|
+
* Reads only the visible-text signature settle polls on. Going through
|
|
1179
|
+
* {@link snapshotPage} also read the frame URL, which rejects once a submit
|
|
1180
|
+
* detaches the OOPIF and would abort the settle mid-poll; a failed read here
|
|
1181
|
+
* degrades to the empty signature like the snapshot's own text read does.
|
|
1182
|
+
*/
|
|
1183
|
+
async function readSettleTextSignature(target) {
|
|
1184
|
+
const result = await Promise.resolve(target.evaluate(DOM_SNAPSHOT_EXPR)).catch(() => null);
|
|
1185
|
+
if (result === null || typeof result !== "object")
|
|
1186
|
+
return "";
|
|
1187
|
+
const { text } = result;
|
|
1188
|
+
return typeof text === "string" ? text : "";
|
|
1189
|
+
}
|
|
1159
1190
|
/**
|
|
1160
1191
|
* Settles after a click using the target's own text signature and in-page
|
|
1161
1192
|
* quiescence reader, so every post-click site decides from the same settle
|
|
1162
1193
|
* signal instead of hand-building the readers.
|
|
1163
1194
|
*/
|
|
1164
|
-
async function settleWithPageQuiescence(page, target, signalCounter, preNetworkCount, submitShaped, preVisibleTextSignature) {
|
|
1165
|
-
await (0, click_settle_1.settleAfterClick)(page, signalCounter, preNetworkCount, submitShaped,
|
|
1195
|
+
async function settleWithPageQuiescence(page, target, signalCounter, preNetworkCount, submitShaped, preVisibleTextSignature, advanced) {
|
|
1196
|
+
await (0, click_settle_1.settleAfterClick)(page, signalCounter, preNetworkCount, submitShaped, () => readSettleTextSignature(target), preVisibleTextSignature, () => readPageQuiescence(target), advanced);
|
|
1197
|
+
}
|
|
1198
|
+
/**
|
|
1199
|
+
* Builds the "has the page finished advancing" test a mid-flow submit settles
|
|
1200
|
+
* against. It is the body-swap half of the {@link hasPageAdvanced} the phantom
|
|
1201
|
+
* classifier credits with, so a header that flipped before its body re-rendered
|
|
1202
|
+
* keeps settle polling while the classifier still credits whatever is left once
|
|
1203
|
+
* the wait is spent.
|
|
1204
|
+
* Undefined for any other step, which keeps the plain quiet-window settle.
|
|
1205
|
+
*/
|
|
1206
|
+
function pageAdvancedSince(preVisibleTextSignature, midFlowSubmit) {
|
|
1207
|
+
if (!midFlowSubmit)
|
|
1208
|
+
return undefined;
|
|
1209
|
+
const pre = {
|
|
1210
|
+
networkCount: 0,
|
|
1211
|
+
url: "",
|
|
1212
|
+
bodyHtmlLength: 0,
|
|
1213
|
+
visibleTextSignature: preVisibleTextSignature,
|
|
1214
|
+
};
|
|
1215
|
+
return (visibleTextSignature) => (0, phantom_click_1.hasPageBodySwapped)(pre, { ...pre, visibleTextSignature });
|
|
1166
1216
|
}
|
|
1167
1217
|
/**
|
|
1168
1218
|
* Captures the pre/post signal triple the submit-verify cascade diffs.
|
|
@@ -2915,10 +2965,18 @@ async function judgeStepOutcome(params) {
|
|
|
2915
2965
|
captureFn,
|
|
2916
2966
|
});
|
|
2917
2967
|
}
|
|
2918
|
-
await (
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2968
|
+
await settleWithPageQuiescence(params.page, target, params.signalCounter, params.preNetworkCount, isStepSettleWaitShaped({
|
|
2969
|
+
step,
|
|
2970
|
+
submitStep: params.submitStep,
|
|
2971
|
+
isFinalStep,
|
|
2972
|
+
flowHasSubmitSemantics: params.flowHasSubmitSemantics,
|
|
2973
|
+
}) || params.elementSubmitShaped === true, params.preVisibleTextSignature, pageAdvancedSince(params.preVisibleTextSignature, isMidFlowSubmitShapedStep({
|
|
2974
|
+
step,
|
|
2975
|
+
submitStep: params.submitStep,
|
|
2976
|
+
isFinalStep,
|
|
2977
|
+
flowHasSubmitSemantics: params.flowHasSubmitSemantics,
|
|
2978
|
+
elementSubmitShaped: params.elementSubmitShaped,
|
|
2979
|
+
})));
|
|
2922
2980
|
const colon = params.preVisibleTextSignature.indexOf(":");
|
|
2923
2981
|
const beforeText = (colon === -1 ? params.preVisibleTextSignature : params.preVisibleTextSignature.slice(colon + 1))
|
|
2924
2982
|
.replace(/\s+/g, " ")
|
|
@@ -4523,12 +4581,17 @@ const UPLOAD_URL_PATTERNS = [
|
|
|
4523
4581
|
"/media",
|
|
4524
4582
|
"/import",
|
|
4525
4583
|
];
|
|
4584
|
+
/** Case-insensitive Content-Type lookup; CDP preserves the page's header casing. */
|
|
4585
|
+
function requestContentType(headers) {
|
|
4586
|
+
const key = Object.keys(headers).find((k) => k.toLowerCase() === "content-type");
|
|
4587
|
+
return key ? (headers[key] ?? "") : "";
|
|
4588
|
+
}
|
|
4526
4589
|
/**
|
|
4527
4590
|
* Poll the recent-capture window for an upload-related POST after a file has
|
|
4528
4591
|
* been attached. Extracted from `tryUploadPrimitive` so the raw-input path,
|
|
4529
4592
|
* the click-to-surface path, and the CDP native-chooser path all verify the
|
|
4530
|
-
* same way. Returns true as soon as a non-GET capture
|
|
4531
|
-
* {@link UPLOAD_URL_PATTERNS} lands; false if the timeout elapses first.
|
|
4593
|
+
* same way. Returns true as soon as a non-GET capture that is multipart, or is not
|
|
4594
|
+
* known to be body-less and has a URL matching {@link UPLOAD_URL_PATTERNS}, lands; false if the timeout elapses first.
|
|
4532
4595
|
*/
|
|
4533
4596
|
async function waitForUploadNetworkSignal(params) {
|
|
4534
4597
|
const { page, fixture, logger, signalCounter, recentCaptureMeta, stopWhen } = params;
|
|
@@ -4541,6 +4604,10 @@ async function waitForUploadNetworkSignal(params) {
|
|
|
4541
4604
|
const uploadCapture = newCaptures.find((cap) => {
|
|
4542
4605
|
if (cap.method === "GET")
|
|
4543
4606
|
return false;
|
|
4607
|
+
if (cap.multipart)
|
|
4608
|
+
return true;
|
|
4609
|
+
if (cap.hasBody === false)
|
|
4610
|
+
return false;
|
|
4544
4611
|
const lowerUrl = cap.url.toLowerCase();
|
|
4545
4612
|
return UPLOAD_URL_PATTERNS.some((p) => lowerUrl.includes(p));
|
|
4546
4613
|
});
|
|
@@ -4672,8 +4739,9 @@ async function tryUploadPrimitive(params) {
|
|
|
4672
4739
|
* Attach the fixture to an already-surfaced `<input type=file>` (raw or freshly
|
|
4673
4740
|
* mounted after a click) and verify. Extracted verbatim from the original
|
|
4674
4741
|
* `tryUploadPrimitive` body so the raw-input path and the click-to-surface
|
|
4675
|
-
* path share one setInputFiles + framework-change-dispatch + network/DOM verify
|
|
4676
|
-
*
|
|
4742
|
+
* path share one setInputFiles + framework-change-dispatch + network/DOM verify implementation.
|
|
4743
|
+
* Returns true only on a verified signal
|
|
4744
|
+
* (upload POST or populated `.files`).
|
|
4677
4745
|
*/
|
|
4678
4746
|
async function attachToSurfacedInput(params) {
|
|
4679
4747
|
const { page, target, fixture, logger, signalCounter, recentCaptureMeta } = params;
|
|
@@ -4740,18 +4808,10 @@ async function attachToSurfacedInput(params) {
|
|
|
4740
4808
|
.evaluate("(() => { const els = document.querySelectorAll('input[type=file]'); for (const el of els) { if (el.files && el.files.length > 0) return el.files.length; } return 0; })()")
|
|
4741
4809
|
.catch(() => 0);
|
|
4742
4810
|
if (typeof attachedLength !== "number" || attachedLength === 0) {
|
|
4743
|
-
|
|
4744
|
-
//
|
|
4745
|
-
//
|
|
4746
|
-
|
|
4747
|
-
// a DataTransfer fires on the visible drop area — they don't observe
|
|
4748
|
-
// the hidden input's `files[]` mutations even with synthetic `change`
|
|
4749
|
-
// dispatches. This is the documented Playwright community workaround.
|
|
4750
|
-
const dragDropOk = await simulateDragDropUpload(target, fixture, logger);
|
|
4751
|
-
if (dragDropOk) {
|
|
4752
|
-
logger.info(`upload primitive: drag-drop fallback succeeded (name=${fixture.name}, size=${fixture.buffer.length}b)`);
|
|
4753
|
-
return true;
|
|
4754
|
-
}
|
|
4811
|
+
// A dispatched drop is unverified (no network signal, no .files), so it is
|
|
4812
|
+
// not success here: return false and let surfaceAndUpload run the verified
|
|
4813
|
+
// drop and the trusted-click/chooser routes.
|
|
4814
|
+
logger.warn("upload primitive: no network activity within timeout and no file attached in DOM; deferring to surface-and-upload");
|
|
4755
4815
|
return false;
|
|
4756
4816
|
}
|
|
4757
4817
|
logger.info(`upload primitive: file attached in DOM after setInputFiles (deferred-upload widget; name=${fixture.name}, filesLength=${attachedLength})`);
|
|
@@ -6220,9 +6280,9 @@ function isNavigatingEvaluateRejection(error) {
|
|
|
6220
6280
|
* wait and the phantom classifier decide from the same reader and baseline.
|
|
6221
6281
|
* Without a page there is nothing to wait on and the snapshot is taken as-is.
|
|
6222
6282
|
*/
|
|
6223
|
-
async function settleAndSnapshotPostClick(target, signalCounter, page, pre) {
|
|
6283
|
+
async function settleAndSnapshotPostClick(target, signalCounter, page, pre, midFlowSubmit = false) {
|
|
6224
6284
|
if (page)
|
|
6225
|
-
await settleWithPageQuiescence(page, target, signalCounter, pre.networkCount, true, pre.visibleTextSignature);
|
|
6285
|
+
await settleWithPageQuiescence(page, target, signalCounter, pre.networkCount, true, pre.visibleTextSignature, pageAdvancedSince(pre.visibleTextSignature, midFlowSubmit));
|
|
6226
6286
|
return snapshotPage(target, signalCounter, page);
|
|
6227
6287
|
}
|
|
6228
6288
|
/**
|
|
@@ -6532,7 +6592,7 @@ async function submitCaptchaGatedForm(target, responseField = "h-captcha-respons
|
|
|
6532
6592
|
if (clickResult.clicked) {
|
|
6533
6593
|
if (!pre || !verification)
|
|
6534
6594
|
return true;
|
|
6535
|
-
const post = await settleAndSnapshotPostClick(target, verification.signalCounter, verification.page, pre);
|
|
6595
|
+
const post = await settleAndSnapshotPostClick(target, verification.signalCounter, verification.page, pre, verification.isMidFlowSubmitStep);
|
|
6536
6596
|
const verdict = (0, phantom_click_1.classifyPhantomClick)({
|
|
6537
6597
|
actResultSuccess: true,
|
|
6538
6598
|
pre,
|
|
@@ -6553,7 +6613,7 @@ async function submitCaptchaGatedForm(target, responseField = "h-captcha-respons
|
|
|
6553
6613
|
throw err;
|
|
6554
6614
|
});
|
|
6555
6615
|
if (runnerUpClickResult.clicked) {
|
|
6556
|
-
const runnerUpPost = await settleAndSnapshotPostClick(target, verification.signalCounter, verification.page, post);
|
|
6616
|
+
const runnerUpPost = await settleAndSnapshotPostClick(target, verification.signalCounter, verification.page, post, verification.isMidFlowSubmitStep);
|
|
6557
6617
|
const runnerUpVerdict = (0, phantom_click_1.classifyPhantomClick)({
|
|
6558
6618
|
actResultSuccess: true,
|
|
6559
6619
|
pre: post,
|
|
@@ -8766,6 +8826,9 @@ async function hasUnfilledRequiredControlForStep(target, instruction) {
|
|
|
8766
8826
|
* upload/dropzone/file-related class or tag names. Tries multiple
|
|
8767
8827
|
* candidates in order. Returns true on first success.
|
|
8768
8828
|
*
|
|
8829
|
+
* Dispatch-only: a true return means the drop events fired, not that the
|
|
8830
|
+
* widget accepted the file; callers must verify.
|
|
8831
|
+
*
|
|
8769
8832
|
* Site-agnostic — DataTransfer + DragEvent dispatch is universal HTML5
|
|
8770
8833
|
* drag-and-drop API. Works on react-dropzone, Material Dropzone, custom
|
|
8771
8834
|
* <uapp-upload>/<app-upload>, and any other drop-zone-based upload UI.
|
|
@@ -9873,11 +9936,7 @@ async function probeChildFrameSubmitFallback(params) {
|
|
|
9873
9936
|
const clickResult = (await Promise.resolve(target.evaluate((0, submit_control_1.buildClickByDeepIndexExpr)(top.deepIndex))).catch(() => ({ clicked: false })));
|
|
9874
9937
|
if (!clickResult.clicked)
|
|
9875
9938
|
continue;
|
|
9876
|
-
await (
|
|
9877
|
-
const snap = await snapshotPage(target, signalCounter);
|
|
9878
|
-
return snap.visibleTextSignature;
|
|
9879
|
-
}, pre.visibleTextSignature, async () => target.evaluate(click_settle_1.QUIESCENCE_PROBE_EXPR));
|
|
9880
|
-
const post = await snapshotPage(target, signalCounter, page);
|
|
9939
|
+
const post = await settleAndSnapshotPostClick(target, signalCounter, page, pre, isMidFlowSubmitStep);
|
|
9881
9940
|
const verdict = (0, phantom_click_1.classifyPhantomClick)({
|
|
9882
9941
|
actResultSuccess: true,
|
|
9883
9942
|
pre,
|
|
@@ -9894,11 +9953,7 @@ async function probeChildFrameSubmitFallback(params) {
|
|
|
9894
9953
|
const runnerUpClickResult = (await Promise.resolve(target.evaluate((0, submit_control_1.buildClickByDeepIndexExpr)(runnerUp.deepIndex))).catch(() => ({ clicked: false })));
|
|
9895
9954
|
if (!runnerUpClickResult.clicked)
|
|
9896
9955
|
continue;
|
|
9897
|
-
await (
|
|
9898
|
-
const snap = await snapshotPage(target, signalCounter);
|
|
9899
|
-
return snap.visibleTextSignature;
|
|
9900
|
-
}, post.visibleTextSignature, async () => target.evaluate(click_settle_1.QUIESCENCE_PROBE_EXPR));
|
|
9901
|
-
const runnerUpPost = await snapshotPage(target, signalCounter, page);
|
|
9956
|
+
const runnerUpPost = await settleAndSnapshotPostClick(target, signalCounter, page, post, isMidFlowSubmitStep);
|
|
9902
9957
|
const runnerUpVerdict = (0, phantom_click_1.classifyPhantomClick)({
|
|
9903
9958
|
actResultSuccess: true,
|
|
9904
9959
|
pre,
|
|
@@ -11308,14 +11363,14 @@ async function executeStepWithHealing(params) {
|
|
|
11308
11363
|
const runnerUp = ranked[1];
|
|
11309
11364
|
if (runnerUp) {
|
|
11310
11365
|
const midTarget = frameTarget ?? (0, frame_target_1.mainFrameTarget)(page);
|
|
11311
|
-
const
|
|
11312
|
-
|
|
11313
|
-
|
|
11314
|
-
|
|
11315
|
-
|
|
11316
|
-
|
|
11317
|
-
readQuiescence: async () => midTarget.evaluate(click_settle_1.QUIESCENCE_PROBE_EXPR),
|
|
11366
|
+
const deepMidFlowSubmit = isMidFlowSubmitShapedStep({
|
|
11367
|
+
step,
|
|
11368
|
+
submitStep,
|
|
11369
|
+
isFinalStep,
|
|
11370
|
+
flowHasSubmitSemantics: flowHasSubmitSemanticsFlag,
|
|
11371
|
+
elementSubmitShaped: !stepDeclaredNonSubmit,
|
|
11318
11372
|
});
|
|
11373
|
+
const midPost = await settleAndSnapshotPostClick(midTarget, signalCounter, page, pre, deepMidFlowSubmit);
|
|
11319
11374
|
const topVerdict = (0, phantom_click_1.classifyPhantomClick)({
|
|
11320
11375
|
actResultSuccess: true,
|
|
11321
11376
|
pre,
|
|
@@ -11324,20 +11379,8 @@ async function executeStepWithHealing(params) {
|
|
|
11324
11379
|
// stray selection flip must not mask a top-pick phantom and skip
|
|
11325
11380
|
// the runner-up retry.
|
|
11326
11381
|
isSubmitShapedStep: true,
|
|
11327
|
-
isMidFlowSubmitStep:
|
|
11328
|
-
|
|
11329
|
-
submitStep,
|
|
11330
|
-
isFinalStep,
|
|
11331
|
-
flowHasSubmitSemantics: flowHasSubmitSemanticsFlag,
|
|
11332
|
-
}),
|
|
11333
|
-
destinationPlausible: (0, phantom_click_1.isPlausibleStepDestination)(step, midPost.url, isMidFlowSubmitShapedStep({
|
|
11334
|
-
step,
|
|
11335
|
-
submitStep,
|
|
11336
|
-
isFinalStep,
|
|
11337
|
-
flowHasSubmitSemantics: flowHasSubmitSemanticsFlag,
|
|
11338
|
-
})
|
|
11339
|
-
? pre.url
|
|
11340
|
-
: undefined),
|
|
11382
|
+
isMidFlowSubmitStep: deepMidFlowSubmit,
|
|
11383
|
+
destinationPlausible: (0, phantom_click_1.isPlausibleStepDestination)(step, midPost.url, deepMidFlowSubmit ? pre.url : undefined),
|
|
11341
11384
|
});
|
|
11342
11385
|
if (topVerdict === "phantom") {
|
|
11343
11386
|
logger.info(`${formatStepPrefix(stepIndex, totalSteps)} deep-submit-locator top pick (${top.tag} "${top.accessibleName}") phantom-clicked; retrying runner-up ${runnerUp.tag} "${runnerUp.accessibleName}" (tier ${runnerUp.tier})`);
|
|
@@ -12068,6 +12111,24 @@ async function executeStepWithHealing(params) {
|
|
|
12068
12111
|
}
|
|
12069
12112
|
// A fill/select/type action cannot open a tab, so skip the discovery wait for it.
|
|
12070
12113
|
await adoptOpenedPage(resolvedAction && STATE_CLASS_METHODS.has(resolvedAction.method ?? "") ? 0 : undefined);
|
|
12114
|
+
const isClick = resolvedAction !== null && resolvedAction.method === "click";
|
|
12115
|
+
// Attribute-based submit-shape read of the resolved click target itself —
|
|
12116
|
+
// independent of the flow-authored `submitStep` flag. Read before the
|
|
12117
|
+
// settle: a view swap removes the clicked control, so a post-swap read
|
|
12118
|
+
// would blind the mid-flow exemption on exactly the case it exists for.
|
|
12119
|
+
// See resolvedClickTargetIsSubmitShaped's doc comment.
|
|
12120
|
+
const resolvedElementIsSubmitShaped = isClick && !stepDeclaredNonSubmit && resolvedAction?.selector
|
|
12121
|
+
? await resolvedClickTargetIsSubmitShaped(frameTarget ?? (0, frame_target_1.mainFrameTarget)(page), resolvedAction.selector)
|
|
12122
|
+
: false;
|
|
12123
|
+
// Computed once: gates every credit signal that takes no post-click URL
|
|
12124
|
+
// (network, DOM read-back) and classifyPhantomClick's destinationPlausible.
|
|
12125
|
+
const stepIsMidFlowSubmit = isMidFlowSubmitShapedStep({
|
|
12126
|
+
step,
|
|
12127
|
+
submitStep,
|
|
12128
|
+
isFinalStep,
|
|
12129
|
+
flowHasSubmitSemantics: flowHasSubmitSemanticsFlag,
|
|
12130
|
+
elementSubmitShaped: resolvedElementIsSubmitShaped,
|
|
12131
|
+
});
|
|
12071
12132
|
await page.waitForTimeout(STEP_PAUSE_MS);
|
|
12072
12133
|
// A successful act that reported no actions still ran a click-class action;
|
|
12073
12134
|
// judging it before its round-trip lands would cascade onto the advanced page.
|
|
@@ -12076,7 +12137,7 @@ async function executeStepWithHealing(params) {
|
|
|
12076
12137
|
: !STATE_CLASS_METHODS.has(resolvedAction.method ?? "");
|
|
12077
12138
|
if (mayTriggerRoundTrip) {
|
|
12078
12139
|
const settleTarget = frameTarget ?? (0, frame_target_1.mainFrameTarget)(page);
|
|
12079
|
-
await settleWithPageQuiescence(page, settleTarget, signalCounter, pre.networkCount, isSettleWaitStep, pre.visibleTextSignature);
|
|
12140
|
+
await settleWithPageQuiescence(page, settleTarget, signalCounter, pre.networkCount, isSettleWaitStep || resolvedElementIsSubmitShaped, pre.visibleTextSignature, pageAdvancedSince(pre.visibleTextSignature, stepIsMidFlowSubmit));
|
|
12080
12141
|
}
|
|
12081
12142
|
const post = await snapshotPage(frameTarget ?? (0, frame_target_1.mainFrameTarget)(page), signalCounter, page);
|
|
12082
12143
|
record.post = post;
|
|
@@ -12085,18 +12146,9 @@ async function executeStepWithHealing(params) {
|
|
|
12085
12146
|
record.resolvedArguments = (resolvedAction.arguments ?? []).map(String);
|
|
12086
12147
|
}
|
|
12087
12148
|
const networkFired = post.networkCount > pre.networkCount;
|
|
12088
|
-
// Computed once: gates every credit signal that takes no post-click URL
|
|
12089
|
-
// (network, DOM read-back) and classifyPhantomClick's destinationPlausible.
|
|
12090
|
-
const stepIsMidFlowSubmit = isMidFlowSubmitShapedStep({
|
|
12091
|
-
step,
|
|
12092
|
-
submitStep,
|
|
12093
|
-
isFinalStep,
|
|
12094
|
-
flowHasSubmitSemantics: flowHasSubmitSemanticsFlag,
|
|
12095
|
-
});
|
|
12096
12149
|
const destinationPlausible = (0, phantom_click_1.isPlausibleStepDestination)(step, post.url, stepIsMidFlowSubmit ? pre.url : undefined);
|
|
12097
12150
|
const urlChanged = (0, phantom_click_1.hasOriginOrPathChanged)(pre.url, post.url) && destinationPlausible;
|
|
12098
12151
|
const isStateClass = resolvedAction !== null && STATE_CLASS_METHODS.has(resolvedAction.method ?? "");
|
|
12099
|
-
const isClick = resolvedAction !== null && resolvedAction.method === "click";
|
|
12100
12152
|
// State-class actions (fill/check/etc.) never move the network counter or URL,
|
|
12101
12153
|
// so the legacy heuristic false-negatived every form fill. Re-read DOM state
|
|
12102
12154
|
// for those; keep the navigation signal authoritative for clicks/links —
|
|
@@ -12193,12 +12245,6 @@ async function executeStepWithHealing(params) {
|
|
|
12193
12245
|
const clickedElementStillPresent = isClick && resolvedAction?.selector
|
|
12194
12246
|
? await resolvedClickTargetStillPresent(frameTarget ?? (0, frame_target_1.mainFrameTarget)(page), resolvedAction.selector)
|
|
12195
12247
|
: true;
|
|
12196
|
-
// Attribute-based submit-shape read of the resolved click target itself —
|
|
12197
|
-
// independent of the flow-authored `submitStep` flag. See
|
|
12198
|
-
// resolvedClickTargetIsSubmitShaped's doc comment.
|
|
12199
|
-
const resolvedElementIsSubmitShaped = isClick && !stepDeclaredNonSubmit && resolvedAction?.selector
|
|
12200
|
-
? await resolvedClickTargetIsSubmitShaped(frameTarget ?? (0, frame_target_1.mainFrameTarget)(page), resolvedAction.selector)
|
|
12201
|
-
: false;
|
|
12202
12248
|
// Client-side view-swap gate: credit a click that produces substantial
|
|
12203
12249
|
// DOM growth (≥5KB) with zero network when it's NOT a submit/final step
|
|
12204
12250
|
// and NOT an advance-pattern step. Fixes the top-window site "Manual Application"
|
|
@@ -12499,6 +12545,9 @@ async function executeStepWithHealing(params) {
|
|
|
12499
12545
|
captureFn,
|
|
12500
12546
|
step,
|
|
12501
12547
|
isFinalStep,
|
|
12548
|
+
submitStep,
|
|
12549
|
+
flowHasSubmitSemantics: flowHasSubmitSemanticsFlag,
|
|
12550
|
+
elementSubmitShaped: resolvedElementIsSubmitShaped,
|
|
12502
12551
|
page,
|
|
12503
12552
|
target: frameTarget ?? (0, frame_target_1.mainFrameTarget)(page),
|
|
12504
12553
|
signalCounter,
|
|
@@ -12740,7 +12789,13 @@ async function executeStepWithHealing(params) {
|
|
|
12740
12789
|
probeResult.checked === true &&
|
|
12741
12790
|
(probeResult.ariaManaged === true || !ancestorStillInvalid);
|
|
12742
12791
|
await page.waitForTimeout(STEP_PAUSE_MS);
|
|
12743
|
-
await settleWithPageQuiescence(page, frameTarget ?? (0, frame_target_1.mainFrameTarget)(page), signalCounter, pre.networkCount, isSettleWaitStep, pre.visibleTextSignature
|
|
12792
|
+
await settleWithPageQuiescence(page, frameTarget ?? (0, frame_target_1.mainFrameTarget)(page), signalCounter, pre.networkCount, isSettleWaitStep || retryResolvedElementIsSubmitShaped, pre.visibleTextSignature, pageAdvancedSince(pre.visibleTextSignature, isMidFlowSubmitShapedStep({
|
|
12793
|
+
step,
|
|
12794
|
+
submitStep,
|
|
12795
|
+
isFinalStep,
|
|
12796
|
+
flowHasSubmitSemantics: flowHasSubmitSemanticsFlag,
|
|
12797
|
+
elementSubmitShaped: retryResolvedElementIsSubmitShaped,
|
|
12798
|
+
})));
|
|
12744
12799
|
const retryPost = await snapshotPage(frameTarget ?? (0, frame_target_1.mainFrameTarget)(page), signalCounter, page);
|
|
12745
12800
|
const retryNetworkFired = retryPost.networkCount > pre.networkCount;
|
|
12746
12801
|
const retryMidFlowSubmit = isMidFlowSubmitShapedStep({
|
|
@@ -13092,6 +13147,9 @@ async function executeStepWithHealing(params) {
|
|
|
13092
13147
|
captureFn,
|
|
13093
13148
|
step,
|
|
13094
13149
|
isFinalStep,
|
|
13150
|
+
submitStep,
|
|
13151
|
+
flowHasSubmitSemantics: flowHasSubmitSemanticsFlag,
|
|
13152
|
+
elementSubmitShaped: resolvedElementIsSubmitShaped,
|
|
13095
13153
|
page,
|
|
13096
13154
|
target: frameTarget ?? (0, frame_target_1.mainFrameTarget)(page),
|
|
13097
13155
|
signalCounter,
|