@astrasyncai/verification-gateway 5.11.0 → 5.13.0

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.
Files changed (98) hide show
  1. package/README.md +4 -0
  2. package/dist/adapters/express.d.mts +1 -1
  3. package/dist/adapters/express.d.ts +1 -1
  4. package/dist/adapters/express.js +394 -39
  5. package/dist/adapters/express.js.map +1 -1
  6. package/dist/adapters/express.mjs +394 -39
  7. package/dist/adapters/express.mjs.map +1 -1
  8. package/dist/adapters/mcp.d.mts +5 -1
  9. package/dist/adapters/mcp.d.ts +5 -1
  10. package/dist/adapters/mcp.js +193 -49
  11. package/dist/adapters/mcp.js.map +1 -1
  12. package/dist/adapters/mcp.mjs +193 -49
  13. package/dist/adapters/mcp.mjs.map +1 -1
  14. package/dist/adapters/nextjs.d.mts +1 -1
  15. package/dist/adapters/nextjs.d.ts +1 -1
  16. package/dist/adapters/nextjs.js +387 -22
  17. package/dist/adapters/nextjs.js.map +1 -1
  18. package/dist/adapters/nextjs.mjs +387 -22
  19. package/dist/adapters/nextjs.mjs.map +1 -1
  20. package/dist/adapters/sdk.d.mts +9 -1
  21. package/dist/adapters/sdk.d.ts +9 -1
  22. package/dist/adapters/sdk.js +125 -16
  23. package/dist/adapters/sdk.js.map +1 -1
  24. package/dist/adapters/sdk.mjs +125 -16
  25. package/dist/adapters/sdk.mjs.map +1 -1
  26. package/dist/agent/index.js +1 -1
  27. package/dist/agent/index.js.map +1 -1
  28. package/dist/agent/index.mjs +1 -1
  29. package/dist/agent/index.mjs.map +1 -1
  30. package/dist/bin/astrasync-claude-hook.js +309 -15
  31. package/dist/bin/astrasync-codex-hook.js +309 -15
  32. package/dist/bin/astrasync-guard.js +309 -15
  33. package/dist/bin/astrasync.js +322 -17
  34. package/dist/browser/background.js +309 -15
  35. package/dist/browser/background.js.map +1 -1
  36. package/dist/browser/background.mjs +309 -15
  37. package/dist/browser/background.mjs.map +1 -1
  38. package/dist/cli/index.js +1 -1
  39. package/dist/cli/index.js.map +1 -1
  40. package/dist/cli/index.mjs +1 -1
  41. package/dist/cli/index.mjs.map +1 -1
  42. package/dist/codex/index.js +309 -15
  43. package/dist/codex/index.js.map +1 -1
  44. package/dist/codex/index.mjs +309 -15
  45. package/dist/codex/index.mjs.map +1 -1
  46. package/dist/cursor/extension.js +309 -15
  47. package/dist/cursor/extension.js.map +1 -1
  48. package/dist/cursor/extension.mjs +309 -15
  49. package/dist/cursor/extension.mjs.map +1 -1
  50. package/dist/edge-config.d.mts +1 -1
  51. package/dist/edge-config.d.ts +1 -1
  52. package/dist/edge-config.js +1 -1
  53. package/dist/edge-config.js.map +1 -1
  54. package/dist/edge-config.mjs +1 -1
  55. package/dist/edge-config.mjs.map +1 -1
  56. package/dist/edge-core/index.d.mts +128 -13
  57. package/dist/edge-core/index.d.ts +128 -13
  58. package/dist/edge-core/index.js +362 -63
  59. package/dist/edge-core/index.js.map +1 -1
  60. package/dist/edge-core/index.mjs +359 -63
  61. package/dist/edge-core/index.mjs.map +1 -1
  62. package/dist/gateway/gateway.js +309 -15
  63. package/dist/gateway/gateway.js.map +1 -1
  64. package/dist/gateway/gateway.mjs +309 -15
  65. package/dist/gateway/gateway.mjs.map +1 -1
  66. package/dist/git-trigger/git-hooks.d.mts +1 -1
  67. package/dist/git-trigger/git-hooks.d.ts +1 -1
  68. package/dist/index.d.mts +118 -15
  69. package/dist/index.d.ts +118 -15
  70. package/dist/index.js +521 -72
  71. package/dist/index.js.map +1 -1
  72. package/dist/index.mjs +515 -72
  73. package/dist/index.mjs.map +1 -1
  74. package/dist/platform-signatures.js +4 -1
  75. package/dist/platform-signatures.js.map +1 -1
  76. package/dist/platform-signatures.mjs +4 -1
  77. package/dist/platform-signatures.mjs.map +1 -1
  78. package/dist/registration/index.js +1 -1
  79. package/dist/registration/index.js.map +1 -1
  80. package/dist/registration/index.mjs +1 -1
  81. package/dist/registration/index.mjs.map +1 -1
  82. package/dist/transport/index.js +1 -1
  83. package/dist/transport/index.js.map +1 -1
  84. package/dist/transport/index.mjs +1 -1
  85. package/dist/transport/index.mjs.map +1 -1
  86. package/dist/{types-CTmUpNpS.d.mts → types-BCkwBA84.d.mts} +12 -0
  87. package/dist/{types-CTmUpNpS.d.ts → types-BCkwBA84.d.ts} +12 -0
  88. package/dist/{types-CtFXmDzm.d.ts → types-C_b4QTyO.d.ts} +18 -0
  89. package/dist/{types-DQrn_kei.d.mts → types-DlshIIR-.d.mts} +18 -0
  90. package/dist/ui/index.d.mts +1 -1
  91. package/dist/ui/index.d.ts +1 -1
  92. package/dist/verify.d.mts +35 -14
  93. package/dist/verify.d.ts +35 -14
  94. package/dist/verify.js +165 -25
  95. package/dist/verify.js.map +1 -1
  96. package/dist/verify.mjs +164 -25
  97. package/dist/verify.mjs.map +1 -1
  98. package/package.json +3 -2
