@agent-cards/sdk 0.21.0 → 0.23.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 (113) hide show
  1. package/CHANGELOG.md +87 -2
  2. package/PREFLIGHT.md +32 -0
  3. package/README.md +1177 -23
  4. package/dist/aci.d.ts +173 -0
  5. package/dist/aci.generated.d.ts +87 -0
  6. package/dist/aci.generated.js +306 -0
  7. package/dist/aci.js +371 -0
  8. package/dist/adyen-merchant-hosted.generated.d.ts +3 -3
  9. package/dist/adyen-merchant-hosted.generated.js +302 -56
  10. package/dist/agentcard.d.ts +9 -2
  11. package/dist/agentcard.js +4 -2
  12. package/dist/amadeus-checkout.generated.d.ts +57 -0
  13. package/dist/amadeus-checkout.generated.js +549 -0
  14. package/dist/amadeus.d.ts +41 -0
  15. package/dist/amadeus.js +81 -0
  16. package/dist/builtin-registry.generated.js +1 -1
  17. package/dist/card-endpoint-facts.d.ts +96 -0
  18. package/dist/card-endpoint-facts.js +275 -0
  19. package/dist/card-endpoint-page.d.ts +54 -0
  20. package/dist/card-endpoint-page.js +69 -0
  21. package/dist/card-endpoint.d.ts +298 -0
  22. package/dist/card-endpoint.js +438 -0
  23. package/dist/card-fields.generated.d.ts +5 -3
  24. package/dist/card-fields.generated.js +284 -7
  25. package/dist/cdp.d.ts +5 -1
  26. package/dist/cdp.js +1155 -141
  27. package/dist/client.d.ts +456 -20
  28. package/dist/client.js +1072 -104
  29. package/dist/creditguard.generated.d.ts +79 -0
  30. package/dist/creditguard.generated.js +662 -0
  31. package/dist/cse-body.js +11 -1
  32. package/dist/cybersource-flex.d.ts +30 -0
  33. package/dist/cybersource-flex.generated.d.ts +27 -1
  34. package/dist/cybersource-flex.generated.js +42 -2
  35. package/dist/cybersource-flex.js +46 -0
  36. package/dist/datatrans.d.ts +96 -0
  37. package/dist/datatrans.generated.d.ts +64 -0
  38. package/dist/datatrans.generated.js +426 -0
  39. package/dist/datatrans.js +178 -0
  40. package/dist/ekashu.d.ts +35 -0
  41. package/dist/ekashu.js +55 -0
  42. package/dist/elavon-converge.d.ts +37 -0
  43. package/dist/elavon-converge.generated.d.ts +49 -0
  44. package/dist/elavon-converge.generated.js +439 -0
  45. package/dist/elavon-converge.js +84 -0
  46. package/dist/eprotect.d.ts +152 -0
  47. package/dist/eprotect.generated.d.ts +77 -0
  48. package/dist/eprotect.generated.js +498 -0
  49. package/dist/eprotect.js +222 -0
  50. package/dist/hosted-form.d.ts +3 -2
  51. package/dist/hosted-form.js +3 -2
  52. package/dist/index.d.ts +17 -3
  53. package/dist/index.js +6 -1
  54. package/dist/juspay-gate.d.ts +82 -0
  55. package/dist/juspay-gate.js +126 -0
  56. package/dist/juspay.generated.d.ts +89 -0
  57. package/dist/juspay.generated.js +705 -0
  58. package/dist/lifecycle.d.ts +60 -6
  59. package/dist/lifecycle.js +122 -8
  60. package/dist/merchant-card-endpoints.generated.d.ts +122 -0
  61. package/dist/merchant-card-endpoints.generated.js +4261 -0
  62. package/dist/merchant-hosted.d.ts +4 -1
  63. package/dist/merchant-hosted.js +5 -2
  64. package/dist/merchant-session-probe.d.ts +48 -0
  65. package/dist/merchant-session-probe.js +53 -0
  66. package/dist/merchant-session.generated.d.ts +69 -0
  67. package/dist/merchant-session.generated.js +919 -0
  68. package/dist/payrails.d.ts +133 -0
  69. package/dist/payrails.generated.d.ts +73 -0
  70. package/dist/payrails.generated.js +596 -0
  71. package/dist/payrails.js +305 -0
  72. package/dist/pelecard.d.ts +32 -0
  73. package/dist/pelecard.generated.d.ts +32 -0
  74. package/dist/pelecard.generated.js +283 -0
  75. package/dist/pelecard.js +42 -0
  76. package/dist/pre-claim.d.ts +81 -2
  77. package/dist/pre-claim.js +1023 -5
  78. package/dist/preflight-catalog.json +2267 -288
  79. package/dist/preflight-schemas.json +183 -6
  80. package/dist/preflight.generated.d.ts +1 -1
  81. package/dist/preflight.generated.js +243 -4
  82. package/dist/preparation.d.ts +12 -3
  83. package/dist/preparation.js +63 -12
  84. package/dist/prepared-processor.d.ts +84 -5
  85. package/dist/prepared-processor.js +147 -6
  86. package/dist/primer.d.ts +53 -0
  87. package/dist/primer.generated.d.ts +38 -0
  88. package/dist/primer.generated.js +624 -0
  89. package/dist/primer.js +82 -0
  90. package/dist/registry.d.ts +100 -8
  91. package/dist/registry.js +85 -11
  92. package/dist/shiji-sts.d.ts +144 -0
  93. package/dist/shiji-sts.generated.d.ts +72 -0
  94. package/dist/shiji-sts.generated.js +913 -0
  95. package/dist/shiji-sts.js +222 -0
  96. package/dist/stripe-checkout.generated.d.ts +1 -1
  97. package/dist/stripe-checkout.generated.js +764 -9
  98. package/dist/stripe-setup.d.ts +16 -0
  99. package/dist/stripe-setup.js +61 -0
  100. package/dist/substitutions.generated.js +187 -29
  101. package/dist/verifone.d.ts +68 -0
  102. package/dist/verifone.generated.d.ts +51 -0
  103. package/dist/verifone.generated.js +1413 -0
  104. package/dist/verifone.js +119 -0
  105. package/dist/voice-types.d.ts +27 -0
  106. package/dist/voice.d.ts +6 -1
  107. package/dist/voice.js +6 -1
  108. package/dist/wspay.d.ts +41 -0
  109. package/dist/wspay.generated.d.ts +41 -0
  110. package/dist/wspay.generated.js +370 -0
  111. package/dist/wspay.js +65 -0
  112. package/examples/preflight/kernel-native/inventory.json +1 -1
  113. package/package.json +3 -3
