@agent-cards/sdk 0.24.2 → 0.25.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.
@@ -39,6 +39,50 @@ export interface CreateAuthorizationInput {
39
39
  checkout_origin?: string;
40
40
  /** Pins the card that pays: one of the person's stored cards. Absent, the person's recommended card pays, else their only card, and `card` on the answer says which. */
41
41
  card_id?: string;
42
+ /**
43
+ * The products the purchase is for, as your agent's cart has them (1 to 20 lines): the approval page lists them
44
+ * above the total, labelled as sent by your company. Shown, never charged: the person approves `amount`.
45
+ * Every amount is in the smallest unit of `currency`. A line the API cannot read is refused by name
46
+ * (`invalid_request`), never dropped.
47
+ */
48
+ line_items?: OrderLineItem[];
49
+ /** The cart's subtotal, shipping, tax and discount, in the smallest unit of `currency`, each shown only when named. Need `line_items`. */
50
+ subtotal?: number;
51
+ shipping?: number;
52
+ tax?: number;
53
+ discount?: number;
54
+ /** Where the order ships, shown in the approval page's Ship to box. Needs `line_items`. Never returned on your reads. */
55
+ ship_to?: OrderShipTo;
56
+ }
57
+ /** One product of the cart an approval shows. */
58
+ export interface OrderLineItem {
59
+ /** The product's name as the store shows it. */
60
+ title: string;
61
+ /** A positive integer. */
62
+ quantity: number;
63
+ /** The price of one, in the smallest unit of the create's `currency`; the line shows `unit_amount × quantity`. */
64
+ unit_amount?: number;
65
+ /** The line's own total, in the smallest unit; shown over `unit_amount × quantity` when both are named. */
66
+ amount?: number;
67
+ brand?: string;
68
+ /** The options chosen, as one string (`'Size S · Pink'`) or by name (`{ Size: 'S', Color: 'Pink' }`, shown as `S · Pink`). */
69
+ options?: string | Record<string, string>;
70
+ /** An https picture of the product. Shown only from the image hosts the approval page loads; any other shows the line without one. */
71
+ image_url?: string;
72
+ }
73
+ /** Where an approval's order ships. */
74
+ export interface OrderShipTo {
75
+ name: string;
76
+ phone?: string;
77
+ /** `country` is a two-letter ISO code; absent means `US`. */
78
+ address: {
79
+ line1: string;
80
+ line2?: string;
81
+ city: string;
82
+ state?: string;
83
+ postal_code: string;
84
+ country?: string;
85
+ };
42
86
  }
43
87
  /** The card that pays, as every read names it. */
44
88
  export interface PayingCard {
package/dist/approvals.js CHANGED
@@ -99,6 +99,15 @@ function resultOf(a) {
99
99
  ...(approvalUrl && a.status === 'awaiting_approval' ? { approval_url: approvalUrl } : {}),
100
100
  };
101
101
  }
102
+ /** The cart fields a create names, passed as given: the API checks them and refuses a bad one by name. */
103
+ function orderFieldsOf(input) {
104
+ const out = {};
105
+ for (const key of ['line_items', 'subtotal', 'shipping', 'tax', 'discount', 'ship_to']) {
106
+ if (input[key] !== undefined)
107
+ out[key] = input[key];
108
+ }
109
+ return out;
110
+ }
102
111
  /** A random idempotency key for one create, so a retried call makes one purchase. */
103
112
  function idempotencyKey() {
104
113
  const c = globalThis.crypto;
@@ -148,6 +157,7 @@ export class ApprovalsModule extends ApiModule {
148
157
  body: {
149
158
  user, merchant: input.merchant, amount: input.amount, currency: input.currency, psp: input.psp ?? 'stripe', mode: input.mode ?? 'token', request,
150
159
  ...(input.return_url ? { return_url: input.return_url } : {}), ...(checkoutOrigin ? { checkout_origin: checkoutOrigin } : {}), ...(input.card_id ? { card_id: input.card_id } : {}),
160
+ ...orderFieldsOf(input),
151
161
  },
152
162
  headers: { 'idempotency-key': input.idempotency_key ?? idempotencyKey() },
153
163
  });
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: b51ae1e970674f5e2b35bd33193e9a5ed5b04142e3764296c28dcb3d91e3d17b
3
+ // artifact-sha256: 59a78202e498531ace1ce3391b9ac8b385f55a86e332aca4ac7abdb807d506e7
4
4
  // src/card-number-key.js
5
5
  var CARD_NUMBER_KEY = /^(number|card_number|cardnumber|cardNum|card_num|pan)$/i;
6
6
  // src/json-path.js
@@ -1965,6 +1965,9 @@ function multipartFormRefusal(body, contentType, rule) {
1965
1965
  const read = judge(body, contentType, rule);
1966
1966
  return read.refusal ?? null;
1967
1967
  }
1968
+ // src/answer-card-leak.js
1969
+ var UTF8_SEQUENCE = "[\\x00-\\x7f]|[\\xc2-\\xdf][\\x80-\\xbf]|\\xe0[\\xa0-\\xbf][\\x80-\\xbf]|[\\xe1-\\xec\\xee\\xef][\\x80-\\xbf]{2}|\\xed[\\x80-\\x9f][\\x80-\\xbf]|\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2}|[\\xf1-\\xf3][\\x80-\\xbf]{3}|\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2}";
1970
+ var UTF8_WHOLE = /* @__PURE__ */ new RegExp(`^(?:${UTF8_SEQUENCE})*$`);
1968
1971
  // src/pay-nl.js
1969
1972
  var PAY_NL_PSP = "pay_nl";
1970
1973
  var PAY_NL_TOKEN_URL = "https://payment.pay.nl/v1/Payment/getCardToken/json";
