@geometra/proxy 1.65.4 → 1.65.5
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/dom-actions.d.ts.map +1 -1
- package/dist/dom-actions.js +182 -0
- package/dist/dom-actions.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dom-actions.d.ts","sourceRoot":"","sources":["../src/dom-actions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAkC,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAE/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEnE,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAA;AAgDvE,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC,CAAA;IACpC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC,CAAA;IACrC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC,CAAA;CACvC;AAED,wBAAgB,qBAAqB,IAAI,eAAe,CAMvD;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAIjE;AAi+FD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,YAAY,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CAkC/F;
|
|
1
|
+
{"version":3,"file":"dom-actions.d.ts","sourceRoot":"","sources":["../src/dom-actions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAkC,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAE/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEnE,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAA;AAgDvE,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC,CAAA;IACpC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC,CAAA;IACrC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC,CAAA;CACvC;AAED,wBAAgB,qBAAqB,IAAI,eAAe,CAMvD;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAIjE;AAi+FD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,YAAY,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CAkC/F;AA61CD,wBAAsB,WAAW,CAC/B,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,CAAC,EAAE;IACL,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,QAAQ,CAAC,EAAE,kBAAkB,CAAA;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,eAAe,CAAA;CACxB,GACA,OAAO,CAAC,IAAI,CAAC,CAsGf;AAslCD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,OAAO,CAC3B,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GACtD,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAsNrD;AAeD,wBAAsB,YAAY,CAChC,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IACL,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,eAAe,CAAA;IACvB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,oFAAoF;IACpF,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,iFAAiF;IACjF,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB,GACA,OAAO,CAAC,IAAI,CAAC,CAoDf;AA8XD,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,GAAG,OAAO,EACvB,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,eAAe,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACvF,OAAO,CAAC,IAAI,CAAC,CA4Ef;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAAC,KAAK,CAAC,EAAE,eAAe,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5J,OAAO,CAAC,IAAI,CAAC,CAiDf;AAED,MAAM,MAAM,aAAa,GAAG,eAAe,CAAA;AAE3C,wBAAsB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,KAAK,kBAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAsIpH;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqHlH;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,eAAe,CAAA;CAAE,GAC5J,OAAO,CAAC,IAAI,CAAC,CAwOf;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,WAAW,CAAC,EAAE,UAAU,GAAG,OAAO,CAAA;IAClC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AA2MD;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkD1G;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA4C/G"}
|
package/dist/dom-actions.js
CHANGED
|
@@ -3314,11 +3314,81 @@ async function beginFileInputCommitGuard(handle) {
|
|
|
3314
3314
|
}
|
|
3315
3315
|
return null;
|
|
3316
3316
|
}
|
|
3317
|
+
function explicitlyAssociatesFileInput(scope, exactInput) {
|
|
3318
|
+
const broadContainerSelector = 'main, nav, aside, article, section, header, footer, ' +
|
|
3319
|
+
'[role="main"], [role="application"], [role="document"], [role="navigation"]';
|
|
3320
|
+
if (scope.matches(broadContainerSelector) || scope.querySelector(broadContainerSelector)) {
|
|
3321
|
+
return false;
|
|
3322
|
+
}
|
|
3323
|
+
const labels = Array.from(exactInput.labels ?? []);
|
|
3324
|
+
const interactiveElements = Array.from(scope.querySelectorAll('input, select, textarea, button, [role="button"], a[href], [contenteditable="true"]'));
|
|
3325
|
+
const hasUnrelatedControl = interactiveElements.some((control) => {
|
|
3326
|
+
if (control === exactInput)
|
|
3327
|
+
return false;
|
|
3328
|
+
if (control instanceof HTMLLabelElement && labels.includes(control))
|
|
3329
|
+
return false;
|
|
3330
|
+
const style = getComputedStyle(control);
|
|
3331
|
+
const visible = style.display !== 'none' &&
|
|
3332
|
+
style.visibility !== 'hidden' &&
|
|
3333
|
+
style.visibility !== 'collapse' &&
|
|
3334
|
+
control.getClientRects().length > 0;
|
|
3335
|
+
if (!visible)
|
|
3336
|
+
return false;
|
|
3337
|
+
if (!control.matches('button, [role="button"], a[href]'))
|
|
3338
|
+
return true;
|
|
3339
|
+
const accessibleText = (control.getAttribute('aria-label') ??
|
|
3340
|
+
control.getAttribute('title') ??
|
|
3341
|
+
control.textContent ?? '').replace(/\s+/g, ' ').trim();
|
|
3342
|
+
const action = /^(attach|upload|browse|choose|select|add)\b/i.exec(accessibleText);
|
|
3343
|
+
if (!action)
|
|
3344
|
+
return true;
|
|
3345
|
+
const remainder = accessibleText.slice(action[0].length).trim();
|
|
3346
|
+
if (!remainder)
|
|
3347
|
+
return !/^(attach|upload|browse|choose)$/i.test(action[1] ?? '');
|
|
3348
|
+
return !/^(?:(?:a|an|the|this|new|your)\s+)?(?:files?|attachments?|upload|documents?|resume|cv|cover letter)\b/i.test(remainder);
|
|
3349
|
+
});
|
|
3350
|
+
if (hasUnrelatedControl)
|
|
3351
|
+
return false;
|
|
3352
|
+
if (scope instanceof HTMLLabelElement &&
|
|
3353
|
+
labels.includes(scope))
|
|
3354
|
+
return true;
|
|
3355
|
+
if (labels.some(label => scope.contains(label)))
|
|
3356
|
+
return true;
|
|
3357
|
+
if (scope instanceof HTMLFieldSetElement)
|
|
3358
|
+
return true;
|
|
3359
|
+
if (scope.getAttribute('role')?.trim().toLowerCase() !== 'group')
|
|
3360
|
+
return false;
|
|
3361
|
+
if (scope.getAttribute('aria-label')?.trim())
|
|
3362
|
+
return true;
|
|
3363
|
+
const labelledBy = scope.getAttribute('aria-labelledby')?.trim().split(/\s+/).filter(Boolean) ?? [];
|
|
3364
|
+
return labelledBy.some(id => {
|
|
3365
|
+
const label = exactInput.ownerDocument.getElementById(id);
|
|
3366
|
+
return Boolean(label && (scope.contains(label) || label === scope.previousElementSibling));
|
|
3367
|
+
});
|
|
3368
|
+
}
|
|
3317
3369
|
const input = element instanceof HTMLInputElement && element.type === 'file' ? element : null;
|
|
3318
3370
|
const guardedAncestors = new Set();
|
|
3371
|
+
const receiptScopes = [];
|
|
3372
|
+
let capturedReceiptScope = false;
|
|
3319
3373
|
let current = input;
|
|
3320
3374
|
while (current) {
|
|
3321
3375
|
guardedAncestors.add(current);
|
|
3376
|
+
if (!capturedReceiptScope &&
|
|
3377
|
+
current !== input &&
|
|
3378
|
+
!(current instanceof HTMLFormElement) &&
|
|
3379
|
+
!(current instanceof HTMLBodyElement) &&
|
|
3380
|
+
!(current instanceof HTMLHtmlElement) &&
|
|
3381
|
+
input !== null &&
|
|
3382
|
+
explicitlyAssociatesFileInput(current, input) &&
|
|
3383
|
+
current.querySelectorAll('input[type="file"]').length === 1) {
|
|
3384
|
+
const initialExactTexts = [current, ...Array.from(current.querySelectorAll('*'))]
|
|
3385
|
+
.map(candidate => candidate.textContent?.replace(/\s+/g, ' ').trim() ?? '')
|
|
3386
|
+
.filter(Boolean);
|
|
3387
|
+
receiptScopes.push({ element: current, initialExactTexts });
|
|
3388
|
+
capturedReceiptScope = true;
|
|
3389
|
+
}
|
|
3390
|
+
if (current instanceof HTMLFormElement)
|
|
3391
|
+
break;
|
|
3322
3392
|
current = composedParent(current);
|
|
3323
3393
|
}
|
|
3324
3394
|
const initial = {
|
|
@@ -3331,6 +3401,7 @@ async function beginFileInputCommitGuard(handle) {
|
|
|
3331
3401
|
const state = {
|
|
3332
3402
|
input,
|
|
3333
3403
|
initial,
|
|
3404
|
+
receiptScopes,
|
|
3334
3405
|
invalidReason: null,
|
|
3335
3406
|
observer: null,
|
|
3336
3407
|
record: () => { },
|
|
@@ -3413,6 +3484,113 @@ async function stopFileInputCommitGuard(guard) {
|
|
|
3413
3484
|
value.observer.disconnect();
|
|
3414
3485
|
}).catch(() => { });
|
|
3415
3486
|
}
|
|
3487
|
+
async function readReactiveFileReceipt(guard, expectedNames) {
|
|
3488
|
+
return await guard.evaluate((value, names) => {
|
|
3489
|
+
function visible(element) {
|
|
3490
|
+
const style = getComputedStyle(element);
|
|
3491
|
+
return style.display !== 'none' &&
|
|
3492
|
+
style.visibility !== 'hidden' &&
|
|
3493
|
+
style.visibility !== 'collapse' &&
|
|
3494
|
+
element.getClientRects().length > 0;
|
|
3495
|
+
}
|
|
3496
|
+
const normalize = (text) => (text ?? '').replace(/\s+/g, ' ').trim();
|
|
3497
|
+
// The guard snapshots at most the exact input's nearest local wrapper.
|
|
3498
|
+
// Never combine its evidence with controls or filenames from an ancestor.
|
|
3499
|
+
const candidate = value.receiptScopes.find((entry) => entry.element.isConnected);
|
|
3500
|
+
if (!candidate) {
|
|
3501
|
+
return { hasScope: false, hasReceipt: false, hasProgress: false, hasError: false };
|
|
3502
|
+
}
|
|
3503
|
+
if (names.some(name => candidate.initialExactTexts.includes(name))) {
|
|
3504
|
+
return { hasScope: true, hasReceipt: false, hasProgress: false, hasError: false };
|
|
3505
|
+
}
|
|
3506
|
+
const scope = candidate.element;
|
|
3507
|
+
const descendants = [scope, ...Array.from(scope.querySelectorAll('*'))];
|
|
3508
|
+
const expectedCounts = new Map();
|
|
3509
|
+
for (const name of names)
|
|
3510
|
+
expectedCounts.set(name, (expectedCounts.get(name) ?? 0) + 1);
|
|
3511
|
+
const observedCounts = new Map();
|
|
3512
|
+
for (const element of descendants) {
|
|
3513
|
+
if (!visible(element))
|
|
3514
|
+
continue;
|
|
3515
|
+
const text = normalize(element.textContent);
|
|
3516
|
+
if (!expectedCounts.has(text))
|
|
3517
|
+
continue;
|
|
3518
|
+
// Count only the innermost exact-text element so nested wrappers cannot
|
|
3519
|
+
// manufacture duplicate filename evidence for one rendered receipt.
|
|
3520
|
+
const nestedExactText = Array.from(element.querySelectorAll('*')).some(descendant => visible(descendant) && normalize(descendant.textContent) === text);
|
|
3521
|
+
if (!nestedExactText)
|
|
3522
|
+
observedCounts.set(text, (observedCounts.get(text) ?? 0) + 1);
|
|
3523
|
+
}
|
|
3524
|
+
const hasExactNames = Array.from(expectedCounts).every(([name, count]) => observedCounts.get(name) === count);
|
|
3525
|
+
const hasRemovalControl = descendants.some((element) => {
|
|
3526
|
+
if (!visible(element) || !element.matches('button, [role="button"], a'))
|
|
3527
|
+
return false;
|
|
3528
|
+
const accessibleText = normalize(element.getAttribute('aria-label') ??
|
|
3529
|
+
element.getAttribute('title') ??
|
|
3530
|
+
element.textContent);
|
|
3531
|
+
const action = /^(remove|delete|clear|replace|change)\b/i.exec(accessibleText);
|
|
3532
|
+
if (!action)
|
|
3533
|
+
return false;
|
|
3534
|
+
const remainder = accessibleText.slice(action[0].length).trim();
|
|
3535
|
+
if (!remainder)
|
|
3536
|
+
return true;
|
|
3537
|
+
if (names.some(name => remainder.toLowerCase().includes(name.toLowerCase())))
|
|
3538
|
+
return true;
|
|
3539
|
+
return /^(?:(?:this|the|selected|uploaded|current)\s+)?(?:file|attachment|upload|document|resume|cv|cover letter)\b/i.test(remainder);
|
|
3540
|
+
});
|
|
3541
|
+
const hasProgress = descendants.some(element => visible(element) && element.matches('[role="progressbar"], progress, [aria-busy="true"]'));
|
|
3542
|
+
const hasError = descendants.some((element) => {
|
|
3543
|
+
if (!visible(element))
|
|
3544
|
+
return false;
|
|
3545
|
+
const role = normalize(element.getAttribute('role')).toLowerCase();
|
|
3546
|
+
if (role === 'alert' || role === 'alertdialog')
|
|
3547
|
+
return true;
|
|
3548
|
+
if (element.getAttribute('aria-invalid')?.trim().toLowerCase() === 'true')
|
|
3549
|
+
return true;
|
|
3550
|
+
const dataError = element.getAttribute('data-error');
|
|
3551
|
+
if (dataError !== null &&
|
|
3552
|
+
!/^(?:false|0|off|none)$/i.test(dataError.trim()))
|
|
3553
|
+
return true;
|
|
3554
|
+
for (const attribute of ['data-state', 'data-status', 'data-upload-state', 'data-file-state']) {
|
|
3555
|
+
const state = element.getAttribute(attribute)?.trim().toLowerCase();
|
|
3556
|
+
if (state && /^(?:error|invalid|failed|failure|rejected)$/.test(state))
|
|
3557
|
+
return true;
|
|
3558
|
+
}
|
|
3559
|
+
return Array.from(element.classList).some(className => /(?:^|[-_:])(?:error|errors|invalid|failed|failure)(?:$|[-_:])/i.test(className));
|
|
3560
|
+
});
|
|
3561
|
+
if (hasExactNames && hasRemovalControl && !hasProgress && !hasError) {
|
|
3562
|
+
return { hasScope: true, hasReceipt: true, hasProgress: false, hasError: false };
|
|
3563
|
+
}
|
|
3564
|
+
return { hasScope: true, hasReceipt: false, hasProgress, hasError };
|
|
3565
|
+
}, expectedNames);
|
|
3566
|
+
}
|
|
3567
|
+
/**
|
|
3568
|
+
* Some reactive uploaders detach the native input while streaming the file,
|
|
3569
|
+
* then render a filename receipt in the same field wrapper. Treat that as
|
|
3570
|
+
* success only when the exact new filenames and a removal control remain
|
|
3571
|
+
* stable after progress completes. A filename in an error message is not a
|
|
3572
|
+
* receipt, and an unbounded form-level match is never considered.
|
|
3573
|
+
*/
|
|
3574
|
+
async function confirmStableReactiveFileReceipt(guard, paths) {
|
|
3575
|
+
const expectedNames = expectedUploadNames(paths);
|
|
3576
|
+
const signalDeadline = Date.now() + 500;
|
|
3577
|
+
let completionDeadline = null;
|
|
3578
|
+
while (Date.now() < (completionDeadline ?? signalDeadline)) {
|
|
3579
|
+
const state = await readReactiveFileReceipt(guard, expectedNames).catch(() => null);
|
|
3580
|
+
if (!state?.hasScope || state.hasError)
|
|
3581
|
+
return false;
|
|
3582
|
+
if (state.hasReceipt) {
|
|
3583
|
+
await delay(100);
|
|
3584
|
+
const stable = await readReactiveFileReceipt(guard, expectedNames).catch(() => null);
|
|
3585
|
+
return Boolean(stable?.hasReceipt && !stable.hasProgress && !stable.hasError);
|
|
3586
|
+
}
|
|
3587
|
+
if (state.hasProgress && completionDeadline === null) {
|
|
3588
|
+
completionDeadline = Date.now() + 15_000;
|
|
3589
|
+
}
|
|
3590
|
+
await delay(50);
|
|
3591
|
+
}
|
|
3592
|
+
return false;
|
|
3593
|
+
}
|
|
3416
3594
|
async function clearAmbiguousRetainedFiles(handle, actualNames, initialNames) {
|
|
3417
3595
|
const selectionChanged = !uploadedNamesMatch(actualNames, initialNames);
|
|
3418
3596
|
if (!selectionChanged) {
|
|
@@ -3554,6 +3732,10 @@ async function commitFilesToExactInput(handle, paths, targetName, opts) {
|
|
|
3554
3732
|
opts?.successor &&
|
|
3555
3733
|
await confirmSameKeyFileInputSuccessor(opts.successor.page, handle, opts.successor.fieldKey, paths, initial))
|
|
3556
3734
|
return;
|
|
3735
|
+
if (!operationError &&
|
|
3736
|
+
identityChanged &&
|
|
3737
|
+
await confirmStableReactiveFileReceipt(guard, paths))
|
|
3738
|
+
return;
|
|
3557
3739
|
const cleanupOutcome = await clearAmbiguousRetainedFiles(handle, final.names, initial.names);
|
|
3558
3740
|
const operationReason = operationError instanceof Error
|
|
3559
3741
|
? `Playwright could not confirm the exact-target commit: ${operationError.message}`
|