@visa/cli 4.1.0-rc.106 → 4.1.0-rc.108

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.
@@ -176,8 +176,8 @@ export function createCliCheckoutEngine(deps = {}) {
176
176
  .catch(() => false);
177
177
  process.stderr.write(marked
178
178
  ? `warning: card-mandate register failed (${reg.reason ?? 'unknown'}) — this mandate ` +
179
- `will NOT be used for tap-free draws; your next checkout will use a fresh ` +
180
- `per-purchase passkey tap. Re-run 'mandate start' to try again.\n`
179
+ `will NOT be used for tap-free draws; your next checkout will interrupt the owner ` +
180
+ `for a fresh per-purchase approval. Re-run 'mandate start' to try again.\n`
181
181
  : // Escalate: the mark write ALSO failed, so the mandate is persisted but
182
182
  // NOT disabled — findCovering could still select an undrawable mandate.
183
183
  // Tell the owner loudly not to rely on it and how to recover.
@@ -564,7 +564,7 @@ export function createCliCheckoutEngine(deps = {}) {
564
564
  confirmationRef: null,
565
565
  receiptPath: null,
566
566
  detail: 'this mandate cannot draw because its delegated card authority is unavailable; ' +
567
- 'restore the runtime binding or use a fresh per-purchase passkey approval',
567
+ 'restore the runtime binding or use a fresh per-purchase approval',
568
568
  vicConfirmation: null,
569
569
  source,
570
570
  remainingMinor: null,
@@ -662,7 +662,7 @@ export function createCliCheckoutEngine(deps = {}) {
662
662
  }
663
663
  throw new Error(verdictFailure.transient
664
664
  ? `the card-mandate draw could not be authorized right now (${verdictFailure.reasons.join(', ') || 'temporary error'}) — retry shortly`
665
- : `this card mandate can no longer be drawn (${verdictFailure.reasons.join(', ') || 'refused'}); it has been disabled — retry the checkout to use a fresh per-purchase passkey tap`, { cause: err });
665
+ : `this card mandate can no longer be drawn (${verdictFailure.reasons.join(', ') || 'refused'}); it has been disabled — retry the checkout to use a fresh per-purchase approval`, { cause: err });
666
666
  }
667
667
  if (!isTransientDrawFailure(err.cause ?? err)) {
668
668
  await ledger.markUnhonored(mandateId, now());
@@ -93,6 +93,7 @@ export type SubmitApprovedCheckoutOptions = {
93
93
  onChallengeHold?: (signal: string | null) => void;
94
94
  resolveEmailOtp?: OtpResolver;
95
95
  };
96
+ export declare function snapshotOrigin(rawUrl: string): string;
96
97
  export type PreparedCheckoutSession = {
97
98
  checkout: PreparedCheckout;
98
99
  context: BrowserContext;
@@ -145,6 +145,19 @@ async function findSubmit(page) {
145
145
  }
146
146
  return null;
147
147
  }
148
+ // The diagnostic snapshot records the page ORIGIN only, never the full URL: a
149
+ // payment-session path/query (e.g. a live Stripe `cs_live_...` checkout-session
150
+ // id) must not be retained in the local receipt, which elsewhere promises
151
+ // "hostname only" (#7101). Falls back to the raw value only if it does not parse
152
+ // as a URL (never a real page.url()).
153
+ export function snapshotOrigin(rawUrl) {
154
+ try {
155
+ return new URL(rawUrl).origin;
156
+ }
157
+ catch {
158
+ return '';
159
+ }
160
+ }
148
161
  async function snapshotSummary(page) {
149
162
  const info = await page
150
163
  .evaluate(() => {
@@ -153,7 +166,7 @@ async function snapshotSummary(page) {
153
166
  return { title: document.title, heading: heading?.textContent?.trim() || '', body };
154
167
  })
155
168
  .catch(() => ({ title: '', heading: '', body: '' }));
156
- return `url=${page.url()} title="${info.title}" heading="${info.heading}" body="${info.body}"`;
169
+ return `url=${snapshotOrigin(page.url())} title="${info.title}" heading="${info.heading}" body="${info.body}"`;
157
170
  }
158
171
  async function readConfirmationRef(page) {
159
172
  const ref = await page
@@ -155,7 +155,12 @@ export async function runHostedApproval(opts) {
155
155
  const verifier = randomBytes(32).toString('base64url');
156
156
  const challenge = createHash('sha256').update(verifier, 'utf8').digest('base64url');
157
157
  const deadline = now() + timeoutMs;
158
- const timeoutError = () => new Error(`no passkey approval within ${Math.round(timeoutMs / 1000)}s — ` +
158
+ // Verification-neutral: what the page asks the human for is a per-card
159
+ // property (passkey ceremony, issuer one-time code, or nothing beyond the
160
+ // signed-in approval) that this runner never learns. Naming a passkey here
161
+ // told operators on code-verified cards to wait for a device prompt that was
162
+ // never coming, and then blamed the timeout on the step they never saw.
163
+ const timeoutError = () => new Error(`no approval within ${Math.round(timeoutMs / 1000)}s — ` +
159
164
  'the checkout was cancelled; run again to retry');
160
165
  // Bound EVERY request by the remaining deadline: race the fetch against the
161
166
  // (injectable) sleep and abort the request when the deadline wins, so a
@@ -312,7 +317,7 @@ export async function runHostedApproval(opts) {
312
317
  }
313
318
  log(assuranceExempt
314
319
  ? 'approval received from the hosted page (code-verified card, no passkey).'
315
- : 'passkey approval received from the hosted page.');
320
+ : 'approval received from the hosted page (passkey-verified card).');
316
321
  return {
317
322
  ...assuranceFromCeremony(target, doc.assuranceData ?? null),
318
323
  ...(assuranceExempt ? { assuranceExempt: true } : {}),