@visa/cli 4.1.0-rc.157 → 4.1.0-rc.158

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.
@@ -1,5 +1,5 @@
1
1
  import { type Browser } from 'playwright-core';
2
- import { prepareCheckout as realPrepareCheckout, submitApprovedCheckout as realSubmitApprovedCheckout, type CheckoutOutcome, type PreparedCheckoutSessionStore } from './executor.js';
2
+ import { prepareCheckout as realPrepareCheckout, submitApprovedCheckout as realSubmitApprovedCheckout, type CheckoutOutcome, type CheckoutFailureCode, type CheckoutResult, type PreparedCheckoutSessionStore } from './executor.js';
3
3
  import { claimMandatePickup as realClaimMandatePickup, runHostedApproval as realRunHostedApproval } from './hosted-approval.js';
4
4
  import { type VgsCheckoutTarget } from './vgs-live-instrument.js';
5
5
  import { serverFetchCryptogram, serverPostConfirmation } from './vgs-gateway/server-mint-client.js';
@@ -51,6 +51,21 @@ export type CliReviewFacts = {
51
51
  submitTargetFingerprint: string;
52
52
  detectedRoles: string[];
53
53
  };
54
+ /**
55
+ * A checkout was inspected successfully but cannot be reviewed safely.
56
+ *
57
+ * The explicit fields survive the CLI's copied-engine boundary structurally,
58
+ * so MCP callers do not have to parse the human-readable message.
59
+ */
60
+ export declare class CheckoutReviewRefusedError extends Error {
61
+ readonly code = "CHECKOUT_REVIEW_REFUSED";
62
+ readonly checkoutOutcome: CheckoutOutcome;
63
+ readonly failureCode?: CheckoutFailureCode;
64
+ readonly requiresAdapter: string[];
65
+ readonly detectedRoles: string[];
66
+ readonly detail?: string;
67
+ constructor(result: CheckoutResult);
68
+ }
54
69
  export type CliPayInput = CliReviewInput & {
55
70
  reviewId: string;
56
71
  submit: boolean;
@@ -118,6 +118,31 @@ async function resolveCardInstrument(input) {
118
118
  '`visa agent grant-card <agent-id> --ceiling <usd> --per-transaction <usd> --wait` to ' +
119
119
  'attach one, or use a pre-provisioned VIC runtime.', readError instanceof Error ? { cause: readError } : undefined);
120
120
  }
