@visa/cli 4.1.0-rc.13 → 4.1.0-rc.131
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/README.md +188 -232
- package/dist/checkout-engine/adapters/generic.d.ts +4 -0
- package/dist/checkout-engine/adapters/generic.js +28 -13
- package/dist/checkout-engine/adapters/index.d.ts +4 -1
- package/dist/checkout-engine/adapters/index.js +10 -3
- package/dist/checkout-engine/adapters/shopify.d.ts +31 -0
- package/dist/checkout-engine/adapters/shopify.js +423 -0
- package/dist/checkout-engine/amount.d.ts +15 -0
- package/dist/checkout-engine/amount.js +72 -0
- package/dist/checkout-engine/cli-engine.d.ts +207 -2
- package/dist/checkout-engine/cli-engine.js +677 -27
- package/dist/checkout-engine/detect.d.ts +1 -1
- package/dist/checkout-engine/detect.js +26 -0
- package/dist/checkout-engine/evidence.d.ts +4 -1
- package/dist/checkout-engine/evidence.js +51 -6
- package/dist/checkout-engine/executor.d.ts +34 -4
- package/dist/checkout-engine/executor.js +266 -115
- package/dist/checkout-engine/hosted-approval.d.ts +133 -8
- package/dist/checkout-engine/hosted-approval.js +400 -49
- package/dist/checkout-engine/index.d.ts +4 -1
- package/dist/checkout-engine/index.js +3 -0
- package/dist/checkout-engine/instrument.d.ts +7 -0
- package/dist/checkout-engine/instrument.js +4 -0
- package/dist/checkout-engine/live-fill-approval.d.ts +0 -20
- package/dist/checkout-engine/live-fill-approval.js +15 -51
- package/dist/checkout-engine/mandate/card-mandate.d.ts +121 -0
- package/dist/checkout-engine/mandate/card-mandate.js +227 -0
- package/dist/checkout-engine/mandate/mandate-ledger.d.ts +165 -0
- package/dist/checkout-engine/mandate/mandate-ledger.js +373 -0
- package/dist/checkout-engine/outcome.d.ts +2 -2
- package/dist/checkout-engine/outcome.js +36 -1
- package/dist/checkout-engine/owner-only-file.d.ts +9 -0
- package/dist/checkout-engine/owner-only-file.js +20 -1
- package/dist/checkout-engine/trace-handles.d.ts +8 -0
- package/dist/checkout-engine/trace-handles.js +12 -0
- package/dist/checkout-engine/types.d.ts +20 -2
- package/dist/checkout-engine/vgs-gateway/server-mint-client.d.ts +82 -0
- package/dist/checkout-engine/vgs-gateway/server-mint-client.js +180 -0
- package/dist/checkout-engine/vgs-live-instrument.d.ts +38 -0
- package/dist/checkout-engine/vgs-live-instrument.js +52 -8
- package/dist/checkout-engine/vic-confirmation.js +2 -2
- package/dist/cli.js +580 -494
- package/dist/mcp-server/index.js +442 -176
- package/dist/skills/pair-visa-agent/RUNTIMES.md +92 -0
- package/dist/skills/pair-visa-agent/SKILL.md +467 -0
- package/dist/skills/pair-visa-agent/scripts/setup.mjs +48 -0
- package/install.ps1 +3 -41
- package/install.sh +4 -36
- package/native/bin/win32-x64/visa-keychain-win.exe +0 -0
- package/package.json +16 -12
- package/server.json +3 -3
- package/dist/checkout-engine/inline-target.d.ts +0 -13
- package/dist/checkout-engine/inline-target.js +0 -37
- package/dist/checkout-engine/pay-args.d.ts +0 -14
- package/dist/checkout-engine/pay-args.js +0 -44
- package/dist/checkout-engine/pay.d.ts +0 -1
- package/dist/checkout-engine/pay.js +0 -13
- package/dist/checkout-engine/repo-env.d.ts +0 -11
- package/dist/checkout-engine/repo-env.js +0 -23
- package/dist/checkout-engine/run-live-fill.d.ts +0 -1
- package/dist/checkout-engine/run-live-fill.js +0 -443
- package/dist/checkout-engine/vgs-gateway/fetch-credential.d.mts +0 -74
- package/dist/checkout-engine/vgs-gateway/fetch-credential.mjs +0 -240
|
@@ -1,15 +1,30 @@
|
|
|
1
1
|
import { type Browser } from 'playwright-core';
|
|
2
2
|
import { prepareCheckout as realPrepareCheckout, submitApprovedCheckout as realSubmitApprovedCheckout, type PreparedCheckoutSessionStore } from './executor.js';
|
|
3
|
-
import { runHostedApproval as realRunHostedApproval } from './hosted-approval.js';
|
|
3
|
+
import { claimMandatePickup as realClaimMandatePickup, runHostedApproval as realRunHostedApproval } from './hosted-approval.js';
|
|
4
4
|
import { type VgsCheckoutTarget } from './vgs-live-instrument.js';
|
|
5
|
+
import { serverFetchCryptogram, serverPostConfirmation } from './vgs-gateway/server-mint-client.js';
|
|
6
|
+
import { type CardMandateFacts } from './mandate/card-mandate.js';
|
|
7
|
+
import { MandateLedger } from './mandate/mandate-ledger.js';
|
|
5
8
|
import { writeReceipt as realWriteReceipt } from './receipt.js';
|
|
6
9
|
import { reportVicOutcome as realReportVicOutcome, type VicConfirmationReport } from './vic-confirmation.js';
|
|
7
|
-
import type { Contact } from './types.js';
|
|
10
|
+
import type { Contact, OtpResolver } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* A card-mandate draw failed transiently (retryable) rather than definitively.
|
|
13
|
+
* Gateway 5xx, "server cryptogram not completed / try again", and network
|
|
14
|
+
* reset/timeout errors are transient: the mandate stays healthy and must NOT be
|
|
15
|
+
* disabled. Walks the error's cause chain so a wrapped MandateDrawDeclinedError
|
|
16
|
+
* is classified by its underlying gateway error. Exported for tests.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isTransientDrawFailure(err: unknown): boolean;
|
|
8
19
|
export type CliReviewInput = {
|
|
9
20
|
url: string;
|
|
10
21
|
amount: string;
|
|
11
22
|
currency: string;
|
|
12
23
|
credentialPath: string;
|
|
24
|
+
/** See {@link CardInstrumentSource}. */
|
|
25
|
+
cardTokenId?: string;
|
|
26
|
+
/** Exact request-key identity selected by the caller. */
|
|
27
|
+
agentJkt?: string;
|
|
13
28
|
contact: Contact;
|
|
14
29
|
approvalBaseUrl: string;
|
|
15
30
|
merchantName?: string;
|
|
@@ -26,6 +41,12 @@ export type CliReviewFacts = {
|
|
|
26
41
|
export type CliPayInput = CliReviewInput & {
|
|
27
42
|
reviewId: string;
|
|
28
43
|
submit: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Headless handoff for this payment attempt. The MCP layer uses it to return
|
|
46
|
+
* the hosted passkey URL to a messaging surface while the engine continues
|
|
47
|
+
* waiting in-process.
|
|
48
|
+
*/
|
|
49
|
+
onApprovalUrl?: (url: string) => void;
|
|
29
50
|
};
|
|
30
51
|
export type CliReceiptFacts = {
|
|
31
52
|
outcome: string;
|
|
@@ -33,6 +54,81 @@ export type CliReceiptFacts = {
|
|
|
33
54
|
receiptPath: string | null;
|
|
34
55
|
detail: string | null;
|
|
35
56
|
vicConfirmation: VicConfirmationReport | null;
|
|
57
|
+
/**
|
|
58
|
+
* Which credential path actually ran: `mandate` = tap-free draw against an
|
|
59
|
+
* existing card mandate; `fresh-tap` = today's 1:1 hosted-passkey mint; `null`
|
|
60
|
+
* = neither ran (a pre-flight refusal, e.g. no prepared review). Transparency,
|
|
61
|
+
* never magic — the caller can always see whether a passkey was skipped.
|
|
62
|
+
*/
|
|
63
|
+
source: 'mandate' | 'fresh-tap' | null;
|
|
64
|
+
/** Remaining mandate budget (minor units) after a mandate draw; else null. */
|
|
65
|
+
remainingMinor: number | null;
|
|
66
|
+
/**
|
|
67
|
+
* Immutable VIC/VGS intent used for server-side receipt correlation. This is
|
|
68
|
+
* an opaque non-credential identifier; it never carries the mint/verdict
|
|
69
|
+
* bearer that authorizes a cryptogram or confirmation. Present only after a
|
|
70
|
+
* card confirmation target exists.
|
|
71
|
+
*/
|
|
72
|
+
processorIntentId?: string | null;
|
|
73
|
+
};
|
|
74
|
+
export type CliStartMandateInput = {
|
|
75
|
+
/** Optional local card-capability selector (legacy name or exact request-key JKT). */
|
|
76
|
+
agentRef?: string;
|
|
77
|
+
ceiling: string;
|
|
78
|
+
currency: string;
|
|
79
|
+
credentialPath: string;
|
|
80
|
+
/** See {@link CardInstrumentSource}. */
|
|
81
|
+
cardTokenId?: string;
|
|
82
|
+
contact: Contact;
|
|
83
|
+
approvalBaseUrl: string;
|
|
84
|
+
/**
|
|
85
|
+
* Per-purchase cap (decimal string, > 0 and <= ceiling). Registered with the
|
|
86
|
+
* approval context so the operator reads it as a worst-case term, and carried
|
|
87
|
+
* onto the budget mint token so it is enforced at draw time.
|
|
88
|
+
*/
|
|
89
|
+
perTransaction?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Agent-supplied one-liner shown on the approval page in a labeled
|
|
92
|
+
* "written by the agent" block — provenance for the human, never trusted.
|
|
93
|
+
*/
|
|
94
|
+
intent?: string;
|
|
95
|
+
};
|
|
96
|
+
export type CliClaimMandateInput = {
|
|
97
|
+
/** Optional local card-capability selector (legacy name or exact request-key JKT). */
|
|
98
|
+
agentRef?: string;
|
|
99
|
+
/** Single-use pickup code the owner handed over from the panel. */
|
|
100
|
+
pickupCode: string;
|
|
101
|
+
/**
|
|
102
|
+
* The agent handoff this runtime just redeemed, when the pickup code rode
|
|
103
|
+
* inside its claim code. A dialog-minted budget pins that handoff instead of
|
|
104
|
+
* a key — there was no key yet — so this is what the pin is checked against.
|
|
105
|
+
*/
|
|
106
|
+
expectedHandoffId?: string;
|
|
107
|
+
credentialPath: string;
|
|
108
|
+
/** See {@link CardInstrumentSource}. */
|
|
109
|
+
cardTokenId?: string;
|
|
110
|
+
approvalBaseUrl: string;
|
|
111
|
+
};
|
|
112
|
+
export type CliMandateFacts = CardMandateFacts & {
|
|
113
|
+
merchantHost: string;
|
|
114
|
+
/**
|
|
115
|
+
* True when the mandate minted its ceiling intent but the #5942 register
|
|
116
|
+
* handshake failed, so `findCovering` will SKIP it and no tap-free draw is
|
|
117
|
+
* possible. The mandate exists but is not usable — the caller must surface
|
|
118
|
+
* this (not report a plain success). Absent/false means registration succeeded;
|
|
119
|
+
* mandate-start now refuses before approval when no capability can register.
|
|
120
|
+
*/
|
|
121
|
+
registerFailed?: boolean;
|
|
122
|
+
/**
|
|
123
|
+
* The server's refusal reason when {@link registerFailed} is true, verbatim.
|
|
124
|
+
* Carried out so the CLI can distinguish causes that need DIFFERENT operator
|
|
125
|
+
* actions — notably `token_mismatch`, which means the on-device grant record's
|
|
126
|
+
* cached token no longer matches the owner's live agentic token (they
|
|
127
|
+
* re-enrolled a card after the grant) and is fixed by re-running `grant-card`,
|
|
128
|
+
* not by retrying `mandate start`. Without the reason every failure reads as
|
|
129
|
+
* "the auth server was unreachable", which sends the operator in a loop.
|
|
130
|
+
*/
|
|
131
|
+
registerFailureReason?: string;
|
|
36
132
|
};
|
|
37
133
|
type Session = {
|
|
38
134
|
browser: Browser;
|
|
@@ -40,21 +136,130 @@ type Session = {
|
|
|
40
136
|
amountMinor: number;
|
|
41
137
|
currency: string;
|
|
42
138
|
contact: Contact;
|
|
139
|
+
agentJkt?: string;
|
|
43
140
|
cleanupTimer: ReturnType<typeof setTimeout>;
|
|
44
141
|
};
|
|
142
|
+
export interface CardDrawVerdictDraw {
|
|
143
|
+
tokenId: string;
|
|
144
|
+
amount: string;
|
|
145
|
+
currency: string;
|
|
146
|
+
merchantName: string;
|
|
147
|
+
merchantUrl: string;
|
|
148
|
+
merchantCountryCode: string;
|
|
149
|
+
}
|
|
150
|
+
export interface CardDrawVerdictCapability {
|
|
151
|
+
/** Opaque to the engine — passed straight back to {@link CardDrawVerdictSeam.fetchVerdict}. */
|
|
152
|
+
agentKey: unknown;
|
|
153
|
+
agentJkt: string;
|
|
154
|
+
/** Auth origin that minted the binding and hosts the /v4/card/draw* routes. */
|
|
155
|
+
authBaseUrl: string;
|
|
156
|
+
}
|
|
157
|
+
export interface CardDrawVerdictSeam {
|
|
158
|
+
loadCapability: (agentRef?: string) => CardDrawVerdictCapability | null;
|
|
159
|
+
fetchVerdict: (input: {
|
|
160
|
+
authBaseUrl: string;
|
|
161
|
+
agentKey: unknown;
|
|
162
|
+
mandateId: string;
|
|
163
|
+
drawId: string;
|
|
164
|
+
draw: CardDrawVerdictDraw;
|
|
165
|
+
}) => Promise<{
|
|
166
|
+
verdict: string;
|
|
167
|
+
remainingCents: number;
|
|
168
|
+
}>;
|
|
169
|
+
}
|
|
170
|
+
export interface CardMandateRegisterSeam {
|
|
171
|
+
loadCapability: (agentRef?: string) => {
|
|
172
|
+
agentKey: unknown;
|
|
173
|
+
agentJkt: string;
|
|
174
|
+
authBaseUrl: string;
|
|
175
|
+
} | null;
|
|
176
|
+
register: (input: {
|
|
177
|
+
authBaseUrl: string;
|
|
178
|
+
agentKey: unknown;
|
|
179
|
+
mandateId: string;
|
|
180
|
+
mintToken: string;
|
|
181
|
+
ceiling: string;
|
|
182
|
+
currency: string;
|
|
183
|
+
}) => Promise<{
|
|
184
|
+
ok: boolean;
|
|
185
|
+
reason?: string;
|
|
186
|
+
/**
|
|
187
|
+
* The ceiling the server committed — `min(requested, the owner's live card
|
|
188
|
+
* grant cap)`. Omitted by an older auth that does not report it, in which
|
|
189
|
+
* case the requested ceiling stands.
|
|
190
|
+
*/
|
|
191
|
+
approvedCeilingMinor?: number;
|
|
192
|
+
}>;
|
|
193
|
+
}
|
|
45
194
|
export type CliEngineDeps = {
|
|
46
195
|
launchBrowser?: () => Promise<Browser>;
|
|
47
196
|
prepareCheckout?: typeof realPrepareCheckout;
|
|
48
197
|
submitApprovedCheckout?: typeof realSubmitApprovedCheckout;
|
|
49
198
|
runHostedApproval?: typeof realRunHostedApproval;
|
|
199
|
+
/** Injectable pickup-code redeem for claimCardMandate — tests pass a fake. */
|
|
200
|
+
claimMandatePickup?: typeof realClaimMandatePickup;
|
|
201
|
+
/**
|
|
202
|
+
* Relay the hosted-approval URL to the caller as DATA the moment it is known,
|
|
203
|
+
* before the (up-to-timeout) poll wait. A headless agent surface wires this to
|
|
204
|
+
* hand the URL to its operator; the raw CLI leaves it unset (the URL prints to
|
|
205
|
+
* stderr and best-effort opens a browser).
|
|
206
|
+
*/
|
|
207
|
+
onApprovalUrl?: (url: string) => void;
|
|
50
208
|
reportVicOutcome?: typeof realReportVicOutcome;
|
|
51
209
|
writeReceipt?: typeof realWriteReceipt;
|
|
52
210
|
store?: PreparedCheckoutSessionStore;
|
|
53
211
|
sessions?: Map<string, Session>;
|
|
54
212
|
ttlMs?: number;
|
|
213
|
+
/** Owner-only card-mandate ledger — defaults to the ~/.visa-mcp singleton. */
|
|
214
|
+
ledger?: MandateLedger;
|
|
215
|
+
/** Injectable clock for mandate expiry decisions (tests pin it). */
|
|
216
|
+
now?: () => Date;
|
|
217
|
+
/**
|
|
218
|
+
* Cryptogram transport for the TAP-FREE mandate draw — defaults to the real
|
|
219
|
+
* server-side mint route. Injectable so a test can drive the draw-reject ->
|
|
220
|
+
* markUnhonored path with no network.
|
|
221
|
+
*/
|
|
222
|
+
serverFetchCryptogram?: typeof serverFetchCryptogram;
|
|
223
|
+
/** Injectable confirmation transport; defaults to verify-web. */
|
|
224
|
+
serverPostConfirmation?: typeof serverPostConfirmation;
|
|
225
|
+
/**
|
|
226
|
+
* #5923 delegated card-draw verdict seam (see {@link CardDrawVerdictSeam}).
|
|
227
|
+
* Injected by the CLI when the runtime holds separately provisioned card
|
|
228
|
+
* authority. When absent, a covering-mandate draw fails before cryptogram mint.
|
|
229
|
+
*/
|
|
230
|
+
cardDrawVerdict?: CardDrawVerdictSeam;
|
|
231
|
+
/**
|
|
232
|
+
* #5942 delegated card-mandate register seam (see {@link CardMandateRegisterSeam}).
|
|
233
|
+
* Required by mandate-start. When absent, the ceremony is refused before
|
|
234
|
+
* passkey approval because a budget token cannot act as draw authority.
|
|
235
|
+
*/
|
|
236
|
+
cardMandateRegister?: CardMandateRegisterSeam;
|
|
237
|
+
/**
|
|
238
|
+
* Canonical mailbox OTP reader supplied by the runtime. The checkout engine
|
|
239
|
+
* owns no mailbox credential and never imports an email provider package.
|
|
240
|
+
*/
|
|
241
|
+
resolveEmailOtp?: OtpResolver;
|
|
55
242
|
};
|
|
56
243
|
export declare function createCliCheckoutEngine(deps?: CliEngineDeps): {
|
|
244
|
+
startCardMandate(input: CliStartMandateInput): Promise<CliMandateFacts>;
|
|
245
|
+
claimCardMandate(input: CliClaimMandateInput): Promise<CliMandateFacts>;
|
|
57
246
|
review(input: CliReviewInput): Promise<CliReviewFacts>;
|
|
247
|
+
/**
|
|
248
|
+
* Give up a prepared review without paying it (#7100).
|
|
249
|
+
*
|
|
250
|
+
* The retained browser is what lets a same-process MCP `review` → `pay`
|
|
251
|
+
* draw against the checkout it already inspected. A TERMINAL review-only
|
|
252
|
+
* run has no such second call — that process tells the operator to re-RUN
|
|
253
|
+
* with `--submit`, and the new process cannot reach this one's in-memory
|
|
254
|
+
* session. So the browser sat open for the full TTL, and because a live
|
|
255
|
+
* browser connection keeps the event loop alive, a command that had already
|
|
256
|
+
* succeeded looked hung until Ctrl-C.
|
|
257
|
+
*
|
|
258
|
+
* Idempotent and non-throwing: an unknown or already-released id is a
|
|
259
|
+
* no-op, so it is safe on an error path that may not have prepared anything
|
|
260
|
+
* and safe to call twice.
|
|
261
|
+
*/
|
|
262
|
+
releaseReview(reviewId: string): Promise<void>;
|
|
58
263
|
pay(input: CliPayInput): Promise<CliReceiptFacts>;
|
|
59
264
|
};
|
|
60
265
|
export {};
|