@agent-cards/sdk 0.20.0 → 0.21.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/PREFLIGHT.md +4 -0
- package/README.md +153 -0
- package/dist/cdp.d.ts +2 -1
- package/dist/cdp.js +161 -31
- package/dist/client.d.ts +97 -1
- package/dist/client.js +172 -5
- package/dist/cybersource-flex.d.ts +183 -0
- package/dist/cybersource-flex.generated.d.ts +92 -0
- package/dist/cybersource-flex.generated.js +689 -0
- package/dist/cybersource-flex.js +275 -0
- package/dist/gmo.d.ts +63 -0
- package/dist/gmo.generated.d.ts +60 -0
- package/dist/gmo.generated.js +586 -0
- package/dist/gmo.js +119 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1 -1
- package/dist/lifecycle.d.ts +8 -3
- package/dist/lifecycle.js +6 -2
- package/dist/pre-claim.d.ts +12 -1
- package/dist/pre-claim.js +135 -9
- package/dist/preflight-catalog.json +116 -0
- package/dist/preflight-schemas.json +8 -0
- package/dist/preflight.generated.js +15 -1
- package/dist/prepared-processor.d.ts +4 -2
- package/dist/prepared-processor.js +12 -2
- package/dist/registry.d.ts +17 -7
- package/dist/stripe-checkout.generated.js +37 -2
- package/examples/preflight/kernel-native/inventory.json +1 -1
- package/package.json +3 -3
|
@@ -6,22 +6,27 @@ import { isPreparedSpreedlyRequest, isSpreedlyTokenRequest, SPREEDLY_TOKEN_ENDPO
|
|
|
6
6
|
import { checkoutComPreparationUrl, isPreparedCheckoutComRequest } from './checkout-com.generated.js';
|
|
7
7
|
import { classifyDeclaredMerchantRequest, classifyMerchantRequest } from './merchant-hosted.js';
|
|
8
8
|
import { fiservCapturePinId, fiservPreparationUrl, isPreparedFiservRequest } from './fiserv.js';
|
|
9
|
+
import { cybersourceFlexPreparationUrl, isPreparedCybersourceFlexRequest } from './cybersource-flex.generated.js';
|
|
9
10
|
export function preparationMode(psp) {
|
|
10
11
|
return psp === 'adyen' || psp === 'fiserv' ? 'cse' : 'token';
|
|
11
12
|
}
|
|
12
13
|
/**
|
|
13
14
|
* Shared endpoint processors cannot attest test/live mode from their URL or key prefix.
|
|
14
15
|
* Adyen can: test and live are separate hosts and key prefixes. Fiserv's are separate
|
|
15
|
-
* hosts too: connect (production) and connect-cert (sandbox).
|
|
16
|
+
* hosts too: connect (production) and connect-cert (sandbox). So are CyberSource
|
|
17
|
+
* Flex's: flex.cybersource.com is live, testflex.cybersource.com is test, and each has
|
|
18
|
+
* its own signing keys.
|
|
16
19
|
*/
|
|
17
20
|
export function validPreparationEnvironment(psp, environment) {
|
|
18
21
|
if (psp === 'bambora' || psp === 'mercado_pago' || psp === 'recurly' || psp === 'spreedly')
|
|
19
22
|
return environment === 'shared';
|
|
20
|
-
return ['square', 'braintree', 'worldpay', 'adyen', 'checkout_com', 'paysafe', 'fiserv'].includes(psp) && ['production', 'sandbox'].includes(environment);
|
|
23
|
+
return ['square', 'braintree', 'worldpay', 'adyen', 'checkout_com', 'paysafe', 'fiserv', 'cybersource_flex'].includes(psp) && ['production', 'sandbox'].includes(environment);
|
|
21
24
|
}
|
|
22
25
|
export function preparationEndpoint(psp, environment) {
|
|
23
26
|
if (!validPreparationEnvironment(psp, environment))
|
|
24
27
|
throw new Error('unsupported_preparation_processor');
|
|
28
|
+
if (psp === 'cybersource_flex')
|
|
29
|
+
return cybersourceFlexPreparationUrl(environment);
|
|
25
30
|
if (psp === 'paysafe')
|
|
26
31
|
return paysafePreparationUrl(environment);
|
|
27
32
|
if (psp === 'fiserv')
|
|
@@ -90,6 +95,11 @@ function freshCardBody(psp, body) {
|
|
|
90
95
|
export function matchesPreparedRequest(psp, environment, requestUrl, method, body, headers) {
|
|
91
96
|
if (method.toUpperCase() !== 'POST' || !validPreparationEnvironment(psp, environment))
|
|
92
97
|
return false;
|
|
98
|
+
// CyberSource Flex: this environment's exact tokens URL, application/jwt with only the headers a
|
|
99
|
+
// browser adds beside it, and a Microform field iframe's JWE. The adapters claim only after the
|
|
100
|
+
// Flex gate verified the issuing field iframe's capture context against that JWE's key.
|
|
101
|
+
if (psp === 'cybersource_flex')
|
|
102
|
+
return isPreparedCybersourceFlexRequest(requestUrl, method.toUpperCase(), body ?? null, environment, headers);
|
|
93
103
|
if (psp === 'paysafe')
|
|
94
104
|
return isPreparedPaysafeRequest(requestUrl, method, body ?? null, environment, headers);
|
|
95
105
|
// Fiserv: that environment's card-capture endpoint exactly, the capture rules on the whole
|
package/dist/registry.d.ts
CHANGED
|
@@ -6,7 +6,12 @@
|
|
|
6
6
|
* site shares another. The list is served from the Agentcard API at runtime so
|
|
7
7
|
* integrators pick up new processors without shipping a release.
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* The shape of the card-bearing body. `jwe`: a compact JWE the processor's own card field
|
|
11
|
+
* sealed (CyberSource Flex), opaque to everyone but the processor; served only with the
|
|
12
|
+
* capability that reads its capture context.
|
|
13
|
+
*/
|
|
14
|
+
export type Encoding = 'json' | 'form' | 'jwe';
|
|
10
15
|
/**
|
|
11
16
|
* How a paused request gets its card. `token` (the default when absent): the
|
|
12
17
|
* cardholder's device calls the processor and the runtime replays the
|
|
@@ -76,10 +81,14 @@ export interface Recognizer {
|
|
|
76
81
|
mode?: CheckoutMode;
|
|
77
82
|
/**
|
|
78
83
|
* Dark launch: a capability name the API attaches to an entry it serves only
|
|
79
|
-
* to a client that declared it (?capabilities=)
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
84
|
+
* to a client that declared it (?capabilities=), from an org Agentcard
|
|
85
|
+
* enabled for the processor. Absent on every entry in BUILTIN_REGISTRY,
|
|
86
|
+
* because a gated entry is left out of the built-in fallback. Carried
|
|
87
|
+
* verbatim by syncRegistry for a client that does declare it
|
|
88
|
+
* (SUPPORTED_CAPABILITIES). authorize() refuses an entry whose capability
|
|
89
|
+
* this build does not list in SUPPORTED_CAPABILITIES
|
|
90
|
+
* (UnsupportedCapabilityError), which only a hand-built registry can hold.
|
|
91
|
+
* GMO names `gmo_shared_pk` and CyberSource Flex names `capture_context`.
|
|
83
92
|
*/
|
|
84
93
|
capability?: string;
|
|
85
94
|
/**
|
|
@@ -102,8 +111,9 @@ export interface Recognizer {
|
|
|
102
111
|
/**
|
|
103
112
|
* True when a processor's host environment is enforced: the API refuses a
|
|
104
113
|
* create whose host environment disagrees with the row's test/live nature, and
|
|
105
|
-
* the device sends only documented test cards to a sandbox host.
|
|
106
|
-
*
|
|
114
|
+
* the device sends only documented test cards to a sandbox host. GMO sets it
|
|
115
|
+
* (stg.token.mul-pay.jp is its test host), and as a dark entry it is never in
|
|
116
|
+
* BUILTIN_REGISTRY; carried verbatim by syncRegistry, and the SDK never acts
|
|
107
117
|
* on it.
|
|
108
118
|
*/
|
|
109
119
|
hostEnvironmentPinned?: boolean;
|
|
@@ -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: 26a574d3944a8fbf0c12ddc9378d2ae3772bd2cdc78f95a5db1b61c037ee5474
|
|
4
4
|
// src/deep-freeze.js
|
|
5
5
|
function deepFreeze(value) {
|
|
6
6
|
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
@@ -632,6 +632,32 @@ var PROCESSOR_DEFINITIONS = deepFreeze([
|
|
|
632
632
|
hostEnvironmentPinned: true,
|
|
633
633
|
encoding: "json",
|
|
634
634
|
passthroughHeaders: ["^x-mp-client-type$"]
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
psp: "cybersource_flex",
|
|
638
|
+
// CyberSource Flex Microform v2. ONE card-bearing request: a POST from a Microform field
|
|
639
|
+
// iframe (the loader picks the number or the securityCode iframe at random) to the capture
|
|
640
|
+
// context's flx.origin + flx.path, /flex/v2/tokens, sent as `application/jwt; charset=utf-8`
|
|
641
|
+
// with a 30 s XHR timeout. The body is a compact JWE the iframe seals under the context's own
|
|
642
|
+
// key, so it is opaque: no injector exists (injectCard and prepareDeviceReplay refuse this
|
|
643
|
+
// psp), and the device verifies the context, rebuilds the iframe's plaintext with the real
|
|
644
|
+
// card and seals it itself (cybersource-flex-replay.js). The same URL also carries Microform
|
|
645
|
+
// v0.11 and Flex API v2 direct traffic, so recognition is not coverage: the SDK creates only
|
|
646
|
+
// for a POST from a reviewed v2 field iframe whose fragment record it holds.
|
|
647
|
+
// Excluded on purpose: api/apitest.cybersource.com (server APIs, never a browser card),
|
|
648
|
+
// /flex/v1/tokens, /flex/v2/public-keys/*, /microform/bundle/* and flex.in.cybersource.com
|
|
649
|
+
// (it resolves but serves neither keys nor bundles). No other entry shares these hosts.
|
|
650
|
+
// `capability` names the capture-context sidecar a client must send on create (the reviewed
|
|
651
|
+
// "sidecar" negotiation term): the entry stays out of BUILTIN_REGISTRY, is served only to a
|
|
652
|
+
// client that declares it, and is off for every org until one is opted in. testflex is the
|
|
653
|
+
// sandbox host and the environment is pinned (S7): test kids and testflex only on sandbox rows.
|
|
654
|
+
capability: "capture_context",
|
|
655
|
+
match: "(?:test)?flex\\.cybersource\\.com/flex/v2/tokens(?![\\w/-])",
|
|
656
|
+
hosts: ["^flex\\.cybersource\\.com$", "^testflex\\.cybersource\\.com$"],
|
|
657
|
+
sandboxHosts: ["^testflex\\.cybersource\\.com$"],
|
|
658
|
+
hostEnvironmentPinned: true,
|
|
659
|
+
encoding: "jwe",
|
|
660
|
+
passthroughHeaders: []
|
|
635
661
|
}
|
|
636
662
|
]);
|
|
637
663
|
var PSP_RECOGNIZERS = deepFreeze(PROCESSOR_DEFINITIONS.map(({ compose, encryptedCardFields, ...definition }) => definition));
|
|
@@ -682,10 +708,19 @@ var WITHOUT_CHECKOUT_SESSIONS = Object.freeze({
|
|
|
682
708
|
var HEADER_NEVER_FORWARD = /^(cookie|set-cookie|authorization2|proxy-authorization|host|content-length|origin|referer)$/i;
|
|
683
709
|
var ALLOWED_MEDIA_TYPES = {
|
|
684
710
|
json: ["application/json", "text/plain"],
|
|
685
|
-
form: ["application/x-www-form-urlencoded"]
|
|
711
|
+
form: ["application/x-www-form-urlencoded"],
|
|
712
|
+
jwe: ["application/jwt"]
|
|
686
713
|
};
|
|
714
|
+
var JWE_CONTENT_TYPE = "application/jwt; charset=utf-8";
|
|
687
715
|
function contentTypeFor(pspOrEntry, headers) {
|
|
688
716
|
const rec = trustedClientRecognizer(pspOrEntry);
|
|
717
|
+
if (rec.encoding === "jwe") {
|
|
718
|
+
const captured = Object.entries(headers || {}).find(([k]) => /^content-type$/i.test(k));
|
|
719
|
+
const base2 = captured && typeof captured[1] === "string" ? captured[1].split(";")[0].trim().toLowerCase() : "";
|
|
720
|
+
if (!ALLOWED_MEDIA_TYPES.jwe.includes(base2))
|
|
721
|
+
throw new Error("Refusing to pay: this processor takes its sealed card only as application/jwt.");
|
|
722
|
+
return JWE_CONTENT_TYPE;
|
|
723
|
+
}
|
|
689
724
|
const encoding = rec && rec.encoding === "form" ? "form" : "json";
|
|
690
725
|
const allowed = ALLOWED_MEDIA_TYPES[encoding];
|
|
691
726
|
const fallback = allowed[0];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": 1,
|
|
3
3
|
"catalog_version": "2026-09-15.1",
|
|
4
|
-
"catalog_sha256": "
|
|
4
|
+
"catalog_sha256": "927bdc284703286962911cd6d9c13f6b2117f5a177db39c06eca506924f81db1",
|
|
5
5
|
"baseline_version": "kernel-native-docs-2026-09-11.1",
|
|
6
6
|
"baseline_sha256": "d86722f49633d8223fccae54cd3d485df4375aee06aa156a273cc689b7c8507c",
|
|
7
7
|
"native_build": null,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-cards/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "Agentcard's SDK: one client, Agentcard, with two modules. checkout pauses a browser purchase and pays it with the person's own card; voice connects a person to your product once and approves a purchase by voice inside it. Card data never enters your process.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"_comment_build": "The public SDK keeps zero runtime dependencies. Its build vendors deterministic metadata and substitution artifacts from the internal payment core, and the voice streaming door from packages/voice/src/core (the phone package, @agent-cards/voice, ships it to phones); TypeScript remains pinned.",
|
|
28
28
|
"build": "node ../payment-core/scripts/build.mjs && node scripts/generate-payment-core.mjs && node scripts/generate-voice-stream.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 pre-claim.test.mjs autopilot.test.mjs stripe-checkout.test.mjs payment-core.test.mjs prepared-processor.test.mjs merchant-hosted.test.mjs merchant-total.test.mjs sandbox-declaration.test.mjs minimum-delay.test.mjs paysafe.test.mjs payu.test.mjs attachment.test.mjs worker-targets.test.mjs mercado-checkout.test.mjs mercado-polling.test.mjs voice.test.mjs agentcard.test.mjs buy.test.mjs readme.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
|
-
"test:browser": "node browser.test.mjs && node stripe-browser.test.mjs && node preparation-browser.test.mjs && node checkout-com-browser.test.mjs && node paysafe-preparation-browser.test.mjs && node owned-shop-browser.test.mjs && node spreedly-browser.test.mjs && node worker-browser.test.mjs && node adyen-merchant-hosted-browser.test.mjs && node fiserv-browser.test.mjs",
|
|
30
|
+
"test": "node test.mjs && node --test lifecycle.test.mjs merchant-abort.test.mjs preparation.test.mjs braintree.test.mjs pre-claim.test.mjs autopilot.test.mjs stripe-checkout.test.mjs payment-core.test.mjs prepared-processor.test.mjs merchant-hosted.test.mjs merchant-total.test.mjs sandbox-declaration.test.mjs minimum-delay.test.mjs paysafe.test.mjs payu.test.mjs attachment.test.mjs worker-targets.test.mjs mercado-checkout.test.mjs mercado-polling.test.mjs voice.test.mjs agentcard.test.mjs buy.test.mjs readme.test.mjs gmo.test.mjs cybersource-flex.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
|
+
"test:browser": "node browser.test.mjs && node stripe-browser.test.mjs && node preparation-browser.test.mjs && node checkout-com-browser.test.mjs && node paysafe-preparation-browser.test.mjs && node owned-shop-browser.test.mjs && node spreedly-browser.test.mjs && node worker-browser.test.mjs && node adyen-merchant-hosted-browser.test.mjs && node fiserv-browser.test.mjs && node gmo-browser.test.mjs && node cybersource-flex-browser.test.mjs",
|
|
32
32
|
"check:payment-core": "node scripts/generate-payment-core.mjs --check",
|
|
33
33
|
"check:voice-stream": "node scripts/generate-voice-stream.mjs --check",
|
|
34
34
|
"test:preflight": "node --test preflight-package.test.mjs preflight-collector.test.mjs kernel-native-qualification.test.mjs",
|