@@ -1,4 +1,4 @@
1
- import { T as TrustLevel, S as SDKOptions, d as VerificationResult, c as VerificationRequest } from '../types-CTmUpNpS.mjs';
1
+ import { T as TrustLevel, S as SDKOptions, d as VerificationResult, c as VerificationRequest } from '../types-BCkwBA84.mjs';
2
2
 
3
3
  /**
4
4
  * AstraSync Universal Verification Gateway — Trust Level helpers.
@@ -101,6 +101,12 @@ declare class VerificationGatewayClient {
101
101
  * fulfil against it only once the order is settled / pending_merchant. An
102
102
  * explicit `buyerEmail` (here or on the bridge handoff body) wins over the
103
103
  * account default.
104
+ *
105
+ * 5.12.0 approval binding: pass the bridge handoff body's `attemptId` (and
106
+ * the same `checkoutSessionId`) so a step-up approval minted for this cart
107
+ * is matched to — and only to — this confirm. A held cart's approval is
108
+ * bound to its checkout session and exact value; a confirm for any other
109
+ * cart is held for its own approval.
104
110
  */
105
111
  confirmCheckout(options: {
106
112
  astraId?: string;
@@ -112,6 +118,8 @@ declare class VerificationGatewayClient {
112
118
  currency?: string;
113
119
  checkoutSessionId?: string;
114
120
  checkoutItems?: VerificationRequest['checkoutItems'];
121
+ /** 5.12.0: the `att_…` attempt-chain id from the bridge handoff body. */
122
+ attemptId?: string;
115
123
  /** 5.6.0: alternate receipt/delivery email (transit-only) — omit to let
116
124
  * the platform default `fulfilment.email` to the buyer's account email. */
117
125
  buyerEmail?: string;
@@ -1,4 +1,4 @@
1
- import { T as TrustLevel, S as SDKOptions, d as VerificationResult, c as VerificationRequest } from '../types-CTmUpNpS.js';
1
+ import { T as TrustLevel, S as SDKOptions, d as VerificationResult, c as VerificationRequest } from '../types-BCkwBA84.js';
2
2
 
3
3
  /**
4
4
  * AstraSync Universal Verification Gateway — Trust Level helpers.
@@ -101,6 +101,12 @@ declare class VerificationGatewayClient {
101
101
  * fulfil against it only once the order is settled / pending_merchant. An
102
102
  * explicit `buyerEmail` (here or on the bridge handoff body) wins over the
103
103
  * account default.
104
+ *
105
+ * 5.12.0 approval binding: pass the bridge handoff body's `attemptId` (and
106
+ * the same `checkoutSessionId`) so a step-up approval minted for this cart
107
+ * is matched to — and only to — this confirm. A held cart's approval is
108
+ * bound to its checkout session and exact value; a confirm for any other
109
+ * cart is held for its own approval.
104
110
  */
105
111
  confirmCheckout(options: {
106
112
  astraId?: string;
@@ -112,6 +118,8 @@ declare class VerificationGatewayClient {
112
118
  currency?: string;
113
119
  checkoutSessionId?: string;
114
120
  checkoutItems?: VerificationRequest['checkoutItems'];
121
+ /** 5.12.0: the `att_…` attempt-chain id from the bridge handoff body. */
122
+ attemptId?: string;
115
123
  /** 5.6.0: alternate receipt/delivery email (transit-only) — omit to let
116
124
  * the platform default `fulfilment.email` to the buyer's account email. */
117
125
  buyerEmail?: string;
@@ -28,7 +28,7 @@ __export(sdk_exports, {
28
28
  module.exports = __toCommonJS(sdk_exports);
29
29
 
30
30
  // src/version.ts
31
- var SDK_VERSION = "5.11.0";
31
+ var SDK_VERSION = "5.13.0";
32
32
 
33
33
  // src/http.ts
34
34
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -63,6 +63,29 @@ function getCachedWellKnownUrls(apiBaseUrl) {
63
63
  return cache.get(apiBaseUrl)?.data;
64
64
  }
65
65
 
66
+ // src/failure-posture.ts
67
+ var DEFAULT_UNAVAILABLE_RETRY_AFTER_S = 30;
68
+ var REJECTED_IDENTITY_DIMENSIONS = /* @__PURE__ */ new Set([
69
+ "identity.invalid_agent_id",
70
+ "identity.unknown_agent",
71
+ "agent.lookup"
72
+ ]);
73
+ var UNKNOWN_AGENT_GUIDANCE = "Register your agent with AstraSync (or, inside an MCP host, add the AstraSync MCP connector for keyless, human-approved registration), then present the canonical ASTRA-* id issued after owner approval.";
74
+ var UNAVAILABLE_DIMENSIONS = /* @__PURE__ */ new Set([
75
+ "verify_access.api_error",
76
+ "middleware.internal_error"
77
+ ]);
78
+ function isVerificationUnavailable(result) {
79
+ if (result.misconfigured) return false;
80
+ return (result.failures ?? []).some((f) => UNAVAILABLE_DIMENSIONS.has(f.dimension));
81
+ }
82
+ function unavailableRetryAfterSeconds(result) {
83
+ if (typeof result.retryAfterMs === "number" && Number.isFinite(result.retryAfterMs)) {
84
+ return Math.max(1, Math.ceil(result.retryAfterMs / 1e3));
85
+ }
86
+ return DEFAULT_UNAVAILABLE_RETRY_AFTER_S;
87
+ }
88
+
66
89
  // src/verify.ts
67
90
  var DEFAULT_CONFIG = {
68
91
  apiBaseUrl: "https://astrasync.ai/api",
@@ -75,7 +98,7 @@ var DEFAULT_CONFIG = {
75
98
  };
76
99
  var initCheckPerformed = false;
77
100
  var deprecationWarningShown = false;
78
- async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
101
+ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey, counterparty) {
79
102
  initCheckPerformed = true;
80
103
  try {
81
104
  const probeUrl = `${apiBaseUrl}/agents/verify-access`;
@@ -93,7 +116,8 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
93
116
  );
94
117
  }
95
118
  if (apiKey) {
96
- const selfCheck = await sdkFetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
119
+ const q = counterparty?.id ? `?counterpartyId=${encodeURIComponent(counterparty.id)}` : counterparty?.url ? `?counterpartyUrl=${encodeURIComponent(counterparty.url)}` : "";
120
+ const selfCheck = await sdkFetch(`${apiBaseUrl}/agents/verify-access/self-check${q}`, {
97
121
  headers: { Authorization: `Bearer ${apiKey}` }
98
122
  });
99
123
  if (selfCheck.status === 401) {
@@ -105,6 +129,13 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
105
129
  console.error(message);
106
130
  } else if (selfCheck.ok) {
107
131
  const body = await selfCheck.json().catch(() => ({}));
132
+ if (body.counterparty && body.counterparty.canVerify === false) {
133
+ const message = `[VerificationGateway] the configured AstraSync API key cannot verify for this endpoint (${body.counterparty.message ?? "endpoint not found or owned by another account"}). Every inbound agent will be turned away until the key or counterparty is corrected.`;
134
+ if (strictInit) {
135
+ throw new Error(`${message} (strictInit=true)`);
136
+ }
137
+ console.error(message);
138
+ }
108
139
  if (typeof body.daysToExpiry === "number" && body.daysToExpiry <= 7) {
109
140
  console.warn(
110
141
  `[VerificationGateway] the configured AstraSync API key expires in ${body.daysToExpiry} day(s) \u2014 rotate it at Settings \u2192 Developer Tools before integrations start failing.`
@@ -212,11 +243,11 @@ function createGuidanceResponse(_config, reason, options = {}) {
212
243
  const isMisconfig = source === "merchant_misconfig";
213
244
  const urls = options.urls;
214
245
  const guidance = isMisconfig ? {
215
- message: "This site's AstraSync integration is misconfigured (its API key was revoked, expired, or rotated). Your identity and the AstraSync platform are fine \u2014 contact the site operator. Retrying will not help.",
246
+ message: "This site's AstraSync integration is misconfigured (its API key was revoked, expired, rotated, or belongs to another account). Your identity and the AstraSync platform are fine \u2014 contact the site operator. Retrying will not help.",
216
247
  registrationUrl: urls?.registrationUrl ?? "",
217
248
  documentationUrl: options.remediation?.docsUrl ?? urls?.documentationUrl ?? "",
218
249
  steps: [
219
- "Report the failure to the site operator \u2014 their AstraSync API key needs rotating",
250
+ "Report the failure to the site operator \u2014 their AstraSync API key needs replacing",
220
251
  "Do not retry: the failure is deterministic until the operator updates their key"
221
252
  ]
222
253
  } : isApiError ? {
@@ -277,11 +308,44 @@ function createGuidanceResponse(_config, reason, options = {}) {
277
308
  // coercing the absent recommendation to a policy 'deny'. Misconfig is
278
309
  // deterministic and intentionally NOT marked retryable.
279
310
  ...isApiError && { retryable: true },
311
+ ...options.httpStatus !== void 0 && { httpStatus: options.httpStatus },
312
+ ...options.retryAfterMs !== void 0 && { retryAfterMs: options.retryAfterMs },
280
313
  correlationId: options.correlationId,
281
314
  attemptId: options.attemptId,
282
315
  verifiedAt: /* @__PURE__ */ new Date()
283
316
  };
284
317
  }
318
+ async function readJsonSafe(response) {
319
+ try {
320
+ const parsed = await response.json();
321
+ return parsed && typeof parsed === "object" ? parsed : {};
322
+ } catch {
323
+ return {};
324
+ }
325
+ }
326
+ function rejectedIdentityGuidance(failures) {
327
+ const f = failures?.find((x) => REJECTED_IDENTITY_DIMENSIONS.has(x.dimension));
328
+ if (!f) return void 0;
329
+ if (f.dimension === "agent.lookup") {
330
+ return `The presented agent identifier is not registered with AstraSync. ${UNKNOWN_AGENT_GUIDANCE}`;
331
+ }
332
+ return f.guidance ? `${f.message} ${f.guidance}` : f.message;
333
+ }
334
+ var MAX_RETRY_AFTER_MS = 15 * 60 * 1e3;
335
+ function parseRetryAfterMs(response) {
336
+ const raw = response.headers?.get?.("retry-after");
337
+ if (!raw) return void 0;
338
+ const trimmed = raw.trim();
339
+ let ms;
340
+ if (/^\d+(\.\d+)?$/.test(trimmed)) {
341
+ ms = Number(trimmed) * 1e3;
342
+ } else {
343
+ const at = Date.parse(trimmed);
344
+ if (Number.isNaN(at)) return void 0;
345
+ ms = at - Date.now();
346
+ }
347
+ return Math.min(MAX_RETRY_AFTER_MS, Math.max(0, Math.round(ms)));
348
+ }
285
349
  async function callVerifyAccessAPI(config, request) {
286
350
  const { credentials, ...requestData } = request;
287
351
  const body = {
@@ -338,7 +402,8 @@ async function callVerifyAccessAPI(config, request) {
338
402
  body: JSON.stringify(body),
339
403
  signal: AbortSignal.timeout(config.verifyTimeoutMs ?? 1e4)
340
404
  });
341
- const data = await response.json();
405
+ const data = await readJsonSafe(response);
406
+ const retryAfterMs = parseRetryAfterMs(response);
342
407
  if (response.status === 410) {
343
408
  return {
344
409
  success: true,
@@ -376,13 +441,31 @@ async function callVerifyAccessAPI(config, request) {
376
441
  }
377
442
  };
378
443
  }
444
+ if (response.status === 404 && credentials.astraId && (data?.error === "AGENT_NOT_FOUND" || typeof data?.message === "string" && /agent/i.test(data.message))) {
445
+ return {
446
+ success: true,
447
+ attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
448
+ access: {
449
+ allowed: false,
450
+ reason: "unknown_agent",
451
+ failures: [
452
+ {
453
+ dimension: "identity.unknown_agent",
454
+ message: "The presented agent identifier is not registered with AstraSync.",
455
+ guidance: UNKNOWN_AGENT_GUIDANCE
456
+ }
457
+ ]
458
+ }
459
+ };
460
+ }
379
461
  if (!response.ok) {
380
- if (response.status === 401) {
462
+ const keyMismatch = response.status === 403 && data?.error === "COUNTERPARTY_KEY_MISMATCH";
463
+ if (response.status === 401 || keyMismatch) {
381
464
  return {
382
465
  success: false,
383
466
  error: data.message || data.error || "Integration API key rejected",
384
467
  misconfig: true,
385
- misconfigCode: typeof data?.code === "string" ? data.code : void 0,
468
+ misconfigCode: keyMismatch ? "counterparty_key_mismatch" : typeof data?.code === "string" ? data.code : void 0,
386
469
  remediation: data?.remediation && typeof data.remediation === "object" ? data.remediation : void 0,
387
470
  correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
388
471
  attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
@@ -390,9 +473,11 @@ async function callVerifyAccessAPI(config, request) {
390
473
  }
391
474
  return {
392
475
  success: false,
393
- error: data.message || data.error || `API returned ${response.status}`,
476
+ error: typeof data?.message === "string" && data.message || typeof data?.error === "string" && data.error || `API returned ${response.status}`,
394
477
  correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
395
- attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
478
+ attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
479
+ httpStatus: response.status,
480
+ ...retryAfterMs !== void 0 && { retryAfterMs }
396
481
  };
397
482
  }
398
483
  return data;
@@ -413,14 +498,22 @@ async function verify(config, request, options) {
413
498
  mergedConfig.apiBaseUrl,
414
499
  mergedConfig.debug,
415
500
  true,
416
- mergedConfig.apiKey
501
+ mergedConfig.apiKey,
502
+ {
503
+ id: mergedConfig.counterpartyId,
504
+ url: mergedConfig.counterpartyUrl ?? request.counterpartyUrl
505
+ }
417
506
  );
418
507
  } else {
419
508
  void performInitCheck(
420
509
  mergedConfig.apiBaseUrl,
421
510
  mergedConfig.debug,
422
511
  false,
423
- mergedConfig.apiKey
512
+ mergedConfig.apiKey,
513
+ {
514
+ id: mergedConfig.counterpartyId,
515
+ url: mergedConfig.counterpartyUrl ?? request.counterpartyUrl
516
+ }
424
517
  );
425
518
  }
426
519
  }
@@ -464,12 +557,14 @@ async function verify(config, request, options) {
464
557
  correlationId: apiResponse.correlationId,
465
558
  attemptId: apiResponse.attemptId,
466
559
  remediation: apiResponse.remediation,
560
+ httpStatus: apiResponse.httpStatus,
561
+ retryAfterMs: apiResponse.retryAfterMs,
467
562
  urls
468
563
  });
469
564
  }
470
565
  if (!apiResponse.access?.allowed) {
471
566
  const aggregatedFailures = apiResponse.access?.failures;
472
- const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true;
567
+ const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true && !aggregatedFailures?.some((f) => REJECTED_IDENTITY_DIMENSIONS.has(f.dimension));
473
568
  const result2 = {
474
569
  identityVerified: idVerifiedFromBackend,
475
570
  policyAllowed: false,
@@ -481,7 +576,10 @@ async function verify(config, request, options) {
481
576
  requiresStepUp: apiResponse.access?.requiresStepUp,
482
577
  requiresApproval: apiResponse.access?.requiresApproval,
483
578
  guidance: {
484
- message: apiResponse.access?.reason || "Access denied by PDLSS policy",
579
+ // 5.12.0: a presented-but-rejected id (malformed / unknown) carries
580
+ // actionable registration guidance on its failure — surface it
581
+ // instead of the bare machine reason ('unknown_agent').
582
+ message: rejectedIdentityGuidance(aggregatedFailures) ?? (apiResponse.access?.reason || "Access denied by PDLSS policy"),
485
583
  registrationUrl: urls?.registrationUrl ?? "",
486
584
  documentationUrl: urls?.documentationUrl ?? "",
487
585
  // 5.1.0: anonymous callers land on this branch — steer MCP-hosted
@@ -581,7 +679,7 @@ async function verify(config, request, options) {
581
679
  registrationUrl: urls?.registrationUrl ?? "",
582
680
  documentationUrl: urls?.documentationUrl ?? ""
583
681
  };
584
- } else if (result.recommendation === "step_up_required") {
682
+ } else if (result.recommendation === "step_up_required" && result.identityVerified) {
585
683
  result.requiresStepUp = true;
586
684
  result.denialReasons = serverDenialReasons ?? result.recommendationReasons ?? ["Step-up verification required"];
587
685
  }
@@ -599,7 +697,11 @@ async function quickVerify(config, credentials) {
599
697
  return {
600
698
  identityVerified: result.identityVerified,
601
699
  policyAllowed: result.policyAllowed,
602
- reason: result.denialReasons?.[0]
700
+ reason: result.denialReasons?.[0],
701
+ ...isVerificationUnavailable(result) && {
702
+ unavailable: true,
703
+ retryAfterMs: unavailableRetryAfterSeconds(result) * 1e3
704
+ }
603
705
  };
604
706
  }
605
707
 
@@ -685,6 +787,12 @@ var VerificationGatewayClient = class {
685
787
  * fulfil against it only once the order is settled / pending_merchant. An
686
788
  * explicit `buyerEmail` (here or on the bridge handoff body) wins over the
687
789
  * account default.
790
+ *
791
+ * 5.12.0 approval binding: pass the bridge handoff body's `attemptId` (and
792
+ * the same `checkoutSessionId`) so a step-up approval minted for this cart
793
+ * is matched to — and only to — this confirm. A held cart's approval is
794
+ * bound to its checkout session and exact value; a confirm for any other
795
+ * cart is held for its own approval.
688
796
  */
689
797
  async confirmCheckout(options) {
690
798
  const credentials = {
@@ -704,6 +812,7 @@ var VerificationGatewayClient = class {
704
812
  commercePhase: "confirm",
705
813
  checkoutSessionId: options.checkoutSessionId,
706
814
  checkoutItems: options.checkoutItems,
815
+ ...options.attemptId && { attemptId: options.attemptId },
707
816
  buyerEmail: options.buyerEmail,
708
817
  counterpartyUrl: options.counterpartyUrl,
709
818
  counterpartyType: options.counterpartyType