@@ -1,7 +1,9 @@
1
1
  import { CheckoutPreparationError, type PrepareCheckoutOptions, type PreparedCheckout, type ReplayResponse } from './client.js';
2
2
  import type { CheckoutMode } from './registry.js';
3
+ import type { PayrailsUnsupportedReason } from './payrails.js';
3
4
  import type { Substitutions } from './substitute.js';
4
5
  import type { GmoUnsupportedReason } from './gmo.js';
6
+ import type { ShijiStsUnsupportedReason } from './shiji-sts.js';
5
7
  /** The application's resolver confirmed the payment for this checkout authorization. */
6
8
  export interface MerchantPaymentConfirmation {
7
9
  kind: 'merchant_payment';
@@ -28,7 +30,8 @@ export interface CheckoutState {
28
30
  status: 'idle' | 'awaiting_approval' | 'ready_to_submit' | 'awaiting_merchant' | 'requires_user_action' | 'completed' | 'declined' | 'timed_out' | 'cancelled' | 'unsupported' | 'outcome_unknown' | 'failed';
29
31
  authorizationId: string | null;
30
32
  preparationId?: string;
31
- mode?: CheckoutMode;
33
+ /** How the card reached the merchant: a processor mode, or `card_endpoint` for a reviewed merchant's own card endpoint. */
34
+ mode?: CheckoutMode | 'card_endpoint';
32
35
  orderId?: string;
33
36
  confirmation?: MerchantPaymentConfirmation;
34
37
  /** Stable SDK category; never includes a request body, processor response, or approval link. */
@@ -116,6 +119,12 @@ export interface CheckoutController {
116
119
  }
117
120
  /** How many times one approval's card-free Stripe confirmation may be checked before it is simply held. */
118
121
  export declare const MAX_STRIPE_CONTINUATION_CHECKS = 3;
122
+ /**
123
+ * How long a Datatrans re-submit waits for the merchant resolver (merchantOrderPending) while the
124
+ * page's card post stays paused. A resolver that has not answered by then reads as not pending, so
125
+ * the post becomes a new approval instead of hanging the checkout.
126
+ */
127
+ export declare const MERCHANT_ORDER_READ_MS = 5000;
119
128
  /** Shared by the raw CDP and Playwright transports. No browser ownership or payment execution lives here. */
120
129
  export declare class CheckoutLifecycle implements CheckoutController {
121
130
  private readonly options;
@@ -128,7 +137,12 @@ export declare class CheckoutLifecycle implements CheckoutController {
128
137
  private stripeTokenPrepared;
129
138
  private stripeContinuation;
130
139
  private stripeContinuationChecks;
140
+ /** The handoff in progress is WSPay's 3-D Secure step; see handedOff. */
141
+ private wspayChallenge;
142
+ private stripeContinuedReason;
143
+ private approvedPaymentMethod;
131
144
  private ownedShopOrderId;
145
+ private readonly handoffs;
132
146
  private reconciliation;
133
147
  private preparationHandler?;
134
148
  private preparationUsed;
@@ -147,6 +161,17 @@ export declare class CheckoutLifecycle implements CheckoutController {
147
161
  preparationFailed(error: CheckoutPreparationError): void;
148
162
  isBlocked(): boolean;
149
163
  isCancelled(): boolean;
164
+ /** Whether the application gave a merchant resolver, so reconcile() reads the merchant's own record. */
165
+ hasMerchantResolver(): boolean;
166
+ /**
167
+ * For a Datatrans re-submit once the approved answer reached the page (pre-claim.ts): whether the
168
+ * application's merchant resolver still reports this approval's order pending. A read only: no
169
+ * answer changes the state or the hold, so a pending order leaves the checkout exactly as it was.
170
+ * False with no resolver, while a request is in flight, once the checkout no longer awaits the
171
+ * merchant, when the resolver throws or answers anything but pending, and when it has not answered
172
+ * within `deadlineMs` (MERCHANT_ORDER_READ_MS): the paused card post never waits on it longer.
173
+ */
174
+ merchantOrderPending(deadlineMs?: number): Promise<boolean>;
150
175
  begin(): void;
151
176
  end(): void;
152
177
  private set;
@@ -187,11 +212,23 @@ export declare class CheckoutLifecycle implements CheckoutController {
187
212
  * turned on (merchant_profile_observe), a card request the profile cannot
188
213
  * finish (merchant_request_unsupported), a recognized processor's request in
189
214
  * a form its gate refuses (GMO's unsupported_gmo_request and
190
- * unsupported_gmo_token_v1), or a CyberSource Flex request that is not a
215
+ * unsupported_gmo_token_v1), a CyberSource Flex request that is not a
191
216
  * reviewed Microform v2 card field's (microform_unsupported,
192
- * cybersource-flex.ts).
217
+ * cybersource-flex.ts), a Juspay card request that is not the reviewed
218
+ * payment (juspay_request_unsupported, juspay-gate.ts), such as save card,
219
+ * EMI, a direct card or a sibling host, a reviewed merchant card endpoint
220
+ * this build does not pay (merchant_card_endpoint_not_enabled), a request that
221
+ * sends the typed card to such a merchant again outside its card request
222
+ * (merchant_card_endpoint_resend_refused), a CreditGuard
223
+ * page that runs its own 3-D Secure (creditguard_three_d_secure), a
224
+ * recognized Primer request in a form its gate refuses (unsupported_primer_sdk,
225
+ * unsupported_primer_request), a Payrails request its gate refuses
226
+ * (`unsupported_payrails_card_payment` and the card-save refusal codes), a
227
+ * Shiji STS request its gate refuses (shiji_sts_keep_on_file and the other
228
+ * shiji-sts.ts reasons), or a post to a processor's own card page that only
229
+ * the cardholder's device can fill (processor_card_page: NMI's).
193
230
  */
194
- unsupported(reason?: 'unrecognized_payment_endpoint' | 'merchant_profile_observe' | 'merchant_request_unsupported' | GmoUnsupportedReason | 'microform_unsupported'): void;
231
+ unsupported(reason?: 'unrecognized_payment_endpoint' | 'merchant_profile_observe' | 'merchant_request_unsupported' | GmoUnsupportedReason | 'microform_unsupported' | 'juspay_request_unsupported' | 'merchant_card_endpoint_not_enabled' | 'merchant_card_endpoint_resend_refused' | 'creditguard_three_d_secure' | 'unsupported_primer_sdk' | 'unsupported_primer_request' | PayrailsUnsupportedReason | ShijiStsUnsupportedReason | 'processor_card_page'): void;
195
232
  /**
196
233
  * A card request that only a prepared checkout pays (an Adyen merchant
197
234
  * profile's, or a Fiserv card capture) arrived with no preparation on this
@@ -201,6 +238,22 @@ export declare class CheckoutLifecycle implements CheckoutController {
201
238
  */
202
239
  preparationRequired(): void;
203
240
  prepareHandoff(replay: ReplayResponse, requestUrl: string): void;
241
+ /**
242
+ * The URLs of the requests this attachment has handed the card to, oldest
243
+ * first. Each is recorded before delivery, since the processor may already
244
+ * have minted a token from the card even if the browser never acknowledges
245
+ * it, and none is forgotten on a retry. The adapters pass them to
246
+ * VaultClient.withoutCard, which then refuses a Nuvei payment without a card.
247
+ */
248
+ cardHandoffs(): readonly string[];
249
+ /**
250
+ * The payment method a Stripe card save may pay with in place of the card
251
+ * it sends again (cdp.ts claimStripeContinuation): the one this
252
+ * attachment's approved `/v1/payment_methods` request returned, while its
253
+ * continuation is still open. Null for any other tokenization, and once the
254
+ * checkout was cancelled, aborted or reconciled.
255
+ */
256
+ approvedStripePaymentMethod(): string | null;
204
257
  /**
205
258
  * The approval a page's card-free Stripe confirmation may continue, or null.
206
259
  * Only once a Stripe tokenization is being handed to the page, and while
@@ -215,9 +268,10 @@ export declare class CheckoutLifecycle implements CheckoutController {
215
268
  * Settle a claimed check. True only when the API allowed it and the checkout
216
269
  * still awaits the merchant (nothing cancelled, aborted or reconciled it
217
270
  * while the API answered): the page's confirmation continues, and no later
218
- * one will.
271
+ * one will. `kind` names what it confirms: a payment (a PaymentIntent) or a
272
+ * card save (a SetupIntent), which the reason then says.
219
273
  */
220
- stripeContinuationChecked(allowed: boolean): boolean;
274
+ stripeContinuationChecked(allowed: boolean, kind?: 'payment' | 'setup'): boolean;
221
275
  private stripeContinuationOpen;
222
276
  handedOff(replay: ReplayResponse): void;
223
277
  failed(error: unknown, handoffStarted?: boolean): void;
package/dist/lifecycle.js CHANGED
@@ -1,7 +1,28 @@
1
1
  import { AdyenTestPlatformRefusedError, ApprovalDeclinedError, ApprovalTimeoutError, CheckoutCancelledError, CheckoutPreparationError, IntentNotConfirmableError, PaymentOutcomeUnknownError, ProcessorRefusedError } from './client.js';
2
+ import { CardEndpointRefusedError } from './card-endpoint.js';
2
3
  import { parseOwnedShopReceipt, OWNED_SHOP_SKU, OWNED_SHOP_AMOUNT_CENTS, OWNED_SHOP_CURRENCY } from './owned-shop.generated.js';
4
+ import { isWspayChallenge } from './wspay.js';
3
5
  /** How many times one approval's card-free Stripe confirmation may be checked before it is simply held. */
4
6
  export const MAX_STRIPE_CONTINUATION_CHECKS = 3;
7
+ /**
8
+ * How long a Datatrans re-submit waits for the merchant resolver (merchantOrderPending) while the
9
+ * page's card post stays paused. A resolver that has not answered by then reads as not pending, so
10
+ * the post becomes a new approval instead of hanging the checkout.
11
+ */
12
+ export const MERCHANT_ORDER_READ_MS = 5_000;
13
+ const STRIPE_PAYMENT_METHOD_ID = /^pm_[A-Za-z0-9]{1,250}$/;
14
+ /** The `pm_` id in a Stripe `/v1/payment_methods` answer, or null for any other body. */
15
+ function stripePaymentMethodId(body) {
16
+ if (typeof body !== 'string')
17
+ return null;
18
+ try {
19
+ const id = JSON.parse(body)?.id;
20
+ return typeof id === 'string' && STRIPE_PAYMENT_METHOD_ID.test(id) ? id : null;
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
5
26
  /** Shared by the raw CDP and Playwright transports. No browser ownership or payment execution lives here. */
6
27
  export class CheckoutLifecycle {
7
28
  options;
@@ -15,7 +36,15 @@ export class CheckoutLifecycle {
15
36
  stripeTokenPrepared = false;
16
37
  stripeContinuation = 'none';
17
38
  stripeContinuationChecks = 0;
39
+ /** The handoff in progress is WSPay's 3-D Secure step; see handedOff. */
40
+ wspayChallenge = false;
41
+ // What the continuation that went through confirmed: a payment, or a card save.
42
+ stripeContinuedReason = 'stripe_payment_continued';
43
+ // The payment method a Stripe /v1/payment_methods approval returned: see approvedStripePaymentMethod.
44
+ approvedPaymentMethod = null;
18
45
  ownedShopOrderId = null;
46
+ // Every request this attachment handed the card to: see cardHandoffs().
47
+ handoffs = [];
19
48
  reconciliation = null;
20
49
  preparationHandler;
21
50
  preparationUsed = false;
@@ -58,6 +87,30 @@ export class CheckoutLifecycle {
58
87
  }
59
88
  isBlocked() { return this.held || this.cancelled; }
60
89
  isCancelled() { return this.cancelled; }
90
+ /** Whether the application gave a merchant resolver, so reconcile() reads the merchant's own record. */
91
+ hasMerchantResolver() { return typeof this.options.resolveMerchantResult === 'function'; }
92
+ /**
93
+ * For a Datatrans re-submit once the approved answer reached the page (pre-claim.ts): whether the
94
+ * application's merchant resolver still reports this approval's order pending. A read only: no
95
+ * answer changes the state or the hold, so a pending order leaves the checkout exactly as it was.
96
+ * False with no resolver, while a request is in flight, once the checkout no longer awaits the
97
+ * merchant, when the resolver throws or answers anything but pending, and when it has not answered
98
+ * within `deadlineMs` (MERCHANT_ORDER_READ_MS): the paused card post never waits on it longer.
99
+ */
100
+ async merchantOrderPending(deadlineMs = MERCHANT_ORDER_READ_MS) {
101
+ const resolver = this.options.resolveMerchantResult;
102
+ if (!resolver || this.active || this.state.status !== 'awaiting_merchant')
103
+ return false;
104
+ let timer;
105
+ const expired = new Promise((resolve) => { timer = setTimeout(() => resolve(false), deadlineMs); });
106
+ const read = Promise.resolve().then(() => resolver(this.getState())).then((result) => !!result && typeof result === 'object' && !Array.isArray(result) && result.status === 'pending', () => false);
107
+ try {
108
+ return await Promise.race([read, expired]);
109
+ }
110
+ finally {
111
+ clearTimeout(timer);
112
+ }
113
+ }
61
114
  begin() {
62
115
  this.active = true;
63
116
  this.set({ status: 'awaiting_approval', authorizationId: null, ...(this.state.preparationId ? { preparationId: this.state.preparationId } : {}) });
@@ -135,9 +188,21 @@ export class CheckoutLifecycle {
135
188
  * turned on (merchant_profile_observe), a card request the profile cannot
136
189
  * finish (merchant_request_unsupported), a recognized processor's request in
137
190
  * a form its gate refuses (GMO's unsupported_gmo_request and
138
- * unsupported_gmo_token_v1), or a CyberSource Flex request that is not a
191
+ * unsupported_gmo_token_v1), a CyberSource Flex request that is not a
139
192
  * reviewed Microform v2 card field's (microform_unsupported,
140
- * cybersource-flex.ts).
193
+ * cybersource-flex.ts), a Juspay card request that is not the reviewed
194
+ * payment (juspay_request_unsupported, juspay-gate.ts), such as save card,
195
+ * EMI, a direct card or a sibling host, a reviewed merchant card endpoint
196
+ * this build does not pay (merchant_card_endpoint_not_enabled), a request that
197
+ * sends the typed card to such a merchant again outside its card request
198
+ * (merchant_card_endpoint_resend_refused), a CreditGuard
199
+ * page that runs its own 3-D Secure (creditguard_three_d_secure), a
200
+ * recognized Primer request in a form its gate refuses (unsupported_primer_sdk,
201
+ * unsupported_primer_request), a Payrails request its gate refuses
202
+ * (`unsupported_payrails_card_payment` and the card-save refusal codes), a
203
+ * Shiji STS request its gate refuses (shiji_sts_keep_on_file and the other
204
+ * shiji-sts.ts reasons), or a post to a processor's own card page that only
205
+ * the cardholder's device can fill (processor_card_page: NMI's).
141
206
  */
142
207
  unsupported(reason = 'unrecognized_payment_endpoint') {
143
208
  this.held = true;
@@ -158,6 +223,8 @@ export class CheckoutLifecycle {
158
223
  this.set({ ...this.state, status: 'failed', reason: 'preparation_required' });
159
224
  }
160
225
  prepareHandoff(replay, requestUrl) {
226
+ this.wspayChallenge = isWspayChallenge(requestUrl, replay);
227
+ this.handoffs.push(requestUrl);
161
228
  if (replay.mode === 'token' && replay.executionMode === 'autopilot' && replay.shopOrderId) {
162
229
  let receipt;
163
230
  try {
@@ -185,11 +252,31 @@ export class CheckoutLifecycle {
185
252
  this.unboundStripeToken = true;
186
253
  this.stripeTokenPrepared = true;
187
254
  this.held = true;
255
+ if (url.pathname === '/v1/payment_methods')
256
+ this.approvedPaymentMethod = stripePaymentMethodId(replay.body);
188
257
  }
189
258
  }
190
259
  catch { /* unknown URL cannot establish a token binding */ }
191
260
  }
192
261
  }
262
+ /**
263
+ * The URLs of the requests this attachment has handed the card to, oldest
264
+ * first. Each is recorded before delivery, since the processor may already
265
+ * have minted a token from the card even if the browser never acknowledges
266
+ * it, and none is forgotten on a retry. The adapters pass them to
267
+ * VaultClient.withoutCard, which then refuses a Nuvei payment without a card.
268
+ */
269
+ cardHandoffs() { return [...this.handoffs]; }
270
+ /**
271
+ * The payment method a Stripe card save may pay with in place of the card
272
+ * it sends again (cdp.ts claimStripeContinuation): the one this
273
+ * attachment's approved `/v1/payment_methods` request returned, while its
274
+ * continuation is still open. Null for any other tokenization, and once the
275
+ * checkout was cancelled, aborted or reconciled.
276
+ */
277
+ approvedStripePaymentMethod() {
278
+ return this.stripeContinuationOpen() ? this.approvedPaymentMethod : null;
279
+ }
193
280
  /**
194
281
  * The approval a page's card-free Stripe confirmation may continue, or null.
195
282
  * Only once a Stripe tokenization is being handed to the page, and while
@@ -211,15 +298,18 @@ export class CheckoutLifecycle {
211
298
  * Settle a claimed check. True only when the API allowed it and the checkout
212
299
  * still awaits the merchant (nothing cancelled, aborted or reconciled it
213
300
  * while the API answered): the page's confirmation continues, and no later
214
- * one will.
301
+ * one will. `kind` names what it confirms: a payment (a PaymentIntent) or a
302
+ * card save (a SetupIntent), which the reason then says.
215
303
  */
216
- stripeContinuationChecked(allowed) {
304
+ stripeContinuationChecked(allowed, kind = 'payment') {
217
305
  if (this.stripeContinuation !== 'checking')
218
306
  return false;
219
307
  const proceed = allowed && this.stripeContinuationOpen();
220
308
  this.stripeContinuation = proceed ? 'continued' : 'none';
221
- if (proceed)
222
- this.set({ ...this.state, reason: 'stripe_payment_continued' });
309
+ if (proceed) {
310
+ this.stripeContinuedReason = kind === 'setup' ? 'stripe_setup_continued' : 'stripe_payment_continued';
311
+ this.set({ ...this.state, reason: this.stripeContinuedReason });
312
+ }
223
313
  return proceed;
224
314
  }
225
315
  stripeContinuationOpen() {
@@ -234,14 +324,31 @@ export class CheckoutLifecycle {
234
324
  this.set({ status: 'completed', authorizationId: replay.authorizationId, mode: 'token', orderId: this.ownedShopOrderId });
235
325
  return;
236
326
  }
327
+ if (this.wspayChallenge) {
328
+ // WSPay answered with its 3-D Secure step, and the card frame now runs the
329
+ // bank's challenge in this browser. Nothing is charged until the cardholder
330
+ // completes it there, which the SDK cannot see, so this reads as
331
+ // requestUserAction('3ds') would, and holds until the merchant is reconciled.
332
+ // The step names no amount (amountVerified is null): WSPay then charges the
333
+ // amount the merchant's server set, and no answer Agentcard receives
334
+ // confirms it, so only the merchant's order can.
335
+ this.held = true;
336
+ this.set({ status: 'requires_user_action', authorizationId: replay.authorizationId, mode: 'token', reason: '3ds',
337
+ ...(this.state.preparationId ? { preparationId: this.state.preparationId } : {}) });
338
+ this.notify({ reason: '3ds', authorizationId: replay.authorizationId });
339
+ return;
340
+ }
237
341
  const mismatch = (!replay.mode || replay.mode === 'token') && replay.amountVerified === false;
238
- this.held = !!this.options.requireMerchantResult || replay.mode === 'hosted_form' || mismatch || this.unboundStripeToken;
342
+ // A card endpoint answer means the merchant already holds the card: its page's own
343
+ // retry, or a step-up that sends the card again, is refused until the application
344
+ // reconciles the order, exactly as for a hosted form the device submitted.
345
+ this.held = !!this.options.requireMerchantResult || replay.mode === 'hosted_form' || replay.mode === 'card_endpoint' || mismatch || this.unboundStripeToken;
239
346
  if (mismatch)
240
347
  this.stripeTokenPrepared = false;
241
348
  this.set({ status: 'awaiting_merchant', authorizationId: replay.authorizationId, mode: replay.mode ?? 'token',
242
349
  ...(this.state.preparationId ? { preparationId: this.state.preparationId } : {}),
243
350
  ...(mismatch ? { reason: 'charged_amount_mismatch' }
244
- : this.stripeContinuation === 'continued' ? { reason: 'stripe_payment_continued' }
351
+ : this.stripeContinuation === 'continued' ? { reason: this.stripeContinuedReason }
245
352
  : this.unboundStripeToken ? { reason: 'stripe_tokenization_unbound' } : {}) });
246
353
  }
247
354
  failed(error, handoffStarted = false) {
@@ -261,6 +368,13 @@ export class CheckoutLifecycle {
261
368
  this.held = true;
262
369
  this.set({ ...this.state, authorizationId, status: 'outcome_unknown', reason: error instanceof PaymentOutcomeUnknownError ? error.reason : error instanceof IntentNotConfirmableError ? 'intent_not_confirmable' : 'browser_handoff_failed' });
263
370
  }
371
+ else if (error instanceof CardEndpointRefusedError) {
372
+ // Refused before anything was created or sent. A refusal that every later request
373
+ // would meet holds the attachment; one about this request alone does not.
374
+ if (error.permanent)
375
+ this.held = true;
376
+ this.set({ ...this.state, status: error.reason === 'not_enabled' ? 'unsupported' : 'failed', reason: `merchant_card_endpoint_${error.reason}` });
377
+ }
264
378
  else if (error instanceof CheckoutCancelledError) {
265
379
  this.cancel();
266
380
  }
@@ -0,0 +1,122 @@
1
+ declare var SubstitutionError: {
2
+ new (message: any): {
3
+ name: string;
4
+ message: string;
5
+ stack?: string;
6
+ cause?: unknown;
7
+ };
8
+ };
9
+ declare var HILTON_CREATE_RESERVATION_DOCUMENTS: readonly string[];
10
+ declare var MERCHANT_CARD_ENDPOINT_PSP: string;
11
+ declare var MERCHANT_CARD_ENDPOINT_MODE: string;
12
+ declare var MERCHANT_CARD_ENDPOINT_PROFILES: any;
13
+ declare var MERCHANT_CARD_ENDPOINT_RECOGNIZERS: any;
14
+ declare var MERCHANT_CARD_ENDPOINT_CLIENT_TABLE: any;
15
+ declare function merchantCardEndpointById(id: any): any;
16
+ declare function trustedMerchantCardEndpoint(idOrEntry: any): any;
17
+ declare function merchantCardEndpointRecognizerById(id: any): any;
18
+ declare function merchantCardEndpointLive(idOrEntry: any): boolean;
19
+ declare var MERCHANT_CARD_ENDPOINT_FACTS_TEXT_MAX: number;
20
+ declare var MERCHANT_CARD_ENDPOINT_FACT_READERS: readonly string[];
21
+ declare function merchantCardEndpointFactsRole(profile: any, cardUrl: any, exchange: any): "card" | "record" | "unread" | "inert" | null;
22
+ declare function projectMerchantCardEndpointFacts(profile: any, cardUrl: any, exchange: any): {
23
+ none: boolean;
24
+ refusal?: undefined;
25
+ record?: undefined;
26
+ } | {
27
+ refusal: any;
28
+ none?: undefined;
29
+ record?: undefined;
30
+ } | {
31
+ record: {
32
+ method: any;
33
+ url: any;
34
+ state: any;
35
+ };
36
+ none?: undefined;
37
+ refusal?: undefined;
38
+ };
39
+ declare function readMerchantCardEndpointFacts(profile: any, cardUrl: any, record: any): any;
40
+ declare function merchantCardEndpointFactsRefusal(profile: any, facts: any, agent: any): {
41
+ code: any;
42
+ reason: any;
43
+ } | null;
44
+ declare var MERCHANT_CARD_ENDPOINT_LIMITS: Readonly<{
45
+ bodyBytes: number;
46
+ answerBytes: number;
47
+ urlLength: 8192;
48
+ headerValueBytes: number;
49
+ headerBytes: number;
50
+ cookies: 64;
51
+ }>;
52
+ declare function merchantCardEndpointRequestOrigin(profile: any): any;
53
+ declare function merchantCardEndpointBodyRefusal(profile: any, body: any, contentType: any): string | null;
54
+ declare function merchantCardEndpointPasses(profile: any, body: any, contentType: any): boolean;
55
+ declare function merchantCardEndpointSessionTtl(profile: any, body: any, contentType: any): any;
56
+ declare function merchantCardEndpointAmount(profile: any, body: any, contentType: any): {
57
+ amountCents: null;
58
+ currency: any;
59
+ } | {
60
+ amountCents: number;
61
+ currency: any;
62
+ };
63
+ declare function merchantCardEndpointCarriesCard(profile: any, body: any, contentType: any): any;
64
+ declare function merchantCardEndpointMatches(profile: any, rawUrl: any, method: any, opts: any): boolean;
65
+ declare function matchMerchantCardEndpoint(rawUrl: any, method: any, opts: any): any;
66
+ declare function matchMerchantCardEndpointResend(rawUrl: any, method: any): any;
67
+ declare function assertMerchantCardEndpoint(authorization: any): URL & {
68
+ profile: any;
69
+ };
70
+ declare function merchantCardEndpointSessionRefusal(profile: any, bundle: any): string | null;
71
+ declare function merchantCardEndpointCheckoutKey(profile: any, bundle: any): string | null;
72
+ declare function merchantCardEndpointEncrypts(profile: any): boolean;
73
+ declare function substituteMerchantCardEndpoint(body: any, contentType: any, profile: any, card: any): any;
74
+ declare function encryptMerchantCardEndpointBody(body: any, contentType: any, profile: any, card: any, crypto: any): Promise<any>;
75
+ declare function merchantEndpointRequest(profile: any, bundle: any, card: any): {
76
+ url: any;
77
+ method: any;
78
+ headers: {
79
+ "content-type": any;
80
+ };
81
+ body: any;
82
+ };
83
+ declare function encryptedMerchantEndpointRequest(profile: any, bundle: any, card: any, crypto: any): Promise<{
84
+ url: any;
85
+ method: any;
86
+ headers: {
87
+ "content-type": any;
88
+ };
89
+ body: any;
90
+ }>;
91
+ declare function responseCardLeak(card: any, response: any): "card_in_response" | "unreadable_in_response" | null;
92
+ declare function merchantCardEndpointAnswerRefusal(profile: any, bodyText: any): "refused_step_in_response" | null;
93
+ declare function merchantCardEndpointAnswer(profile: any, response: any, card: any): {
94
+ status: any;
95
+ withheld: string;
96
+ headers: {};
97
+ set_cookies: never[];
98
+ bodyText: null;
99
+ } | {
100
+ status: any;
101
+ headers: {};
102
+ set_cookies: any[];
103
+ bodyText: any;
104
+ withheld?: undefined;
105
+ };
106
+ declare function merchantCardEndpointNavigationAnswer(profile: any, answer: any, requestUrl: any): {
107
+ kind: string;
108
+ reason?: undefined;
109
+ status?: undefined;
110
+ location?: undefined;
111
+ } | {
112
+ kind: string;
113
+ reason: string;
114
+ status?: undefined;
115
+ location?: undefined;
116
+ } | {
117
+ kind: string;
118
+ status: any;
119
+ location: string;
120
+ reason?: undefined;
121
+ };
122
+ export { HILTON_CREATE_RESERVATION_DOCUMENTS, MERCHANT_CARD_ENDPOINT_CLIENT_TABLE, MERCHANT_CARD_ENDPOINT_FACTS_TEXT_MAX, MERCHANT_CARD_ENDPOINT_FACT_READERS, MERCHANT_CARD_ENDPOINT_LIMITS, MERCHANT_CARD_ENDPOINT_MODE, MERCHANT_CARD_ENDPOINT_PROFILES, MERCHANT_CARD_ENDPOINT_PSP, MERCHANT_CARD_ENDPOINT_RECOGNIZERS, SubstitutionError, assertMerchantCardEndpoint, encryptMerchantCardEndpointBody, encryptedMerchantEndpointRequest, matchMerchantCardEndpoint, matchMerchantCardEndpointResend, merchantCardEndpointAmount, merchantCardEndpointAnswer, merchantCardEndpointAnswerRefusal, merchantCardEndpointBodyRefusal, merchantCardEndpointById, merchantCardEndpointCarriesCard, merchantCardEndpointCheckoutKey, merchantCardEndpointEncrypts, merchantCardEndpointFactsRefusal, merchantCardEndpointFactsRole, merchantCardEndpointLive, merchantCardEndpointMatches, merchantCardEndpointNavigationAnswer, merchantCardEndpointPasses, merchantCardEndpointRecognizerById, merchantCardEndpointRequestOrigin, merchantCardEndpointSessionRefusal, merchantCardEndpointSessionTtl, merchantEndpointRequest, projectMerchantCardEndpointFacts, readMerchantCardEndpointFacts, responseCardLeak, substituteMerchantCardEndpoint, trustedMerchantCardEndpoint };