@visa/cli 4.1.0-rc.203 → 4.1.0-rc.205
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/checkout-engine/cli-engine.d.ts +5 -0
- package/dist/checkout-engine/cli-engine.js +6 -0
- package/dist/checkout-engine/mandate/card-mandate.d.ts +1 -1
- package/dist/checkout-engine/mandate/card-mandate.js +0 -1
- package/dist/checkout-engine/mandate/mandate-ledger.d.ts +1 -5
- package/dist/checkout-engine/mandate/mandate-ledger.js +19 -4
- package/dist/cli.js +411 -406
- package/dist/mcp-server/index.js +327 -322
- package/native/bin/win32-x64/visa-keychain-win.exe +0 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -198,6 +198,8 @@ export interface CardDrawVerdictDraw {
|
|
|
198
198
|
export interface CardDrawVerdictCapability {
|
|
199
199
|
/** Opaque to the engine — passed straight back to {@link CardDrawVerdictSeam.fetchVerdict}. */
|
|
200
200
|
agentKey: unknown;
|
|
201
|
+
/** Root-signed delegation for a short-lived device key. */
|
|
202
|
+
runtimeCertificate?: string;
|
|
201
203
|
agentJkt: string;
|
|
202
204
|
/** Auth origin that minted the binding and hosts the /v4/card/draw* routes. */
|
|
203
205
|
authBaseUrl: string;
|
|
@@ -207,6 +209,7 @@ export interface CardDrawVerdictSeam {
|
|
|
207
209
|
fetchVerdict: (input: {
|
|
208
210
|
authBaseUrl: string;
|
|
209
211
|
agentKey: unknown;
|
|
212
|
+
runtimeCertificate?: string;
|
|
210
213
|
mandateId: string;
|
|
211
214
|
drawId: string;
|
|
212
215
|
draw: CardDrawVerdictDraw;
|
|
@@ -218,12 +221,14 @@ export interface CardDrawVerdictSeam {
|
|
|
218
221
|
export interface CardMandateRegisterSeam {
|
|
219
222
|
loadCapability: (agentRef?: string) => {
|
|
220
223
|
agentKey: unknown;
|
|
224
|
+
runtimeCertificate?: string;
|
|
221
225
|
agentJkt: string;
|
|
222
226
|
authBaseUrl: string;
|
|
223
227
|
} | null;
|
|
224
228
|
register: (input: {
|
|
225
229
|
authBaseUrl: string;
|
|
226
230
|
agentKey: unknown;
|
|
231
|
+
runtimeCertificate?: string;
|
|
227
232
|
mandateId: string;
|
|
228
233
|
mintToken: string;
|
|
229
234
|
ceiling: string;
|
|
@@ -241,6 +241,9 @@ export function createCliCheckoutEngine(deps = {}) {
|
|
|
241
241
|
.register({
|
|
242
242
|
authBaseUrl: args.registerCap.authBaseUrl,
|
|
243
243
|
agentKey: args.registerCap.agentKey,
|
|
244
|
+
...(args.registerCap.runtimeCertificate
|
|
245
|
+
? { runtimeCertificate: args.registerCap.runtimeCertificate }
|
|
246
|
+
: {}),
|
|
244
247
|
mandateId: args.mandateId,
|
|
245
248
|
mintToken: args.mintToken,
|
|
246
249
|
ceiling: args.ceiling,
|
|
@@ -804,6 +807,9 @@ export function createCliCheckoutEngine(deps = {}) {
|
|
|
804
807
|
const { verdict } = await verdictSeam.fetchVerdict({
|
|
805
808
|
authBaseUrl: capability.authBaseUrl,
|
|
806
809
|
agentKey: capability.agentKey,
|
|
810
|
+
...(capability.runtimeCertificate
|
|
811
|
+
? { runtimeCertificate: capability.runtimeCertificate }
|
|
812
|
+
: {}),
|
|
807
813
|
mandateId,
|
|
808
814
|
// One draw per review; the reviewId is auth's idempotency key.
|
|
809
815
|
drawId: input.reviewId,
|
|
@@ -51,7 +51,7 @@ export type CreateCardMandateDeps = {
|
|
|
51
51
|
ledger: MandateLedger;
|
|
52
52
|
/** verify-web origin the intent is minted against (persisted for later draws). */
|
|
53
53
|
approvalBaseUrl: string;
|
|
54
|
-
/**
|
|
54
|
+
/** @deprecated Accepted from older callers but deliberately never persisted. */
|
|
55
55
|
mintToken?: string;
|
|
56
56
|
now?: () => Date;
|
|
57
57
|
};
|
|
@@ -123,7 +123,6 @@ export async function createCardMandate(input, deps) {
|
|
|
123
123
|
merchantHost: host,
|
|
124
124
|
merchantCountryCode: input.merchant.countryCode.toUpperCase(),
|
|
125
125
|
approvalBaseUrl: deps.approvalBaseUrl,
|
|
126
|
-
...(deps.mintToken ? { mintToken: deps.mintToken } : {}),
|
|
127
126
|
expiresAt: new Date(expiryMs).toISOString(),
|
|
128
127
|
maxDraws,
|
|
129
128
|
createdAt: now.toISOString(),
|
|
@@ -31,11 +31,7 @@ export type CardMandateRecord = {
|
|
|
31
31
|
merchantCountryCode: string;
|
|
32
32
|
/** verify-web origin the ceiling intent was minted against. */
|
|
33
33
|
approvalBaseUrl: string;
|
|
34
|
-
/**
|
|
35
|
-
* Scoped token released by the ceiling approval. It bootstraps the one intent
|
|
36
|
-
* + register ceremony only. Each cryptogram AND its outcome confirmation use
|
|
37
|
-
* the exact per-draw verdict instead. Owner-only (0600).
|
|
38
|
-
*/
|
|
34
|
+
/** @deprecated Read-migration only. New writers never persist this bearer. */
|
|
39
35
|
mintToken?: string;
|
|
40
36
|
expiresAt: string;
|
|
41
37
|
/** Network purchase-count cap disclosed at approval. Absent on legacy rows. */
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
//
|
|
12
12
|
// VGS's decline_threshold is a per-transaction NETWORK control; this ledger is
|
|
13
13
|
// the SEPARATE cumulative budget control. The file holds identifiers and
|
|
14
|
-
// accounting state
|
|
15
|
-
//
|
|
14
|
+
// accounting state only — never a bootstrap mint token, PAN, DPAN, CVC, or
|
|
15
|
+
// cryptogram values. Cross-process concurrency is NOT solved by a file
|
|
16
16
|
// (same caveat csmoove notes); the in-process mutex below serializes draws
|
|
17
17
|
// within one CLI process, which is the live-spike target.
|
|
18
18
|
//
|
|
@@ -121,6 +121,18 @@ export class MandateLedger {
|
|
|
121
121
|
if (!doc || !Array.isArray(doc.mandates)) {
|
|
122
122
|
return { version: CARD_MANDATE_LEDGER_VERSION, mandates: [] };
|
|
123
123
|
}
|
|
124
|
+
// One-time migration for pre-hardening ledgers. The budget mint is a
|
|
125
|
+
// bootstrap bearer used only during create/register and must not survive
|
|
126
|
+
// process exit. Scrub it eagerly on read, not merely on the next mutation.
|
|
127
|
+
let scrubbedBootstrapToken = false;
|
|
128
|
+
for (const mandate of doc.mandates) {
|
|
129
|
+
if (Object.prototype.hasOwnProperty.call(mandate, 'mintToken')) {
|
|
130
|
+
delete mandate.mintToken;
|
|
131
|
+
scrubbedBootstrapToken = true;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (scrubbedBootstrapToken)
|
|
135
|
+
await writeOwnerOnlyJson(this.path, doc);
|
|
124
136
|
// Self-heal: prune reservations stranded by a crash before commit/release
|
|
125
137
|
// so `remaining` reflects reality. In-memory here; a mutating caller then
|
|
126
138
|
// persists the pruned state via save().
|
|
@@ -161,9 +173,12 @@ export class MandateLedger {
|
|
|
161
173
|
const exp = Date.parse(m.expiresAt);
|
|
162
174
|
return !Number.isFinite(exp) || exp >= pruneBefore;
|
|
163
175
|
});
|
|
164
|
-
|
|
176
|
+
// Even an older caller that still supplies the deprecated field cannot
|
|
177
|
+
// persist the bootstrap bearer.
|
|
178
|
+
const { mintToken: _discardedBootstrapToken, ...safeRecord } = record;
|
|
179
|
+
file.mandates.push(safeRecord);
|
|
165
180
|
await this.save(file);
|
|
166
|
-
return
|
|
181
|
+
return safeRecord;
|
|
167
182
|
});
|
|
168
183
|
}
|
|
169
184
|
/** Read a single mandate (no lock — a snapshot copy). */
|