121
+ /**
122
+ * A checkout was inspected successfully but cannot be reviewed safely.
123
+ *
124
+ * The explicit fields survive the CLI's copied-engine boundary structurally,
125
+ * so MCP callers do not have to parse the human-readable message.
126
+ */
127
+ export class CheckoutReviewRefusedError extends Error {
128
+ code = 'CHECKOUT_REVIEW_REFUSED';
129
+ checkoutOutcome;
130
+ failureCode;
131
+ requiresAdapter;
132
+ detectedRoles;
133
+ detail;
134
+ constructor(result) {
135
+ super(result.detail
136
+ ? `review refused: ${result.outcome} — ${result.detail}`
137
+ : `review refused: ${result.outcome}`);
138
+ this.name = 'CheckoutReviewRefusedError';
139
+ this.checkoutOutcome = result.outcome;
140
+ this.failureCode = result.failureCode;
141
+ this.requiresAdapter = [...result.requiresAdapter];
142
+ this.detectedRoles = Object.keys(result.fields);
143
+ this.detail = result.detail;
144
+ }
145
+ }
121
146
  function payAttemptFingerprint(input) {
122
147
  return JSON.stringify([
123
148
  input.url,
@@ -488,8 +513,7 @@ export function createCliCheckoutEngine(deps = {}) {
488
513
  contact: input.contact,
489
514
  }, store);
490
515
  if (prep.status !== 'ready') {
491
- await browser.close();
492
- throw new Error(`review refused: ${prep.result.outcome} — ${prep.result.detail ?? ''}`);
516
+ throw new CheckoutReviewRefusedError(prep.result);
493
517
  }
494
518
  const r = prep.checkout.review;
495
519
  // Expire the companion session on the SAME schedule as the store entry
@@ -11,6 +11,8 @@ export type CheckoutMode = 'dry-run' | 'submit';
11
11
  export type CheckoutOutcome = 'reviewed-dry-run'
12
12
  /** Historical receipt value from the credential-disclosing dry-run. */
13
13
  | 'filled-dry-run' | 'partial-fill' | 'adapter-required' | 'confirmed' | 'declined' | 'action-required' | 'cancelled' | 'blocked-by-mandate' | 'failed';
14
+ /** Stable machine-readable cause for an expected terminal checkout result. */
15
+ export type CheckoutFailureCode = 'card-number-field-unavailable' | 'human-action-required' | 'mandate-blocked';
14
16
  export type CredentialLifecycle = 'not-requested' | 'minted-not-exposed' | 'partially-exposed' | 'fully-filled';
15
17
  export type CredentialTiming = {
16
18
  approvedAt?: string;
@@ -26,6 +28,7 @@ export type CheckoutResult = {
26
28
  requiresAdapter: string[];
27
29
  credentialLifecycle: CredentialLifecycle;
28
30
  credentialTiming: CredentialTiming;
31
+ failureCode?: CheckoutFailureCode;
29
32
  detail?: string;
30
33
  };
31
34
  export type PrepareCheckoutOptions = {
@@ -341,7 +341,7 @@ function unknownPreparedCheckoutResult(reviewId) {
341
341
  evidence.step('approval', { approved: false, reviewId, reason: detail });
342
342
  return makeResult('failed', {}, evidence, [], detail);
343
343
  }
344
- function makeResult(outcome, fields, evidence, requiresAdapter, detail, confirmationRef) {
344
+ function makeResult(outcome, fields, evidence, requiresAdapter, detail, confirmationRef, failureCode) {
345
345
  const steps = evidence.getSteps();
346
346
  const approved = steps.find((step) => step.type === 'approval' && step.data.approved === true);
347
347
  const minted = steps.find((step) => step.type === 'credential-minted');
@@ -359,6 +359,12 @@ function makeResult(outcome, fields, evidence, requiresAdapter, detail, confirma
359
359
  : filledRoles.has('number') || filledRoles.has('cvc')
360
360
  ? 'partially-exposed'
361
361
  : 'minted-not-exposed';
362
+ const terminalFailureCode = failureCode ??
363
+ (outcome === 'action-required'
364
+ ? 'human-action-required'
365
+ : outcome === 'blocked-by-mandate'
366
+ ? 'mandate-blocked'
367
+ : undefined);
362
368
  return {
363
369
  outcome,
364
370
  fields,
@@ -373,6 +379,7 @@ function makeResult(outcome, fields, evidence, requiresAdapter, detail, confirma
373
379
  : {}),
374
380
  ...(completed ? { fillCompletedAt: completed.ts } : {}),
375
381
  },
382
+ ...(terminalFailureCode ? { failureCode: terminalFailureCode } : {}),
376
383
  ...(detail ? { detail } : {}),
377
384
  ...(confirmationRef ? { confirmationRef } : {}),
378
385
  };
@@ -844,7 +851,7 @@ export async function prepareCheckout(opts, store = defaultPreparedCheckoutStore
844
851
  evidence.setSnapshotSummary(await snapshotSummary(page));
845
852
  return {
846
853
  status: 'finished',
847
- result: makeResult('failed', fields, evidence, requiresAdapter, reason),
854
+ result: makeResult('failed', fields, evidence, requiresAdapter, reason, undefined, 'card-number-field-unavailable'),
848
855
  };
849
856
  }
850
857
  const facts = await readTransactionFacts(page, options, 'review');
@@ -1,6 +1,6 @@
1
- export { createCliCheckoutEngine, type CliReviewInput, type CliReviewFacts, type CliPayInput, type CliReceiptFacts, type CliStartMandateInput, type CliMandateFacts, type CliEngineDeps, } from './cli-engine.js';
1
+ export { createCliCheckoutEngine, type CliReviewInput, type CliReviewFacts, type CliPayInput, type CliReceiptFacts, type CliStartMandateInput, type CliMandateFacts, type CliEngineDeps, CheckoutReviewRefusedError, } from './cli-engine.js';
2
2
  export { prepareCheckout, submitApprovedCheckout, runCheckout, InMemoryPreparedCheckoutStore, } from './executor.js';
3
- export type { CheckoutResult, CheckoutReview, CheckoutOutcome } from './executor.js';
3
+ export type { CheckoutResult, CheckoutReview, CheckoutOutcome, CheckoutFailureCode, } from './executor.js';
4
4
  export { readConfirmedMerchants, type ConfirmedMerchant, type ConfirmedCharge, } from './confirmed-merchants.js';
5
5
  export { KNOWN_MERCHANT_IDENTITIES, type MerchantIdentity } from './known-merchants.js';
6
6
  export { RECEIPT_DIR } from './receipt-dir.js';
@@ -1,7 +1,7 @@
1
1
  // Public API of @visa/checkout-engine. The pay_merchant tool in @visa/cli
2
2
  // consumes createCliCheckoutEngine() through a structural seam; the core engine
3
3
  // primitives are re-exported for direct/embedded use.
4
- export { createCliCheckoutEngine, } from './cli-engine.js';
4
+ export { createCliCheckoutEngine, CheckoutReviewRefusedError, } from './cli-engine.js';
5
5
  export { prepareCheckout, submitApprovedCheckout, runCheckout, InMemoryPreparedCheckoutStore, } from './executor.js';
6
6
  export { readConfirmedMerchants, } from './confirmed-merchants.js';
7
7
  export { KNOWN_MERCHANT_IDENTITIES } from './known-merchants.js';