package/dist/cdp.js CHANGED
@@ -44,6 +44,7 @@ import { CYBERSOURCE_SECURE_ACCEPTANCE_PATTERNS, CYBERSOURCE_SECURE_ACCEPTANCE_R
44
44
  import { CheckoutAttachmentError, attachmentDeadline, attachmentFailure, withinAttachmentDeadline } from './attachment.js';
45
45
  import { cseBody } from './cse-body.js';
46
46
  import { STRIPE_SETUP_INTENT_CONFIRM, setupConfirmPayingWith } from './stripe-setup.js';
47
+ import { confirmPayingWith } from './stripe-continuation.js';
47
48
  import { replayTemplatedUrl, reviewedMerchantProfileUrlPatterns } from './merchant-hosted.js';
48
49
  import { verifoneTemplatedUrl } from './verifone.js';
49
50
  import { MerchantHandoffWatch } from './merchant-handoff.js';
@@ -1113,30 +1114,41 @@ function claimStripeContinuation(opts, lifecycle, url, method, body) {
1113
1114
  }
1114
1115
  if (parsed.origin !== 'https://api.stripe.com')
1115
1116
  return null;
1116
- if (STRIPE_PAYMENT_INTENT_CONFIRM.test(parsed.pathname)) {
1117
- if (typeof opts.vault.checkStripeContinuation !== 'function' || opts.vault.withoutCard?.(url, body) !== 'refuse')
1118
- return null;
1119
- const authorizationId = lifecycle.claimStripeContinuation();
1120
- return authorizationId ? { authorizationId, kind: 'payment', body, rewritten: false } : null;
1121
- }
1122
- if (!STRIPE_SETUP_INTENT_CONFIRM.test(parsed.pathname) || typeof opts.vault.checkStripeSetupContinuation !== 'function')
1117
+ const payment = STRIPE_PAYMENT_INTENT_CONFIRM.test(parsed.pathname);
1118
+ const setup = !payment && STRIPE_SETUP_INTENT_CONFIRM.test(parsed.pathname);
1119
+ if (!payment && !setup)
1120
+ return null;
1121
+ // Each kind needs the client method that judges it; an older client keeps the ordinary hold.
1122
+ if (payment && typeof opts.vault.checkStripeContinuation !== 'function')
1123
+ return null;
1124
+ if (setup && typeof opts.vault.checkStripeSetupContinuation !== 'function')
1123
1125
  return null;
1124
1126
  const withoutCard = opts.vault.withoutCard?.(url, body);
1125
1127
  let send = null;
1126
1128
  if (withoutCard === 'refuse')
1127
1129
  send = body;
1128
1130
  else if (withoutCard === null) {
1129
- // The card again, inline: only the approved payment method may replace it,
1130
- // and only when what is left carries no card at all.
1131
- const paymentMethod = lifecycle.approvedStripePaymentMethod();
1132
- send = paymentMethod ? setupConfirmPayingWith(body, paymentMethod) : null;
1131
+ // The card again, inline: only the object the cardholder's approval
1132
+ // returned may replace it, and only when what is left carries no card at
1133
+ // all. A payment pays with whichever object its approval produced (a
1134
+ // confirmation token, for a store that creates one for a fraud check and
1135
+ // then confirms with the Payment Element); a card save pays with a payment
1136
+ // method alone, which is all a SetupIntent confirm takes.
1137
+ if (payment) {
1138
+ const way = lifecycle.approvedStripeWay();
1139
+ send = way ? confirmPayingWith(body, way) : null;
1140
+ }
1141
+ else {
1142
+ const paymentMethod = lifecycle.approvedStripePaymentMethod();
1143
+ send = paymentMethod ? setupConfirmPayingWith(body, paymentMethod) : null;
1144
+ }
1133
1145
  if (send !== null && opts.vault.withoutCard?.(url, send) !== 'refuse')
1134
1146
  send = null;
1135
1147
  }
1136
1148
  if (send === null)
1137
1149
  return null;
1138
1150
  const authorizationId = lifecycle.claimStripeContinuation();
1139
- return authorizationId ? { authorizationId, kind: 'setup', body: send, rewritten: send !== body } : null;
1151
+ return authorizationId ? { authorizationId, kind: payment ? 'payment' : 'setup', body: send, rewritten: send !== body } : null;
1140
1152
  }
1141
1153
  /**
1142
1154
  * Ask the API about a claimed continuation, with the body it would continue
@@ -1159,7 +1171,7 @@ async function checkStripeContinuation(opts, lifecycle, claim, request) {
1159
1171
  if (proceed) {
1160
1172
  opts.onEvent?.(kind === 'setup'
1161
1173
  ? { type: 'stripe_setup_continued', detail: { authorizationId, setupIntentId: intentId, rewritten: claim.rewritten } }
1162
- : { type: 'stripe_payment_continued', detail: { authorizationId, paymentIntentId: intentId } });
1174
+ : { type: 'stripe_payment_continued', detail: { authorizationId, paymentIntentId: intentId, rewritten: claim.rewritten } });
1163
1175
  }
1164
1176
  else if (intentId !== null)
1165
1177
  opts.onEvent?.({ type: 'blocked', detail: 'stripe_continuation_superseded' });
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: 169752c8d6a6c9f131c83502766f0026b2ffa45cf9f27c450735eef5ad2fa931
3
+ // artifact-sha256: c4280e1c95d016a93163f49d9d66178a9c4fdfae08e4570952c9c7f533a1c643
4
4
  // src/answer-card-leak.js
5
5
  var DECIMAL = /\p{Nd}/u;
6
6
  function digitValue(char) {
@@ -20,6 +20,8 @@ function enclosedValue(char) {
20
20
  var asciiDigits = (text2) => (typeof text2.normalize === "function" ? text2.normalize("NFKC") : text2).replace(ENCLOSED_CHAR, enclosedValue).replace(/\p{Nd}/gu, (char) => char >= "0" && char <= "9" ? char : digitValue(char));
21
21
  var digitCount = (text2) => (asciiDigits(String(text2)).match(/\p{N}/gu) ?? []).length;
22
22
  var NAME_DIGITS = 3;
23
+ var UTF8_SEQUENCE = "[\\x00-\\x7f]|[\\xc2-\\xdf][\\x80-\\xbf]|\\xe0[\\xa0-\\xbf][\\x80-\\xbf]|[\\xe1-\\xec\\xee\\xef][\\x80-\\xbf]{2}|\\xed[\\x80-\\x9f][\\x80-\\xbf]|\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2}|[\\xf1-\\xf3][\\x80-\\xbf]{3}|\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2}";
24
+ var UTF8_WHOLE = /* @__PURE__ */ new RegExp(`^(?:${UTF8_SEQUENCE})*$`);
23
25
  // src/datatrans.js
24
26
  var DATATRANS_HOSTS = Object.freeze(["pay.datatrans.com", "pay.sandbox.datatrans.com"]);
25
27
  var DATATRANS_TOKENIZE_PATH = "/upp/payment/SecureFields/paymentField";
package/dist/index.d.ts CHANGED
@@ -46,7 +46,7 @@ export type { ApiTransport } from './api-module.js';
46
46
  export { BuyModule, BuyError, isBuyDeclined, BUY_TURN_TIMEOUT_MS } from './buy.js';
