@agent-cards/checkout 0.11.0 → 0.12.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.
- package/CHANGELOG.md +2 -0
- package/README.md +56 -10
- package/dist/index.d.ts +1 -1
- package/dist/lifecycle.d.ts +13 -2
- package/dist/lifecycle.js +23 -7
- package/dist/stripe-checkout.d.ts +6 -2
- package/dist/stripe-checkout.generated.d.ts +25 -1
- package/dist/stripe-checkout.generated.js +80 -31
- package/dist/stripe-checkout.js +16 -9
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- Complete a merchant-confirmed payment when the merchant supplies no order or receipt ID. Return `{ status: 'completed', confirmation: { kind: 'merchant_payment', authorizationId } }` from the merchant resolver using the current checkout authorization. The resolver must verify the original payment request, amount, currency, selected card and merchant success; HTTP 200 or a success page alone is insufficient. The completed state carries `confirmation` without inventing `orderId`, clears stale reasons and continues to block another payment. Existing completion results with a genuine `orderId` keep working.
|
|
6
|
+
|
|
5
7
|
- Approve a Recurly checkout before its native card request starts. Call `prepare` with `psp: 'recurly'` and `environment: 'shared'`, then submit the merchant's form once. The same selected card and approved purchase bind a new-card POST on the US or EU endpoint. The matching API, database migration and Vault release are required. Token issuance and merchant payment completion remain separate results.
|
|
6
8
|
|
|
7
9
|
- Keep the selected card's issuer in guest Mercado Pago Checkout Pro in Mexico. The Vault resolves the card's eight-digit prefix against the merchant's captured checkout configuration over browser TLS. The SDK returns the original card-token response and corrects one native card association. Missing configuration, ambiguous issuers, changed checkout context, and a different card brand or type stop continuation. The matching API, Vault and encrypted relay release is required. Other Mercado Pago checkout families and merchant payment completion need separate validation.
|
package/README.md
CHANGED
|
@@ -367,17 +367,56 @@ const checkout = await attachToPlaywright(page, {
|
|
|
367
367
|
|
|
368
368
|
// Your existing agent dispatches checkout. Later, once the paused request resumes:
|
|
369
369
|
const state = await checkout.reconcile();
|
|
370
|
-
if (state.status === 'completed'
|
|
370
|
+
if (state.status === 'completed') await finishAgentTask(state);
|
|
371
371
|
```
|
|
372
372
|
|
|
373
|
-
`resolveMerchantResult` must
|
|
374
|
-
|
|
373
|
+
`resolveMerchantResult` must verify the merchant's result for the original
|
|
374
|
+
payment attempt. It returns one of:
|
|
375
375
|
|
|
376
|
-
- `{ status: 'completed', orderId }`: merchant-confirmed success.
|
|
376
|
+
- `{ status: 'completed', orderId }`: merchant-confirmed success with a genuine order or receipt ID. Existing integrations keep this form.
|
|
377
|
+
- `{ status: 'completed', confirmation: { kind: 'merchant_payment', authorizationId } }`: merchant-confirmed payment when no order or receipt ID is available. The ID must match the current checkout authorization.
|
|
377
378
|
- `{ status: 'failed' }`: merchant confirmed the attempt failed; no successful payment/order exists.
|
|
378
379
|
- `{ status: 'pending' }` or `{ status: 'unknown' }`: keep waiting or reconcile; never click Pay again.
|
|
379
380
|
- `{ status: 'requires_user_action', reason: '3ds' | 'redirect' | 'other' }`: deliver your own browser live view or supported challenge UI to the user.
|
|
380
381
|
|
|
382
|
+
For a merchant that confirms payment without returning an order ID, your
|
|
383
|
+
resolver can return the explicit payment confirmation:
|
|
384
|
+
|
|
385
|
+
```ts
|
|
386
|
+
const checkout = await attachToPlaywright(page, {
|
|
387
|
+
vault, user, merchant, amount, currency,
|
|
388
|
+
requireMerchantResult: true,
|
|
389
|
+
resolveMerchantResult: async state => {
|
|
390
|
+
const payment = await readOriginalMerchantPayment(state);
|
|
391
|
+
if (!payment.confirmed || !state.authorizationId) return { status: 'unknown' };
|
|
392
|
+
return {
|
|
393
|
+
status: 'completed',
|
|
394
|
+
confirmation: {
|
|
395
|
+
kind: 'merchant_payment',
|
|
396
|
+
authorizationId: state.authorizationId,
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
},
|
|
400
|
+
});
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
`readOriginalMerchantPayment` is your merchant-specific check. The check must
|
|
404
|
+
match the original payment request, amount, currency and selected card, and
|
|
405
|
+
verify authoritative merchant success for that attempt. HTTP 200 alone, a card
|
|
406
|
+
token, a success URL or text that anyone can open does not establish payment.
|
|
407
|
+
Copying `state.authorizationId` without checking the payment is insufficient.
|
|
408
|
+
The SDK checks the authorization binding; it does not independently authenticate
|
|
409
|
+
the merchant evidence supplied by your resolver.
|
|
410
|
+
|
|
411
|
+
Return one completion form at a time. The payment-confirmation form leaves
|
|
412
|
+
`state.orderId` absent and exposes `state.confirmation` with the exported
|
|
413
|
+
`MerchantPaymentConfirmation` type. Your consumer should finish on
|
|
414
|
+
`state.status === 'completed'` and treat `orderId` as optional. A missing or
|
|
415
|
+
mismatched authorization, or `{ status: 'completed' }` without either completion
|
|
416
|
+
form, leaves the outcome unknown. Confirmed completion clears stale failure or
|
|
417
|
+
authentication reasons and continues to block further payment submissions.
|
|
418
|
+
Never invent an order ID from a token or authorization ID.
|
|
419
|
+
|
|
381
420
|
The SDK does not infer order success from `authorized` or a tokenization reply,
|
|
382
421
|
and does not claim to detect or solve arbitrary 3DS challenges. Your merchant
|
|
383
422
|
resolver (or `checkout.requestUserAction('3ds')` when your browser observes it)
|
|
@@ -388,22 +427,29 @@ isolated from the payment handoff.
|
|
|
388
427
|
Native Stripe Checkout emits `checkout_blocked` before the existing `blocked`
|
|
389
428
|
event when its local preparation rejects a request. Its
|
|
390
429
|
`StripeCheckoutBlockedDetail` contains only fixed codes: `version: 1`,
|
|
391
|
-
`processor: 'stripe'`, endpoint family, phase, stage, reason, gate state, and
|
|
392
|
-
disposition. It contains no URLs, identifiers, request
|
|
430
|
+
`processor: 'stripe'`, endpoint family, phase, stage, reason, optional validation code, gate state, and
|
|
431
|
+
disposition. It contains no URLs, identifiers, request-derived field names or values, or exception text.
|
|
393
432
|
|
|
394
433
|
| Field | Values |
|
|
395
434
|
| --- | --- |
|
|
396
435
|
| `endpoint_family` | `payment_methods`, `payment_page_confirm`, `other` |
|
|
397
436
|
| `phase` | `tokenization`, `final`, `unknown` |
|
|
398
437
|
| `stage` | `request_read`, `classification`, `claim`, `readiness`, `document`, `stub_response` |
|
|
438
|
+
| `validation_code` | Shared-core `StripeCheckoutValidationCode`; present only for `request_validation_failed` |
|
|
399
439
|
| `gate_state` | `fresh`, `stubbed`, `submitted`, `stopped` |
|
|
400
440
|
| `disposition` | `active_claim_preserved`, `checkout_stopped` |
|
|
401
441
|
|
|
402
442
|
`reason` is the exported `StripeCheckoutBlockReason` union. It identifies SDK
|
|
403
443
|
claim and readiness failures, such as `duplicate_confirmation`, `document_changed`,
|
|
404
|
-
or `attachment_not_ready`.
|
|
405
|
-
`request_validation_failed`
|
|
406
|
-
|
|
444
|
+
or `attachment_not_ready`. A shared-core rejection reports
|
|
445
|
+
`request_validation_failed` and a fixed `validation_code` identifying the failed
|
|
446
|
+
check, or `unclassified` when no recognized code is available. Initial request
|
|
447
|
+
classification uses phase `unknown`; a billing capture rejection uses
|
|
448
|
+
`tokenization`, and a billing attachment rejection uses `final`.
|
|
449
|
+
For example, `form_field_unknown` identifies an allowlist rejection without
|
|
450
|
+
revealing the field name or value. Identifying that field requires a separate
|
|
451
|
+
reviewed synthetic fixture; the code alone does not establish or fix a processor
|
|
452
|
+
schema mismatch. `gate_state` records the state before the adapter handles
|
|
407
453
|
the failure, though document validation may already have stopped the gate.
|
|
408
454
|
|
|
409
455
|
`active_claim_preserved` means a valid duplicate was refused without invalidating
|
|
@@ -579,7 +625,7 @@ When the cardholder has enabled an eligible spending rule in their vault, the sa
|
|
|
579
625
|
|
|
580
626
|
Use `executionMode: 'user_approval'` to require the existing confirmation flow. Without a selected card or grant, the backend can use exactly one eligible rule; ambiguous card selection keeps confirmation. A `grantId` restricts selection to that rule. The initial executor supports only the configured controlled Stripe test flow, and production remains disabled.
|
|
581
627
|
|
|
582
|
-
For controlled hosted Stripe Checkout, both attachment functions accept `stripeCheckout: { sessionId, publishableKey, environment? }`. The default is TEST, requiring `cs_test_` and `pk_test_`. LIVE requires explicit `environment: 'production'`, a `cs_live_` Session and its `pk_live_` key. Both modes require `executionMode: 'autopilot'`, an explicit `grantId`, and a positive numeric USD `amount` in cents. The top-level document must be that Session on `checkout.stripe.com`. Direct `authorize()` calls use `stripeCheckoutEnvironment: 'production'` for the same explicit LIVE opt-in; the attachment functions pass it automatically.
|
|
628
|
+
For controlled hosted Stripe Checkout, both attachment functions accept `stripeCheckout: { sessionId, publishableKey, environment? }`. The default is TEST, requiring `cs_test_` and `pk_test_`. LIVE requires explicit `environment: 'production'`, a `cs_live_` Session and its `pk_live_` key. Both modes require `executionMode: 'autopilot'`, an explicit `grantId`, and a positive numeric USD `amount` in cents. The top-level document must be that exact Session on `https://checkout.stripe.com`, at `/c/pay/{sessionId}`, `/pay/{sessionId}`, `/g/pay/{sessionId}`, or `/f/pay/{sessionId}`. The SDK validates the existing URL without rewriting or navigating it. Direct `authorize()` calls use `stripeCheckoutEnvironment: 'production'` for the same explicit LIVE opt-in; the attachment functions pass it automatically.
|
|
583
629
|
|
|
584
630
|
The SDK answers dummy-card tokenization locally, then sends the browser's final native confirmation through the shared core and enclave. The local response is preparation only: it creates no authorization and makes no processor request. The final result includes `checkoutSessionId` only after the selected grant, restricted terminal response, and captured amount have been checked. Continue to confirm the merchant order through the checkout controller.
|
|
585
631
|
|
package/dist/index.d.ts
CHANGED
|
@@ -10,4 +10,4 @@ export { hostedFormSubmittedPage, HOSTED_FORM_SUBMITTED_OUTCOME } from './hosted
|
|
|
10
10
|
export type { HostedFormSubmittedPageInput, SyntheticPage } from './hosted-form.js';
|
|
11
11
|
export { BUILTIN_REGISTRY, cardUrlPatterns, findRecognizer } from './registry.js';
|
|
12
12
|
export type { Recognizer, CheckoutMode } from './registry.js';
|
|
13
|
-
export type { CheckoutController, CheckoutState, MerchantResult, UserAction, LifecycleOptions, PaymentEndpointGuard } from './lifecycle.js';
|
|
13
|
+
export type { CheckoutController, CheckoutState, MerchantResult, MerchantPaymentConfirmation, UserAction, LifecycleOptions, PaymentEndpointGuard } from './lifecycle.js';
|
package/dist/lifecycle.d.ts
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import { CheckoutPreparationError, type PrepareCheckoutOptions, type PreparedCheckout, type ReplayResponse } from './client.js';
|
|
2
2
|
import type { CheckoutMode } from './registry.js';
|
|
3
|
-
/**
|
|
3
|
+
/** The application's resolver confirmed the payment for this checkout authorization. */
|
|
4
|
+
export interface MerchantPaymentConfirmation {
|
|
5
|
+
kind: 'merchant_payment';
|
|
6
|
+
authorizationId: string;
|
|
7
|
+
}
|
|
8
|
+
/** Only authoritative merchant evidence can confirm completion; a processor token is insufficient. */
|
|
4
9
|
export type MerchantResult = {
|
|
5
10
|
status: 'completed';
|
|
6
11
|
orderId: string;
|
|
12
|
+
confirmation?: never;
|
|
13
|
+
} | {
|
|
14
|
+
status: 'completed';
|
|
15
|
+
confirmation: MerchantPaymentConfirmation;
|
|
16
|
+
orderId?: never;
|
|
7
17
|
} | {
|
|
8
18
|
status: 'failed';
|
|
9
19
|
} | {
|
|
@@ -18,6 +28,7 @@ export interface CheckoutState {
|
|
|
18
28
|
preparationId?: string;
|
|
19
29
|
mode?: CheckoutMode;
|
|
20
30
|
orderId?: string;
|
|
31
|
+
confirmation?: MerchantPaymentConfirmation;
|
|
21
32
|
/** Stable SDK category; never includes a request body, processor response, or approval link. */
|
|
22
33
|
reason?: string;
|
|
23
34
|
}
|
|
@@ -30,7 +41,7 @@ export interface UserAction {
|
|
|
30
41
|
export interface LifecycleOptions {
|
|
31
42
|
onStateChange?: (state: Readonly<CheckoutState>) => void;
|
|
32
43
|
onUserAction?: (action: UserAction) => void | Promise<void>;
|
|
33
|
-
/** Read authoritative merchant order state; do not click Pay or initiate a new charge here. */
|
|
44
|
+
/** Read authoritative merchant payment or order state; do not click Pay or initiate a new charge here. */
|
|
34
45
|
resolveMerchantResult?: (state: Readonly<CheckoutState>) => Promise<MerchantResult>;
|
|
35
46
|
/** Hold further card requests after handoff until the merchant result is reconciled. Default false for compatibility. */
|
|
36
47
|
requireMerchantResult?: boolean;
|
package/dist/lifecycle.js
CHANGED
|
@@ -17,7 +17,9 @@ export class CheckoutLifecycle {
|
|
|
17
17
|
constructor(options) {
|
|
18
18
|
this.options = options;
|
|
19
19
|
}
|
|
20
|
-
getState() {
|
|
20
|
+
getState() {
|
|
21
|
+
return { ...this.state, ...(this.state.confirmation ? { confirmation: { ...this.state.confirmation } } : {}) };
|
|
22
|
+
}
|
|
21
23
|
setPreparationHandler(handler) { this.preparationHandler = handler; }
|
|
22
24
|
prepare(options) {
|
|
23
25
|
if (!this.preparationHandler)
|
|
@@ -195,14 +197,28 @@ export class CheckoutLifecycle {
|
|
|
195
197
|
catch {
|
|
196
198
|
result = { status: 'unknown' };
|
|
197
199
|
}
|
|
198
|
-
if (!result || typeof result !== 'object')
|
|
200
|
+
if (!result || typeof result !== 'object' || Array.isArray(result))
|
|
199
201
|
result = { status: 'unknown' };
|
|
200
|
-
|
|
202
|
+
// The resolver is trusted application code: it must check the original
|
|
203
|
+
// request, amount, currency, selected card and authoritative merchant
|
|
204
|
+
// result. The SDK binds its explicit confirmation to this authorization;
|
|
205
|
+
// it does not turn an HTTP response or a success URL into payment proof.
|
|
206
|
+
const orderConfirmed = result.status === 'completed' && result.confirmation === undefined
|
|
207
|
+
&& typeof result.orderId === 'string' && result.orderId.length > 0;
|
|
208
|
+
const paymentConfirmed = result.status === 'completed' && result.orderId === undefined
|
|
209
|
+
&& result.confirmation && typeof result.confirmation === 'object' && !Array.isArray(result.confirmation)
|
|
210
|
+
&& result.confirmation.kind === 'merchant_payment'
|
|
211
|
+
&& typeof this.state.authorizationId === 'string' && this.state.authorizationId.length > 0
|
|
212
|
+
&& result.confirmation.authorizationId === this.state.authorizationId;
|
|
213
|
+
if (result.status === 'completed' && (orderConfirmed || paymentConfirmed)) {
|
|
201
214
|
this.held = true;
|
|
202
|
-
//
|
|
203
|
-
//
|
|
204
|
-
|
|
205
|
-
|
|
215
|
+
// Completion supersedes an earlier failure/challenge, while retaining
|
|
216
|
+
// preparation and authorization context. Never copy arbitrary evidence
|
|
217
|
+
// into public state or release the hold on additional payment requests.
|
|
218
|
+
const { reason: _previousReason, orderId: _previousOrder, confirmation: _previousConfirmation, ...context } = this.state;
|
|
219
|
+
this.set({ ...context, status: 'completed', ...(orderConfirmed
|
|
220
|
+
? { orderId: result.orderId }
|
|
221
|
+
: { confirmation: { kind: 'merchant_payment', authorizationId: this.state.authorizationId } }) });
|
|
206
222
|
}
|
|
207
223
|
else if (result.status === 'failed') {
|
|
208
224
|
// Keep the guard armed until the application deliberately starts another attempt.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { STRIPE_CHECKOUT_VALIDATION_CODES } from './stripe-checkout.generated.js';
|
|
1
2
|
import type { PausedRequest } from './client.js';
|
|
2
3
|
/** Test by default. Production requires explicit opt-in and an independently admitted live grant. */
|
|
3
4
|
export interface StripeCheckoutOptions {
|
|
@@ -19,11 +20,12 @@ type Step = {
|
|
|
19
20
|
};
|
|
20
21
|
type Phase = Step['phase'] | 'unknown';
|
|
21
22
|
type GateState = 'fresh' | 'stubbed' | 'submitted' | 'stopped';
|
|
23
|
+
type ValidationCode = (typeof STRIPE_CHECKOUT_VALIDATION_CODES)[keyof typeof STRIPE_CHECKOUT_VALIDATION_CODES];
|
|
22
24
|
export type StripeCheckoutBlockStage = 'request_read' | 'classification' | 'claim' | 'readiness' | 'document' | 'stub_response';
|
|
23
25
|
type ReadinessReason = 'attachment_not_ready' | 'cancelled' | 'checkout_inactive' | 'approval_pending' | 'request_inactive';
|
|
24
26
|
export type StripeCheckoutBlockReason = ReadinessReason | 'request_unavailable' | 'request_validation_failed' | 'context_already_present' | 'duplicate_tokenization' | 'duplicate_confirmation' | 'preparation_unavailable' | 'preparation_missing' | 'claim_invalidated' | 'document_changed' | 'document_unavailable' | 'readiness_unavailable' | 'stub_response_failed';
|
|
25
27
|
/** Native pre-authorization refusal metadata. Never contains request or exception text.
|
|
26
|
-
*
|
|
28
|
+
* A classification code comes only from the shared core's fixed vocabulary.
|
|
27
29
|
* gate_state is observed before the adapter retires a failed claim. A preserved duplicate
|
|
28
30
|
* belongs to a competing request: consumers must not cancel the active checkout for it.
|
|
29
31
|
*/
|
|
@@ -34,6 +36,7 @@ export interface StripeCheckoutBlockedDetail {
|
|
|
34
36
|
phase: Phase;
|
|
35
37
|
stage: StripeCheckoutBlockStage;
|
|
36
38
|
reason: StripeCheckoutBlockReason;
|
|
39
|
+
validation_code?: ValidationCode;
|
|
37
40
|
gate_state: GateState;
|
|
38
41
|
disposition: 'active_claim_preserved' | 'checkout_stopped';
|
|
39
42
|
}
|
|
@@ -41,7 +44,8 @@ declare class StripeCheckoutRejectionError extends Error {
|
|
|
41
44
|
readonly stage: StripeCheckoutBlockStage;
|
|
42
45
|
readonly reason: StripeCheckoutBlockReason;
|
|
43
46
|
readonly phase?: Phase | undefined;
|
|
44
|
-
|
|
47
|
+
readonly validationCode?: ValidationCode | undefined;
|
|
48
|
+
constructor(message: string, stage: StripeCheckoutBlockStage, reason: StripeCheckoutBlockReason, phase?: Phase | undefined, validationCode?: ValidationCode | undefined);
|
|
45
49
|
}
|
|
46
50
|
export declare function stripeCheckoutReadinessError(reason: ReadinessReason): Error;
|
|
47
51
|
/** A valid competing request must not retire the request that already claimed this step. */
|
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
declare var STRIPE_CHECKOUT_OPERATION: string;
|
|
2
2
|
declare var STRIPE_CHECKOUT_CONTEXT_HEADER: string;
|
|
3
|
+
declare var STRIPE_CHECKOUT_VALIDATION_CODES: Readonly<{
|
|
4
|
+
unclassified: "unclassified";
|
|
5
|
+
request_shape: "request_shape";
|
|
6
|
+
request_body_bounds: "request_body_bounds";
|
|
7
|
+
request_headers: "request_headers";
|
|
8
|
+
form_encoding: "form_encoding";
|
|
9
|
+
form_field_unknown: "form_field_unknown";
|
|
10
|
+
form_field_duplicate: "form_field_duplicate";
|
|
11
|
+
form_value_bounds: "form_value_bounds";
|
|
12
|
+
context_invalid: "context_invalid";
|
|
13
|
+
session_binding: "session_binding";
|
|
14
|
+
publishable_key: "publishable_key";
|
|
15
|
+
mode_binding: "mode_binding";
|
|
16
|
+
attribution_session: "attribution_session";
|
|
17
|
+
tokenization_fields: "tokenization_fields";
|
|
18
|
+
billing_email: "billing_email";
|
|
19
|
+
billing_binding: "billing_binding";
|
|
20
|
+
billing_conflict: "billing_conflict";
|
|
21
|
+
expected_amount: "expected_amount";
|
|
22
|
+
payment_method_type: "payment_method_type";
|
|
23
|
+
synthetic_payment_method: "synthetic_payment_method";
|
|
24
|
+
required_final_fields: "required_final_fields";
|
|
25
|
+
}>;
|
|
26
|
+
declare function stripeCheckoutValidationCode(error: any): "unclassified" | "request_shape" | "request_body_bounds" | "request_headers" | "form_encoding" | "form_field_unknown" | "form_field_duplicate" | "form_value_bounds" | "context_invalid" | "session_binding" | "publishable_key" | "mode_binding" | "attribution_session" | "tokenization_fields" | "billing_email" | "billing_binding" | "billing_conflict" | "expected_amount" | "payment_method_type" | "synthetic_payment_method" | "required_final_fields";
|
|
3
27
|
declare function validateStripeCheckoutIdentity(value: any): Readonly<{
|
|
4
28
|
environment: any;
|
|
5
29
|
livemode: boolean;
|
|
@@ -55,4 +79,4 @@ declare function prepareStripeCheckoutReplay(request: any, card: any, options?:
|
|
|
55
79
|
};
|
|
56
80
|
where: string[];
|
|
57
81
|
};
|
|
58
|
-
export { STRIPE_CHECKOUT_CONTEXT_HEADER, STRIPE_CHECKOUT_OPERATION, attachStripeCheckoutBilling, captureStripeCheckoutBilling, classifyStripeCheckoutRequest, createStripeCheckoutTokenizationStub, encodeStripeCheckoutContext, hasStripeCheckoutMarker, isStripeCheckoutEndpoint, isStripeCheckoutHostedMode, parseStripeCheckoutContext, parseStripeCheckoutResponse, prepareStripeCheckoutReplay, validateStripeCheckoutCard, validateStripeCheckoutIdentity };
|
|
82
|
+
export { STRIPE_CHECKOUT_CONTEXT_HEADER, STRIPE_CHECKOUT_OPERATION, STRIPE_CHECKOUT_VALIDATION_CODES, attachStripeCheckoutBilling, captureStripeCheckoutBilling, classifyStripeCheckoutRequest, createStripeCheckoutTokenizationStub, encodeStripeCheckoutContext, hasStripeCheckoutMarker, isStripeCheckoutEndpoint, isStripeCheckoutHostedMode, parseStripeCheckoutContext, parseStripeCheckoutResponse, prepareStripeCheckoutReplay, stripeCheckoutValidationCode, validateStripeCheckoutCard, validateStripeCheckoutIdentity };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
// Generated from @agent-cards/payment-core. Do not edit.
|
|
3
|
-
// artifact-sha256:
|
|
3
|
+
// artifact-sha256: edd2d9de25c51bf0f4ebdbe729366e6d94b9a045b054a0910571e0565bd3cae0
|
|
4
4
|
// src/definitions.js
|
|
5
5
|
function deepFreeze(value) {
|
|
6
6
|
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
@@ -527,19 +527,49 @@ var STRIPE_CHECKOUT_CONTEXT_HEADER = "x-agentcard-stripe-checkout-context";
|
|
|
527
527
|
var SESSION = /^cs_(?:test|live)_[A-Za-z0-9]{1,200}(?![\s\S])/;
|
|
528
528
|
var KEY = /^pk_(?:test|live)_[A-Za-z0-9_]{1,256}(?![\s\S])/;
|
|
529
529
|
var SYNTHETIC = /^pm_agentcard_checkout_[A-Za-z0-9_-]{16,80}(?![\s\S])/;
|
|
530
|
-
var
|
|
531
|
-
|
|
530
|
+
var STRIPE_CHECKOUT_VALIDATION_CODES = Object.freeze({
|
|
531
|
+
unclassified: "unclassified",
|
|
532
|
+
request_shape: "request_shape",
|
|
533
|
+
request_body_bounds: "request_body_bounds",
|
|
534
|
+
request_headers: "request_headers",
|
|
535
|
+
form_encoding: "form_encoding",
|
|
536
|
+
form_field_unknown: "form_field_unknown",
|
|
537
|
+
form_field_duplicate: "form_field_duplicate",
|
|
538
|
+
form_value_bounds: "form_value_bounds",
|
|
539
|
+
context_invalid: "context_invalid",
|
|
540
|
+
session_binding: "session_binding",
|
|
541
|
+
publishable_key: "publishable_key",
|
|
542
|
+
mode_binding: "mode_binding",
|
|
543
|
+
attribution_session: "attribution_session",
|
|
544
|
+
tokenization_fields: "tokenization_fields",
|
|
545
|
+
billing_email: "billing_email",
|
|
546
|
+
billing_binding: "billing_binding",
|
|
547
|
+
billing_conflict: "billing_conflict",
|
|
548
|
+
expected_amount: "expected_amount",
|
|
549
|
+
payment_method_type: "payment_method_type",
|
|
550
|
+
synthetic_payment_method: "synthetic_payment_method",
|
|
551
|
+
required_final_fields: "required_final_fields"
|
|
552
|
+
});
|
|
553
|
+
var validationCodes = /* @__PURE__ */ new WeakMap();
|
|
554
|
+
var reject = (code = "unclassified") => {
|
|
555
|
+
const error = new Error("stripe_checkout_rejected");
|
|
556
|
+
validationCodes.set(error, code);
|
|
557
|
+
throw error;
|
|
532
558
|
};
|
|
559
|
+
function stripeCheckoutValidationCode(error) {
|
|
560
|
+
const code = validationCodes.get(error);
|
|
561
|
+
return Object.values(STRIPE_CHECKOUT_VALIDATION_CODES).find((value) => value === code) ?? STRIPE_CHECKOUT_VALIDATION_CODES.unclassified;
|
|
562
|
+
}
|
|
533
563
|
var object = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
534
564
|
var opaque = (value) => typeof value === "string" && value.length <= 8192 && !/[\x00-\x1f\x7f]/.test(value);
|
|
535
565
|
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
536
566
|
function validateStripeCheckoutIdentity(value) {
|
|
537
567
|
if (!object(value) || !["test", "production"].includes(value.environment ?? "test") || value.environment === null || !["sessionId", "publishableKey", "livemode"].some((key) => Object.hasOwn(value, key)))
|
|
538
|
-
reject();
|
|
568
|
+
reject("mode_binding");
|
|
539
569
|
const environment = value.environment ?? "test", livemode = environment === "production";
|
|
540
570
|
const mode = livemode ? "live" : "test";
|
|
541
571
|
if (Object.hasOwn(value, "sessionId") && (typeof value.sessionId !== "string" || !SESSION.test(value.sessionId) || !value.sessionId.startsWith(`cs_${mode}_`)) || Object.hasOwn(value, "publishableKey") && (typeof value.publishableKey !== "string" || !KEY.test(value.publishableKey) || !value.publishableKey.startsWith(`pk_${mode}_`)) || Object.hasOwn(value, "livemode") && value.livemode !== livemode)
|
|
542
|
-
reject();
|
|
572
|
+
reject("mode_binding");
|
|
543
573
|
return Object.freeze({ environment, livemode });
|
|
544
574
|
}
|
|
545
575
|
var TEST_CARDS = ["4242424242424242", "4000000000000002", "4000002500003155"];
|
|
@@ -587,7 +617,7 @@ function encodeAscii(value) {
|
|
|
587
617
|
}
|
|
588
618
|
function context(value) {
|
|
589
619
|
if (!object(value) || Object.keys(value).length !== 3 || value.version !== 1 || !["version", "session_id", "synthetic_payment_method_id"].every((key) => Object.hasOwn(value, key)) || !SESSION.test(value.session_id) || !SYNTHETIC.test(value.synthetic_payment_method_id))
|
|
590
|
-
reject();
|
|
620
|
+
reject("context_invalid");
|
|
591
621
|
return { version: 1, session_id: value.session_id, synthetic_payment_method_id: value.synthetic_payment_method_id };
|
|
592
622
|
}
|
|
593
623
|
function encodeStripeCheckoutContext(value) {
|
|
@@ -601,7 +631,7 @@ function parseStripeCheckoutContext(request) {
|
|
|
601
631
|
if (!entries.length)
|
|
602
632
|
return null;
|
|
603
633
|
if (entries.length !== 1 || typeof entries[0][1] !== "string" || !/^[A-Za-z0-9_-]{1,1024}$/.test(entries[0][1]))
|
|
604
|
-
reject();
|
|
634
|
+
reject("context_invalid");
|
|
605
635
|
const encoded = entries[0][1];
|
|
606
636
|
let text = "", bits = 0, count = 0;
|
|
607
637
|
for (const char of encoded) {
|
|
@@ -617,10 +647,10 @@ function parseStripeCheckoutContext(request) {
|
|
|
617
647
|
value = context(JSON.parse(text));
|
|
618
648
|
}
|
|
619
649
|
catch {
|
|
620
|
-
reject();
|
|
650
|
+
reject("context_invalid");
|
|
621
651
|
}
|
|
622
652
|
if (encodeStripeCheckoutContext(value) !== encoded)
|
|
623
|
-
reject();
|
|
653
|
+
reject("context_invalid");
|
|
624
654
|
return value;
|
|
625
655
|
}
|
|
626
656
|
function endpoint(raw) {
|
|
@@ -657,6 +687,9 @@ var finalFields = /* @__PURE__ */ new Set([
|
|
|
657
687
|
"sid",
|
|
658
688
|
"passive_captcha_token",
|
|
659
689
|
"passive_captcha_ekey",
|
|
690
|
+
"pxcts",
|
|
691
|
+
"pxvid",
|
|
692
|
+
"px3",
|
|
660
693
|
...[
|
|
661
694
|
"checkout_config_id",
|
|
662
695
|
"checkout_session_id",
|
|
@@ -696,24 +729,32 @@ var tokenFields = /* @__PURE__ */ new Set([
|
|
|
696
729
|
].map((key) => `client_attribution_metadata[${key}]`)
|
|
697
730
|
]);
|
|
698
731
|
function form(request, fields) {
|
|
699
|
-
if (!object(request) || request.method !== "POST" || typeof request.body !== "string"
|
|
700
|
-
reject();
|
|
732
|
+
if (!object(request) || request.method !== "POST" || typeof request.body !== "string")
|
|
733
|
+
reject("request_shape");
|
|
734
|
+
if (request.body.length > 2e4)
|
|
735
|
+
reject("request_body_bounds");
|
|
736
|
+
if (!object(request.headers) || Object.keys(request.headers).length > 40 || Object.values(request.headers).some((value) => !opaque(value)))
|
|
737
|
+
reject("request_headers");
|
|
701
738
|
const pairs = [];
|
|
702
739
|
const seen = /* @__PURE__ */ new Set();
|
|
703
740
|
for (const raw of request.body.split("&")) {
|
|
704
741
|
const index = raw.indexOf("=");
|
|
705
742
|
if (index < 1)
|
|
706
|
-
reject();
|
|
743
|
+
reject("form_encoding");
|
|
707
744
|
let key, value;
|
|
708
745
|
try {
|
|
709
746
|
key = decodeURIComponent(raw.slice(0, index).replace(/\+/g, " "));
|
|
710
747
|
value = decodeURIComponent(raw.slice(index + 1).replace(/\+/g, " "));
|
|
711
748
|
}
|
|
712
749
|
catch {
|
|
713
|
-
reject();
|
|
750
|
+
reject("form_encoding");
|
|
714
751
|
}
|
|
715
|
-
if (!fields.has(key)
|
|
716
|
-
reject();
|
|
752
|
+
if (!fields.has(key))
|
|
753
|
+
reject("form_field_unknown");
|
|
754
|
+
if (seen.has(key))
|
|
755
|
+
reject("form_field_duplicate");
|
|
756
|
+
if (!opaque(value))
|
|
757
|
+
reject("form_value_bounds");
|
|
717
758
|
seen.add(key);
|
|
718
759
|
pairs.push({ key, value, raw });
|
|
719
760
|
}
|
|
@@ -722,27 +763,27 @@ function form(request, fields) {
|
|
|
722
763
|
function keyFor(request, values, expected) {
|
|
723
764
|
const authorization = Object.entries(request.headers).filter(([key2]) => key2.toLowerCase() === "authorization");
|
|
724
765
|
if (authorization.length > 1)
|
|
725
|
-
reject();
|
|
766
|
+
reject("publishable_key");
|
|
726
767
|
let headerKey;
|
|
727
768
|
if (authorization.length) {
|
|
728
769
|
const match = /^Bearer (pk_(?:test|live)_[A-Za-z0-9_]{1,256})$/.exec(authorization[0][1]);
|
|
729
770
|
if (!match)
|
|
730
|
-
reject();
|
|
771
|
+
reject("publishable_key");
|
|
731
772
|
headerKey = match[1];
|
|
732
773
|
}
|
|
733
774
|
const key = values.get("key") || headerKey;
|
|
734
775
|
if (!KEY.test(key) || headerKey && headerKey !== key || expected !== void 0 && expected !== key)
|
|
735
|
-
reject();
|
|
776
|
+
reject("publishable_key");
|
|
736
777
|
return key;
|
|
737
778
|
}
|
|
738
779
|
var billingEmail = (value) => value === null || typeof value === "string" && value.length > 0 && value.length <= 320 && opaque(value);
|
|
739
780
|
function captureStripeCheckoutBilling(request, options) {
|
|
740
781
|
const phase = classifyStripeCheckoutRequest(request, options);
|
|
741
782
|
if (phase?.phase !== "tokenization" || !SYNTHETIC.test(options?.syntheticPaymentMethodId))
|
|
742
|
-
reject();
|
|
783
|
+
reject("billing_binding");
|
|
743
784
|
const email = form(request, tokenFields).values.get("billing_details[email]") ?? null;
|
|
744
785
|
if (!billingEmail(email))
|
|
745
|
-
reject();
|
|
786
|
+
reject("billing_email");
|
|
746
787
|
return Object.freeze({
|
|
747
788
|
session_id: phase.session_id,
|
|
748
789
|
synthetic_payment_method_id: options.syntheticPaymentMethodId,
|
|
@@ -752,11 +793,11 @@ function captureStripeCheckoutBilling(request, options) {
|
|
|
752
793
|
function attachStripeCheckoutBilling(request, captured, options) {
|
|
753
794
|
const phase = classifyStripeCheckoutRequest(request, options);
|
|
754
795
|
if (phase?.phase !== "final" || !object(captured) || Object.keys(captured).length !== 3 || !["session_id", "synthetic_payment_method_id", "email"].every((key) => Object.hasOwn(captured, key)) || captured.session_id !== phase.session_id || captured.synthetic_payment_method_id !== phase.synthetic_payment_method_id || !billingEmail(captured.email))
|
|
755
|
-
reject();
|
|
796
|
+
reject("billing_binding");
|
|
756
797
|
const field = "payment_method_data[billing_details][email]";
|
|
757
798
|
const existing = form(request, finalFields).values.get(field);
|
|
758
799
|
if (existing !== void 0 && existing !== captured.email)
|
|
759
|
-
reject();
|
|
800
|
+
reject("billing_conflict");
|
|
760
801
|
if (captured.email === null || existing !== void 0)
|
|
761
802
|
return { ...request };
|
|
762
803
|
const body = `${request.body}&${encodeURIComponent(field)}=${encodeURIComponent(captured.email)}`;
|
|
@@ -768,14 +809,14 @@ function classifyStripeCheckoutRequest(request, options = {}) {
|
|
|
768
809
|
const url = endpoint(request?.url);
|
|
769
810
|
if (!url) {
|
|
770
811
|
if (hasStripeCheckoutMarker(request))
|
|
771
|
-
reject();
|
|
812
|
+
reject("context_invalid");
|
|
772
813
|
return null;
|
|
773
814
|
}
|
|
774
815
|
const final = isStripeCheckoutEndpoint(request.url);
|
|
775
816
|
const token = url.pathname === "/v1/payment_methods";
|
|
776
817
|
if (!final && !token) {
|
|
777
818
|
if (hasStripeCheckoutMarker(request))
|
|
778
|
-
reject();
|
|
819
|
+
reject("context_invalid");
|
|
779
820
|
return null;
|
|
780
821
|
}
|
|
781
822
|
if (token && options.sessionId === void 0 && !hasStripeCheckoutMarker(request))
|
|
@@ -783,26 +824,34 @@ function classifyStripeCheckoutRequest(request, options = {}) {
|
|
|
783
824
|
const marker = parseStripeCheckoutContext(request);
|
|
784
825
|
const sessionId = final ? url.pathname.split("/")[3] : options.sessionId;
|
|
785
826
|
if (!SESSION.test(sessionId) || options.sessionId !== void 0 && options.sessionId !== sessionId || marker && marker.session_id !== sessionId)
|
|
786
|
-
reject();
|
|
827
|
+
reject("session_binding");
|
|
787
828
|
const { values } = form(request, final ? finalFields : tokenFields);
|
|
788
829
|
const key = keyFor(request, values, options.publishableKey);
|
|
789
830
|
validateStripeCheckoutIdentity({ environment: options.environment, sessionId, publishableKey: key });
|
|
790
831
|
const attributionSession = values.get("client_attribution_metadata[checkout_session_id]");
|
|
791
832
|
if (attributionSession !== void 0 && attributionSession !== sessionId)
|
|
792
|
-
reject();
|
|
833
|
+
reject("attribution_session");
|
|
793
834
|
if (token) {
|
|
794
835
|
const number = values.get("card[number]");
|
|
795
836
|
if (values.get("type") !== "card" || typeof number !== "string" || number.length > 64 || /[^0-9 -]/.test(number) || !["4111111111111111", "4242424242424242"].includes(number.replace(/[ -]/g, "")) || !/^\d{3}$/.test(values.get("card[cvc]") ?? "") || !/^(?:0?[1-9]|1[0-2])$/.test(values.get("card[exp_month]") ?? "") || !/^(?:\d{2}|\d{4})$/.test(values.get("card[exp_year]") ?? "") || values.has("allow_redisplay") && values.get("allow_redisplay") !== "unspecified")
|
|
796
|
-
reject();
|
|
837
|
+
reject("tokenization_fields");
|
|
797
838
|
return { phase: "tokenization", session_id: sessionId, publishable_key: key };
|
|
798
839
|
}
|
|
799
840
|
const amount = values.get("expected_amount");
|
|
800
841
|
const syntheticId = values.get("payment_method");
|
|
801
842
|
const email = values.get("payment_method_data[billing_details][email]");
|
|
802
843
|
if (email !== void 0 && !billingEmail(email))
|
|
803
|
-
reject();
|
|
804
|
-
if (!/^[1-9]\d{0,11}$/.test(amount ?? "") || !Number.isSafeInteger(Number(amount)) || options.amountCents !== void 0 && options.amountCents !== Number(amount)
|
|
805
|
-
reject();
|
|
844
|
+
reject("billing_email");
|
|
845
|
+
if (!/^[1-9]\d{0,11}$/.test(amount ?? "") || !Number.isSafeInteger(Number(amount)) || options.amountCents !== void 0 && options.amountCents !== Number(amount))
|
|
846
|
+
reject("expected_amount");
|
|
847
|
+
if (values.get("expected_payment_method_type") !== "card")
|
|
848
|
+
reject("payment_method_type");
|
|
849
|
+
if (!SYNTHETIC.test(syntheticId))
|
|
850
|
+
reject("synthetic_payment_method");
|
|
851
|
+
if (["init_checksum", "js_checksum", "version", "rv_timestamp"].some((key2) => !values.get(key2)))
|
|
852
|
+
reject("required_final_fields");
|
|
853
|
+
if (options.syntheticPaymentMethodId !== void 0 && options.syntheticPaymentMethodId !== syntheticId || marker && marker.synthetic_payment_method_id !== syntheticId)
|
|
854
|
+
reject("synthetic_payment_method");
|
|
806
855
|
return {
|
|
807
856
|
phase: "final",
|
|
808
857
|
session_id: sessionId,
|
|
@@ -912,4 +961,4 @@ function prepareStripeCheckoutReplay(request, card, options = {}) {
|
|
|
912
961
|
where: Object.keys(replacements)
|
|
913
962
|
};
|
|
914
963
|
}
|
|
915
|
-
export { STRIPE_CHECKOUT_CONTEXT_HEADER, STRIPE_CHECKOUT_OPERATION, attachStripeCheckoutBilling, captureStripeCheckoutBilling, classifyStripeCheckoutRequest, createStripeCheckoutTokenizationStub, encodeStripeCheckoutContext, hasStripeCheckoutMarker, isStripeCheckoutEndpoint, isStripeCheckoutHostedMode, parseStripeCheckoutContext, parseStripeCheckoutResponse, prepareStripeCheckoutReplay, validateStripeCheckoutCard, validateStripeCheckoutIdentity };
|
|
964
|
+
export { STRIPE_CHECKOUT_CONTEXT_HEADER, STRIPE_CHECKOUT_OPERATION, STRIPE_CHECKOUT_VALIDATION_CODES, attachStripeCheckoutBilling, captureStripeCheckoutBilling, classifyStripeCheckoutRequest, createStripeCheckoutTokenizationStub, encodeStripeCheckoutContext, hasStripeCheckoutMarker, isStripeCheckoutEndpoint, isStripeCheckoutHostedMode, parseStripeCheckoutContext, parseStripeCheckoutResponse, prepareStripeCheckoutReplay, stripeCheckoutValidationCode, validateStripeCheckoutCard, validateStripeCheckoutIdentity };
|
package/dist/stripe-checkout.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { classifyStripeCheckoutRequest, createStripeCheckoutTokenizationStub, encodeStripeCheckoutContext, isStripeCheckoutEndpoint, STRIPE_CHECKOUT_CONTEXT_HEADER, captureStripeCheckoutBilling, attachStripeCheckoutBilling, validateStripeCheckoutIdentity, } from './stripe-checkout.generated.js';
|
|
1
|
+
import { classifyStripeCheckoutRequest, createStripeCheckoutTokenizationStub, encodeStripeCheckoutContext, isStripeCheckoutEndpoint, STRIPE_CHECKOUT_CONTEXT_HEADER, captureStripeCheckoutBilling, attachStripeCheckoutBilling, validateStripeCheckoutIdentity, stripeCheckoutValidationCode, STRIPE_CHECKOUT_VALIDATION_CODES, } from './stripe-checkout.generated.js';
|
|
2
2
|
class StripeCheckoutRejectionError extends Error {
|
|
3
3
|
stage;
|
|
4
4
|
reason;
|
|
5
5
|
phase;
|
|
6
|
-
|
|
6
|
+
validationCode;
|
|
7
|
+
constructor(message, stage, reason, phase, validationCode) {
|
|
7
8
|
super(message);
|
|
8
9
|
this.stage = stage;
|
|
9
10
|
this.reason = reason;
|
|
10
11
|
this.phase = phase;
|
|
12
|
+
this.validationCode = validationCode;
|
|
11
13
|
}
|
|
12
14
|
}
|
|
13
15
|
export function stripeCheckoutReadinessError(reason) {
|
|
@@ -59,8 +61,10 @@ export class StripeCheckoutGate {
|
|
|
59
61
|
readiness: 'readiness_unavailable', document: 'document_unavailable', stub_response: 'stub_response_failed',
|
|
60
62
|
};
|
|
61
63
|
const rejection = error instanceof StripeCheckoutRejectionError ? error : undefined;
|
|
64
|
+
const reason = rejection?.reason ?? fallback[stage];
|
|
62
65
|
return { version: 1, processor: 'stripe', endpoint_family: family,
|
|
63
|
-
phase: rejection?.phase ?? phase, stage: rejection?.stage ?? stage, reason
|
|
66
|
+
phase: rejection?.phase ?? phase, stage: rejection?.stage ?? stage, reason,
|
|
67
|
+
...(reason === 'request_validation_failed' ? { validation_code: rejection?.validationCode ?? STRIPE_CHECKOUT_VALIDATION_CODES.unclassified } : {}),
|
|
64
68
|
gate_state: this.state, disposition: error instanceof StripeCheckoutClaimConflictError ? 'active_claim_preserved' : 'checkout_stopped' };
|
|
65
69
|
}
|
|
66
70
|
assertClaim(step) {
|
|
@@ -73,7 +77,7 @@ export class StripeCheckoutGate {
|
|
|
73
77
|
return;
|
|
74
78
|
const url = new URL(raw);
|
|
75
79
|
if (url.origin !== 'https://checkout.stripe.com' || url.username || url.password
|
|
76
|
-
|| ![`/c/pay/${this.binding.sessionId}`, `/pay/${this.binding.sessionId}`].includes(url.pathname)) {
|
|
80
|
+
|| ![`/c/pay/${this.binding.sessionId}`, `/pay/${this.binding.sessionId}`, `/g/pay/${this.binding.sessionId}`, `/f/pay/${this.binding.sessionId}`].includes(url.pathname)) {
|
|
77
81
|
this.invalidate();
|
|
78
82
|
throw new StripeCheckoutRejectionError('Native Stripe Checkout document changed.', 'document', 'document_changed');
|
|
79
83
|
}
|
|
@@ -87,8 +91,8 @@ export class StripeCheckoutGate {
|
|
|
87
91
|
try {
|
|
88
92
|
phase = classifyStripeCheckoutRequest(request, this.binding);
|
|
89
93
|
}
|
|
90
|
-
catch {
|
|
91
|
-
throw new StripeCheckoutRejectionError('stripe_checkout_rejected', 'classification', 'request_validation_failed', 'unknown');
|
|
94
|
+
catch (error) {
|
|
95
|
+
throw new StripeCheckoutRejectionError('stripe_checkout_rejected', 'classification', 'request_validation_failed', 'unknown', stripeCheckoutValidationCode(error));
|
|
92
96
|
}
|
|
93
97
|
if (!phase)
|
|
94
98
|
return null;
|
|
@@ -106,7 +110,10 @@ export class StripeCheckoutGate {
|
|
|
106
110
|
this.billing = captureStripeCheckoutBilling(request, this.binding);
|
|
107
111
|
response = createStripeCheckoutTokenizationStub(request, this.binding);
|
|
108
112
|
}
|
|
109
|
-
catch {
|
|
113
|
+
catch (error) {
|
|
114
|
+
const code = stripeCheckoutValidationCode(error);
|
|
115
|
+
if (code !== STRIPE_CHECKOUT_VALIDATION_CODES.unclassified)
|
|
116
|
+
throw new StripeCheckoutRejectionError('stripe_checkout_rejected', 'classification', 'request_validation_failed', 'tokenization', code);
|
|
110
117
|
throw new StripeCheckoutRejectionError('stripe_checkout_rejected', 'stub_response', 'stub_response_failed', 'tokenization');
|
|
111
118
|
}
|
|
112
119
|
this.state = 'stubbed';
|
|
@@ -120,9 +127,9 @@ export class StripeCheckoutGate {
|
|
|
120
127
|
try {
|
|
121
128
|
final = attachStripeCheckoutBilling(request, this.billing, this.binding);
|
|
122
129
|
}
|
|
123
|
-
catch {
|
|
130
|
+
catch (error) {
|
|
124
131
|
this.invalidate();
|
|
125
|
-
throw new StripeCheckoutRejectionError('stripe_checkout_rejected', 'classification', 'request_validation_failed', 'final');
|
|
132
|
+
throw new StripeCheckoutRejectionError('stripe_checkout_rejected', 'classification', 'request_validation_failed', 'final', stripeCheckoutValidationCode(error));
|
|
126
133
|
}
|
|
127
134
|
this.state = 'submitted';
|
|
128
135
|
this.billing = undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-cards/checkout",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Let browser agents pay with the user's own card, without your infrastructure ever touching card data.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"_comment_build": "The public SDK keeps zero runtime dependencies. Its build vendors deterministic metadata and substitution artifacts from the internal payment core; TypeScript remains pinned.",
|
|
28
28
|
"build": "node ../payment-core/scripts/build.mjs && node scripts/generate-payment-core.mjs && npx -y -p typescript@5.9.3 tsc && node scripts/generate-preflight-contract.mjs",
|
|
29
29
|
"prepublishOnly": "pnpm build",
|
|
30
|
-
"test": "node test.mjs && node --test lifecycle.test.mjs merchant-abort.test.mjs preparation.test.mjs braintree.test.mjs autopilot.test.mjs stripe-checkout.test.mjs payment-core.test.mjs prepared-processor.test.mjs minimum-delay.test.mjs paysafe.test.mjs attachment.test.mjs mercado-checkout.test.mjs mercado-polling.test.mjs && node --test preflight-package.test.mjs preflight-collector.test.mjs && node --test kernel-native-qualification.test.mjs",
|
|
30
|
+
"test": "node test.mjs && node --test lifecycle.test.mjs merchant-abort.test.mjs preparation.test.mjs braintree.test.mjs autopilot.test.mjs stripe-checkout.test.mjs payment-core.test.mjs prepared-processor.test.mjs minimum-delay.test.mjs paysafe.test.mjs attachment.test.mjs mercado-checkout.test.mjs mercado-polling.test.mjs && node --test preflight-package.test.mjs preflight-collector.test.mjs && node --test kernel-native-qualification.test.mjs && node --test ../vault/scripts/recurly-validation/watch-duty-sdk-result.test.mjs",
|
|
31
31
|
"test:browser": "node browser.test.mjs && node stripe-browser.test.mjs && node preparation-browser.test.mjs && node owned-shop-browser.test.mjs",
|
|
32
32
|
"check:payment-core": "node scripts/generate-payment-core.mjs --check",
|
|
33
33
|
"test:preflight": "node --test preflight-package.test.mjs preflight-collector.test.mjs kernel-native-qualification.test.mjs",
|