@agent-cards/checkout 0.9.1 → 0.11.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 +8 -0
- package/PREFLIGHT.md +1 -1
- package/README.md +59 -1
- package/dist/cdp.d.ts +3 -0
- package/dist/cdp.js +199 -10
- package/dist/client.d.ts +8 -0
- package/dist/client.js +66 -5
- package/dist/index.d.ts +1 -0
- package/dist/mercado-checkout.d.ts +20 -0
- package/dist/mercado-checkout.generated.d.ts +52 -0
- package/dist/mercado-checkout.generated.js +198 -0
- package/dist/mercado-checkout.js +108 -0
- package/dist/preflight-capabilities.generated.d.ts +26 -1
- package/dist/preflight-capabilities.generated.js +31 -1
- package/dist/preflight-catalog.json +34 -4
- package/dist/preflight-schemas.json +4 -4
- package/dist/preflight.generated.d.ts +27 -2
- package/dist/preflight.generated.js +2 -2
- package/dist/preparation.js +2 -0
- package/dist/prepared-processor.d.ts +1 -1
- package/dist/prepared-processor.js +7 -1
- package/dist/recurly.generated.d.ts +1 -0
- package/dist/recurly.generated.js +87 -0
- package/dist/stripe-checkout.d.ts +77 -0
- package/dist/stripe-checkout.generated.d.ts +58 -0
- package/dist/stripe-checkout.generated.js +915 -0
- package/dist/stripe-checkout.js +133 -0
- package/examples/preflight/kernel-native/inventory.json +2 -2
- package/examples/preflight/kernel-profile.empty.json +1 -1
- package/examples/preflight/mollie-hosted.result.json +2 -2
- package/examples/preflight/stripe-script.direct.result.json +2 -2
- package/examples/preflight/stripe-script.result.json +2 -2
- package/package.json +2 -2
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { classifyStripeCheckoutRequest, createStripeCheckoutTokenizationStub, encodeStripeCheckoutContext, isStripeCheckoutEndpoint, STRIPE_CHECKOUT_CONTEXT_HEADER, captureStripeCheckoutBilling, attachStripeCheckoutBilling, validateStripeCheckoutIdentity, } from './stripe-checkout.generated.js';
|
|
2
|
+
class StripeCheckoutRejectionError extends Error {
|
|
3
|
+
stage;
|
|
4
|
+
reason;
|
|
5
|
+
phase;
|
|
6
|
+
constructor(message, stage, reason, phase) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.stage = stage;
|
|
9
|
+
this.reason = reason;
|
|
10
|
+
this.phase = phase;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function stripeCheckoutReadinessError(reason) {
|
|
14
|
+
return new StripeCheckoutRejectionError('checkout_interception_not_ready', 'readiness', reason);
|
|
15
|
+
}
|
|
16
|
+
/** A valid competing request must not retire the request that already claimed this step. */
|
|
17
|
+
export class StripeCheckoutClaimConflictError extends StripeCheckoutRejectionError {
|
|
18
|
+
constructor(phase) {
|
|
19
|
+
super(phase === 'tokenization' ? 'Native Stripe Checkout preparation is already claimed.'
|
|
20
|
+
: 'Native Stripe Checkout confirmation is already claimed.', 'claim', phase === 'tokenization' ? 'duplicate_tokenization' : 'duplicate_confirmation', phase);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/** The two native browser requests belong to one attachment and one grant.
|
|
24
|
+
* Processor rules and form transformations live in the generated shared core.
|
|
25
|
+
* The local stub contains no selected-card data and starts no authorization.
|
|
26
|
+
*/
|
|
27
|
+
export class StripeCheckoutGate {
|
|
28
|
+
state = 'fresh';
|
|
29
|
+
billing;
|
|
30
|
+
binding;
|
|
31
|
+
constructor(options) {
|
|
32
|
+
if (!options.stripeCheckout)
|
|
33
|
+
return;
|
|
34
|
+
const { sessionId, publishableKey, environment } = options.stripeCheckout;
|
|
35
|
+
validateStripeCheckoutIdentity({ environment, sessionId, publishableKey });
|
|
36
|
+
if (options.executionMode !== 'autopilot' || !/^apg_[A-Za-z0-9_-]{1,128}(?![\s\S])/.test(options.grantId ?? '')
|
|
37
|
+
|| !Number.isSafeInteger(options.amount) || Number(options.amount) <= 0 || options.currency !== 'usd')
|
|
38
|
+
throw new Error('Native Stripe Checkout requires a mode-bound session, grant and numeric USD amount.');
|
|
39
|
+
this.binding = Object.freeze({ environment, sessionId, publishableKey, amountCents: options.amount,
|
|
40
|
+
syntheticPaymentMethodId: `pm_agentcard_checkout_${crypto.randomUUID().replaceAll('-', '')}` });
|
|
41
|
+
}
|
|
42
|
+
matches(url) { return !!this.binding && isStripeCheckoutEndpoint(url); }
|
|
43
|
+
isEnabled() { return !!this.binding; }
|
|
44
|
+
isPrepared() { return this.state !== 'fresh'; }
|
|
45
|
+
invalidate() { this.state = 'stopped'; this.billing = undefined; }
|
|
46
|
+
/** Observability only: this endpoint label never participates in a payment decision. */
|
|
47
|
+
describeRejection(error, rawUrl, stage, phase = 'unknown') {
|
|
48
|
+
let family = 'other';
|
|
49
|
+
try {
|
|
50
|
+
const url = new URL(rawUrl);
|
|
51
|
+
if (url.origin === 'https://api.stripe.com' && url.pathname === '/v1/payment_methods')
|
|
52
|
+
family = 'payment_methods';
|
|
53
|
+
else if (isStripeCheckoutEndpoint(rawUrl))
|
|
54
|
+
family = 'payment_page_confirm';
|
|
55
|
+
}
|
|
56
|
+
catch { /* No untrusted URL or parser error leaves this method. */ }
|
|
57
|
+
const fallback = {
|
|
58
|
+
request_read: 'request_unavailable', classification: 'request_validation_failed', claim: 'preparation_unavailable',
|
|
59
|
+
readiness: 'readiness_unavailable', document: 'document_unavailable', stub_response: 'stub_response_failed',
|
|
60
|
+
};
|
|
61
|
+
const rejection = error instanceof StripeCheckoutRejectionError ? error : undefined;
|
|
62
|
+
return { version: 1, processor: 'stripe', endpoint_family: family,
|
|
63
|
+
phase: rejection?.phase ?? phase, stage: rejection?.stage ?? stage, reason: rejection?.reason ?? fallback[stage],
|
|
64
|
+
gate_state: this.state, disposition: error instanceof StripeCheckoutClaimConflictError ? 'active_claim_preserved' : 'checkout_stopped' };
|
|
65
|
+
}
|
|
66
|
+
assertClaim(step) {
|
|
67
|
+
if (this.state !== (step.phase === 'tokenization' ? 'stubbed' : 'submitted'))
|
|
68
|
+
throw new StripeCheckoutRejectionError('Native Stripe Checkout preparation is unavailable.', 'claim', 'claim_invalidated', step.phase);
|
|
69
|
+
}
|
|
70
|
+
/** Check the actual top-level hosted document before preparing either step. */
|
|
71
|
+
assertDocument(raw) {
|
|
72
|
+
if (!this.binding)
|
|
73
|
+
return;
|
|
74
|
+
const url = new URL(raw);
|
|
75
|
+
if (url.origin !== 'https://checkout.stripe.com' || url.username || url.password
|
|
76
|
+
|| ![`/c/pay/${this.binding.sessionId}`, `/pay/${this.binding.sessionId}`].includes(url.pathname)) {
|
|
77
|
+
this.invalidate();
|
|
78
|
+
throw new StripeCheckoutRejectionError('Native Stripe Checkout document changed.', 'document', 'document_changed');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
claim(request) {
|
|
82
|
+
if (!this.binding)
|
|
83
|
+
return null;
|
|
84
|
+
if (request.method.toUpperCase() !== 'POST')
|
|
85
|
+
return null;
|
|
86
|
+
let phase;
|
|
87
|
+
try {
|
|
88
|
+
phase = classifyStripeCheckoutRequest(request, this.binding);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
throw new StripeCheckoutRejectionError('stripe_checkout_rejected', 'classification', 'request_validation_failed', 'unknown');
|
|
92
|
+
}
|
|
93
|
+
if (!phase)
|
|
94
|
+
return null;
|
|
95
|
+
const diagnosticPhase = phase.phase === 'tokenization' ? 'tokenization' : phase.phase === 'final' ? 'final' : 'unknown';
|
|
96
|
+
if (Object.keys(request.headers).some(name => name.toLowerCase() === STRIPE_CHECKOUT_CONTEXT_HEADER))
|
|
97
|
+
throw new StripeCheckoutRejectionError('Native Stripe Checkout already carries a context.', 'claim', 'context_already_present', diagnosticPhase);
|
|
98
|
+
if (phase.phase === 'tokenization') {
|
|
99
|
+
if (this.state === 'stubbed' || this.state === 'submitted')
|
|
100
|
+
throw new StripeCheckoutClaimConflictError('tokenization');
|
|
101
|
+
if (this.state !== 'fresh')
|
|
102
|
+
throw new StripeCheckoutRejectionError('Native Stripe Checkout preparation is unavailable.', 'claim', 'preparation_unavailable', 'tokenization');
|
|
103
|
+
this.state = 'stopped';
|
|
104
|
+
let response;
|
|
105
|
+
try {
|
|
106
|
+
this.billing = captureStripeCheckoutBilling(request, this.binding);
|
|
107
|
+
response = createStripeCheckoutTokenizationStub(request, this.binding);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
throw new StripeCheckoutRejectionError('stripe_checkout_rejected', 'stub_response', 'stub_response_failed', 'tokenization');
|
|
111
|
+
}
|
|
112
|
+
this.state = 'stubbed';
|
|
113
|
+
return { phase: 'tokenization', response };
|
|
114
|
+
}
|
|
115
|
+
if (phase.phase === 'final' && this.state === 'submitted')
|
|
116
|
+
throw new StripeCheckoutClaimConflictError('final');
|
|
117
|
+
if (phase.phase !== 'final' || this.state !== 'stubbed')
|
|
118
|
+
throw new StripeCheckoutRejectionError('Native Stripe Checkout has no matching prepared request.', 'claim', 'preparation_missing', diagnosticPhase);
|
|
119
|
+
let final;
|
|
120
|
+
try {
|
|
121
|
+
final = attachStripeCheckoutBilling(request, this.billing, this.binding);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
this.invalidate();
|
|
125
|
+
throw new StripeCheckoutRejectionError('stripe_checkout_rejected', 'classification', 'request_validation_failed', 'final');
|
|
126
|
+
}
|
|
127
|
+
this.state = 'submitted';
|
|
128
|
+
this.billing = undefined;
|
|
129
|
+
return { phase: 'final', request: { ...final, headers: { ...final.headers,
|
|
130
|
+
[STRIPE_CHECKOUT_CONTEXT_HEADER]: encodeStripeCheckoutContext({ version: 1,
|
|
131
|
+
session_id: this.binding.sessionId, synthetic_payment_method_id: this.binding.syntheticPaymentMethodId }) } } };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": 1,
|
|
3
|
-
"catalog_version": "2026-09-
|
|
4
|
-
"catalog_sha256": "
|
|
3
|
+
"catalog_version": "2026-09-14.1",
|
|
4
|
+
"catalog_sha256": "c5bf9f8f7372def80d2abf0e9f2942c1b33514ed516b66d3f60e98c11d43bf5c",
|
|
5
5
|
"baseline_version": "kernel-native-docs-2026-09-11.1",
|
|
6
6
|
"baseline_sha256": "d86722f49633d8223fccae54cd3d485df4375aee06aa156a273cc689b7c8507c",
|
|
7
7
|
"native_build": null,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"snapshot": {
|
|
3
3
|
"schema_version": 1,
|
|
4
|
-
"catalog_version": "2026-09-
|
|
4
|
+
"catalog_version": "2026-09-14.1",
|
|
5
5
|
"signals": [
|
|
6
6
|
{
|
|
7
7
|
"rule_id": "mollie-hosted-credit-card",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"result": {
|
|
35
35
|
"schema_version": 1,
|
|
36
|
-
"catalog_version": "2026-09-
|
|
36
|
+
"catalog_version": "2026-09-14.1",
|
|
37
37
|
"integration": {
|
|
38
38
|
"id": "kernel_native",
|
|
39
39
|
"version": "example-native-adapter"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"snapshot": {
|
|
3
3
|
"schema_version": 1,
|
|
4
|
-
"catalog_version": "2026-09-
|
|
4
|
+
"catalog_version": "2026-09-14.1",
|
|
5
5
|
"signals": [
|
|
6
6
|
{
|
|
7
7
|
"rule_id": "stripe-js-v3",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"result": {
|
|
28
28
|
"schema_version": 1,
|
|
29
|
-
"catalog_version": "2026-09-
|
|
29
|
+
"catalog_version": "2026-09-14.1",
|
|
30
30
|
"integration": {
|
|
31
31
|
"id": "direct_sdk",
|
|
32
32
|
"version": "bundled"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"snapshot": {
|
|
3
3
|
"schema_version": 1,
|
|
4
|
-
"catalog_version": "2026-09-
|
|
4
|
+
"catalog_version": "2026-09-14.1",
|
|
5
5
|
"signals": [
|
|
6
6
|
{
|
|
7
7
|
"rule_id": "stripe-js-v3",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"result": {
|
|
28
28
|
"schema_version": 1,
|
|
29
|
-
"catalog_version": "2026-09-
|
|
29
|
+
"catalog_version": "2026-09-14.1",
|
|
30
30
|
"integration": {
|
|
31
31
|
"id": "kernel_native",
|
|
32
32
|
"version": "example-native-adapter"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-cards/checkout",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.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 payment-core.test.mjs prepared-processor.test.mjs minimum-delay.test.mjs paysafe.test.mjs attachment.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",
|
|
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",
|