@agent-cards/sdk 0.23.11 → 0.23.12

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.
@@ -0,0 +1,50 @@
1
+ declare var PADDLE_VGS_PSP: string;
2
+ declare var PADDLE_VGS_CAPABILITY: string;
3
+ declare var PADDLE_VGS_OPERATION: string;
4
+ declare var PADDLE_VGS_CONTENT_TYPE: string;
5
+ declare var PADDLE_VGS_CARDS_URLS: Readonly<{
6
+ production: "https://vault.paddle.com/cards";
7
+ sandbox: "https://sandbox-vault.paddle.com/cards";
8
+ }>;
9
+ declare var PADDLE_VGS_REFUSAL_CODES: readonly string[];
10
+ declare function paddleVgsEnvironment(url: any): "production" | "sandbox" | null;
11
+ declare function isPaddleVgsCardsUrl(url: any): boolean;
12
+ declare function paddleVgsBodyVerdict(body: any): Readonly<{
13
+ verdict: "refuse";
14
+ code: any;
15
+ }> | Readonly<{
16
+ verdict: "card";
17
+ }>;
18
+ declare function paddleVgsRequestRefusal(request: any): any;
19
+ declare function isPreparedPaddleVgsRequest(url: any, method: any, body: any, environment: any, headers: any): boolean;
20
+ declare var PADDLE_VGS_MERCHANT_PINS: readonly any[];
21
+ declare function paddleVgsMerchantPin(merchantOrigin: any, pins?: readonly any[]): any;
22
+ declare function paddleVgsMerchantRefusal(environment: any, merchantOrigin: any, authorization: any, pins?: readonly any[]): "unsupported_environment" | "paddle_vgs_merchant_unreviewed" | "paddle_vgs_seller_unreviewed" | null;
23
+ declare function paddleVgsSellerClaimsPinned(pins?: readonly any[]): boolean;
24
+ declare function paddleVgsRefusalMessage(code: any): any;
25
+ declare var PADDLE_VGS_CARD_NETWORKS: readonly string[];
26
+ declare function paddleVgsCardRefusal(body: any, card: any): any;
27
+ declare function paddleVgsStoredCardRefusal(brand: any): "paddle_vgs_card_unsupported" | null;
28
+ declare function paddleVgsTypedCardRefusal(body: any, stored: any): any;
29
+ declare function injectPaddleVgsCard(body: any, card: any): {
30
+ body: string;
31
+ where: string[];
32
+ };
33
+ declare function paddleVgsRefusalCode(text: any): string | null;
34
+ declare function paddleVgsAnswerOutcome(status: any, text: any, card: any): {
35
+ outcome: string;
36
+ reason: string;
37
+ code?: undefined;
38
+ body?: undefined;
39
+ } | {
40
+ outcome: string;
41
+ code: string;
42
+ reason?: undefined;
43
+ body?: undefined;
44
+ } | {
45
+ outcome: string;
46
+ body: string;
47
+ reason?: undefined;
48
+ code?: undefined;
49
+ };
50
+ export { PADDLE_VGS_CAPABILITY, PADDLE_VGS_CARDS_URLS, 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, paddleVgsCardRefusal, paddleVgsEnvironment, paddleVgsMerchantPin, paddleVgsMerchantRefusal, paddleVgsRefusalCode, paddleVgsRefusalMessage, paddleVgsRequestRefusal, paddleVgsSellerClaimsPinned, paddleVgsStoredCardRefusal, paddleVgsTypedCardRefusal };
@@ -0,0 +1,289 @@
1
+ // @ts-nocheck
2
+ // Generated from @agent-cards/payment-core. Do not edit.
3
+ // artifact-sha256: b33914c3bb882b868a28a7d7abb91d6cca450c0145dca0aa338474400b6f923e
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
+ function storedCardId(answer) {
258
+ const data = answer && answer.data;
259
+ if (!record(data) || data.type !== "cards" || typeof data.id !== "string")
260
+ return null;
261
+ const id = data.id;
262
+ return STORED_CARD_ID.test(id) && /[A-Za-z]/.test(id) && !PAN_LIKE.test(id) ? 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
+ export { PADDLE_VGS_CAPABILITY, PADDLE_VGS_CARDS_URLS, 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, paddleVgsCardRefusal, paddleVgsEnvironment, paddleVgsMerchantPin, paddleVgsMerchantRefusal, 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: 66c54c571ca1294220b070eaca1ca3888feebcd7f2562b761d74ded25a453c57
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
- "paymentMethodCode",
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
- if (!amount || !part || !sameKeys(part, COMPOSITION_KEYS) || part.paymentMethodCode !== "card" || part.integrationType !== "api")
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
- if (typeof part.storeInstrument !== "boolean" || typeof part.enrollInstrumentToNetworkOffers !== "boolean")
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: part.enrollInstrumentToNetworkOffers,
501
+ enrollInstrumentToNetworkOffers,
506
502
  encryptedData: data.encryptedData,
507
503
  vaultProviderConfigId: data.vaultProviderConfigId,
508
504
  wrappedKeyBytes: jwe.wrappedKey.length
@@ -16,8 +16,12 @@
16
16
  * CyberSource's reply 30 times, a second apart, from Save (Arrow Electronics), too soon for an
17
17
  * approval after Save. Its environments are its two hosts: secureacceptance (production) and
18
18
  * testsecureacceptance (sandbox).
19
+ *
20
+ * paddle_vgs: prepared only. Paddle's checkout frame aborts its card request to its VGS card vault 10
21
+ * seconds after Pay and sends it once more, too soon for an approval after Pay. Its environments are its
22
+ * two card URLs: vault.paddle.com (production) and sandbox-vault.paddle.com (sandbox).
19
23
  */
20
- export type PreparationProcessor = 'square' | 'braintree' | 'worldpay' | 'bambora' | 'mercado_pago' | 'recurly' | 'spreedly' | 'adyen' | 'checkout_com' | 'paysafe' | 'fiserv' | 'cybersource_flex' | 'aci' | 'creditguard' | 'worldpay_eprotect' | 'amadeus_checkout' | 'verifone' | 'cybersource_secure_acceptance';
24
+ export type PreparationProcessor = 'square' | 'braintree' | 'worldpay' | 'bambora' | 'mercado_pago' | 'recurly' | 'spreedly' | 'adyen' | 'checkout_com' | 'paysafe' | 'fiserv' | 'cybersource_flex' | 'aci' | 'creditguard' | 'worldpay_eprotect' | 'amadeus_checkout' | 'verifone' | 'cybersource_secure_acceptance' | 'paddle_vgs';
21
25
  export type PreparationEnvironment = 'production' | 'sandbox' | 'shared';
22
26
  /**
23
27
  * How the approved card reaches the processor: the device's own request (token), or
@@ -39,8 +43,11 @@ export declare function preparationRequestMethod(psp: string): 'GET' | 'POST';
39
43
  * sending it, and a Pay button that runs the tokenization again sends the same placeholder and
40
44
  * fields (WooCommerce's Bambora plugin shows the timeout, clears its token fields and lets Pay be
41
45
  * clicked again). The cardholder's device answers with a token that pays nothing until the
42
- * merchant's server charges it. Every other prepared checkout still answers only the request it
43
- * was bound to.
46
+ * merchant's server charges it. Paddle VGS too: Paddle's frame aborts its card request to its VGS
47
+ * card vault 10 seconds after sending it and sends the same body under the same bearer once more, and
48
+ * the device's answer is the stored card's id, which pays nothing until Paddle's /pay names it. Only
49
+ * that repeat, byte for byte under the same bearer, is answered (cdp.ts paddleVgsRetryKey).
50
+ * Every other prepared checkout still answers only the request it was bound to.
44
51
  */
45
52
  export declare function preparedApprovalAnswersRetry(psp: string): boolean;
46
53
  /**
@@ -50,7 +57,8 @@ export declare function preparedApprovalAnswersRetry(psp: string): boolean;
50
57
  * Flex's: flex.cybersource.com is live, testflex.cybersource.com is test, and each has
51
58
  * its own signing keys. A Verifone preparation pays in the environment of the key its reviewed
52
59
  * profile pins. CyberSource Secure Acceptance's are separate hosts too: secureacceptance is
53
- * live, testsecureacceptance is test.
60
+ * live, testsecureacceptance is test. So are Paddle VGS's two card URLs: vault is live,
61
+ * sandbox-vault is test.
54
62
  */
55
63
  export declare function validPreparationEnvironment(psp: string, environment: string): boolean;
56
64
  /**
@@ -13,6 +13,7 @@ import { eprotectPreparationUrl, isPreparedEprotectRequest } from './eprotect.ge
13
13
  import { amadeusEnvironment, amadeusPreparationUrls, amadeusRequestRefusal, isPreparedAmadeusRequest } from './amadeus-checkout.generated.js';
14
14
  import { isPreparedVerifoneRequest } from './verifone.js';
15
15
  import { isPreparedSecureAcceptanceRequest, secureAcceptanceEnvironment, secureAcceptancePreparationUrl, secureAcceptanceRequestRefusal, } from './cybersource-secure-acceptance.generated.js';
16
+ import { PADDLE_VGS_CARDS_URLS, isPreparedPaddleVgsRequest } from './paddle-vgs.generated.js';
16
17
  export function preparationMode(psp) {
17
18
  return psp === 'adyen' || psp === 'fiserv' || psp === 'verifone' ? 'cse' : 'token';
18
19
  }
@@ -30,11 +31,14 @@ export function preparationRequestMethod(psp) {
30
31
  * sending it, and a Pay button that runs the tokenization again sends the same placeholder and
31
32
  * fields (WooCommerce's Bambora plugin shows the timeout, clears its token fields and lets Pay be
32
33
  * clicked again). The cardholder's device answers with a token that pays nothing until the
33
- * merchant's server charges it. Every other prepared checkout still answers only the request it
34
- * was bound to.
34
+ * merchant's server charges it. Paddle VGS too: Paddle's frame aborts its card request to its VGS
35
+ * card vault 10 seconds after sending it and sends the same body under the same bearer once more, and
36
+ * the device's answer is the stored card's id, which pays nothing until Paddle's /pay names it. Only
37
+ * that repeat, byte for byte under the same bearer, is answered (cdp.ts paddleVgsRetryKey).
38
+ * Every other prepared checkout still answers only the request it was bound to.
35
39
  */
36
40
  export function preparedApprovalAnswersRetry(psp) {
37
- return psp === 'bambora';
41
+ return psp === 'bambora' || psp === 'paddle_vgs';
38
42
  }
39
43
  /**
40
44
  * Shared endpoint processors cannot attest test/live mode from their URL or key prefix.
@@ -43,13 +47,14 @@ export function preparedApprovalAnswersRetry(psp) {
43
47
  * Flex's: flex.cybersource.com is live, testflex.cybersource.com is test, and each has
44
48
  * its own signing keys. A Verifone preparation pays in the environment of the key its reviewed
45
49
  * profile pins. CyberSource Secure Acceptance's are separate hosts too: secureacceptance is
46
- * live, testsecureacceptance is test.
50
+ * live, testsecureacceptance is test. So are Paddle VGS's two card URLs: vault is live,
51
+ * sandbox-vault is test.
47
52
  */
48
53
  export function validPreparationEnvironment(psp, environment) {
49
54
  if (psp === 'bambora' || psp === 'mercado_pago' || psp === 'recurly' || psp === 'spreedly')
50
55
  return environment === 'shared';
51
56
  return ['square', 'braintree', 'worldpay', 'adyen', 'checkout_com', 'paysafe', 'fiserv', 'cybersource_flex', 'aci', 'creditguard', 'worldpay_eprotect', 'amadeus_checkout', 'verifone',
52
- 'cybersource_secure_acceptance'].includes(psp) && ['production', 'sandbox'].includes(environment);
57
+ 'cybersource_secure_acceptance', 'paddle_vgs'].includes(psp) && ['production', 'sandbox'].includes(environment);
53
58
  }
54
59
  /**
55
60
  * ACI's prepared endpoint, the literal the API names (backend checkout-prepared-processor.ts): its
@@ -91,6 +96,9 @@ export function preparationEndpoint(psp, environment) {
91
96
  // The token-create URL on the environment's host, as the API names it: the one request the claim binds.
92
97
  if (psp === 'cybersource_secure_acceptance')
93
98
  return secureAcceptancePreparationUrl(environment);
99
+ // Paddle VGS: the environment's one card URL, the only URL the claim takes for it.
100
+ if (psp === 'paddle_vgs')
101
+ return PADDLE_VGS_CARDS_URLS[environment];
94
102
  // A Verifone endpoint is its reviewed profile's leg, never one per environment (verifone.ts).
95
103
  if (psp === 'verifone')
96
104
  throw new Error('unsupported_preparation_processor');
@@ -236,6 +244,10 @@ export function matchesPreparedRequest(psp, environment, requestUrl, method, bod
236
244
  // Flex gate verified the issuing field iframe's capture context against that JWE's key.
237
245
  if (psp === 'cybersource_flex')
238
246
  return isPreparedCybersourceFlexRequest(requestUrl, method.toUpperCase(), body ?? null, environment, headers);
247
+ // Paddle VGS: the environment's own card URL and payment-core's whole request rule (the checkout's bearer,
248
+ // the JSON:API content type and the frame's body), the rule the API and the Vault bind with too.
249
+ if (psp === 'paddle_vgs')
250
+ return isPreparedPaddleVgsRequest(requestUrl, method.toUpperCase(), body ?? null, environment, headers ?? {});
239
251
  if (psp === 'creditguard')
240
252
  return matchesPreparedCreditguard(environment, requestUrl, body, headers, binding);
241
253
  // A Verifone request is judged only through the profile its preparation names (matchesPreparation).