@agent-cards/sdk 0.23.11 → 0.23.13
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 +12 -0
- package/LICENSE +38 -0
- package/PREFLIGHT.md +2 -0
- package/README.md +9 -7
- package/dist/builtin-registry.generated.js +1 -1
- package/dist/card-fields.generated.js +74 -1
- package/dist/cdp.js +63 -10
- package/dist/client.d.ts +24 -7
- package/dist/client.js +135 -16
- package/dist/lifecycle.d.ts +11 -2
- package/dist/lifecycle.js +4 -1
- package/dist/paddle-vgs-pay.d.ts +55 -0
- package/dist/paddle-vgs-pay.js +115 -0
- package/dist/paddle-vgs.generated.d.ts +78 -0
- package/dist/paddle-vgs.generated.js +408 -0
- package/dist/payrails.generated.js +8 -12
- package/dist/paysafe.generated.d.ts +5 -7
- package/dist/paysafe.generated.js +50 -18
- package/dist/pre-claim.d.ts +8 -0
- package/dist/pre-claim.js +48 -1
- package/dist/prepared-processor.d.ts +12 -4
- package/dist/prepared-processor.js +17 -5
- package/dist/primer.generated.js +90 -17
- package/dist/stripe-checkout.generated.js +64 -3
- package/package.json +3 -3
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// Generated from @agent-cards/payment-core. Do not edit.
|
|
3
|
+
// artifact-sha256: f3437a15e11b72b9958179cc9610fdafb411cc5db76be536af62c08360a45575
|
|
4
|
+
// src/paddle-vgs.js
|
|
5
|
+
var PADDLE_VGS_PSP = "paddle_vgs";
|
|
6
|
+
var PADDLE_VGS_CAPABILITY = "paddle_vgs_cards";
|
|
7
|
+
var PADDLE_VGS_OPERATION = "paddle_vgs.card_request";
|
|
8
|
+
var PADDLE_VGS_CONTENT_TYPE = "application/vnd.api+json";
|
|
9
|
+
var PADDLE_VGS_CARDS_URLS = /* @__PURE__ */ Object.freeze({
|
|
10
|
+
production: "https://vault.paddle.com/cards",
|
|
11
|
+
sandbox: "https://sandbox-vault.paddle.com/cards"
|
|
12
|
+
});
|
|
13
|
+
var PADDLE_VGS_REFUSAL_CODES = /* @__PURE__ */ Object.freeze(["paddle_vgs_url_refused", "paddle_vgs_headers_refused", "paddle_vgs_body_unsupported"]);
|
|
14
|
+
var BODY_LIMIT = 4096;
|
|
15
|
+
var ROOT_KEYS = /* @__PURE__ */ Object.freeze(["data"]);
|
|
16
|
+
var DATA_KEYS = /* @__PURE__ */ Object.freeze(["type", "attributes"]);
|
|
17
|
+
var ATTRIBUTE_KEYS = /* @__PURE__ */ Object.freeze(["pan", "cvc", "exp_month", "exp_year", "cardholder"]);
|
|
18
|
+
var WHERE = /* @__PURE__ */ Object.freeze(["data.attributes.pan", "data.attributes.cvc", "data.attributes.exp_month", "data.attributes.exp_year"]);
|
|
19
|
+
var CARD_NUMBER = /^[0-9]{12,19}$/;
|
|
20
|
+
var SECURITY_CODE = /^[0-9]{3,4}$/;
|
|
21
|
+
var NAME_LIMIT = 256;
|
|
22
|
+
var CONTROL = /[\u0000-\u001f\u007f]/;
|
|
23
|
+
var PAN_LIKE = /(?:[0-9][ _.:-]*){12,}/;
|
|
24
|
+
var cardLikeName = (name) => (name.match(/[0-9]/g) ?? []).length >= 12;
|
|
25
|
+
var BEARER = /^Bearer [A-Za-z0-9_-]{8,512}\.([A-Za-z0-9_-]{8,4096})\.[A-Za-z0-9_-]{8,1024}$/;
|
|
26
|
+
var BEARER_LIFETIME_SECONDS = 1200;
|
|
27
|
+
var BASE64URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
28
|
+
var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
29
|
+
var sameKeys = (value, keys) => {
|
|
30
|
+
const own = Object.keys(value);
|
|
31
|
+
return own.length === keys.length && own.every((key, at) => key === keys[at]);
|
|
32
|
+
};
|
|
33
|
+
var refuse = (code) => Object.freeze({ verdict: "refuse", code });
|
|
34
|
+
var CARD = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
35
|
+
function base64UrlText(segment) {
|
|
36
|
+
let bits = 0;
|
|
37
|
+
let value = 0;
|
|
38
|
+
let escaped = "";
|
|
39
|
+
for (const character of segment) {
|
|
40
|
+
const sextet = BASE64URL.indexOf(character);
|
|
41
|
+
if (sextet < 0)
|
|
42
|
+
return null;
|
|
43
|
+
value = value << 6 | sextet;
|
|
44
|
+
bits += 6;
|
|
45
|
+
if (bits >= 8) {
|
|
46
|
+
bits -= 8;
|
|
47
|
+
escaped += "%" + (value >> bits & 255).toString(16).padStart(2, "0");
|
|
48
|
+
value &= (1 << bits) - 1;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
return decodeURIComponent(escaped);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function bearerClaims(authorization) {
|
|
59
|
+
const match = typeof authorization === "string" ? BEARER.exec(authorization) : null;
|
|
60
|
+
const text = match ? base64UrlText(match[1]) : null;
|
|
61
|
+
if (text === null)
|
|
62
|
+
return null;
|
|
63
|
+
try {
|
|
64
|
+
const claims = JSON.parse(text);
|
|
65
|
+
return record(claims) ? claims : null;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function bearerRunning(authorization, nowSeconds = Math.floor(Date.now() / 1e3)) {
|
|
72
|
+
const claims = bearerClaims(authorization);
|
|
73
|
+
if (!claims || !Number.isSafeInteger(claims.iat) || !Number.isSafeInteger(claims.exp))
|
|
74
|
+
return false;
|
|
75
|
+
return claims.exp > claims.iat && claims.exp - claims.iat <= BEARER_LIFETIME_SECONDS && claims.exp > nowSeconds;
|
|
76
|
+
}
|
|
77
|
+
function paddleVgsEnvironment(url) {
|
|
78
|
+
if (url === PADDLE_VGS_CARDS_URLS.production)
|
|
79
|
+
return "production";
|
|
80
|
+
if (url === PADDLE_VGS_CARDS_URLS.sandbox)
|
|
81
|
+
return "sandbox";
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
function isPaddleVgsCardsUrl(url) {
|
|
85
|
+
return paddleVgsEnvironment(url) !== null;
|
|
86
|
+
}
|
|
87
|
+
function readBody(body) {
|
|
88
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT)
|
|
89
|
+
return null;
|
|
90
|
+
let value;
|
|
91
|
+
try {
|
|
92
|
+
value = JSON.parse(body);
|
|
93
|
+
if (!record(value) || JSON.stringify(value) !== body)
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
function paddleVgsBodyVerdict(body) {
|
|
102
|
+
const value = readBody(body);
|
|
103
|
+
if (value === null || !sameKeys(value, ROOT_KEYS) || !record(value.data) || !sameKeys(value.data, DATA_KEYS) || value.data.type !== "cards" || !record(value.data.attributes) || !sameKeys(value.data.attributes, ATTRIBUTE_KEYS)) {
|
|
104
|
+
return refuse("paddle_vgs_body_unsupported");
|
|
105
|
+
}
|
|
106
|
+
const card = value.data.attributes;
|
|
107
|
+
const holder = card.cardholder;
|
|
108
|
+
if (typeof card.pan !== "string" || !CARD_NUMBER.test(card.pan) || typeof card.cvc !== "string" || !SECURITY_CODE.test(card.cvc) || !Number.isInteger(card.exp_month) || card.exp_month < 1 || card.exp_month > 12 || !Number.isInteger(card.exp_year) || card.exp_year < 0 || card.exp_year > 99 || !record(holder) || !sameKeys(holder, ["name"]) || typeof holder.name !== "string" || holder.name.length > NAME_LIMIT || CONTROL.test(holder.name) || cardLikeName(holder.name)) {
|
|
109
|
+
return refuse("paddle_vgs_body_unsupported");
|
|
110
|
+
}
|
|
111
|
+
return CARD;
|
|
112
|
+
}
|
|
113
|
+
function headerValue(headers, name) {
|
|
114
|
+
const found = Object.keys(headers).filter((key) => key.toLowerCase() === name);
|
|
115
|
+
return found.length === 1 && typeof headers[found[0]] === "string" ? headers[found[0]] : null;
|
|
116
|
+
}
|
|
117
|
+
function paddleVgsRequestRefusal(request) {
|
|
118
|
+
if (!record(request) || typeof request.method !== "string" || request.method.toUpperCase() !== "POST")
|
|
119
|
+
return "paddle_vgs_url_refused";
|
|
120
|
+
if (!isPaddleVgsCardsUrl(request.url))
|
|
121
|
+
return "paddle_vgs_url_refused";
|
|
122
|
+
const headers = record(request.headers) ? request.headers : {};
|
|
123
|
+
const contentType = headerValue(headers, "content-type");
|
|
124
|
+
const authorization = headerValue(headers, "authorization");
|
|
125
|
+
if (contentType === null || contentType.trim().toLowerCase() !== PADDLE_VGS_CONTENT_TYPE || authorization === null || !bearerRunning(authorization))
|
|
126
|
+
return "paddle_vgs_headers_refused";
|
|
127
|
+
const verdict = paddleVgsBodyVerdict(request.body);
|
|
128
|
+
return verdict.verdict === "card" ? null : verdict.code;
|
|
129
|
+
}
|
|
130
|
+
function isPreparedPaddleVgsRequest(url, method, body, environment, headers) {
|
|
131
|
+
return (environment === "production" || environment === "sandbox") && paddleVgsEnvironment(url) === environment && paddleVgsRequestRefusal({ url, method, headers, body }) === null;
|
|
132
|
+
}
|
|
133
|
+
var pin = (fields) => Object.freeze({
|
|
134
|
+
...fields,
|
|
135
|
+
origins: Object.freeze([...fields.origins]),
|
|
136
|
+
sellerClaim: fields.sellerClaim ? Object.freeze({ ...fields.sellerClaim }) : null
|
|
137
|
+
});
|
|
138
|
+
var PADDLE_VGS_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
|
|
139
|
+
pin({ id: "rectangle_pro", merchant: "Rectangle Pro", origins: ["https://rectangleapp.com"], sellerClaim: null })
|
|
140
|
+
]);
|
|
141
|
+
function paddleVgsMerchantPin(merchantOrigin, pins = PADDLE_VGS_MERCHANT_PINS) {
|
|
142
|
+
if (typeof merchantOrigin !== "string" || !Array.isArray(pins))
|
|
143
|
+
return null;
|
|
144
|
+
return pins.find((entry) => !!entry && Array.isArray(entry.origins) && entry.origins.includes(merchantOrigin)) ?? null;
|
|
145
|
+
}
|
|
146
|
+
function paddleVgsMerchantRefusal(environment, merchantOrigin, authorization, pins = PADDLE_VGS_MERCHANT_PINS) {
|
|
147
|
+
if (environment === "sandbox")
|
|
148
|
+
return null;
|
|
149
|
+
if (environment !== "production")
|
|
150
|
+
return "unsupported_environment";
|
|
151
|
+
const found = paddleVgsMerchantPin(merchantOrigin, pins);
|
|
152
|
+
if (!found)
|
|
153
|
+
return "paddle_vgs_merchant_unreviewed";
|
|
154
|
+
if (found.sellerClaim && authorization !== void 0) {
|
|
155
|
+
const claims = bearerClaims(authorization);
|
|
156
|
+
if (!claims || claims[found.sellerClaim.name] !== found.sellerClaim.value)
|
|
157
|
+
return "paddle_vgs_seller_unreviewed";
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
function paddleVgsSellerClaimsPinned(pins = PADDLE_VGS_MERCHANT_PINS) {
|
|
162
|
+
return Array.isArray(pins) && pins.length > 0 && pins.every((entry) => !!entry && !!entry.sellerClaim && typeof entry.sellerClaim.name === "string" && entry.sellerClaim.name !== "" && typeof entry.sellerClaim.value === "string" && entry.sellerClaim.value !== "");
|
|
163
|
+
}
|
|
164
|
+
var REFUSAL_MESSAGES = /* @__PURE__ */ Object.freeze({
|
|
165
|
+
paddle_vgs_url_refused: "Refusing to pay: this Paddle card request does not go to Paddle's card vault exactly as Paddle's checkout sends it. Nothing was sent.",
|
|
166
|
+
paddle_vgs_headers_refused: "Refusing to pay: this Paddle card request does not carry the checkout's own headers. Nothing was sent.",
|
|
167
|
+
paddle_vgs_body_unsupported: "Refusing to pay: this is not the card request of Paddle's checkout. Nothing was sent."
|
|
168
|
+
});
|
|
169
|
+
function paddleVgsRefusalMessage(code) {
|
|
170
|
+
return Object.prototype.hasOwnProperty.call(REFUSAL_MESSAGES, code) ? REFUSAL_MESSAGES[code] : REFUSAL_MESSAGES.paddle_vgs_body_unsupported;
|
|
171
|
+
}
|
|
172
|
+
var CARD_MISMATCH_REFUSAL = "Refusing to pay: this Paddle payment names a card expiry or network that is not your card's. Nothing was sent.";
|
|
173
|
+
var PADDLE_VGS_CARD_NETWORKS = /* @__PURE__ */ Object.freeze(["visa", "mastercard", "amex"]);
|
|
174
|
+
function cardNetwork(number) {
|
|
175
|
+
if (typeof number !== "string" || !CARD_NUMBER.test(number))
|
|
176
|
+
return null;
|
|
177
|
+
const two = Number(number.slice(0, 2));
|
|
178
|
+
const four = Number(number.slice(0, 4));
|
|
179
|
+
if (number[0] === "4")
|
|
180
|
+
return "visa";
|
|
181
|
+
if (two >= 51 && two <= 55 || four >= 2221 && four <= 2720)
|
|
182
|
+
return "mastercard";
|
|
183
|
+
if (two === 34 || two === 37)
|
|
184
|
+
return "amex";
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
function paddleVgsCardRefusal(body, card) {
|
|
188
|
+
const verdict = paddleVgsBodyVerdict(body);
|
|
189
|
+
if (verdict.verdict !== "card")
|
|
190
|
+
return verdict.code;
|
|
191
|
+
const attributes = JSON.parse(body).data.attributes;
|
|
192
|
+
const number = card ? String(card.number) : "";
|
|
193
|
+
const month = card ? Number(card.month) : NaN;
|
|
194
|
+
const year = card ? Number(card.year) % 100 : NaN;
|
|
195
|
+
const network = cardNetwork(number);
|
|
196
|
+
if (attributes.exp_month !== month || attributes.exp_year !== year || network === null || cardNetwork(attributes.pan) !== network) {
|
|
197
|
+
return "paddle_vgs_card_mismatch";
|
|
198
|
+
}
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
var storedBrand = (brand) => typeof brand === "string" && brand !== "" ? brand.toLowerCase() : null;
|
|
202
|
+
function paddleVgsStoredCardRefusal(brand) {
|
|
203
|
+
const network = storedBrand(brand);
|
|
204
|
+
return network === null || PADDLE_VGS_CARD_NETWORKS.includes(network) ? null : "paddle_vgs_card_unsupported";
|
|
205
|
+
}
|
|
206
|
+
function paddleVgsTypedCardRefusal(body, stored) {
|
|
207
|
+
const verdict = paddleVgsBodyVerdict(body);
|
|
208
|
+
if (verdict.verdict !== "card")
|
|
209
|
+
return verdict.code;
|
|
210
|
+
const attributes = JSON.parse(body).data.attributes;
|
|
211
|
+
const card = stored && typeof stored === "object" ? stored : {};
|
|
212
|
+
if (Number.isInteger(card.expiryMonth) && attributes.exp_month !== card.expiryMonth)
|
|
213
|
+
return "paddle_vgs_card_mismatch";
|
|
214
|
+
if (Number.isInteger(card.expiryYear) && attributes.exp_year !== card.expiryYear % 100)
|
|
215
|
+
return "paddle_vgs_card_mismatch";
|
|
216
|
+
const brand = storedBrand(card.brand);
|
|
217
|
+
if (brand !== null && cardNetwork(attributes.pan) !== brand)
|
|
218
|
+
return "paddle_vgs_card_mismatch";
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
function injectPaddleVgsCard(body, card) {
|
|
222
|
+
const verdict = paddleVgsBodyVerdict(body);
|
|
223
|
+
if (verdict.verdict !== "card")
|
|
224
|
+
throw new Error(paddleVgsRefusalMessage(verdict.code));
|
|
225
|
+
const number = card ? String(card.number) : "";
|
|
226
|
+
const cvc = card ? String(card.cvc) : "";
|
|
227
|
+
const month = card ? Number(card.month) : NaN;
|
|
228
|
+
const year = card ? Number(card.year) % 100 : NaN;
|
|
229
|
+
if (!CARD_NUMBER.test(number) || !SECURITY_CODE.test(cvc) || !Number.isInteger(month) || month < 1 || month > 12 || !Number.isInteger(year) || year < 0) {
|
|
230
|
+
throw new Error("Could not fill the card fields for Paddle. Nothing was sent.");
|
|
231
|
+
}
|
|
232
|
+
if (paddleVgsCardRefusal(body, { number, month, year }) !== null)
|
|
233
|
+
throw new Error(CARD_MISMATCH_REFUSAL);
|
|
234
|
+
const value = JSON.parse(body);
|
|
235
|
+
const attributes = value.data.attributes;
|
|
236
|
+
attributes.pan = number;
|
|
237
|
+
attributes.cvc = cvc;
|
|
238
|
+
attributes.exp_month = month;
|
|
239
|
+
attributes.exp_year = year;
|
|
240
|
+
return { body: JSON.stringify(value), where: [...WHERE] };
|
|
241
|
+
}
|
|
242
|
+
var ANSWER_LIMIT = 65536;
|
|
243
|
+
var STORED_CARD_ID = /^[A-Za-z0-9_-]{1,128}$/;
|
|
244
|
+
var REFUSAL_CODE = /^[A-Za-z0-9_.:-]{1,64}$/;
|
|
245
|
+
var MAX_CODE_DIGITS = 11;
|
|
246
|
+
function readAnswer(text) {
|
|
247
|
+
if (typeof text !== "string" || text === "" || text.length > ANSWER_LIMIT)
|
|
248
|
+
return null;
|
|
249
|
+
try {
|
|
250
|
+
const value = JSON.parse(text);
|
|
251
|
+
return record(value) ? value : null;
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
var isStoredCardId = (id) => typeof id === "string" && STORED_CARD_ID.test(id) && /[A-Za-z]/.test(id) && !PAN_LIKE.test(id);
|
|
258
|
+
function storedCardId(answer) {
|
|
259
|
+
const data = answer && answer.data;
|
|
260
|
+
if (!record(data) || data.type !== "cards")
|
|
261
|
+
return null;
|
|
262
|
+
return isStoredCardId(data.id) ? data.id : null;
|
|
263
|
+
}
|
|
264
|
+
var boundedCode = (value) => typeof value === "string" && REFUSAL_CODE.test(value) && (value.match(/[0-9]/g) ?? []).length <= MAX_CODE_DIGITS ? value : null;
|
|
265
|
+
function paddleVgsRefusalCode(text) {
|
|
266
|
+
const answer = readAnswer(text);
|
|
267
|
+
if (!answer)
|
|
268
|
+
return null;
|
|
269
|
+
const first = Array.isArray(answer.errors) && record(answer.errors[0]) ? answer.errors[0] : null;
|
|
270
|
+
return boundedCode(first && first.error_code) ?? boundedCode(first && first.code) ?? boundedCode(answer.error_code) ?? boundedCode(answer.code);
|
|
271
|
+
}
|
|
272
|
+
function paddleVgsAnswerOutcome(status, text, card) {
|
|
273
|
+
if (!Number.isInteger(status))
|
|
274
|
+
return { outcome: "unknown", reason: "paddle_vgs_unconfirmed" };
|
|
275
|
+
if (status >= 500)
|
|
276
|
+
return { outcome: "unknown", reason: "server_error" };
|
|
277
|
+
if (status >= 400 && status < 500)
|
|
278
|
+
return { outcome: "refused", code: paddleVgsRefusalCode(text) ?? `http_${status}` };
|
|
279
|
+
if (status !== 200 && status !== 201)
|
|
280
|
+
return { outcome: "unknown", reason: "paddle_vgs_unconfirmed" };
|
|
281
|
+
const id = storedCardId(readAnswer(text));
|
|
282
|
+
if (id === null)
|
|
283
|
+
return { outcome: "unknown", reason: "paddle_vgs_unsafe_response" };
|
|
284
|
+
const number = card ? String(card.number).replace(/[^0-9]/g, "") : "";
|
|
285
|
+
if (number && id.replace(/[^0-9]/g, "").includes(number))
|
|
286
|
+
return { outcome: "unknown", reason: "paddle_vgs_unsafe_response" };
|
|
287
|
+
return { outcome: "approved", body: JSON.stringify({ data: { type: "cards", id } }) };
|
|
288
|
+
}
|
|
289
|
+
var PADDLE_VGS_CARD_ID_WINDOW_MS = 6e4;
|
|
290
|
+
var PAY_URL = /^https:\/\/(sandbox-)?checkout-service\.paddle\.com\/(checkout|transaction-checkout)\/[A-Za-z0-9_-]{1,64}\/pay$/;
|
|
291
|
+
function paddleVgsPayTarget(url) {
|
|
292
|
+
const match = typeof url === "string" ? PAY_URL.exec(url) : null;
|
|
293
|
+
return match ? Object.freeze({ environment: match[1] ? "sandbox" : "production", line: match[2] === "checkout" ? "classic" : "billing" }) : null;
|
|
294
|
+
}
|
|
295
|
+
function paddleVgsPayCarriesStoredCard(body) {
|
|
296
|
+
if (typeof body !== "string")
|
|
297
|
+
return true;
|
|
298
|
+
try {
|
|
299
|
+
return JSON.stringify(JSON.parse(body)).includes('"vgs_card"');
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
var FRAME_BRANDS = /* @__PURE__ */ Object.freeze(["visa", "master", "american_express", "discover", "diners_club", "jcb", "maestro", "dankort", "unionpay", "unknown"]);
|
|
306
|
+
var PAY_BRANDS = /* @__PURE__ */ Object.freeze({ visa: "visa", mastercard: "master", amex: "american_express" });
|
|
307
|
+
var FACT_KEYS = /* @__PURE__ */ Object.freeze(["card_first_six", "card_last_four", "expiry_month", "expiry_year", "card_brand"]);
|
|
308
|
+
var FIRST_SIX = /^[0-9]{6}$/;
|
|
309
|
+
var LAST_FOUR = /^[0-9]{4}$/;
|
|
310
|
+
var fullYear = (year) => {
|
|
311
|
+
const value = Number(year);
|
|
312
|
+
return Number.isInteger(value) && value >= 0 && value <= 99 ? 2e3 + value : value;
|
|
313
|
+
};
|
|
314
|
+
var expiryMonth = (month) => Number.isInteger(month) && month >= 1 && month <= 12;
|
|
315
|
+
var expiryYear = (year) => Number.isInteger(year) && year >= 2e3 && year <= 2099;
|
|
316
|
+
function paddleVgsCardFacts(card) {
|
|
317
|
+
const number = card ? String(card.number) : "";
|
|
318
|
+
const network = cardNetwork(number);
|
|
319
|
+
const month = card ? Number(card.month) : NaN;
|
|
320
|
+
const year = card ? fullYear(card.year) : NaN;
|
|
321
|
+
if (network === null || !expiryMonth(month) || !expiryYear(year))
|
|
322
|
+
throw new Error("Could not read this card's details for Paddle. Nothing was sent.");
|
|
323
|
+
return Object.freeze({ card_first_six: number.slice(0, 6), card_last_four: number.slice(-4), expiry_month: month, expiry_year: year, card_brand: PAY_BRANDS[network] });
|
|
324
|
+
}
|
|
325
|
+
function paddleVgsCardFactsOf(value) {
|
|
326
|
+
if (!record(value))
|
|
327
|
+
return null;
|
|
328
|
+
const keys = Object.keys(value);
|
|
329
|
+
if (keys.length !== FACT_KEYS.length || !FACT_KEYS.every((key) => keys.includes(key)))
|
|
330
|
+
return null;
|
|
331
|
+
const { card_first_six: firstSix, card_last_four: lastFour, expiry_month: month, expiry_year: year, card_brand: brand } = value;
|
|
332
|
+
const network = typeof firstSix === "string" && FIRST_SIX.test(firstSix) ? cardNetwork(`${firstSix}000000`) : null;
|
|
333
|
+
if (network === null || PAY_BRANDS[network] !== brand || typeof lastFour !== "string" || !LAST_FOUR.test(lastFour) || !expiryMonth(month) || !expiryYear(year))
|
|
334
|
+
return null;
|
|
335
|
+
return Object.freeze({ card_first_six: firstSix, card_last_four: lastFour, expiry_month: month, expiry_year: year, card_brand: brand });
|
|
336
|
+
}
|
|
337
|
+
function paddleVgsCardFactsAgree(facts, stored) {
|
|
338
|
+
const read = paddleVgsCardFactsOf(facts);
|
|
339
|
+
if (!read)
|
|
340
|
+
return false;
|
|
341
|
+
const card = record(stored) ? stored : {};
|
|
342
|
+
const network = Object.keys(PAY_BRANDS).find((name) => PAY_BRANDS[name] === read.card_brand);
|
|
343
|
+
const brand = storedBrand(card.brand);
|
|
344
|
+
return !(typeof card.last4 === "string" && LAST_FOUR.test(card.last4) && card.last4 !== read.card_last_four) && (brand === null || brand === network) && !(Number.isInteger(card.expiryMonth) && card.expiryMonth !== read.expiry_month) && !(Number.isInteger(card.expiryYear) && card.expiryYear % 100 !== read.expiry_year % 100);
|
|
345
|
+
}
|
|
346
|
+
var PAY_BODY_LIMIT = 16384;
|
|
347
|
+
var PAY_DATA_KEYS = /* @__PURE__ */ Object.freeze(["payment_method_type", "payment_method_data"]);
|
|
348
|
+
var PAY_CARD_KEYS = /* @__PURE__ */ Object.freeze(["metadata", "three_d_s", "vgs_card"]);
|
|
349
|
+
var METADATA_KEYS = /* @__PURE__ */ Object.freeze(["cardholder_name", ...FACT_KEYS]);
|
|
350
|
+
var BROWSER_INFO = /^[A-Za-z0-9+/]{1,4096}={0,2}$/;
|
|
351
|
+
var RADAR_TOKEN = /^[\x21-\x7e]{1,512}$/;
|
|
352
|
+
var COUNTRY_CODE = /^[A-Za-z]{2}$/;
|
|
353
|
+
var FRONTEND_HOST = /^https:\/\/[\x21-\x7e]{1,1024}$/;
|
|
354
|
+
var radarKeys = (value) => sameKeys(value, ["token", "country_code"]) || sameKeys(value, ["country_code", "token"]);
|
|
355
|
+
function readPay(body, line) {
|
|
356
|
+
if (typeof body !== "string" || body === "" || body.length > PAY_BODY_LIMIT)
|
|
357
|
+
return null;
|
|
358
|
+
let value;
|
|
359
|
+
try {
|
|
360
|
+
value = JSON.parse(body);
|
|
361
|
+
if (!record(value) || JSON.stringify(value) !== body)
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
catch {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
const data = value.data;
|
|
368
|
+
if (!sameKeys(value, ["data"]) || !record(data) || !(sameKeys(data, PAY_DATA_KEYS) || sameKeys(data, [...PAY_DATA_KEYS, "checkout"])) || data.payment_method_type !== (line === "classic" ? "CARD" : "card"))
|
|
369
|
+
return null;
|
|
370
|
+
if (data.checkout !== void 0 && !(record(data.checkout) && sameKeys(data.checkout, ["frontend_host"]) && typeof data.checkout.frontend_host === "string" && FRONTEND_HOST.test(data.checkout.frontend_host)))
|
|
371
|
+
return null;
|
|
372
|
+
const method = data.payment_method_data;
|
|
373
|
+
const card = record(method) && sameKeys(method, ["card"]) ? method.card : null;
|
|
374
|
+
if (!record(card) || !(sameKeys(card, PAY_CARD_KEYS) || sameKeys(card, [...PAY_CARD_KEYS, "session_tracking"])))
|
|
375
|
+
return null;
|
|
376
|
+
const metadata = card.metadata;
|
|
377
|
+
if (!record(metadata) || !sameKeys(metadata, METADATA_KEYS) || typeof metadata.cardholder_name !== "string" || metadata.cardholder_name.length > NAME_LIMIT || CONTROL.test(metadata.cardholder_name) || cardLikeName(metadata.cardholder_name) || typeof metadata.card_first_six !== "string" || !FIRST_SIX.test(metadata.card_first_six) || typeof metadata.card_last_four !== "string" || !LAST_FOUR.test(metadata.card_last_four) || !expiryMonth(metadata.expiry_month) || !expiryYear(metadata.expiry_year) || !FRAME_BRANDS.includes(metadata.card_brand))
|
|
378
|
+
return null;
|
|
379
|
+
const details = card.three_d_s;
|
|
380
|
+
if (!record(details) || !sameKeys(details, ["browser_info"]) || typeof details.browser_info !== "string" || !BROWSER_INFO.test(details.browser_info))
|
|
381
|
+
return null;
|
|
382
|
+
if (!record(card.vgs_card) || !sameKeys(card.vgs_card, ["card_id"]) || !isStoredCardId(card.vgs_card.card_id))
|
|
383
|
+
return null;
|
|
384
|
+
if (card.session_tracking !== void 0) {
|
|
385
|
+
const tracking = card.session_tracking;
|
|
386
|
+
const radar = record(tracking) && sameKeys(tracking, ["stripe_radar"]) ? tracking.stripe_radar : null;
|
|
387
|
+
if (!record(radar) || !radarKeys(radar) || typeof radar.token !== "string" || !RADAR_TOKEN.test(radar.token) || typeof radar.country_code !== "string" || !COUNTRY_CODE.test(radar.country_code))
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
return value;
|
|
391
|
+
}
|
|
392
|
+
function paddleVgsPayVerdict(request, approved) {
|
|
393
|
+
const facts = record(approved) ? paddleVgsCardFactsOf(approved.facts) : null;
|
|
394
|
+
if (!facts || !isStoredCardId(approved.cardId) || approved.environment !== "production" && approved.environment !== "sandbox") {
|
|
395
|
+
return refuse("paddle_vgs_pay_unbound");
|
|
396
|
+
}
|
|
397
|
+
const target = record(request) && typeof request.method === "string" && request.method.toUpperCase() === "POST" ? paddleVgsPayTarget(request.url) : null;
|
|
398
|
+
const value = target ? readPay(request.body, target.line) : null;
|
|
399
|
+
if (!value)
|
|
400
|
+
return refuse("paddle_vgs_pay_unsupported");
|
|
401
|
+
const card = value.data.payment_method_data.card;
|
|
402
|
+
if (target.environment !== approved.environment || card.vgs_card.card_id !== approved.cardId)
|
|
403
|
+
return refuse("paddle_vgs_pay_card_mismatch");
|
|
404
|
+
for (const key of FACT_KEYS)
|
|
405
|
+
card.metadata[key] = facts[key];
|
|
406
|
+
return Object.freeze({ verdict: "continue", body: JSON.stringify(value) });
|
|
407
|
+
}
|
|
408
|
+
export { PADDLE_VGS_CAPABILITY, PADDLE_VGS_CARDS_URLS, PADDLE_VGS_CARD_ID_WINDOW_MS, PADDLE_VGS_CARD_NETWORKS, PADDLE_VGS_CONTENT_TYPE, PADDLE_VGS_MERCHANT_PINS, PADDLE_VGS_OPERATION, PADDLE_VGS_PSP, PADDLE_VGS_REFUSAL_CODES, injectPaddleVgsCard, isPaddleVgsCardsUrl, isPreparedPaddleVgsRequest, paddleVgsAnswerOutcome, paddleVgsBodyVerdict, paddleVgsCardFacts, paddleVgsCardFactsAgree, paddleVgsCardFactsOf, paddleVgsCardRefusal, paddleVgsEnvironment, paddleVgsMerchantPin, paddleVgsMerchantRefusal, paddleVgsPayCarriesStoredCard, paddleVgsPayTarget, paddleVgsPayVerdict, paddleVgsRefusalCode, paddleVgsRefusalMessage, paddleVgsRequestRefusal, paddleVgsSellerClaimsPinned, paddleVgsStoredCardRefusal, paddleVgsTypedCardRefusal };
|
|
@@ -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: 38065a5bd834d5233979a0528fde4345378914e8e8b1a63e329bff0994572da5
|
|
4
4
|
// src/json-path.js
|
|
5
5
|
function roundTrips(parsed, body) {
|
|
6
6
|
try {
|
|
@@ -404,14 +404,8 @@ function payrailsCardOnFileRefusal(body) {
|
|
|
404
404
|
}
|
|
405
405
|
var AUTHORIZE_LIMIT = 32768;
|
|
406
406
|
var AUTHORIZE_KEYS = Object.freeze(["amount", "paymentComposition", "returnInfo", "meta"]);
|
|
407
|
-
var COMPOSITION_KEYS = Object.freeze([
|
|
408
|
-
|
|
409
|
-
"integrationType",
|
|
410
|
-
"amount",
|
|
411
|
-
"storeInstrument",
|
|
412
|
-
"paymentInstrumentData",
|
|
413
|
-
"enrollInstrumentToNetworkOffers"
|
|
414
|
-
]);
|
|
407
|
+
var COMPOSITION_KEYS = Object.freeze(["paymentMethodCode", "integrationType", "amount", "storeInstrument", "paymentInstrumentData"]);
|
|
408
|
+
var ENROLLMENT_COMPOSITION_KEYS = Object.freeze([...COMPOSITION_KEYS, "enrollInstrumentToNetworkOffers"]);
|
|
415
409
|
var RETURN_KEYS = Object.freeze(["success", "cancel", "error", "pending"]);
|
|
416
410
|
var AMOUNT_VALUE = /^[0-9]{1,15}(?:\.[0-9]{1,12})?$/;
|
|
417
411
|
var CURRENCY = /^[A-Z]{3}$/;
|
|
@@ -476,12 +470,14 @@ function readAuthorizeBody(body) {
|
|
|
476
470
|
const amount = readAmount(parsed.amount);
|
|
477
471
|
const parts = parsed.paymentComposition;
|
|
478
472
|
const part = Array.isArray(parts) && parts.length === 1 && record(parts[0]) ? parts[0] : null;
|
|
479
|
-
|
|
473
|
+
const flagged = !!part && owns(part, "enrollInstrumentToNetworkOffers");
|
|
474
|
+
if (!amount || !part || !sameKeys(part, flagged ? ENROLLMENT_COMPOSITION_KEYS : COMPOSITION_KEYS) || part.paymentMethodCode !== "card" || part.integrationType !== "api")
|
|
480
475
|
return malformed;
|
|
481
476
|
const partAmount = readAmount(part.amount);
|
|
482
477
|
if (!partAmount || partAmount.value !== amount.value || partAmount.currency !== amount.currency)
|
|
483
478
|
return malformed;
|
|
484
|
-
|
|
479
|
+
const enrollInstrumentToNetworkOffers = flagged ? part.enrollInstrumentToNetworkOffers : false;
|
|
480
|
+
if (typeof part.storeInstrument !== "boolean" || typeof enrollInstrumentToNetworkOffers !== "boolean")
|
|
485
481
|
return malformed;
|
|
486
482
|
const data = part.paymentInstrumentData;
|
|
487
483
|
const keys = record(data) ? Object.keys(data) : [];
|
|
@@ -502,7 +498,7 @@ function readAuthorizeBody(body) {
|
|
|
502
498
|
value: Object.freeze({
|
|
503
499
|
amount: Object.freeze({ value: amount.value, currency: amount.currency }),
|
|
504
500
|
storeInstrument: part.storeInstrument,
|
|
505
|
-
enrollInstrumentToNetworkOffers
|
|
501
|
+
enrollInstrumentToNetworkOffers,
|
|
506
502
|
encryptedData: data.encryptedData,
|
|
507
503
|
vaultProviderConfigId: data.vaultProviderConfigId,
|
|
508
504
|
wrappedKeyBytes: jwe.wrappedKey.length
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
export type PaysafePreparationEnvironment = 'production' | 'sandbox';
|
|
2
2
|
export declare function paysafePreparationUrl(environment: string): string;
|
|
3
|
-
/** Exact strings refuse credentials, queries, fragments and URL normalization. */
|
|
3
|
+
/** The environment of a reviewed build's card URL. Exact strings refuse credentials, queries, fragments and URL normalization. */
|
|
4
4
|
export declare function paysafeEnvironment(url: string): PaysafePreparationEnvironment | undefined;
|
|
5
|
-
/** Checkout
|
|
6
|
-
* consume only its new-card request, including native clientInfo and headers
|
|
7
|
-
* Saved cards, alternate APIs and 3DS-only requests
|
|
8
|
-
*
|
|
9
|
-
* e9e111ff03073cc936a47674e8e7c5db4a6d1050e1b65bf5e20723116fd5080c.
|
|
10
|
-
* The guard checks original bytes and never changes the request.
|
|
5
|
+
/** A reviewed Checkout build (BUILDS) starts a 40-second XHR when Pay is pressed. Prior approval may
|
|
6
|
+
* consume only its new-card request, including native clientInfo and headers, on the card URL that
|
|
7
|
+
* build sends to in the approved environment. Saved cards, alternate APIs and 3DS-only requests
|
|
8
|
+
* require separate review. The guard checks original bytes and never changes the request.
|
|
11
9
|
*/
|
|
12
10
|
export declare function isPreparedPaysafeRequest(url: string, method: string, body: string | null, environment: string, headers?: Record<string, string>): boolean;
|
|
@@ -1,10 +1,34 @@
|
|
|
1
1
|
// Generated from @agent-cards/payment-core. Do not edit.
|
|
2
|
-
// source-sha256:
|
|
2
|
+
// source-sha256: afa00cd57246e51361474c66c5ab4282bd5b39f0297fdf68616e164e19ed1741
|
|
3
3
|
import { readTokenizationJson } from './braintree.js';
|
|
4
|
+
/** The card URL a preparation names: Checkout 1.8.0's. The bind takes the exact URL of the build the request names (BUILDS). */
|
|
4
5
|
const ENDPOINTS = {
|
|
5
6
|
production: 'https://hosted.paysafe.com/checkout/api/v1/tokenize',
|
|
6
7
|
sandbox: 'https://hosted.test.paysafe.com/checkout/api/v1/tokenize',
|
|
7
8
|
};
|
|
9
|
+
/**
|
|
10
|
+
* The Paysafe Checkout builds whose new-card request a prior approval may consume, each read from
|
|
11
|
+
* Paysafe's public bundle. A request binds only to the build its own clientInfo.version names, on
|
|
12
|
+
* that build's URL and headers, so a build Paysafe ships later is refused, and nothing is sent,
|
|
13
|
+
* until it is read and listed here. The request moved inside 1.x: 1.8.0 to 1.12.0 post to
|
|
14
|
+
* hosted.paysafe.com with a correlationId header, 1.16.1 to api.paysafe.com with three other
|
|
15
|
+
* headers, so a version range would hold one build's request to another build's rules.
|
|
16
|
+
*
|
|
17
|
+
* 1.8.0: hosted.paysafe.com/checkout/1.8.0/main.bundle.js, SHA-256
|
|
18
|
+
* e9e111ff03073cc936a47674e8e7c5db4a6d1050e1b65bf5e20723116fd5080c; LIVE/TEST select hosted[.test].
|
|
19
|
+
* 1.16.1: the checkout/v1/latest loader (SHA-256 5fac65c4f7a74b45388ad3ce7c02282f05e832226792bebc417cd9ff191be4f0)
|
|
20
|
+
* names it and frames checkout/v1/latest/index.html. Its main.js (SHA-256
|
|
21
|
+
* 328c6443da930f3648826248afa3c342cdd07d04e49a78b0878dda187772bf80) posts to environment +
|
|
22
|
+
* "checkout/api/v1/tokenize", and its vendor.js (SHA-256 7348275bd07256e295f4b83b292c7fe5115dd7ac35d1b1fe3d26eda3c37d2835)
|
|
23
|
+
* maps LIVE/TEST to api[.test].paysafe.com and sets X-Internal-Correlation-Id, X-Paysafe-Credentials,
|
|
24
|
+
* X-App-Version (the clientInfo version) and X-TransactionSource (CheckoutV1 for paysafe.checkout).
|
|
25
|
+
* The TEST host serves the same bytes (read 2026-10-15).
|
|
26
|
+
*/
|
|
27
|
+
const BUILDS = [
|
|
28
|
+
{ version: '1.8.0', endpoints: ENDPOINTS, correlation: 'correlationid', fixed: {} },
|
|
29
|
+
{ version: '1.16.1', correlation: 'x-internal-correlation-id', fixed: { 'x-app-version': '1.16.1', 'x-transactionsource': 'CheckoutV1' },
|
|
30
|
+
endpoints: { production: 'https://api.paysafe.com/checkout/api/v1/tokenize', sandbox: 'https://api.test.paysafe.com/checkout/api/v1/tokenize' } },
|
|
31
|
+
];
|
|
8
32
|
const record = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
9
33
|
const keys = (value, allowed) => record(value) && Object.keys(value).every(key => allowed.includes(key));
|
|
10
34
|
const exact = (pattern, value) => typeof value === 'string' && pattern.exec(value)?.[0] === value;
|
|
@@ -16,27 +40,31 @@ export function paysafePreparationUrl(environment) {
|
|
|
16
40
|
throw new Error('unsupported_preparation_environment');
|
|
17
41
|
return ENDPOINTS[environment];
|
|
18
42
|
}
|
|
19
|
-
/** Exact strings refuse credentials, queries, fragments and URL normalization. */
|
|
43
|
+
/** The environment of a reviewed build's card URL. Exact strings refuse credentials, queries, fragments and URL normalization. */
|
|
20
44
|
export function paysafeEnvironment(url) {
|
|
21
|
-
|
|
45
|
+
const build = BUILDS.find(candidate => url === candidate.endpoints.production || url === candidate.endpoints.sandbox);
|
|
46
|
+
return !build ? undefined : url === build.endpoints.production ? 'production' : 'sandbox';
|
|
22
47
|
}
|
|
23
48
|
const ADDRESS_FIELDS = ['city', 'country', 'zip', 'street', 'street2', 'state'];
|
|
24
49
|
function billing(value) {
|
|
25
50
|
return keys(value, ADDRESS_FIELDS) && Object.values(value).every(value => text(value))
|
|
26
51
|
&& (!own(value, 'country') || exact(/^[A-Z]{2}$/, value.country));
|
|
27
52
|
}
|
|
28
|
-
|
|
53
|
+
/** The reviewed build whose new-card body this is: never a saved card, a 3-D Secure request or another app's body. */
|
|
54
|
+
function freshCardBuild(value) {
|
|
29
55
|
if (!keys(value, ['card', 'clientInfo', 'billingAddress']) || !keys(value.card, ['cardNum', 'cardExpiry', 'cvv', 'holderName']))
|
|
30
|
-
return
|
|
56
|
+
return undefined;
|
|
31
57
|
const card = value.card;
|
|
32
58
|
if (!exact(/^[0-9]{12,19}$/, card.cardNum) || !exact(/^[0-9]{3,4}$/, card.cvv)
|
|
33
59
|
|| !keys(card.cardExpiry, ['month', 'year']) || !exact(/^(?:0[1-9]|1[0-2])$/, card.cardExpiry.month)
|
|
34
60
|
|| !exact(/^20[0-9]{2}$/, card.cardExpiry.year) || own(card, 'holderName') && !text(card.holderName)
|
|
35
61
|
|| own(value, 'billingAddress') && !billing(value.billingAddress))
|
|
36
|
-
return
|
|
62
|
+
return undefined;
|
|
37
63
|
const info = value.clientInfo;
|
|
38
|
-
|
|
39
|
-
|
|
64
|
+
if (!keys(info, ['correlationId', 'invocationId', 'version', 'appName'])
|
|
65
|
+
|| !uuid(info.correlationId) || !uuid(info.invocationId) || info.appName !== 'paysafe.checkout')
|
|
66
|
+
return undefined;
|
|
67
|
+
return BUILDS.find(build => build.version === info.version);
|
|
40
68
|
}
|
|
41
69
|
const BROWSER_HEADERS = new Set(['accept', 'accept-language', 'accept-encoding', 'content-length', 'origin', 'referer',
|
|
42
70
|
'user-agent', 'host', 'connection', 'cache-control', 'pragma', 'priority', 'dnt',
|
|
@@ -53,9 +81,11 @@ function singleUseCredential(value) {
|
|
|
53
81
|
return false;
|
|
54
82
|
}
|
|
55
83
|
}
|
|
56
|
-
|
|
84
|
+
/** The build's own headers, each once with its native value, and only headers a browser adds beside them. */
|
|
85
|
+
function nativeHeaders(headers, correlationId, build) {
|
|
57
86
|
if (!record(headers))
|
|
58
87
|
return false;
|
|
88
|
+
const native = ['content-type', 'x-paysafe-credentials', build.correlation, ...Object.keys(build.fixed)];
|
|
59
89
|
const parsed = new Map();
|
|
60
90
|
let bytes = 0;
|
|
61
91
|
for (const [name, value] of Object.entries(headers)) {
|
|
@@ -63,25 +93,27 @@ function nativeHeaders(headers, correlationId) {
|
|
|
63
93
|
if (parsed.size >= 64 || parsed.has(lower) || !exact(/^[A-Za-z0-9-]+$/, name) || !text(value, 8192)
|
|
64
94
|
|| (bytes += name.length + value.length) > 32768)
|
|
65
95
|
return false;
|
|
66
|
-
if (!
|
|
96
|
+
if (!native.includes(lower) && !BROWSER_HEADERS.has(lower)
|
|
67
97
|
&& !exact(/^sec-ch-ua(?:-[a-z0-9-]+)?$/, lower))
|
|
68
98
|
return false;
|
|
69
99
|
parsed.set(lower, value);
|
|
70
100
|
}
|
|
71
101
|
return exact(/^application\/json(?:;\s*charset=utf-8)?$/i, parsed.get('content-type'))
|
|
72
|
-
&& parsed.get(
|
|
102
|
+
&& parsed.get(build.correlation) === correlationId && singleUseCredential(parsed.get('x-paysafe-credentials'))
|
|
103
|
+
&& Object.entries(build.fixed).every(([name, value]) => parsed.get(name) === value);
|
|
73
104
|
}
|
|
74
|
-
/** Checkout
|
|
75
|
-
* consume only its new-card request, including native clientInfo and headers
|
|
76
|
-
* Saved cards, alternate APIs and 3DS-only requests
|
|
77
|
-
*
|
|
78
|
-
* e9e111ff03073cc936a47674e8e7c5db4a6d1050e1b65bf5e20723116fd5080c.
|
|
79
|
-
* The guard checks original bytes and never changes the request.
|
|
105
|
+
/** A reviewed Checkout build (BUILDS) starts a 40-second XHR when Pay is pressed. Prior approval may
|
|
106
|
+
* consume only its new-card request, including native clientInfo and headers, on the card URL that
|
|
107
|
+
* build sends to in the approved environment. Saved cards, alternate APIs and 3DS-only requests
|
|
108
|
+
* require separate review. The guard checks original bytes and never changes the request.
|
|
80
109
|
*/
|
|
81
110
|
export function isPreparedPaysafeRequest(url, method, body, environment, headers) {
|
|
82
111
|
if (method !== 'POST' || (environment !== 'production' && environment !== 'sandbox')
|
|
83
112
|
|| paysafeEnvironment(url) !== environment)
|
|
84
113
|
return false;
|
|
85
114
|
const value = readTokenizationJson(body);
|
|
86
|
-
|
|
115
|
+
if (!value || !record(value.clientInfo))
|
|
116
|
+
return false;
|
|
117
|
+
const build = freshCardBuild(value);
|
|
118
|
+
return !!build && url === build.endpoints[environment] && nativeHeaders(headers, value.clientInfo.correlationId, build);
|
|
87
119
|
}
|
package/dist/pre-claim.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { type CardEndpointProfile } from './card-endpoint.js';
|
|
|
13
13
|
import { type PayrailsSessionCapture, type PayrailsSidecar } from './payrails.js';
|
|
14
14
|
import { type VerifoneProfile } from './verifone.js';
|
|
15
15
|
import { type WorldlineMyCheckoutProducts } from './worldline-mycheckout.js';
|
|
16
|
+
import { type PaddleVgsPayGate } from './paddle-vgs-pay.js';
|
|
16
17
|
/** The native Stripe step the gate claimed, or null when none was: exactly what StripeCheckoutGate.claim returns. */
|
|
17
18
|
type StripeStep = ReturnType<StripeCheckoutGate['claim']>;
|
|
18
19
|
/** A synthetic response a gate fulfills locally. The effect applies CORS and encoding. */
|
|
@@ -189,6 +190,12 @@ export interface PreClaimContext {
|
|
|
189
190
|
* Absent, no MyCheckout card submit is held to a product here.
|
|
190
191
|
*/
|
|
191
192
|
worldlineMyCheckout?: WorldlineMyCheckoutProducts;
|
|
193
|
+
/**
|
|
194
|
+
* The attachment's binding of Paddle's /pay to the stored card's id it handed a frame (paddle-vgs-pay.ts),
|
|
195
|
+
* judged by the request's frame (`frame`). Absent, or for an org the API did not serve Paddle VGS to, Paddle's
|
|
196
|
+
* checkout services are not this gate's.
|
|
197
|
+
*/
|
|
198
|
+
paddleVgsPay?: PaddleVgsPayGate;
|
|
192
199
|
}
|
|
193
200
|
/**
|
|
194
201
|
* The URL an event may name for a request. For an armed merchant profile's
|
|
@@ -211,6 +218,7 @@ export declare const ekashuPreClaim: PreClaimGate;
|
|
|
211
218
|
export declare const paypalHostedFieldsPreClaim: PreClaimGate;
|
|
212
219
|
export declare const cybersourceSecureAcceptancePreClaim: PreClaimGate;
|
|
213
220
|
export declare const worldlineMyCheckoutPreClaim: PreClaimGate;
|
|
221
|
+
export declare const paddleVgsPayPreClaim: PreClaimGate;
|
|
214
222
|
/** The processor gates, in order. A new family adds one entry here; the terminal
|
|
215
223
|
* arbiter runs after all of them and is not part of this list. A gate appended
|
|
216
224
|
* after Stripe is never offered a step Stripe claimed: Stripe answers, aborts or
|