@agent-cards/checkout 0.13.0 → 0.15.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 +1 -0
- package/README.md +24 -4
- package/dist/adyen.generated.d.ts +24 -0
- package/dist/adyen.generated.js +64 -0
- package/dist/builtin-registry.generated.js +1 -1
- package/dist/client.d.ts +3 -1
- package/dist/client.js +5 -5
- package/dist/preflight-capabilities.generated.d.ts +65 -2
- package/dist/preflight-capabilities.generated.js +102 -2
- package/dist/preflight-catalog.json +150 -2
- package/dist/preflight-schemas.json +6 -0
- package/dist/preflight.generated.d.ts +65 -2
- package/dist/preflight.generated.js +2 -2
- package/dist/prepared-processor.d.ts +5 -2
- package/dist/prepared-processor.js +16 -3
- package/dist/spreedly.generated.d.ts +10 -0
- package/dist/spreedly.generated.js +332 -0
- package/dist/stripe-checkout.generated.js +9 -1
- package/examples/preflight/kernel-native/inventory.json +10 -1
- package/package.json +2 -2
|
@@ -1,20 +1,29 @@
|
|
|
1
|
+
import { adyenPreparationUrl, isPreparedAdyenRequest } from './adyen.generated.js';
|
|
1
2
|
import { braintreeEnvironment, isPreparedBraintreeRequest, readTokenizationJson } from './braintree.js';
|
|
2
3
|
import { isPreparedRecurlyRequest } from './recurly.generated.js';
|
|
3
|
-
|
|
4
|
+
import { isPreparedSpreedlyRequest, isSpreedlyTokenRequest, SPREEDLY_TOKEN_ENDPOINT } from './spreedly.generated.js';
|
|
5
|
+
export function preparationMode(psp) {
|
|
6
|
+
return psp === 'adyen' ? 'cse' : 'token';
|
|
7
|
+
}
|
|
8
|
+
/** Shared endpoint processors cannot attest test/live mode from their URL or key prefix. Adyen can: test and live are separate hosts and key prefixes. */
|
|
4
9
|
export function validPreparationEnvironment(psp, environment) {
|
|
5
|
-
if (psp === 'bambora' || psp === 'mercado_pago' || psp === 'recurly')
|
|
10
|
+
if (psp === 'bambora' || psp === 'mercado_pago' || psp === 'recurly' || psp === 'spreedly')
|
|
6
11
|
return environment === 'shared';
|
|
7
|
-
return ['square', 'braintree', 'worldpay'].includes(psp) && ['production', 'sandbox'].includes(environment);
|
|
12
|
+
return ['square', 'braintree', 'worldpay', 'adyen'].includes(psp) && ['production', 'sandbox'].includes(environment);
|
|
8
13
|
}
|
|
9
14
|
export function preparationEndpoint(psp, environment) {
|
|
10
15
|
if (!validPreparationEnvironment(psp, environment))
|
|
11
16
|
throw new Error('unsupported_preparation_processor');
|
|
17
|
+
if (psp === 'adyen')
|
|
18
|
+
return adyenPreparationUrl(environment);
|
|
12
19
|
if (psp === 'bambora')
|
|
13
20
|
return 'https://api.bam.shift4api.net/scripts/tokenization/tokens';
|
|
14
21
|
if (psp === 'mercado_pago')
|
|
15
22
|
return 'https://api.mercadopago.com/v1/card_tokens';
|
|
16
23
|
if (psp === 'recurly')
|
|
17
24
|
return 'https://api.recurly.com/js/v1/token';
|
|
25
|
+
if (psp === 'spreedly')
|
|
26
|
+
return SPREEDLY_TOKEN_ENDPOINT;
|
|
18
27
|
if (psp === 'worldpay')
|
|
19
28
|
return environment === 'production'
|
|
20
29
|
? 'https://access.worldpay.com/sessions/card' : 'https://try.access.worldpay.com/sessions/card';
|
|
@@ -67,8 +76,12 @@ function freshCardBody(psp, body) {
|
|
|
67
76
|
export function matchesPreparedRequest(psp, environment, requestUrl, method, body) {
|
|
68
77
|
if (method.toUpperCase() !== 'POST' || !validPreparationEnvironment(psp, environment))
|
|
69
78
|
return false;
|
|
79
|
+
if (psp === 'adyen')
|
|
80
|
+
return isPreparedAdyenRequest(requestUrl, method, body ?? null, environment);
|
|
70
81
|
if (psp === 'braintree')
|
|
71
82
|
return braintreeEnvironment(requestUrl) === environment && isPreparedBraintreeRequest(body ?? null);
|
|
83
|
+
if (psp === 'spreedly')
|
|
84
|
+
return isSpreedlyTokenRequest(requestUrl, method) && isPreparedSpreedlyRequest(body ?? null);
|
|
72
85
|
try {
|
|
73
86
|
const request = new URL(requestUrl), endpoint = new URL(preparationEndpoint(psp, environment));
|
|
74
87
|
if (request.username || request.password || request.hash)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
declare var SPREEDLY_TOKEN_ENDPOINT: string;
|
|
2
|
+
declare function isSpreedlyTokenRequest(url: any, method?: string): boolean;
|
|
3
|
+
declare function isPreparedSpreedlyRequest(body: any): boolean;
|
|
4
|
+
declare function isSpreedlyRequest(request: any): boolean;
|
|
5
|
+
declare function injectSpreedlyCard(body: any, card: any): {
|
|
6
|
+
body: string;
|
|
7
|
+
where: string[];
|
|
8
|
+
};
|
|
9
|
+
declare function sanitizeSpreedlyTokenResponse(body: any): string;
|
|
10
|
+
export { SPREEDLY_TOKEN_ENDPOINT, injectSpreedlyCard, isPreparedSpreedlyRequest, isSpreedlyRequest, isSpreedlyTokenRequest, sanitizeSpreedlyTokenResponse };
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// Generated from @agent-cards/payment-core. Do not edit.
|
|
3
|
+
// artifact-sha256: bd953f414724afdcc2930f895f106fbc908b78875358b33d01c0ee55985b9a29
|
|
4
|
+
// src/spreedly.js
|
|
5
|
+
var SPREEDLY_TOKEN_ENDPOINT = "https://core.spreedly.com/v1/payment_methods/restricted.json";
|
|
6
|
+
var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
7
|
+
var owns = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
8
|
+
var exact = (pattern, value) => typeof value === "string" && pattern.exec(value)?.[0] === value;
|
|
9
|
+
var text = (value, max = 1024) => typeof value === "string" && value.length <= max && !/[\u0000-\u001f\u007f]/.test(value);
|
|
10
|
+
var id = (value) => exact(/^[A-Za-z0-9_-]{1,128}$/, value);
|
|
11
|
+
var keys = (value, allowed) => record(value) && Object.keys(value).every((key) => allowed.includes(key));
|
|
12
|
+
var digits = (value, min, max) => typeof value === "string" && value.length >= min && value.length <= max && !/[^0-9]/.test(value);
|
|
13
|
+
var month = (value) => (Number.isInteger(value) || digits(value, 1, 2)) && Number(value) >= 1 && Number(value) <= 12;
|
|
14
|
+
var year = (value) => (Number.isInteger(value) || digits(value, 2, 4)) && (Number(value) >= 0 && Number(value) <= 99 || Number(value) >= 2e3 && Number(value) <= 9999);
|
|
15
|
+
var CARD_TEXT = [
|
|
16
|
+
"first_name",
|
|
17
|
+
"last_name",
|
|
18
|
+
"full_name",
|
|
19
|
+
"email",
|
|
20
|
+
"address1",
|
|
21
|
+
"address2",
|
|
22
|
+
"city",
|
|
23
|
+
"state",
|
|
24
|
+
"zip",
|
|
25
|
+
"country",
|
|
26
|
+
"phone_number",
|
|
27
|
+
"company",
|
|
28
|
+
"shipping_address1",
|
|
29
|
+
"shipping_address2",
|
|
30
|
+
"shipping_city",
|
|
31
|
+
"shipping_state",
|
|
32
|
+
"shipping_zip",
|
|
33
|
+
"shipping_country",
|
|
34
|
+
"shipping_phone_number"
|
|
35
|
+
];
|
|
36
|
+
var AUTH = ["nonce", "timestamp", "certificate_token", "signature"];
|
|
37
|
+
var CARD_TYPES = /* @__PURE__ */ new Set([
|
|
38
|
+
"visa",
|
|
39
|
+
"master",
|
|
40
|
+
"american_express",
|
|
41
|
+
"diners_club",
|
|
42
|
+
"discover",
|
|
43
|
+
"jcb",
|
|
44
|
+
"maestro",
|
|
45
|
+
"maestro_no_luhn",
|
|
46
|
+
"elo",
|
|
47
|
+
"carnet",
|
|
48
|
+
"dankort",
|
|
49
|
+
"alelo",
|
|
50
|
+
"cabal",
|
|
51
|
+
"naranja",
|
|
52
|
+
"unionpay",
|
|
53
|
+
"alia",
|
|
54
|
+
"creditel",
|
|
55
|
+
"confiable",
|
|
56
|
+
"synchrony",
|
|
57
|
+
"routex",
|
|
58
|
+
"mada",
|
|
59
|
+
"passcard",
|
|
60
|
+
"edenred",
|
|
61
|
+
"anda",
|
|
62
|
+
"tarjeta_d",
|
|
63
|
+
"sodexo",
|
|
64
|
+
"sodexo_no_luhn",
|
|
65
|
+
"panal",
|
|
66
|
+
"verve",
|
|
67
|
+
"tuya",
|
|
68
|
+
"uatp",
|
|
69
|
+
"patagonia_365",
|
|
70
|
+
"tarjeta_sol",
|
|
71
|
+
"tarjeta_unica",
|
|
72
|
+
"consumax",
|
|
73
|
+
"tarjeta_fertil",
|
|
74
|
+
"favacard",
|
|
75
|
+
"elebar",
|
|
76
|
+
"tarjeta_axis",
|
|
77
|
+
"tarjeta_plan_platino",
|
|
78
|
+
"tarjeta_fiel",
|
|
79
|
+
"copeplus",
|
|
80
|
+
"tarjeta_credimas",
|
|
81
|
+
"tarjeta_local",
|
|
82
|
+
"tarjeta_sucredito",
|
|
83
|
+
"sidecreer",
|
|
84
|
+
"cliper",
|
|
85
|
+
"centrocard",
|
|
86
|
+
"wex",
|
|
87
|
+
"codensa"
|
|
88
|
+
]);
|
|
89
|
+
var panLike = (value) => /(?:[0-9][ _.:-]*){12,}/.test(value);
|
|
90
|
+
var opaqueId = (value) => id(value) && /[A-Za-z]/.test(value) && !panLike(value);
|
|
91
|
+
function readJson(body) {
|
|
92
|
+
if (typeof body !== "string" || !body || body.length > 65536)
|
|
93
|
+
return null;
|
|
94
|
+
let at = 0, nodes = 0;
|
|
95
|
+
const fail = () => {
|
|
96
|
+
throw new Error("invalid_spreedly_json");
|
|
97
|
+
};
|
|
98
|
+
const space = () => {
|
|
99
|
+
while (" \r\n".includes(body[at] ?? "\0"))
|
|
100
|
+
at++;
|
|
101
|
+
};
|
|
102
|
+
const string = () => {
|
|
103
|
+
space();
|
|
104
|
+
const start = at;
|
|
105
|
+
if (body[at++] !== '"')
|
|
106
|
+
fail();
|
|
107
|
+
while (at < body.length) {
|
|
108
|
+
const char = body[at++];
|
|
109
|
+
if (char === "\\") {
|
|
110
|
+
at++;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (char === '"')
|
|
114
|
+
return JSON.parse(body.slice(start, at));
|
|
115
|
+
}
|
|
116
|
+
return fail();
|
|
117
|
+
};
|
|
118
|
+
const value = (depth) => {
|
|
119
|
+
if (depth > 12 || ++nodes > 1e3)
|
|
120
|
+
fail();
|
|
121
|
+
space();
|
|
122
|
+
const char = body[at];
|
|
123
|
+
if (char === '"')
|
|
124
|
+
return string();
|
|
125
|
+
if (char === "{") {
|
|
126
|
+
at++;
|
|
127
|
+
const result = /* @__PURE__ */ Object.create(null), seen = /* @__PURE__ */ new Set();
|
|
128
|
+
space();
|
|
129
|
+
if (body[at] === "}") {
|
|
130
|
+
at++;
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
while (true) {
|
|
134
|
+
const key = string();
|
|
135
|
+
if (seen.has(key) || ["__proto__", "prototype", "constructor"].includes(key))
|
|
136
|
+
fail();
|
|
137
|
+
seen.add(key);
|
|
138
|
+
space();
|
|
139
|
+
if (body[at++] !== ":")
|
|
140
|
+
fail();
|
|
141
|
+
result[key] = value(depth + 1);
|
|
142
|
+
space();
|
|
143
|
+
const next = body[at++];
|
|
144
|
+
if (next === "}")
|
|
145
|
+
return result;
|
|
146
|
+
if (next !== ",")
|
|
147
|
+
fail();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (char === "[") {
|
|
151
|
+
at++;
|
|
152
|
+
const result = [];
|
|
153
|
+
space();
|
|
154
|
+
if (body[at] === "]") {
|
|
155
|
+
at++;
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
while (true) {
|
|
159
|
+
result.push(value(depth + 1));
|
|
160
|
+
space();
|
|
161
|
+
const next = body[at++];
|
|
162
|
+
if (next === "]")
|
|
163
|
+
return result;
|
|
164
|
+
if (next !== ",")
|
|
165
|
+
fail();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
for (const literal of ["true", "false", "null"]) {
|
|
169
|
+
if (body.startsWith(literal, at)) {
|
|
170
|
+
at += literal.length;
|
|
171
|
+
return JSON.parse(literal);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
const number = /^-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/.exec(body.slice(at));
|
|
175
|
+
if (!number)
|
|
176
|
+
fail();
|
|
177
|
+
at += number[0].length;
|
|
178
|
+
const parsed = Number(number[0]);
|
|
179
|
+
if (!Number.isFinite(parsed))
|
|
180
|
+
fail();
|
|
181
|
+
return parsed;
|
|
182
|
+
};
|
|
183
|
+
try {
|
|
184
|
+
const parsed = value(0);
|
|
185
|
+
space();
|
|
186
|
+
return at === body.length && record(parsed) ? parsed : null;
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function isSpreedlyTokenRequest(url, method = "POST") {
|
|
193
|
+
if (method !== "POST" || typeof url !== "string" || !url.startsWith(SPREEDLY_TOKEN_ENDPOINT + "?"))
|
|
194
|
+
return false;
|
|
195
|
+
try {
|
|
196
|
+
const parsed = new URL(url);
|
|
197
|
+
if (parsed.href !== url || parsed.origin + parsed.pathname !== SPREEDLY_TOKEN_ENDPOINT || parsed.hash)
|
|
198
|
+
return false;
|
|
199
|
+
const seen = /* @__PURE__ */ new Set();
|
|
200
|
+
for (const pair of parsed.search.slice(1).split("&")) {
|
|
201
|
+
const separator = pair.indexOf("=");
|
|
202
|
+
const name = pair.slice(0, separator), value = pair.slice(separator + 1);
|
|
203
|
+
if (separator < 1 || seen.has(name))
|
|
204
|
+
return false;
|
|
205
|
+
seen.add(name);
|
|
206
|
+
if (name === "from" ? value !== "iframe" : name === "v" ? !exact(/^1\.[0-9]{1,4}$/, value) : name === "client" ? !exact(/^[A-Za-z0-9_.-]{1,64}$/, value) : true)
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
return seen.has("from") && seen.has("v");
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function preparedBody(body) {
|
|
216
|
+
const value = readJson(body);
|
|
217
|
+
if (!keys(value, ["environment_key", "payment_method", ...AUTH]) || !id(value.environment_key) || !keys(value.payment_method, ["credit_card", "allow_blank_name", "allow_expired_date", "metadata"]))
|
|
218
|
+
return null;
|
|
219
|
+
const suppliedAuth = AUTH.filter((key) => owns(value, key));
|
|
220
|
+
if (suppliedAuth.length && (suppliedAuth.length !== AUTH.length || !text(value.nonce) || !value.nonce || !(digits(value.timestamp, 1, 16) || Number.isSafeInteger(value.timestamp) && value.timestamp > 0) || !id(value.certificate_token) || !exact(/^[A-Za-z0-9+/=_-]{1,8192}$/, value.signature)))
|
|
221
|
+
return null;
|
|
222
|
+
const pm = value.payment_method, cc = pm.credit_card;
|
|
223
|
+
if (!keys(cc, ["number", "verification_value", "month", "year", "eligible_for_card_updater", ...CARD_TEXT]) || !digits(cc.number, 12, 19) || !digits(cc.verification_value, 3, 4) || !month(cc.month) || !year(cc.year) || CARD_TEXT.some((key) => owns(cc, key) && !text(cc[key])) || owns(cc, "eligible_for_card_updater") && cc.eligible_for_card_updater !== false)
|
|
224
|
+
return null;
|
|
225
|
+
if (owns(pm, "allow_blank_name") && typeof pm.allow_blank_name !== "boolean" || owns(pm, "allow_expired_date") && pm.allow_expired_date !== false)
|
|
226
|
+
return null;
|
|
227
|
+
if (owns(pm, "metadata") && (!record(pm.metadata) || Object.keys(pm.metadata).length > 20 || Object.entries(pm.metadata).some(([key, value2]) => !exact(/^[A-Za-z][A-Za-z0-9_-]{0,63}$/, key) || !(value2 === null || typeof value2 === "boolean" || Number.isFinite(value2) || text(value2)))))
|
|
228
|
+
return null;
|
|
229
|
+
return value;
|
|
230
|
+
}
|
|
231
|
+
function isPreparedSpreedlyRequest(body) {
|
|
232
|
+
return preparedBody(body) !== null;
|
|
233
|
+
}
|
|
234
|
+
function isSpreedlyRequest(request) {
|
|
235
|
+
if (!record(request) || request.method !== "POST" || !isSpreedlyTokenRequest(request.url, request.method) || !record(request.headers))
|
|
236
|
+
return false;
|
|
237
|
+
const body = preparedBody(request.body);
|
|
238
|
+
if (!body)
|
|
239
|
+
return false;
|
|
240
|
+
const headers = /* @__PURE__ */ new Map();
|
|
241
|
+
for (const [name, value] of Object.entries(request.headers)) {
|
|
242
|
+
const lower = name.toLowerCase();
|
|
243
|
+
if (headers.has(lower) || !text(value, 8192))
|
|
244
|
+
return false;
|
|
245
|
+
headers.set(lower, value);
|
|
246
|
+
}
|
|
247
|
+
return exact(/^application\/json(?:;\s*charset=utf-8)?$/i, headers.get("content-type")) && headers.get("spreedly-environment-key") === body.environment_key;
|
|
248
|
+
}
|
|
249
|
+
function injectSpreedlyCard(body, card) {
|
|
250
|
+
const value = preparedBody(body);
|
|
251
|
+
if (!value)
|
|
252
|
+
throw new Error("Refusing to pay: unsupported Spreedly new-card request.");
|
|
253
|
+
if (!card || !digits(card.number, 12, 19) || !digits(card.cvc, 3, 4) || !month(card.month) || !year(card.year)) {
|
|
254
|
+
throw new Error("Could not fill the card fields for Spreedly. Nothing was sent.");
|
|
255
|
+
}
|
|
256
|
+
const cc = value.payment_method.credit_card;
|
|
257
|
+
cc.number = card.number;
|
|
258
|
+
cc.verification_value = card.cvc;
|
|
259
|
+
cc.month = typeof cc.month === "number" ? Number(card.month) : String(card.month);
|
|
260
|
+
const selectedYear = String(card.year), nativeYear = String(cc.year);
|
|
261
|
+
const replacementYear = nativeYear.length === 2 && selectedYear.length === 4 ? selectedYear.slice(-2) : nativeYear.length === 4 && selectedYear.length === 2 ? "20" + selectedYear : selectedYear;
|
|
262
|
+
cc.year = typeof cc.year === "number" ? Number(replacementYear) : replacementYear;
|
|
263
|
+
return { body: JSON.stringify(value), where: ["number", "verification_value", "month", "year"].map((key) => "payment_method.credit_card." + key) };
|
|
264
|
+
}
|
|
265
|
+
function sanitizeSpreedlyTokenResponse(body) {
|
|
266
|
+
const value = readJson(body), transaction = value?.transaction, pm = transaction?.payment_method;
|
|
267
|
+
const fail = () => {
|
|
268
|
+
throw new Error("Invalid Spreedly token response.");
|
|
269
|
+
};
|
|
270
|
+
if (!record(transaction) || !record(pm) || transaction.succeeded !== true || transaction.transaction_type !== "AddPaymentMethod" || transaction.state !== "succeeded" || pm.payment_method_type !== "credit_card" || !opaqueId(pm.token))
|
|
271
|
+
return fail();
|
|
272
|
+
if (!text(pm.number, 32) || !exact(/^[Xx*]{8,15}[0-9]{4}$/, pm.number.replace(/-/g, "")) || !digits(pm.last_four_digits, 4, 4) || !pm.number.endsWith(pm.last_four_digits) || !exact(/^[Xx*]{3,4}$/, pm.verification_value) || !month(pm.month) || !year(pm.year))
|
|
273
|
+
return fail();
|
|
274
|
+
const safePm = {
|
|
275
|
+
token: pm.token,
|
|
276
|
+
payment_method_type: "credit_card",
|
|
277
|
+
number: pm.number,
|
|
278
|
+
verification_value: pm.verification_value,
|
|
279
|
+
last_four_digits: pm.last_four_digits,
|
|
280
|
+
month: pm.month,
|
|
281
|
+
year: pm.year
|
|
282
|
+
};
|
|
283
|
+
if (owns(pm, "card_type")) {
|
|
284
|
+
if (!CARD_TYPES.has(pm.card_type))
|
|
285
|
+
return fail();
|
|
286
|
+
safePm.card_type = pm.card_type;
|
|
287
|
+
}
|
|
288
|
+
if (owns(pm, "storage_state")) {
|
|
289
|
+
if (!["cached", "retained"].includes(pm.storage_state))
|
|
290
|
+
return fail();
|
|
291
|
+
safePm.storage_state = pm.storage_state;
|
|
292
|
+
}
|
|
293
|
+
if (owns(pm, "fingerprint")) {
|
|
294
|
+
if (!opaqueId(pm.fingerprint))
|
|
295
|
+
return fail();
|
|
296
|
+
safePm.fingerprint = pm.fingerprint;
|
|
297
|
+
}
|
|
298
|
+
for (const [key, width] of [["first_six_digits", 6], ["first_eight_digits", 8]]) {
|
|
299
|
+
if (owns(pm, key) && pm[key] !== null) {
|
|
300
|
+
if (!digits(pm[key], width, width))
|
|
301
|
+
return fail();
|
|
302
|
+
safePm[key] = pm[key];
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
for (const key of ["test", "eligible_for_card_updater"]) {
|
|
306
|
+
if (owns(pm, key)) {
|
|
307
|
+
if (typeof pm[key] !== "boolean")
|
|
308
|
+
return fail();
|
|
309
|
+
safePm[key] = pm[key];
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
for (const key of CARD_TEXT) {
|
|
313
|
+
if (!owns(pm, key))
|
|
314
|
+
continue;
|
|
315
|
+
if (pm[key] !== null && (!text(pm[key]) || panLike(pm[key])))
|
|
316
|
+
return fail();
|
|
317
|
+
safePm[key] = pm[key];
|
|
318
|
+
}
|
|
319
|
+
if (owns(pm, "errors")) {
|
|
320
|
+
if (!Array.isArray(pm.errors) || pm.errors.length)
|
|
321
|
+
return fail();
|
|
322
|
+
safePm.errors = [];
|
|
323
|
+
}
|
|
324
|
+
const safeTransaction = { succeeded: true, transaction_type: "AddPaymentMethod", state: "succeeded", payment_method: safePm };
|
|
325
|
+
if (owns(transaction, "token")) {
|
|
326
|
+
if (!opaqueId(transaction.token))
|
|
327
|
+
return fail();
|
|
328
|
+
safeTransaction.token = transaction.token;
|
|
329
|
+
}
|
|
330
|
+
return JSON.stringify({ transaction: safeTransaction });
|
|
331
|
+
}
|
|
332
|
+
export { SPREEDLY_TOKEN_ENDPOINT, injectSpreedlyCard, isPreparedSpreedlyRequest, isSpreedlyRequest, isSpreedlyTokenRequest, sanitizeSpreedlyTokenResponse };
|
|
@@ -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: 43d29486fe62b4f04eff7e737852d00589ab7fee366c25d863f25c2c0df54562
|
|
4
4
|
// src/definitions.js
|
|
5
5
|
function deepFreeze(value) {
|
|
6
6
|
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
@@ -11,6 +11,14 @@ function deepFreeze(value) {
|
|
|
11
11
|
return value;
|
|
12
12
|
}
|
|
13
13
|
var PROCESSOR_DEFINITIONS = deepFreeze([
|
|
14
|
+
{
|
|
15
|
+
psp: "spreedly",
|
|
16
|
+
// Native iframe new-card tokenization only; spreedly.js pins the query and body.
|
|
17
|
+
match: "core\\.spreedly\\.com/v1/payment_methods/restricted\\.json",
|
|
18
|
+
hosts: ["^core\\.spreedly\\.com$"],
|
|
19
|
+
encoding: "json",
|
|
20
|
+
passthroughHeaders: ["^spreedly-environment-key$"]
|
|
21
|
+
},
|
|
14
22
|
{
|
|
15
23
|
psp: "shopify",
|
|
16
24
|
match: "(checkout\\.pci\\.shopifyinc\\.com|deposit\\.[a-z0-9-]+\\.shopifycs\\.com)/sessions",
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": 1,
|
|
3
3
|
"catalog_version": "2026-09-15.1",
|
|
4
|
-
"catalog_sha256": "
|
|
4
|
+
"catalog_sha256": "e1bbae82b91134c8be5919fddd5d60ea56f6897b570f8ccb2f305cd5b0a1c085",
|
|
5
5
|
"baseline_version": "kernel-native-docs-2026-09-11.1",
|
|
6
6
|
"baseline_sha256": "d86722f49633d8223fccae54cd3d485df4375aee06aa156a273cc689b7c8507c",
|
|
7
7
|
"native_build": null,
|
|
8
8
|
"processors": [
|
|
9
|
+
{
|
|
10
|
+
"psp": "spreedly",
|
|
11
|
+
"mode": "token",
|
|
12
|
+
"documentation": "not_documented",
|
|
13
|
+
"status": "unknown",
|
|
14
|
+
"limitations": [
|
|
15
|
+
"No adapter declaration was found in the pinned documentation. Native runtime evidence is missing."
|
|
16
|
+
]
|
|
17
|
+
},
|
|
9
18
|
{
|
|
10
19
|
"psp": "shopify",
|
|
11
20
|
"mode": "token",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-cards/checkout",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.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",
|
|
@@ -28,7 +28,7 @@
|
|
|
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
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
|
-
"test:browser": "node browser.test.mjs && node stripe-browser.test.mjs && node preparation-browser.test.mjs && node owned-shop-browser.test.mjs",
|
|
31
|
+
"test:browser": "node browser.test.mjs && node stripe-browser.test.mjs && node preparation-browser.test.mjs && node owned-shop-browser.test.mjs && node spreedly-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",
|
|
34
34
|
"test:preflight:browser": "node preflight-browser.test.mjs",
|