@visa/cli 4.1.0-rc.196 → 4.1.0-rc.197
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.
|
@@ -128,8 +128,8 @@ export type SubmitCandidateMeta = {
|
|
|
128
128
|
visible: boolean;
|
|
129
129
|
area: number;
|
|
130
130
|
};
|
|
131
|
-
export declare function preferredSubmitIndex(cands: readonly SubmitCandidateMeta[],
|
|
132
|
-
|
|
131
|
+
export declare function preferredSubmitIndex(cands: readonly SubmitCandidateMeta[], opts?: {
|
|
132
|
+
allowDeferred?: boolean;
|
|
133
133
|
}): number;
|
|
134
134
|
export declare function snapshotOrigin(rawUrl: string): string;
|
|
135
135
|
export type PreparedCheckoutSession = {
|
|
@@ -131,21 +131,28 @@ async function fingerprintSubmitTarget(locator, kind, fallbackLabel) {
|
|
|
131
131
|
// (observed live: `<h3 id="billingAddress"> intercepts pointer events`, retried
|
|
132
132
|
// until the 6s timeout, deterministically, on casper.com). Rank the real
|
|
133
133
|
// controls ahead of the inert ones and prefer a pay-labelled control.
|
|
134
|
-
export function preferredSubmitIndex(cands,
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if (
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
134
|
+
export function preferredSubmitIndex(cands, opts = {}) {
|
|
135
|
+
const indexed = cands.map((c, i) => ({ c, i }));
|
|
136
|
+
const usable = indexed.filter(({ c }) => c.visible && !c.ariaHidden && c.tabIndex !== -1 && c.area > 0);
|
|
137
|
+
const usablePayLike = usable.find(({ c }) => PAY_LABEL.test(c.label));
|
|
138
|
+
if (usablePayLike)
|
|
139
|
+
return usablePayLike.i;
|
|
140
|
+
if (!opts.allowDeferred)
|
|
141
|
+
return usable[0]?.i ?? -1;
|
|
142
|
+
// A genuine multi-step checkout can keep its final submit control inside a
|
|
143
|
+
// hidden payment section until a safe, non-submit Continue button advances
|
|
144
|
+
// the page. The human still needs that exact control bound into the review
|
|
145
|
+
// before approval. Accept it for fingerprinting only when it is not marked
|
|
146
|
+
// inert; the pre-click lookup remains strict and will refuse unless the same
|
|
147
|
+
// control becomes visible and has non-zero area after reveal.
|
|
148
|
+
const deferred = indexed.filter(({ c }) => !c.ariaHidden && c.tabIndex !== -1);
|
|
149
|
+
if (deferred.length === 0)
|
|
143
150
|
return -1;
|
|
144
|
-
const
|
|
145
|
-
return
|
|
151
|
+
const deferredPayLike = deferred.find(({ c }) => PAY_LABEL.test(c.label));
|
|
152
|
+
return (deferredPayLike ?? usable[0] ?? deferred[0]).i;
|
|
146
153
|
}
|
|
147
154
|
const PAY_LABEL = /pay|place order|complete order|submit order|buy now/i;
|
|
148
|
-
async function findSubmit(page,
|
|
155
|
+
async function findSubmit(page, opts = {}) {
|
|
149
156
|
const controls = page.locator('button[type="submit"], input[type="submit"]');
|
|
150
157
|
const handles = await controls.all().catch(() => []);
|
|
151
158
|
if (handles.length > 0) {
|
|
@@ -164,7 +171,7 @@ async function findSubmit(page, options = {}) {
|
|
|
164
171
|
area: box ? box.width * box.height : 0,
|
|
165
172
|
};
|
|
166
173
|
}));
|
|
167
|
-
const idx = preferredSubmitIndex(metas,
|
|
174
|
+
const idx = preferredSubmitIndex(metas, opts);
|
|
168
175
|
if (idx >= 0) {
|
|
169
176
|
const chosen = handles[idx];
|
|
170
177
|
const label = metas[idx].label || 'submit';
|
|
@@ -917,10 +924,10 @@ export async function prepareCheckout(opts, store = defaultPreparedCheckoutStore
|
|
|
917
924
|
result: makeResult('blocked-by-mandate', fields, evidence, requiresAdapter, verdict.reason),
|
|
918
925
|
};
|
|
919
926
|
}
|
|
920
|
-
//
|
|
921
|
-
//
|
|
922
|
-
// the
|
|
923
|
-
const submit = await findSubmit(page, {
|
|
927
|
+
// Multi-step pages may expose the final submit control in a hidden section
|
|
928
|
+
// before a safe Continue reveals it. Fingerprint that exact control for the
|
|
929
|
+
// human review; the eventual click path still requires it to be usable.
|
|
930
|
+
const submit = await findSubmit(page, { allowDeferred: true });
|
|
924
931
|
const review = Object.freeze({
|
|
925
932
|
id: randomUUID(),
|
|
926
933
|
url: page.url(),
|
|
@@ -1043,8 +1050,8 @@ export async function submitApprovedCheckout(reviewId, opts, store = defaultPrep
|
|
|
1043
1050
|
}
|
|
1044
1051
|
// Revalidate the same future target before credential minting. This may be
|
|
1045
1052
|
// hidden on a multi-step checkout; the final lookup after reveal requires
|
|
1046
|
-
//
|
|
1047
|
-
const approvalSubmit = await findSubmit(page, {
|
|
1053
|
+
// the reviewed control to be visible and usable before any click.
|
|
1054
|
+
const approvalSubmit = await findSubmit(page, { allowDeferred: true });
|
|
1048
1055
|
const submitChangedAtApproval = submitTargetChangeReason(checkout.review, approvalSubmit);
|
|
1049
1056
|
if (submitChangedAtApproval) {
|
|
1050
1057
|
evidence.step('approval', {
|