@agent-cards/checkout 0.15.1 → 0.16.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 +4 -0
- package/README.md +14 -5
- package/dist/cdp.d.ts +38 -1
- package/dist/cdp.js +912 -75
- package/dist/checkout-com.generated.d.ts +4 -0
- package/dist/checkout-com.generated.js +183 -0
- package/dist/client.d.ts +32 -4
- package/dist/client.js +45 -9
- package/dist/index.d.ts +1 -1
- package/dist/lifecycle.d.ts +25 -0
- package/dist/lifecycle.js +34 -0
- package/dist/preparation.d.ts +1 -1
- package/dist/preparation.js +2 -2
- package/dist/prepared-processor.d.ts +2 -2
- package/dist/prepared-processor.js +7 -2
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- Keep the cardholder's approval when the merchant page gives up on its own card request. A page whose script times out its tokenization while the person is still deciding (Braintree after 60 seconds, Square after about 10) no longer cancels the approval: the SDK reports `merchant_request_lost`, answers the page's next request for the same purchase from the same authorization, and reads `ready_to_submit` with reason `awaiting_merchant_retry` when the approval lands before the page asks again, so one more Pay click completes the purchase with no second prompt. The wait for that request is bounded by `merchantRetryWaitMs` (two minutes by default, never past the approval window); an approval the page never asks for again is retired through the API as `merchant_never_retried` and the controller reads `declined` with that reason. Applies to `token` and `cse` checkouts; hosted forms, prepared checkouts and native Stripe Checkout keep cancelling. `VaultClient.cancelAuthorization` takes the reason and `checkoutModeOf` reads a request's mode. The matching API and Vault releases are required for the new reason; an older API answers its retirement as unknown, which the SDK holds.
|
|
6
|
+
|
|
7
|
+
- Approve a Checkout.com guest card checkout before Pay with `prepare({ psp: 'checkout_com', environment: 'production' | 'sandbox' })`. Phone approval finishes before Flow starts its 12-second tokenization deadline. One fresh card request on the matching API or CAG host consumes the approval; saved-card, wallet and reusable-token requests are refused. Matching API, Vault and database releases are required. A token does not establish merchant payment completion.
|
|
8
|
+
|
|
5
9
|
- Approve an Adyen Sessions checkout before Pay with `prepare({ psp: 'adyen', environment: 'production' | 'sandbox' })`. The cardholder approves and picks the card first; when the merchant's Sessions `/payments` request pauses, the device encrypts the approved card under the merchant's Adyen key and the request continues from your browser, so Adyen Web's own 60-second request timeout covers only the pause, the bind and the encryption. `sandbox` is Adyen's test host with a `test_` client key; `production` is the live host families with a `live_` key. A stored-card, single-blob or store-the-card request never uses the approval. The matching API, Vault and database migration are required.
|
|
6
10
|
|
|
7
11
|
- Approve Spreedly's native hosted-card checkout with `prepare({ psp: 'spreedly', environment: 'shared' })`. The Vault tokenizes the selected card over the encrypted relay and returns the native response. Matching API, Vault, relay and database releases are required; tokenization alone does not confirm payment. Saved-card updates and other Spreedly flows remain unsupported.
|
package/README.md
CHANGED
|
@@ -82,10 +82,10 @@ when the charge disagreed). Every result carries `amountAuthority`:
|
|
|
82
82
|
Agentcard derives it.
|
|
83
83
|
|
|
84
84
|
Then let your agent click "Pay" like it always does. `attachToCdp` pauses the
|
|
85
|
-
request for approval
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
`controller.prepare()` before the first Pay action
|
|
85
|
+
request for approval. Merchant timeouts still apply to the request itself: Square's observed tokenization deadline
|
|
86
|
+
is about 10 seconds, Braintree's native request timeout is 60 seconds, and Adyen Web's own request timeout abandons its Sessions payment call 60 seconds after Pay (observed on Adyen Web 6.41 and 6.44), each including approval and handoff. These are the processors' limits, not ones the SDK enforces: the SDK's own authorization wait stays 15 minutes.
|
|
87
|
+
|
|
88
|
+
The approval outlives the page's own request. When the page's script gives up on its paused card request while the cardholder is still deciding, the SDK keeps the approval pending (state `awaiting_approval`, reason `merchant_request_lost`, event `merchant_request_lost`) and answers the page's next request for the same purchase from it: same endpoint, same method, same top-level document, same page total, and a body of the same shape carrying the same card placeholder and the same amount when the request names one. An amount has to be in evidence somewhere (your `amount` hint, a `pageAmount` reader, or the request's own bytes); with none, a retry is a new question and the approval is retired unused. Braintree's client re-issues its mutation on its own within a second; on other processors the agent clicks Pay again. If the approval lands before the page asks again, the controller reads `ready_to_submit` with reason `awaiting_merchant_retry` (event `approval_awaiting_merchant_retry`): click Pay once, and that request is answered with no second prompt on the phone. The wait for that request is bounded (`merchantRetryWaitMs`, two minutes by default, never past the approval window); when it ends with no request, the SDK retires the approval through the API with reason `merchant_never_retried`, the controller reads `declined` with that reason, nothing was charged, and the cardholder's approval page says so. This applies to `token` and `cse` checkouts; a hosted form, a prepared checkout and a native Stripe Checkout step keep the behaviour below. For human approval on a short-deadline processor, `controller.prepare()` before the first Pay action, shown below, still finishes the request inside its own deadline. For Adyen, `prepare()` moves the approval before Pay, so only the device-side encryption runs inside Adyen Web's minute.
|
|
89
89
|
|
|
90
90
|
Playwright:
|
|
91
91
|
|
|
@@ -511,6 +511,7 @@ await page.getByRole('button', { name: 'Pay', exact: true }).click();
|
|
|
511
511
|
| Square | `production` or `sandbox` | Matching Square `/v2/card-nonce` host |
|
|
512
512
|
| Braintree | `production` or `sandbox` | Matching Braintree GraphQL host and guest `TokenizeCreditCard` mutation |
|
|
513
513
|
| Worldpay | `production` or `sandbox` | Matching Access Worldpay host and `/sessions/card` |
|
|
514
|
+
| Checkout.com | `production` or `sandbox` | Fresh guest-card JSON POST to `/tokens` on the matching API or card-acquisition-gateway host |
|
|
514
515
|
| Bambora | `shared` | `/scripts/tokenization/tokens` on `api.bam.shift4api.net` or `api.na.bambora.com` |
|
|
515
516
|
| Mercado Pago | `shared` | `api.mercadopago.com/v1/card_tokens` with a fresh card body |
|
|
516
517
|
| Recurly | `shared` | Form-encoded POST to `/js/v1/token` on `api.recurly.com` or `api.eu.recurly.com` |
|
|
@@ -519,6 +520,14 @@ await page.getByRole('button', { name: 'Pay', exact: true }).click();
|
|
|
519
520
|
|
|
520
521
|
Use `environment: 'shared'` for Bambora, Mercado Pago, Recurly and Spreedly because the same endpoint serves test and live requests. Agentcard cannot establish the processor's test mode from that URL or a credential prefix. Configure test mode through the merchant's processor account when testing. Agentcard's own `sandbox` flag remains separate. Prepared Worldpay, Bambora, Mercado Pago and Recurly requests reject saved-card and recurring request bodies; a refused request retires the local preparation. Reconcile any existing merchant attempt before creating a new attachment.
|
|
521
522
|
|
|
523
|
+
Prepare a Checkout.com checkout before the agent clicks Pay:
|
|
524
|
+
|
|
525
|
+
```ts
|
|
526
|
+
await controller.prepare({ psp: 'checkout_com', environment: 'production' });
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
Keep the phone approval page open, then click Pay once after readiness. Checkout.com Flow 1.228.0 gives its card iframe 12 seconds to return a token; approval before Pay leaves that interval for request binding and tokenization. Prepared requests must use an exact `/tokens` URL on `api.checkout.com` or `card-acquisition-gateway.checkout.com`, or the corresponding `.sandbox.checkout.com` host for `sandbox`. The request must describe a fresh card with a CVV and public-key authentication. Wallet, saved-card, reusable-token and recurring variants are refused. A native API fallback after the first CAG request cannot reuse approval. Match the actual merchant charge to the approved amount separately; a token does not enforce that amount.
|
|
530
|
+
|
|
522
531
|
Prepare an Adyen Sessions checkout before the agent clicks Pay:
|
|
523
532
|
|
|
524
533
|
```ts
|
|
@@ -563,7 +572,7 @@ Braintree's native `ClientConfiguration` GraphQL query can run before, during or
|
|
|
563
572
|
|
|
564
573
|
Readiness lasts up to 30 seconds (`preparation.expiresAt`) and appears as `ready_to_submit`, with `paymentStatus: 'not_started'`. Trigger the caller-owned Pay action immediately after the promise resolves. Expiry, navigation, cancellation, an early request or a changed checkout fails closed. A preparation and its attachment are single use; reconcile any bound authorization before creating a new attachment. The SDK never clicks Pay, reuses a stale request, changes native request deadlines, or automatically retries a failed prepared checkout.
|
|
565
574
|
|
|
566
|
-
After Pay, the processor's native deadline still covers fresh authorization binding, device replay and token handoff. A disconnected or backgrounded cardholder device, or a slow transport, can still miss it. A subsequent SCA challenge has its own lifetime after token handoff. If the
|
|
575
|
+
After Pay, the processor's native deadline still covers fresh authorization binding, device replay and token handoff. A disconnected or backgrounded cardholder device, or a slow transport, can still miss it. A subsequent SCA challenge has its own lifetime after token handoff. If the page's own script abandons an unprepared `token` or `cse` request while the cardholder decides, the approval survives and answers the page's next request for the same purchase (see "The approval outlives the page's own request" above). If the frame that sent the request is removed, the document moves to another URL, the page closes or crashes, or a prepared request is abandoned, the attachment blocks further requests and tries to retire the pre-replay authorization; a started replay or unconfirmed cancellation remains unknown. Without `prepare()`, approval loading and human interaction still share the native deadline, so a delayed approval finishes the page's retry rather than its first request.
|
|
567
576
|
|
|
568
577
|
Lost authorization polling, local approval timeouts, or interrupted browser
|
|
569
578
|
handoffs produce `outcome_unknown` and block automatic retry. The thrown
|
package/dist/cdp.d.ts
CHANGED
|
@@ -67,11 +67,40 @@ export declare function withCorsHeaders(headers: Record<string, string>, cors: R
|
|
|
67
67
|
/**
|
|
68
68
|
* Browser-level, session-aware CDP connection. A page-scoped Playwright or
|
|
69
69
|
* Puppeteer CDPSession is NOT this interface; use attachToPlaywright for those.
|
|
70
|
+
*
|
|
71
|
+
* Forward commands and events over a browser WebSocket with flattened sessions.
|
|
72
|
+
* An omitted sessionId means the browser root, never a default page session.
|
|
73
|
+
* Attachment requires Target.getTargetInfo on the supplied page session, then
|
|
74
|
+
* Target.setDiscoverTargets and Target.getTargets at the browser root. Forward
|
|
75
|
+
* root Target.targetCreated/targetInfoChanged events with no sessionId, and
|
|
76
|
+
* preserve the sessionId on child attachment, Fetch, and Network events.
|
|
77
|
+
* Page/iframe sessions must support Page, Fetch, Network, and Target; dedicated
|
|
78
|
+
* workers require Network, Target, and Runtime.runIfWaitingForDebugger.
|
|
79
|
+
* Unsupported or incomplete discovery fails with CheckoutAttachmentError
|
|
80
|
+
* before fetch_armed. TypeScript describes forwarding; attachment verifies
|
|
81
|
+
* the browser's runtime capabilities and returned metadata.
|
|
70
82
|
*/
|
|
71
83
|
export interface CdpLike {
|
|
84
|
+
/** Read the merchant target on the page session; returns { targetInfo: CdpTargetInfo }. */
|
|
85
|
+
send(method: 'Target.getTargetInfo', params: Record<string, never>, sessionId: string): Promise<any>;
|
|
86
|
+
/** Enable root discovery events, including targets outside the page tree. */
|
|
87
|
+
send(method: 'Target.setDiscoverTargets', params: {
|
|
88
|
+
discover: boolean;
|
|
89
|
+
}, sessionId?: undefined): Promise<any>;
|
|
90
|
+
/** Read { targetInfos: CdpTargetInfo[] }; missing sessionId must remain browser-scoped. */
|
|
91
|
+
send(method: 'Target.getTargets', params?: Record<string, never>, sessionId?: undefined): Promise<any>;
|
|
92
|
+
/** Forward other CDP commands unchanged; unsupported commands must reject. */
|
|
72
93
|
send(method: string, params?: any, sessionId?: string): Promise<any>;
|
|
94
|
+
/** Deliver browser-root events as well as events from flattened child sessions. */
|
|
73
95
|
on(handler: (method: string, params: any, sessionId?: string) => void): void;
|
|
74
96
|
}
|
|
97
|
+
/** Browser Target metadata used to establish which checkout owns a worker. */
|
|
98
|
+
export interface CdpTargetInfo {
|
|
99
|
+
targetId: string;
|
|
100
|
+
type: string;
|
|
101
|
+
/** Absent for the default browser context. */
|
|
102
|
+
browserContextId?: string;
|
|
103
|
+
}
|
|
75
104
|
export interface AttachOptions extends LifecycleOptions, ExecutionMetadata {
|
|
76
105
|
/** Explicit native hosted Stripe Checkout TEST integration; requires an Autopilot grant. */
|
|
77
106
|
stripeCheckout?: StripeCheckoutOptions;
|
|
@@ -104,7 +133,7 @@ export interface AttachOptions extends LifecycleOptions, ExecutionMetadata {
|
|
|
104
133
|
} | undefined>;
|
|
105
134
|
cardId?: string;
|
|
106
135
|
timeoutMs?: number;
|
|
107
|
-
/**
|
|
136
|
+
/** Interception setup and request ownership deadline, separate from approval. Defaults to 30000 ms; maximum 300000 ms. */
|
|
108
137
|
attachmentTimeoutMs?: number;
|
|
109
138
|
/** Explicit payment endpoints to block if the registry cannot handle their method/format. Unlisted traffic is untouched. */
|
|
110
139
|
paymentEndpoints?: readonly PaymentEndpointGuard[];
|
|
@@ -117,6 +146,14 @@ export interface AttachOptions extends LifecycleOptions, ExecutionMetadata {
|
|
|
117
146
|
approvalCooldownMs?: number;
|
|
118
147
|
/** How long a hosted form the device already submitted stays refused on a re-post. Defaults to HOSTED_FORM_REPEAT_QUIET_MS. */
|
|
119
148
|
hostedFormRepeatQuietMs?: number;
|
|
149
|
+
/**
|
|
150
|
+
* After the cardholder approves with no live page request to answer (the
|
|
151
|
+
* page's own script gave up on its request while they decided), how long
|
|
152
|
+
* the approval waits for the page to ask again before it is retired as
|
|
153
|
+
* `merchant_never_retried`. Capped by the approval window. Defaults to
|
|
154
|
+
* MERCHANT_RETRY_WAIT_MS.
|
|
155
|
+
*/
|
|
156
|
+
merchantRetryWaitMs?: number;
|
|
120
157
|
}
|
|
121
158
|
/**
|
|
122
159
|
* Take over card tokenization for a page.
|