47
47
  export type { BuyStatus, BuyCart, BuyCartLine, BuyDeliveryAddress, BuyPaymentSource, BuyOutcome, BuyPlacement, BuyCatalog, BuyUnmatched, BuyTurn, BuyDeclined, BuyOrder, BuyLastCheckout, BuyConversation, BuyAskInput, BuyConfirmInput, BuyConversationInput, BuyCheckoutHandoff, BuyOpenOffer, BuyBrowserCheckout, BuyApiAmount, } from './buy.js';
48
48
  export { ApprovalsModule, CANCEL_REASONS, SANDBOX_REQUEST } from './approvals.js';
49
- export type { CreateAuthorizationInput, Authorization, AuthorizationResult, AuthorizationFields, Cancelled, PayingCard, ChoosableCard } from './approvals.js';
49
+ export type { CreateAuthorizationInput, OrderLineItem, OrderShipTo, Authorization, AuthorizationResult, AuthorizationFields, Cancelled, PayingCard, ChoosableCard } from './approvals.js';
50
50
  export { verifyWebhook, signWebhook, parseWebhookEvent, parseSignatureHeader, isCheckoutAuthorizationEvent, isVaultEvent, CHECKOUT_AUTHORIZATION_EVENT_TYPES, VAULT_EVENT_TYPES } from './webhooks.js';
51
51
  export type { WebhookEvent, AgentcardEvent, CheckoutAuthorizationEvent, CheckoutAuthorizationEventType, CheckoutAuthorizationEventData, VaultEvent, VaultEventType, VaultEventData, OtherEvent, VerifyWebhookOptions } from './webhooks.js';
52
52
  export { AgentcardError } from './api-types.js';
@@ -6,6 +6,7 @@ import type { ShijiStsUnsupportedReason } from './shiji-sts.js';
6
6
  import type { PaddleVgsPayRefusal } from './paddle-vgs-pay.js';
7
7
  import type { PaypalCardFormReason } from './paypal-card-forms.js';
8
8
  import { type CardRequestHold, type HoldReleaseInput, type HoldReleaseOutcome } from './hold.js';
9
+ import { type StripeApprovedWay } from './stripe-continuation.js';
9
10
  /** The application's resolver confirmed the payment for this checkout authorization. */
10
11
  export interface MerchantPaymentConfirmation {
11
12
  kind: 'merchant_payment';
@@ -104,7 +105,7 @@ export declare class CheckoutLifecycle implements CheckoutController {
104
105
  private wspayChallenge;
105
106
  private heldBeforeHandoff;
106
107
  private stripeContinuedReason;
107
- private approvedPaymentMethod;
108
+ private approvedWay;
108
109
  private ownedShopOrderId;
109
110
  private orderRefusal;
110
111
  private readonly handoffs;
@@ -268,12 +269,19 @@ export declare class CheckoutLifecycle implements CheckoutController {
268
269
  * VaultClient.withoutCard, which then refuses a Nuvei payment without a card.
269
270
  */
270
271
  cardHandoffs(): readonly string[];
272
+ /**
273
+ * The object a Stripe confirmation may pay with in place of the card it sends
274
+ * again (cdp.ts claimStripeContinuation): the one this attachment's approved
275
+ * tokenization returned, with the field that names it, while its continuation
276
+ * is still open. Null for a tokenization no confirmation names by id
277
+ * (`/v1/tokens`), and once the checkout was cancelled, aborted or reconciled.
278
+ */
279
+ approvedStripeWay(): StripeApprovedWay | null;
271
280
  /**
272
281
  * The payment method a Stripe card save may pay with in place of the card
273
- * it sends again (cdp.ts claimStripeContinuation): the one this
274
- * attachment's approved `/v1/payment_methods` request returned, while its
275
- * continuation is still open. Null for any other tokenization, and once the
276
- * checkout was cancelled, aborted or reconciled.
282
+ * it sends again: the `pm_` an approved `/v1/payment_methods` request
283
+ * returned. Null for every other approved object, since a SetupIntent
284
+ * confirm pays with a payment method alone.
277
285
  */
278
286
  approvedStripePaymentMethod(): string | null;
279
287
  /**
package/dist/lifecycle.js CHANGED
@@ -3,6 +3,7 @@ import { CardEndpointRefusedError } from './card-endpoint.js';
3
3
  import { parseOwnedShopReceipt, OWNED_SHOP_SKU, OWNED_SHOP_AMOUNT_CENTS, OWNED_SHOP_CURRENCY } from './owned-shop.generated.js';
4
4
  import { isWspayChallenge } from './wspay.js';
5
5
  import { HoldAnsweredError, HoldEndedError } from './hold.js';
6
+ import { stripeApprovedWay } from './stripe-continuation.js';
6
7
  /**
7
8
  * The statuses that end an attempt: its outcome is known (`completed`, `declined`, `failed`,
8
9
  * `timed_out`, `unsupported`, `cancelled`), or the SDK already reported it unknown with its own
@@ -25,19 +26,6 @@ export const MAX_STRIPE_CONTINUATION_CHECKS = 3;
25
26
  * the post becomes a new approval instead of hanging the checkout.
26
27
  */
27
28
  export const MERCHANT_ORDER_READ_MS = 5_000;
28
- const STRIPE_PAYMENT_METHOD_ID = /^pm_[A-Za-z0-9]{1,250}$/;
29
- /** The `pm_` id in a Stripe `/v1/payment_methods` answer, or null for any other body. */
30
- function stripePaymentMethodId(body) {
31
- if (typeof body !== 'string')
32
- return null;
33
- try {
34
- const id = JSON.parse(body)?.id;
35
- return typeof id === 'string' && STRIPE_PAYMENT_METHOD_ID.test(id) ? id : null;
36
- }
37
- catch {
38
- return null;
39
- }
40
- }
41
29
  /** Shared by the raw CDP and Playwright transports. No browser ownership or payment execution lives here. */
42
30
  export class CheckoutLifecycle {
43
31
  options;
@@ -62,8 +50,9 @@ export class CheckoutLifecycle {
62
50
  heldBeforeHandoff = false;
63
51
  // What the continuation that went through confirmed: a payment, or a card save.
64
52
  stripeContinuedReason = 'stripe_payment_continued';
65
- // The payment method a Stripe /v1/payment_methods approval returned: see approvedStripePaymentMethod.
66
- approvedPaymentMethod = null;
53
+ // The object a Stripe tokenization approval returned, and the field a confirmation
54
+ // names it by: see approvedStripeWay.
55
+ approvedWay = null;
67
56
  ownedShopOrderId = null;
68
57
  // The reason Nike's order was refused while this attempt was under way (merchantOrderRefused): its handoff keeps it failed.
69
58
  orderRefusal = null;
@@ -367,8 +356,7 @@ export class CheckoutLifecycle {
367
356
  this.unboundStripeToken = true;
368
357
  this.stripeTokenPrepared = true;
369
358
  this.held = true;
370
- if (url.pathname === '/v1/payment_methods')
371
- this.approvedPaymentMethod = stripePaymentMethodId(replay.body);
359
+ this.approvedWay = stripeApprovedWay(url.pathname, replay.body);
372
360
  }
373
361
  }
374
362
  catch { /* unknown URL cannot establish a token binding */ }
@@ -382,15 +370,25 @@ export class CheckoutLifecycle {
382
370
  * VaultClient.withoutCard, which then refuses a Nuvei payment without a card.
383
371
  */
384
372
  cardHandoffs() { return [...this.handoffs]; }
373
+ /**
374
+ * The object a Stripe confirmation may pay with in place of the card it sends
375
+ * again (cdp.ts claimStripeContinuation): the one this attachment's approved
376
+ * tokenization returned, with the field that names it, while its continuation
377
+ * is still open. Null for a tokenization no confirmation names by id
378
+ * (`/v1/tokens`), and once the checkout was cancelled, aborted or reconciled.
379
+ */
380
+ approvedStripeWay() {
381
+ return this.stripeContinuationOpen() ? this.approvedWay : null;
382
+ }
385
383
  /**
386
384
  * The payment method a Stripe card save may pay with in place of the card
387
- * it sends again (cdp.ts claimStripeContinuation): the one this
388
- * attachment's approved `/v1/payment_methods` request returned, while its
389
- * continuation is still open. Null for any other tokenization, and once the
390
- * checkout was cancelled, aborted or reconciled.
385
+ * it sends again: the `pm_` an approved `/v1/payment_methods` request
386
+ * returned. Null for every other approved object, since a SetupIntent
387
+ * confirm pays with a payment method alone.
391
388
  */
392
389
  approvedStripePaymentMethod() {
393
- return this.stripeContinuationOpen() ? this.approvedPaymentMethod : null;
390
+ const way = this.approvedStripeWay();
391
+ return way?.field === 'payment_method' ? way.id : null;
394
392
  }
395
393
  /**
396
394
  * The approval a page's card-free Stripe confirmation may continue, or null.
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: 4acbca9604c5eee50f5f73dc3dea5ab0d40c9cba1214ccda0d2074271b3554a5
3
+ // artifact-sha256: e2228c7919341a7b3615b285c3aa77948c247c13145a1e394a1bb1c64acbca06
4
4
  // src/json-path.js
5
5
  var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
6
6
  function isPlainObject(v) {
@@ -318,17 +318,39 @@ function enclosedValue(char) {
318
318
  }
319
319
  var asciiDigits = (text) => (typeof text.normalize === "function" ? text.normalize("NFKC") : text).replace(ENCLOSED_CHAR, enclosedValue).replace(/\p{Nd}/gu, (char) => char >= "0" && char <= "9" ? char : digitValue(char));
320
320
  var unescaped = (text) => text.replace(/\\u([0-9a-fA-F]{4})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
321
+ var UTF8_SEQUENCE = "[\\x00-\\x7f]|[\\xc2-\\xdf][\\x80-\\xbf]|\\xe0[\\xa0-\\xbf][\\x80-\\xbf]|[\\xe1-\\xec\\xee\\xef][\\x80-\\xbf]{2}|\\xed[\\x80-\\x9f][\\x80-\\xbf]|\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2}|[\\xf1-\\xf3][\\x80-\\xbf]{3}|\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2}";
322
+ var UTF8_WHOLE = /* @__PURE__ */ new RegExp(`^(?:${UTF8_SEQUENCE})*$`);
323
+ var UTF8_ONE = /* @__PURE__ */ new RegExp(UTF8_SEQUENCE, "g");
324
+ function utf8Of(bytes) {
325
+ if (!/[\x80-\xff]/.test(bytes) || !UTF8_WHOLE.test(bytes))
326
+ return null;
327
+ return bytes.replace(UTF8_ONE, (sequence) => {
328
+ if (sequence.length === 1)
329
+ return sequence;
330
+ const lead = sequence.charCodeAt(0);
331
+ let point = lead & (sequence.length === 2 ? 31 : sequence.length === 3 ? 15 : 7);
332
+ for (let i = 1; i < sequence.length; i += 1)
333
+ point = point << 6 | sequence.charCodeAt(i) & 63;
334
+ return String.fromCodePoint(point);
335
+ });
336
+ }
337
+ var utf8Runs = (text) => text.replace(/[\x80-\xff]+/g, (run) => utf8Of(run) ?? run);
321
338
  var decodedInPlace = (text) => text.replace(BASE64_PIECE, (piece) => {
322
339
  const bare = piece.replace(/=+$/, "");
323
340
  for (let skip = 0; skip < 4 && skip < bare.length - 1; skip += 1) {
324
341
  const bytes = base64Text(bare.slice(skip));
325
342
  if (/^[\x20-\x7e]+$/.test(bytes))
326
343
  return bare.slice(0, skip) + bytes;
344
+ const utf82 = utf8Of(bytes);
345
+ if (utf82 !== null && !/\p{C}/u.test(utf82))
346
+ return bare.slice(0, skip) + utf82;
327
347
  }
328
348
  return piece;
329
349
  });
330
350
  function collect(text, layers, streams, runs) {
331
351
  const base = /* @__PURE__ */ new Set([...readings(text), ...readings(unescaped(text))]);
352
+ for (const reading of [...base])
353
+ base.add(utf8Runs(reading));
332
354
  for (const reading of /* @__PURE__ */ new Set([...base, ...[...base].map(decodedInPlace)])) {
333
355
  const digits = asciiDigits(reading);
334
356
  const sequence = digits.match(/[0-9]+/g) ?? [];
@@ -341,8 +363,13 @@ function collect(text, layers, streams, runs) {
341
363
  if (layers === 0)
342
364
  continue;
343
365
  for (const run of new Set(reading.match(BASE64_RUN))) {
344
- for (let skip = 0; skip < 4; skip += 1)
345
- collect(base64Text(run.slice(skip)), layers - 1, streams, runs);
366
+ for (let skip = 0; skip < 4; skip += 1) {
367
+ const bytes = base64Text(run.slice(skip));
368
+ collect(bytes, layers - 1, streams, runs);
369
+ const utf82 = utf8Of(bytes);
370
+ if (utf82 !== null)
371
+ collect(utf82, layers - 1, streams, runs);
372
+ }
346
373
  }
347
374
  }
348
375
  }
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: d6d50b6577a932c3586fcade6b8cbd03c562bd3394e8addcb954d797ea9999b4
3
+ // artifact-sha256: d5e732dd0bce3debee02e3f31107e65059e0d3888b54a605357a5817bb8909ce
4
4
  // src/json-path.js
5
5
  function roundTrips(parsed, body) {
6
6
  try {
@@ -29,6 +29,8 @@ function enclosedValue(char) {
29
29
  var asciiDigits = (text) => (typeof text.normalize === "function" ? text.normalize("NFKC") : text).replace(ENCLOSED_CHAR, enclosedValue).replace(/\p{Nd}/gu, (char) => char >= "0" && char <= "9" ? char : digitValue(char));
30
30
  var digitCount = (text) => (asciiDigits(String(text)).match(/\p{N}/gu) ?? []).length;
31
31
  var NAME_DIGITS = 3;
32
+ var UTF8_SEQUENCE = "[\\x00-\\x7f]|[\\xc2-\\xdf][\\x80-\\xbf]|\\xe0[\\xa0-\\xbf][\\x80-\\xbf]|[\\xe1-\\xec\\xee\\xef][\\x80-\\xbf]{2}|\\xed[\\x80-\\x9f][\\x80-\\xbf]|\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2}|[\\xf1-\\xf3][\\x80-\\xbf]{3}|\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2}";
33
+ var UTF8_WHOLE = /* @__PURE__ */ new RegExp(`^(?:${UTF8_SEQUENCE})*$`);
32
34
  // src/sha256.js
33
35
  var K = /* @__PURE__ */ new Uint32Array([
34
36
  1116352408,
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: 90e78fe2563fa4e058ffb098ef6a1354baffee49d6d73fc52018b2700683b755
3
+ // artifact-sha256: 8c51d9a96bc459152335ed188a90bb7d6b3548469c16938af3e384afdad5370b
4
4
  // src/card-number-key.js
5
5
  var CARD_NUMBER_KEY = /^(number|card_number|cardnumber|cardNum|card_num|pan)$/i;
6
6
  // src/json-path.js
@@ -1992,6 +1992,8 @@ function enclosedValue(char) {
1992
1992
  var asciiDigits = (text11) => (typeof text11.normalize === "function" ? text11.normalize("NFKC") : text11).replace(ENCLOSED_CHAR, enclosedValue).replace(/\p{Nd}/gu, (char) => char >= "0" && char <= "9" ? char : digitValue(char));
1993
1993
  var digitCount = (text11) => (asciiDigits(String(text11)).match(/\p{N}/gu) ?? []).length;
1994
1994
  var NAME_DIGITS = 3;
1995
+ var UTF8_SEQUENCE = "[\\x00-\\x7f]|[\\xc2-\\xdf][\\x80-\\xbf]|\\xe0[\\xa0-\\xbf][\\x80-\\xbf]|[\\xe1-\\xec\\xee\\xef][\\x80-\\xbf]{2}|\\xed[\\x80-\\x9f][\\x80-\\xbf]|\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2}|[\\xf1-\\xf3][\\x80-\\xbf]{3}|\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2}";
1996
+ var UTF8_WHOLE = /* @__PURE__ */ new RegExp(`^(?:${UTF8_SEQUENCE})*$`);
1995
1997
  // src/pay-nl.js
1996
1998
  var PAY_NL_PSP = "pay_nl";
1997
1999
  var PAY_NL_TOKEN_URL = "https://payment.pay.nl/v1/Payment/getCardToken/json";
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: 2b384766928412dadfb553ebd4ae0ba3454599de5b60b5abcb0fd26775fb53b5
3
+ // artifact-sha256: b2ba367a9b8d1758f1deea226abb2ca6637b40a88aa0c5ee7f359e074f4c017e
4
4
  // src/deep-freeze.js
5
5
  function deepFreeze(value) {
6
6
  if (value && typeof value === "object" && !Object.isFrozen(value)) {
@@ -5797,6 +5797,9 @@ function trustedClientRecognizer(pspOrEntry) {
5797
5797
  throw new Error("Refusing to pay: unknown payment processor.");
5798
5798
  return definition;
5799
5799
  }
5800
+ // src/answer-card-leak.js
5801
+ var UTF8_SEQUENCE = "[\\x00-\\x7f]|[\\xc2-\\xdf][\\x80-\\xbf]|\\xe0[\\xa0-\\xbf][\\x80-\\xbf]|[\\xe1-\\xec\\xee\\xef][\\x80-\\xbf]{2}|\\xed[\\x80-\\x9f][\\x80-\\xbf]|\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2}|[\\xf1-\\xf3][\\x80-\\xbf]{3}|\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2}";
5802
+ var UTF8_WHOLE = /* @__PURE__ */ new RegExp(`^(?:${UTF8_SEQUENCE})*$`);
5800
5803
  // src/datatrans.js
5801
5804
  var DATATRANS_HOSTS = Object.freeze(["pay.datatrans.com", "pay.sandbox.datatrans.com"]);
5802
5805
  var DATATRANS_REFUSAL_REASONS = Object.freeze(["unsupported", "card_on_file", "brand_mismatch", "unregistered_merchant"]);
@@ -0,0 +1,45 @@
1
+ /**
2
+ * How an approved tokenization is named in the confirmation that pays with it,
3
+ * by the Stripe endpoint whose answer produced it. The same four endpoints mint
4
+ * an approved object (lifecycle.ts), and this table holds the three a
5
+ * confirmation names by id on its own. It mirrors APPROVED_OBJECT in the
6
+ * backend's checkout-continuation.ts, which judges exactly this shape: exactly
7
+ * one such field, and no payment_method_data field left beside it.
8
+ *
9
+ * `/v1/tokens` is deliberately absent. Its field lives inside the method data
10
+ * (payment_method_data[card][token]), so paying with a card token means writing
11
+ * into the method data this rewrite strips rather than replacing it, and no page
12
+ * has been seen doing that. A confirm carrying a card token keeps the ordinary
13
+ * hold until one is.
14
+ */
15
+ export declare const STRIPE_APPROVED_WAY: Readonly<Record<string, Readonly<{
16
+ field: string;
17
+ prefix: string;
18
+ }>>>;
19
+ /** An approved object a confirmation can pay with: the field that names it, and its id. */
20
+ export type StripeApprovedWay = {
21
+ field: string;
22
+ id: string;
23
+ };
24
+ /**
25
+ * The approved object a Stripe tokenization answer returned, for the endpoint
26
+ * that answered: its field and its id. Null for an endpoint no confirmation
27
+ * names by id, for a body that will not parse, and for an id that is not the
28
+ * one that endpoint mints, so a confirmation can never be sent paying with
29
+ * something another endpoint produced.
30
+ */
31
+ export declare function stripeApprovedWay(pathname: string, body: unknown): StripeApprovedWay | null;
32
+ /**
33
+ * The page's confirmation, paying with `way` instead of the card it carries:
34
+ * every `payment_method_data[...]` field goes (the card, and the billing details
35
+ * and telemetry Stripe.js sends beside it; the approved object already carries
36
+ * the billing details of the approved request), and `<field>=<id>` takes the
37
+ * place of the first one. Every other field stays byte for byte as the page
38
+ * wrote it (client_secret, key, expected_payment_method_type, use_stripe_sdk,
39
+ * return_url, mandate and option fields). Null, and nothing is rewritten, when
40
+ * the field is not one a confirmation pays with, when the id is not one Stripe
41
+ * mints, when a key cannot be decoded, when the body already names a way to pay
42
+ * (payment_method, source, confirmation_token), or when it carries no
43
+ * payment_method_data at all.
44
+ */
45
+ export declare function confirmPayingWith(body: string, way: StripeApprovedWay): string | null;
@@ -0,0 +1,106 @@
1
+ // What a Stripe confirmation the cardholder already approved may pay with,
2
+ // shared by the card save and the payment (cdp.ts claimStripeContinuation).
3
+ // Kept in its own module, outside the package's published entries, so its
4
+ // tests can reach it and lifecycle.ts can read the same table.
5
+ //
6
+ // A page tokenizes the card through an approval and then confirms. Some pages
7
+ // confirm with the object they got back, which carries no card. Others send
8
+ // the card again inline, as payment_method_data[card][number] in the confirm:
9
+ // confirmCardSetup with the Card Element after createPaymentMethod does on a
10
+ // SetupIntent, and a store that creates a confirmation token for a fraud check
11
+ // and then calls confirmPayment({ elements }) does on a PaymentIntent. The card
12
+ // in that second request is whatever the agent typed; the approved object holds
13
+ // the cardholder's card. So that confirm is sent paying with the approved
14
+ // object instead, with no card in it, and the API decides whether it is the
15
+ // payment the cardholder approved.
16
+ /**
17
+ * How an approved tokenization is named in the confirmation that pays with it,
18
+ * by the Stripe endpoint whose answer produced it. The same four endpoints mint
19
+ * an approved object (lifecycle.ts), and this table holds the three a
20
+ * confirmation names by id on its own. It mirrors APPROVED_OBJECT in the
21
+ * backend's checkout-continuation.ts, which judges exactly this shape: exactly
22
+ * one such field, and no payment_method_data field left beside it.
23
+ *
24
+ * `/v1/tokens` is deliberately absent. Its field lives inside the method data
25
+ * (payment_method_data[card][token]), so paying with a card token means writing
26
+ * into the method data this rewrite strips rather than replacing it, and no page
27
+ * has been seen doing that. A confirm carrying a card token keeps the ordinary
28
+ * hold until one is.
29
+ */
30
+ export const STRIPE_APPROVED_WAY = Object.freeze({
31
+ '/v1/payment_methods': Object.freeze({ field: 'payment_method', prefix: 'pm_' }),
32
+ '/v1/confirmation_tokens': Object.freeze({ field: 'confirmation_token', prefix: 'ctoken_' }),
33
+ '/v1/sources': Object.freeze({ field: 'source', prefix: 'src_' }),
34
+ });
35
+ // The other ways a confirmation can say what it pays with. A body that already
36
+ // names one is not the shape rewritten here, the field about to be written
37
+ // included: there is then nothing to replace, and the body already names a way
38
+ // to pay, so the ordinary hold decides it.
39
+ const OTHER_WAYS_TO_PAY = new Set(['payment_method', 'source', 'confirmation_token']);
40
+ // An id as Stripe mints it, and as a form field can carry it unescaped.
41
+ const APPROVED_ID = /^[a-z]+_[A-Za-z0-9]{1,250}$/;
42
+ /**
43
+ * The approved object a Stripe tokenization answer returned, for the endpoint
44
+ * that answered: its field and its id. Null for an endpoint no confirmation
45
+ * names by id, for a body that will not parse, and for an id that is not the
46
+ * one that endpoint mints, so a confirmation can never be sent paying with
47
+ * something another endpoint produced.
48
+ */
49
+ export function stripeApprovedWay(pathname, body) {
50
+ const way = Object.prototype.hasOwnProperty.call(STRIPE_APPROVED_WAY, pathname) ? STRIPE_APPROVED_WAY[pathname] : undefined;
51
+ if (!way || typeof body !== 'string')
52
+ return null;
53
+ let id;
54
+ try {
55
+ id = JSON.parse(body)?.id;
56
+ }
57
+ catch {
58
+ return null;
59
+ }
60
+ if (typeof id !== 'string' || !id.startsWith(way.prefix) || !APPROVED_ID.test(id))
61
+ return null;
62
+ return { field: way.field, id };
63
+ }
64
+ /**
65
+ * The page's confirmation, paying with `way` instead of the card it carries:
66
+ * every `payment_method_data[...]` field goes (the card, and the billing details
67
+ * and telemetry Stripe.js sends beside it; the approved object already carries
68
+ * the billing details of the approved request), and `<field>=<id>` takes the
69
+ * place of the first one. Every other field stays byte for byte as the page
70
+ * wrote it (client_secret, key, expected_payment_method_type, use_stripe_sdk,
71
+ * return_url, mandate and option fields). Null, and nothing is rewritten, when
72
+ * the field is not one a confirmation pays with, when the id is not one Stripe
73
+ * mints, when a key cannot be decoded, when the body already names a way to pay
74
+ * (payment_method, source, confirmation_token), or when it carries no
75
+ * payment_method_data at all.
76
+ */
77
+ export function confirmPayingWith(body, way) {
78
+ if (typeof body !== 'string' || body === '')
79
+ return null;
80
+ if (!way || !OTHER_WAYS_TO_PAY.has(way.field) || !APPROVED_ID.test(way.id))
81
+ return null;
82
+ const kept = [];
83
+ let replaced = false;
84
+ for (const chunk of body.split('&')) {
85
+ if (chunk === '')
86
+ continue;
87
+ const eq = chunk.indexOf('=');
88
+ let key;
89
+ try {
90
+ key = decodeURIComponent((eq < 0 ? chunk : chunk.slice(0, eq)).replace(/\+/g, ' '));
91
+ }
92
+ catch {
93
+ return null;
94
+ }
95
+ if (OTHER_WAYS_TO_PAY.has(key))
96
+ return null;
97
+ if (key.startsWith('payment_method_data[')) {
98
+ if (!replaced)
99
+ kept.push(`${way.field}=${way.id}`);
100
+ replaced = true;
101
+ continue;
102
+ }
103
+ kept.push(chunk);
104
+ }
105
+ return replaced ? kept.join('&') : null;
106
+ }
@@ -2,15 +2,10 @@
2
2
  export declare const STRIPE_SETUP_INTENT_CONFIRM: RegExp;
3
3
  /**
4
4
  * The page's SetupIntent confirm, paying with `paymentMethod` instead of the
5
- * card it carries: every `payment_method_data[...]` field goes (the card, and
6
- * the billing details and telemetry Stripe.js sends beside it; the payment
7
- * method already carries the billing details of the approved request), and
8
- * `payment_method=<id>` takes the place of the first one. Every other field
9
- * stays byte for byte as the page wrote it (client_secret, key,
10
- * expected_payment_method_type, use_stripe_sdk, return_url, mandate and option
11
- * fields). Null, and nothing is rewritten, when the id is not a payment
12
- * method's, when a key cannot be decoded, when the body already names another
13
- * way to pay (payment_method, source, confirmation_token), or when it carries
14
- * no payment_method_data at all.
5
+ * card it carries (confirmPayingWith, with the payment method as the way to
6
+ * pay). Null, and nothing is rewritten, when the id is not a payment method's,
7
+ * when a key cannot be decoded, when the body already names another way to pay
8
+ * (payment_method, source, confirmation_token), or when it carries no
9
+ * payment_method_data at all.
15
10
  */
16
11
  export declare function setupConfirmPayingWith(body: string, paymentMethod: string): string | null;
@@ -1,6 +1,8 @@
1
1
  // The SetupIntent confirm a Stripe card save continues with, shared by both
2
2
  // adapters (cdp.ts claimStripeContinuation). Kept in its own module, outside the
3
- // package's published entries, so its tests can reach it.
3
+ // package's published entries, so its tests can reach it. The rewrite itself,
4
+ // and the table of approved objects a confirmation can pay with, live in
5
+ // stripe-continuation.ts, which the payment side reads too.
4
6
  //
5
7
  // A page that creates the payment method first (createPaymentMethod, which the
6
8
  // cardholder approves) and then confirms a SetupIntent usually pays with the
@@ -12,50 +14,20 @@
12
14
  // agent typed; the approved payment method holds the cardholder's card. So that
13
15
  // confirm continues paying with the approved payment method instead, once the
14
16
  // API allows it.
17
+ import { confirmPayingWith } from './stripe-continuation.js';
15
18
  /** A SetupIntent confirm's path, as Stripe.js sends it. */
16
19
  export const STRIPE_SETUP_INTENT_CONFIRM = /^\/v1\/setup_intents\/seti_[A-Za-z0-9]+\/confirm$/;
17
20
  const PAYMENT_METHOD_ID = /^pm_[A-Za-z0-9]{1,250}$/;
18
- // The other ways a confirm can say what it pays with. A body that already names
19
- // one is not the shape rewritten here.
20
- const OTHER_WAYS_TO_PAY = new Set(['payment_method', 'source', 'confirmation_token']);
21
21
  /**
22
22
  * The page's SetupIntent confirm, paying with `paymentMethod` instead of the
23
- * card it carries: every `payment_method_data[...]` field goes (the card, and
24
- * the billing details and telemetry Stripe.js sends beside it; the payment
25
- * method already carries the billing details of the approved request), and
26
- * `payment_method=<id>` takes the place of the first one. Every other field
27
- * stays byte for byte as the page wrote it (client_secret, key,
28
- * expected_payment_method_type, use_stripe_sdk, return_url, mandate and option
29
- * fields). Null, and nothing is rewritten, when the id is not a payment
30
- * method's, when a key cannot be decoded, when the body already names another
31
- * way to pay (payment_method, source, confirmation_token), or when it carries
32
- * no payment_method_data at all.
23
+ * card it carries (confirmPayingWith, with the payment method as the way to
24
+ * pay). Null, and nothing is rewritten, when the id is not a payment method's,
25
+ * when a key cannot be decoded, when the body already names another way to pay
26
+ * (payment_method, source, confirmation_token), or when it carries no
27
+ * payment_method_data at all.
33
28
  */
34
29
  export function setupConfirmPayingWith(body, paymentMethod) {
35
- if (!PAYMENT_METHOD_ID.test(paymentMethod) || typeof body !== 'string' || body === '')
30
+ if (!PAYMENT_METHOD_ID.test(paymentMethod))
36
31
  return null;
37
- const kept = [];
38
- let replaced = false;
39
- for (const chunk of body.split('&')) {
40
- if (chunk === '')
41
- continue;
42
- const eq = chunk.indexOf('=');
43
- let key;
44
- try {
45
- key = decodeURIComponent((eq < 0 ? chunk : chunk.slice(0, eq)).replace(/\+/g, ' '));
46
- }
47
- catch {
48
- return null;
49
- }
50
- if (OTHER_WAYS_TO_PAY.has(key))
51
- return null;
52
- if (key.startsWith('payment_method_data[')) {
53
- if (!replaced)
54
- kept.push(`payment_method=${paymentMethod}`);
55
- replaced = true;
56
- continue;
57
- }
58
- kept.push(chunk);
59
- }
60
- return replaced ? kept.join('&') : null;
32
+ return confirmPayingWith(body, { field: 'payment_method', id: paymentMethod });
61
33
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-cards/sdk",
3
- "version": "0.24.2",
3
+ "version": "0.25.0",
4
4
  "description": "Agentcard's SDK: one client, Agentcard, with two modules. checkout pauses a browser purchase and pays it with the person's own card; buy asks the Purchase API for a cart and places it. Card data never enters your process.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -30,7 +30,7 @@
30
30
  "_comment_test": "check:built runs first and names the command when a file the build generates (the copies in src/, the preflight contracts in dist/, the Kernel inventory) is missing or stale; verify:pack runs last, on the same dist.",
31
31
  "check:built": "node scripts/generate-payment-core.mjs --check && node scripts/generate-url-masks.mjs --check && node scripts/generate-capabilities.mjs --check && node scripts/generate-agent-amount.mjs --check && node scripts/generate-preflight-contract.mjs --check && node scripts/generate-kernel-native-inventory.mjs --check",
32
32
  "verify:pack": "node scripts/verify-pack.mjs",
33
- "test": "npm run check:built && node test.mjs && node --test lifecycle.test.mjs merchant-abort.test.mjs preparation.test.mjs braintree.test.mjs pre-claim.test.mjs ekashu.test.mjs redsys.test.mjs quickpay.test.mjs paytrail.test.mjs paypal-hosted-fields.test.mjs paypal-card-forms.test.mjs cybersource-secure-acceptance.test.mjs ebanx.test.mjs payrexx.test.mjs payrexx-follow-ups.test.mjs payrexx-adapters.test.mjs nike-order.test.mjs nike-order-adapters.test.mjs autopilot.test.mjs stripe-checkout.test.mjs stripe-setup.test.mjs stripe-legacy-checkout.test.mjs payment-core.test.mjs prepared-processor.test.mjs merchant-hosted.test.mjs merchant-total.test.mjs sandbox-declaration.test.mjs minimum-delay.test.mjs paysafe.test.mjs wix-payments.test.mjs hipay.test.mjs openpay.test.mjs processout.test.mjs payu.test.mjs attachment.test.mjs worker-targets.test.mjs mercado-checkout.test.mjs mercado-polling.test.mjs amadeus.test.mjs pelecard.test.mjs aci.test.mjs primer.test.mjs payrails.test.mjs elavon-converge.test.mjs agentcard.test.mjs buy.test.mjs clean-dist.test.mjs approvals.test.mjs gmo.test.mjs cybersource-flex.test.mjs juspay-gate.test.mjs card-endpoint.test.mjs card-endpoint-fastspring.test.mjs card-endpoint-navigation.test.mjs merchant-session-probe.test.mjs datatrans.test.mjs authorize-net-dpm.test.mjs creditguard.test.mjs eprotect.test.mjs wspay.test.mjs shiji-sts.test.mjs worldline-mycheckout.test.mjs verifone.test.mjs gravy.test.mjs paddle-vgs.test.mjs sbps.test.mjs hold.test.mjs paddle-tokenex.test.mjs lyra.test.mjs gopay.test.mjs paygent.test.mjs twoc2p.test.mjs tap-payments.test.mjs pay-nl.test.mjs toast.test.mjs redact-url.test.mjs hosted-entry.test.mjs comgate.test.mjs przelewy24.test.mjs tokenex-iframe.test.mjs transbank.test.mjs sumup.test.mjs clover.test.mjs eximbay.test.mjs xendit.test.mjs omise.test.mjs fastspring.test.mjs amazon-payment-services.test.mjs barion.test.mjs paymob.test.mjs payu-latam.test.mjs nexi-checkout.test.mjs oceanpayment.test.mjs pin-payments.test.mjs payplug.test.mjs cardlink-vpos.test.mjs eghl.test.mjs paymentwall.test.mjs vtex-payments.test.mjs vtex-payments-window.test.mjs iyzico.test.mjs usaepay.test.mjs viva-wallet.test.mjs aurus.test.mjs monei.test.mjs paystack.test.mjs frisbii.test.mjs token-repeat.test.mjs && node --test preflight-package.test.mjs preflight-collector.test.mjs browser-tests.test.mjs && node --test kernel-native-qualification.test.mjs && node --test ../vault/scripts/recurly-validation/watch-duty-sdk-result.test.mjs && node scripts/verify-pack.mjs",
33
+ "test": "npm run check:built && node test.mjs && node --test lifecycle.test.mjs merchant-abort.test.mjs preparation.test.mjs braintree.test.mjs pre-claim.test.mjs ekashu.test.mjs redsys.test.mjs quickpay.test.mjs paytrail.test.mjs paypal-hosted-fields.test.mjs paypal-card-forms.test.mjs cybersource-secure-acceptance.test.mjs ebanx.test.mjs payrexx.test.mjs payrexx-follow-ups.test.mjs payrexx-adapters.test.mjs nike-order.test.mjs nike-order-adapters.test.mjs autopilot.test.mjs stripe-checkout.test.mjs stripe-setup.test.mjs stripe-payment-continuation.test.mjs stripe-legacy-checkout.test.mjs payment-core.test.mjs prepared-processor.test.mjs merchant-hosted.test.mjs merchant-total.test.mjs sandbox-declaration.test.mjs minimum-delay.test.mjs paysafe.test.mjs wix-payments.test.mjs hipay.test.mjs openpay.test.mjs processout.test.mjs payu.test.mjs attachment.test.mjs worker-targets.test.mjs mercado-checkout.test.mjs mercado-polling.test.mjs amadeus.test.mjs pelecard.test.mjs aci.test.mjs primer.test.mjs payrails.test.mjs elavon-converge.test.mjs agentcard.test.mjs buy.test.mjs clean-dist.test.mjs approvals.test.mjs gmo.test.mjs cybersource-flex.test.mjs juspay-gate.test.mjs card-endpoint.test.mjs card-endpoint-fastspring.test.mjs card-endpoint-navigation.test.mjs merchant-session-probe.test.mjs datatrans.test.mjs authorize-net-dpm.test.mjs creditguard.test.mjs eprotect.test.mjs wspay.test.mjs shiji-sts.test.mjs worldline-mycheckout.test.mjs verifone.test.mjs gravy.test.mjs paddle-vgs.test.mjs sbps.test.mjs hold.test.mjs paddle-tokenex.test.mjs lyra.test.mjs gopay.test.mjs paygent.test.mjs twoc2p.test.mjs tap-payments.test.mjs pay-nl.test.mjs toast.test.mjs redact-url.test.mjs hosted-entry.test.mjs comgate.test.mjs przelewy24.test.mjs tokenex-iframe.test.mjs transbank.test.mjs sumup.test.mjs clover.test.mjs eximbay.test.mjs xendit.test.mjs omise.test.mjs fastspring.test.mjs amazon-payment-services.test.mjs barion.test.mjs paymob.test.mjs payu-latam.test.mjs nexi-checkout.test.mjs oceanpayment.test.mjs pin-payments.test.mjs payplug.test.mjs cardlink-vpos.test.mjs eghl.test.mjs paymentwall.test.mjs vtex-payments.test.mjs vtex-payments-window.test.mjs iyzico.test.mjs usaepay.test.mjs viva-wallet.test.mjs aurus.test.mjs monei.test.mjs paystack.test.mjs frisbii.test.mjs token-repeat.test.mjs && node --test preflight-package.test.mjs preflight-collector.test.mjs browser-tests.test.mjs && node --test kernel-native-qualification.test.mjs && node --test ../vault/scripts/recurly-validation/watch-duty-sdk-result.test.mjs && node scripts/verify-pack.mjs",
34
34
  "test:browser": "node browser-tests.mjs",
35
35
  "check:payment-core": "node scripts/generate-payment-core.mjs --check",
36
36
  "test:preflight": "node --test preflight-package.test.mjs preflight-collector.test.mjs kernel-native-qualification.test.mjs",