@agent-cards/sdk 0.23.22 → 0.23.24

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.
Files changed (54) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/PREFLIGHT.md +2 -0
  3. package/README.md +34 -4
  4. package/dist/aci.generated.js +3 -3
  5. package/dist/agent-amount.generated.d.ts +7 -0
  6. package/dist/agent-amount.generated.js +3 -0
  7. package/dist/amadeus.d.ts +5 -2
  8. package/dist/amadeus.js +18 -3
  9. package/dist/amazon-payment-services.d.ts +25 -0
  10. package/dist/amazon-payment-services.generated.d.ts +76 -0
  11. package/dist/amazon-payment-services.generated.js +883 -0
  12. package/dist/amazon-payment-services.js +53 -0
  13. package/dist/capabilities.generated.d.ts +2 -0
  14. package/dist/capabilities.generated.js +3 -0
  15. package/dist/card-fields.generated.js +1127 -25
  16. package/dist/cdp.js +116 -15
  17. package/dist/client.d.ts +107 -8
  18. package/dist/client.js +277 -128
  19. package/dist/hosted-entry.js +2 -1
  20. package/dist/hosted-form.d.ts +5 -0
  21. package/dist/hosted-form.js +5 -0
  22. package/dist/index.d.ts +1 -0
  23. package/dist/index.js +1 -0
  24. package/dist/openpay.generated.d.ts +67 -0
  25. package/dist/openpay.generated.js +446 -0
  26. package/dist/paddle-checkout-watch.d.ts +70 -0
  27. package/dist/paddle-checkout-watch.js +239 -0
  28. package/dist/paddle-tokenex.generated.d.ts +29 -1
  29. package/dist/paddle-tokenex.generated.js +175 -26
  30. package/dist/paytrail.d.ts +58 -0
  31. package/dist/paytrail.js +98 -0
  32. package/dist/pre-claim.d.ts +4 -0
  33. package/dist/pre-claim.js +46 -2
  34. package/dist/prepared-processor.d.ts +12 -4
  35. package/dist/prepared-processor.js +31 -5
  36. package/dist/primer.generated.js +1155 -53
  37. package/dist/registry.d.ts +4 -3
  38. package/dist/registry.js +12 -4
  39. package/dist/sbps.d.ts +57 -0
  40. package/dist/sbps.generated.d.ts +96 -0
  41. package/dist/sbps.generated.js +427 -0
  42. package/dist/sbps.js +90 -0
  43. package/dist/stripe-checkout.generated.js +458 -8
  44. package/dist/tap-payments.d.ts +43 -0
  45. package/dist/tap-payments.generated.d.ts +59 -0
  46. package/dist/tap-payments.generated.js +990 -0
  47. package/dist/tap-payments.js +72 -0
  48. package/dist/transbank.d.ts +33 -0
  49. package/dist/transbank.js +62 -0
  50. package/dist/url-mask-parts.d.ts +24 -0
  51. package/dist/url-mask-parts.js +22 -0
  52. package/dist/url-masks.generated.d.ts +3 -0
  53. package/dist/url-masks.generated.js +2 -0
  54. package/package.json +4 -4
@@ -0,0 +1,990 @@
1
+ // @ts-nocheck
2
+ // Generated from @agent-cards/payment-core. Do not edit.
3
+ // artifact-sha256: 25bf499d00df8220a58e6f28f22522db1f7a4048dcdbd95ad321614df5b68b6d
4
+ // src/sha256.js
5
+ var K = /* @__PURE__ */ new Uint32Array([
6
+ 1116352408,
7
+ 1899447441,
8
+ 3049323471,
9
+ 3921009573,
10
+ 961987163,
11
+ 1508970993,
12
+ 2453635748,
13
+ 2870763221,
14
+ 3624381080,
15
+ 310598401,
16
+ 607225278,
17
+ 1426881987,
18
+ 1925078388,
19
+ 2162078206,
20
+ 2614888103,
21
+ 3248222580,
22
+ 3835390401,
23
+ 4022224774,
24
+ 264347078,
25
+ 604807628,
26
+ 770255983,
27
+ 1249150122,
28
+ 1555081692,
29
+ 1996064986,
30
+ 2554220882,
31
+ 2821834349,
32
+ 2952996808,
33
+ 3210313671,
34
+ 3336571891,
35
+ 3584528711,
36
+ 113926993,
37
+ 338241895,
38
+ 666307205,
39
+ 773529912,
40
+ 1294757372,
41
+ 1396182291,
42
+ 1695183700,
43
+ 1986661051,
44
+ 2177026350,
45
+ 2456956037,
46
+ 2730485921,
47
+ 2820302411,
48
+ 3259730800,
49
+ 3345764771,
50
+ 3516065817,
51
+ 3600352804,
52
+ 4094571909,
53
+ 275423344,
54
+ 430227734,
55
+ 506948616,
56
+ 659060556,
57
+ 883997877,
58
+ 958139571,
59
+ 1322822218,
60
+ 1537002063,
61
+ 1747873779,
62
+ 1955562222,
63
+ 2024104815,
64
+ 2227730452,
65
+ 2361852424,
66
+ 2428436474,
67
+ 2756734187,
68
+ 3204031479,
69
+ 3329325298
70
+ ]);
71
+ var rotr = (x, n) => x >>> n | x << 32 - n;
72
+ function utf8(text) {
73
+ const out = [];
74
+ for (const char of text) {
75
+ let cp = char.codePointAt(0);
76
+ if (cp >= 55296 && cp <= 57343)
77
+ cp = 65533;
78
+ if (cp < 128)
79
+ out.push(cp);
80
+ else if (cp < 2048)
81
+ out.push(192 | cp >> 6, 128 | cp & 63);
82
+ else if (cp < 65536)
83
+ out.push(224 | cp >> 12, 128 | cp >> 6 & 63, 128 | cp & 63);
84
+ else
85
+ out.push(240 | cp >> 18, 128 | cp >> 12 & 63, 128 | cp >> 6 & 63, 128 | cp & 63);
86
+ }
87
+ return Uint8Array.from(out);
88
+ }
89
+ function sha256Hex(input) {
90
+ const isBytes = Object.prototype.toString.call(input) === "[object Uint8Array]";
91
+ if (typeof input !== "string" && !isBytes)
92
+ throw new TypeError("sha256Hex takes a string or a Uint8Array.");
93
+ const bytes = typeof input === "string" ? utf8(input) : input;
94
+ const length = bytes.length;
95
+ const padded = new Uint8Array((length + 8 >> 6) + 1 << 6);
96
+ padded.set(bytes);
97
+ padded[length] = 128;
98
+ const view = new DataView(padded.buffer);
99
+ view.setUint32(padded.length - 8, Math.floor(length / 536870912));
100
+ view.setUint32(padded.length - 4, length << 3 >>> 0);
101
+ const H = new Uint32Array([1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225]);
102
+ const W = new Uint32Array(64);
103
+ for (let offset = 0; offset < padded.length; offset += 64) {
104
+ for (let t = 0; t < 16; t++)
105
+ W[t] = view.getUint32(offset + t * 4);
106
+ for (let t = 16; t < 64; t++) {
107
+ const s0 = rotr(W[t - 15], 7) ^ rotr(W[t - 15], 18) ^ W[t - 15] >>> 3;
108
+ const s1 = rotr(W[t - 2], 17) ^ rotr(W[t - 2], 19) ^ W[t - 2] >>> 10;
109
+ W[t] = W[t - 16] + s0 + W[t - 7] + s1 >>> 0;
110
+ }
111
+ let a = H[0], b = H[1], c = H[2], d = H[3], e = H[4], f = H[5], g = H[6], h = H[7];
112
+ for (let t = 0; t < 64; t++) {
113
+ const t1 = h + (rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) + (e & f ^ ~e & g) + K[t] + W[t] >>> 0;
114
+ const t2 = (rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) + (a & b ^ a & c ^ b & c) >>> 0;
115
+ h = g;
116
+ g = f;
117
+ f = e;
118
+ e = d + t1 >>> 0;
119
+ d = c;
120
+ c = b;
121
+ b = a;
122
+ a = t1 + t2 >>> 0;
123
+ }
124
+ H[0] += a;
125
+ H[1] += b;
126
+ H[2] += c;
127
+ H[3] += d;
128
+ H[4] += e;
129
+ H[5] += f;
130
+ H[6] += g;
131
+ H[7] += h;
132
+ }
133
+ return Array.from(H, (word) => word.toString(16).padStart(8, "0")).join("");
134
+ }
135
+ // src/rsa-pkcs1v15.js
136
+ var RsaPkcs1v15Error = class extends Error {
137
+ constructor(reason) {
138
+ super("RSA PKCS#1 v1.5 encryption refused.");
139
+ this.name = "RsaPkcs1v15Error";
140
+ this.code = "rsa_pkcs1v15_refused";
141
+ this.reason = reason;
142
+ }
143
+ };
144
+ var refuse = (reason) => new RsaPkcs1v15Error(reason);
145
+ var BASE64 = /^[A-Za-z0-9+/]+={0,2}$/;
146
+ var SHA256_HEX = /^[0-9a-f]{64}$/;
147
+ var RSA_ALGORITHM = [48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0];
148
+ var MODULUS_BYTES = [128, 256, 384, 512];
149
+ var MIN_PADDING = 8;
150
+ var MAX_DRAWS = 16;
151
+ var TYPED_ARRAY = Object.getPrototypeOf(Uint8Array.prototype);
152
+ var typedArrayName = Object.getOwnPropertyDescriptor(TYPED_ARRAY, Symbol.toStringTag).get;
153
+ function parseRsaPublicKey(key) {
154
+ const spki = key && typeof key === "object" ? key.spki : void 0;
155
+ const pin2 = key && typeof key === "object" ? key.sha256 : void 0;
156
+ const named = key && typeof key === "object" && Object.prototype.hasOwnProperty.call(key, "exponent") ? key.exponent : void 0;
157
+ if (named !== void 0 && named !== 17)
158
+ throw refuse("key");
159
+ if (typeof spki !== "string" || spki.length > 1024 || spki.length % 4 !== 0 || !BASE64.test(spki))
160
+ throw refuse("key");
161
+ if (typeof pin2 !== "string" || !SHA256_HEX.test(pin2))
162
+ throw refuse("key");
163
+ let binary;
164
+ try {
165
+ binary = atob(spki);
166
+ }
167
+ catch {
168
+ throw refuse("key");
169
+ }
170
+ if (btoa(binary) !== spki)
171
+ throw refuse("key");
172
+ const der = Uint8Array.from(binary, (c) => c.charCodeAt(0));
173
+ if (sha256Hex(der) !== pin2)
174
+ throw refuse("key");
175
+ const outer = readElement(der, 0, 48);
176
+ if (outer.end !== der.length || outer.start + RSA_ALGORITHM.length > der.length)
177
+ throw refuse("key");
178
+ if (!RSA_ALGORITHM.every((byte, i) => der[outer.start + i] === byte))
179
+ throw refuse("key");
180
+ const bits = readElement(der, outer.start + RSA_ALGORITHM.length, 3);
181
+ if (bits.end !== outer.end || bits.start === bits.end || der[bits.start] !== 0)
182
+ throw refuse("key");
183
+ const rsa = readElement(der, bits.start + 1, 48);
184
+ if (rsa.end !== bits.end)
185
+ throw refuse("key");
186
+ const modulus = readPositiveInteger(der, rsa.start);
187
+ const exponent = readPositiveInteger(der, modulus.end);
188
+ if (exponent.end !== rsa.end)
189
+ throw refuse("key");
190
+ const n = modulus.bytes;
191
+ if (!MODULUS_BYTES.includes(n.length) || !(n[0] & 128) || !(n[n.length - 1] & 1))
192
+ throw refuse("key");
193
+ const e = exponent.bytes;
194
+ const expected = named === 17 ? [17] : [1, 0, 1];
195
+ if (e.length !== expected.length || !expected.every((byte, i) => e[i] === byte))
196
+ throw refuse("key");
197
+ return Object.freeze({ n: toBigInt(n), e: named === 17 ? 17n : 65537n, size: n.length });
198
+ }
199
+ function rsaesPkcs1v15Encrypt(key, message, random) {
200
+ const { n, e, size } = parseRsaPublicKey(key);
201
+ if (typedArrayName.call(message) !== "Uint8Array")
202
+ throw refuse("message");
203
+ let bytes;
204
+ try {
205
+ bytes = new Uint8Array(message);
206
+ }
207
+ catch {
208
+ throw refuse("message");
209
+ }
210
+ const em = new Uint8Array(size);
211
+ try {
212
+ if (bytes.length > size - MIN_PADDING - 3)
213
+ throw refuse("message");
214
+ em[1] = 2;
215
+ fillNonZero(em.subarray(2, size - bytes.length - 1), random);
216
+ em.set(bytes, size - bytes.length);
217
+ return toBytes(modPow(toBigInt(em), e, n), size);
218
+ }
219
+ finally {
220
+ em.fill(0);
221
+ bytes.fill(0);
222
+ }
223
+ }
224
+ function readElement(der, at, tag) {
225
+ if (at + 2 > der.length || der[at] !== tag)
226
+ throw refuse("key");
227
+ let length = der[at + 1];
228
+ let start = at + 2;
229
+ if (length & 128) {
230
+ const count = length & 127;
231
+ if (count === 0 || count > 2 || start + count > der.length || der[start] === 0)
232
+ throw refuse("key");
233
+ length = count === 1 ? der[start] : der[start] * 256 + der[start + 1];
234
+ if (length < 128)
235
+ throw refuse("key");
236
+ start += count;
237
+ }
238
+ if (start + length > der.length)
239
+ throw refuse("key");
240
+ return { start, end: start + length };
241
+ }
242
+ function readPositiveInteger(der, at) {
243
+ const { start, end } = readElement(der, at, 2);
244
+ if (end === start || der[start] & 128)
245
+ throw refuse("key");
246
+ if (der[start] === 0 && (end - start === 1 || !(der[start + 1] & 128)))
247
+ throw refuse("key");
248
+ return { bytes: der.subarray(der[start] === 0 ? start + 1 : start, end), end };
249
+ }
250
+ function fillNonZero(target, random) {
251
+ if (!random || typeof random.getRandomValues !== "function")
252
+ throw refuse("random");
253
+ const draw = new Uint8Array(target.length);
254
+ let filled = 0;
255
+ try {
256
+ for (let round = 0; round < MAX_DRAWS && filled < target.length; round++) {
257
+ draw.fill(0);
258
+ random.getRandomValues(draw);
259
+ for (let i = 0; i < draw.length && filled < target.length; i++)
260
+ if (draw[i] !== 0)
261
+ target[filled++] = draw[i];
262
+ }
263
+ }
264
+ catch {
265
+ throw refuse("random");
266
+ }
267
+ finally {
268
+ draw.fill(0);
269
+ }
270
+ if (filled < target.length)
271
+ throw refuse("random");
272
+ }
273
+ function toBigInt(bytes) {
274
+ let hex = "";
275
+ for (let i = 0; i < bytes.length; i++)
276
+ hex += (bytes[i] < 16 ? "0" : "") + bytes[i].toString(16);
277
+ return BigInt(`0x${hex}`);
278
+ }
279
+ function toBytes(value, size) {
280
+ const hex = value.toString(16).padStart(size * 2, "0");
281
+ const out = new Uint8Array(size);
282
+ for (let i = 0; i < size; i++)
283
+ out[i] = parseInt(hex.slice(2 * i, 2 * i + 2), 16);
284
+ return out;
285
+ }
286
+ function modPow(base, exponent, modulus) {
287
+ let result = 1n;
288
+ let square = base % modulus;
289
+ for (let rest = exponent; rest > 0n; rest >>= 1n) {
290
+ if (rest & 1n)
291
+ result = result * square % modulus;
292
+ square = square * square % modulus;
293
+ }
294
+ return result;
295
+ }
296
+ // src/adyen-jwe.js
297
+ var ADYEN_JWE_HEADER = { alg: "RSA-OAEP-256", enc: "A256GCM", version: "1" };
298
+ var BASE64URL = /^[A-Za-z0-9_-]+$/;
299
+ function isAdyenJweCompact(s) {
300
+ if (typeof s !== "string" || s.length > 2048)
301
+ return false;
302
+ const parts = s.split(".");
303
+ if (parts.length !== 5)
304
+ return false;
305
+ const [header, encryptedKey, iv, ciphertext, tag] = parts;
306
+ if (!parts.every((p) => p.length > 0 && BASE64URL.test(p)))
307
+ return false;
308
+ if (encryptedKey.length !== 342 || iv.length !== 16 || tag.length !== 22)
309
+ return false;
310
+ if (ciphertext.length > 1024)
311
+ return false;
312
+ return isAdyenJweHeader(header);
313
+ }
314
+ function isAdyenJweHeader(segment) {
315
+ if (!BASE64URL.test(segment) || segment.length > 128)
316
+ return false;
317
+ let parsed;
318
+ try {
319
+ parsed = JSON.parse(new TextDecoder().decode(Uint8Array.from(atob(segment.replace(/-/g, "+").replace(/_/g, "/")), (c) => c.charCodeAt(0))));
320
+ }
321
+ catch {
322
+ return false;
323
+ }
324
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
325
+ return false;
326
+ const obj = parsed;
327
+ const keys = Object.keys(obj).sort();
328
+ if (keys.join(",") !== "alg,enc,version")
329
+ return false;
330
+ return obj.alg === ADYEN_JWE_HEADER.alg && obj.enc === ADYEN_JWE_HEADER.enc && obj.version === ADYEN_JWE_HEADER.version;
331
+ }
332
+ // src/json-path.js
333
+ var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
334
+ function isPlainObject(v) {
335
+ return !!v && typeof v === "object" && !Array.isArray(v);
336
+ }
337
+ var MAX_PATH_STEPS = 16;
338
+ function isJsonPath(path) {
339
+ return Array.isArray(path) && path.length <= MAX_PATH_STEPS && path.every((step) => typeof step === "string" ? step.length > 0 && !FORBIDDEN_KEYS.has(step) : Number.isSafeInteger(step) && step >= 0);
340
+ }
341
+ function jsonAt(root, path) {
342
+ let node = root;
343
+ for (const step of path) {
344
+ if (typeof step === "string") {
345
+ if (!isPlainObject(node) || FORBIDDEN_KEYS.has(step) || !Object.prototype.hasOwnProperty.call(node, step))
346
+ return { found: false };
347
+ }
348
+ else if (!Array.isArray(node) || !Number.isSafeInteger(step) || step < 0 || step >= node.length) {
349
+ return { found: false };
350
+ }
351
+ node = node[step];
352
+ }
353
+ return { found: true, value: node };
354
+ }
355
+ function roundTrips(parsed, body) {
356
+ try {
357
+ return JSON.stringify(parsed) === body;
358
+ }
359
+ catch {
360
+ return false;
361
+ }
362
+ }
363
+ function sameSteps(a, b) {
364
+ return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((step, i) => step === b[i]);
365
+ }
366
+ function pathsOverlap(a, b) {
367
+ const n = Math.min(a.length, b.length);
368
+ for (let i = 0; i < n; i += 1)
369
+ if (a[i] !== b[i])
370
+ return false;
371
+ return true;
372
+ }
373
+ function describePath(path) {
374
+ return path.length ? path.map((step) => typeof step === "number" ? `[${step}]` : `.${step}`).join("").replace(/^\./, "") : "(root)";
375
+ }
376
+ // src/substitution-primitives.js
377
+ var SubstitutionError = class extends Error {
378
+ constructor(message) {
379
+ super(message);
380
+ this.name = "SubstitutionError";
381
+ }
382
+ };
383
+ var SWAP_MEMBERS = /* @__PURE__ */ new Set(["path", "fields", "remove", "set"]);
384
+ function checkedSet(set, path, names, remove) {
385
+ if (!Array.isArray(set))
386
+ throw new SubstitutionError("substitutions.set is not a list");
387
+ const entries = [...set].map((raw) => {
388
+ const entry = isPlainObject(raw) ? Object.fromEntries(Object.entries(raw)) : null;
389
+ if (!entry || Object.keys(entry).sort().join(",") !== "path,value")
390
+ throw new SubstitutionError("a set entry is not a {path, value}");
391
+ const at = Array.isArray(entry.path) ? [...entry.path] : entry.path;
392
+ if (!isJsonPath(at) || at.length === 0 || typeof at[at.length - 1] !== "string")
393
+ throw new SubstitutionError("refusing set path");
394
+ const value = entry.value;
395
+ if (value !== null && !["string", "boolean"].includes(typeof value) && !(typeof value === "number" && Number.isFinite(value))) {
396
+ throw new SubstitutionError(`the set value at ${describePath(at)} is not a string, number, boolean or null`);
397
+ }
398
+ const key = at[at.length - 1];
399
+ if (sameSteps(at.slice(0, -1), path) && (names.includes(key) || remove.includes(key))) {
400
+ throw new SubstitutionError(`the set entry at ${describePath(at)} writes over an encrypted field or a removed key`);
401
+ }
402
+ return { path: at, value };
403
+ });
404
+ for (const [i, a] of entries.entries()) {
405
+ for (const b of entries.slice(i + 1)) {
406
+ if (pathsOverlap(a.path, b.path))
407
+ throw new SubstitutionError(`two set entries write at ${describePath(a.path)}`);
408
+ }
409
+ }
410
+ return entries;
411
+ }
412
+ var ADYEN_JWE = /* @__PURE__ */ Object.freeze({ accepts: isAdyenJweCompact, label: "an Adyen JWE" });
413
+ function swapMerchantHostedFields(body, spec, ciphertext = ADYEN_JWE) {
414
+ if (!isPlainObject(spec))
415
+ throw new SubstitutionError("refusing a substitution that is not an object");
416
+ for (const member of Object.keys(spec)) {
417
+ if (!SWAP_MEMBERS.has(member))
418
+ throw new SubstitutionError(`unexpected substitution member ${member}`);
419
+ }
420
+ const path = Array.isArray(spec.path) ? [...spec.path] : spec.path;
421
+ const fields = isPlainObject(spec.fields) ? Object.fromEntries(Object.entries(spec.fields)) : null;
422
+ const remove = Array.isArray(spec.remove) ? [...spec.remove] : spec.remove ?? [];
423
+ if (!isJsonPath(path))
424
+ throw new SubstitutionError("refusing substitution path");
425
+ if (!fields || Object.keys(fields).length === 0)
426
+ throw new SubstitutionError("substitutions carry no fields");
427
+ const names = Object.keys(fields);
428
+ const values = names.map((name) => fields[name]);
429
+ for (const name of names) {
430
+ if (FORBIDDEN_KEYS.has(name))
431
+ throw new SubstitutionError(`refusing substitution field ${name}`);
432
+ if (!ciphertext.accepts(fields[name]))
433
+ throw new SubstitutionError(`substitution for ${name} is not ${ciphertext.label}`);
434
+ }
435
+ if (!Array.isArray(remove))
436
+ throw new SubstitutionError("substitutions.remove is not a list");
437
+ for (const key of remove) {
438
+ if (typeof key !== "string" || !key || FORBIDDEN_KEYS.has(key))
439
+ throw new SubstitutionError(`refusing removal of ${String(key)}`);
440
+ if (names.includes(key))
441
+ throw new SubstitutionError(`substitution field ${key} is also listed for removal`);
442
+ }
443
+ if (new Set(remove).size !== remove.length)
444
+ throw new SubstitutionError("substitutions.remove names a key twice");
445
+ const set = checkedSet(spec.set ?? [], path, names, remove);
446
+ if (typeof body !== "string")
447
+ throw new SubstitutionError("the paused body is not JSON");
448
+ let parsed;
449
+ try {
450
+ parsed = JSON.parse(body);
451
+ }
452
+ catch {
453
+ throw new SubstitutionError("the paused body is not JSON");
454
+ }
455
+ if (!isPlainObject(parsed))
456
+ throw new SubstitutionError("the paused body is not a JSON object");
457
+ const holder = jsonAt(parsed, path);
458
+ if (!holder.found || !isPlainObject(holder.value))
459
+ throw new SubstitutionError(`the paused body has no object at ${describePath(path)}`);
460
+ const swaps = /* @__PURE__ */ new Map();
461
+ for (const name of names) {
462
+ const dummy = Object.prototype.hasOwnProperty.call(holder.value, name) ? holder.value[name] : void 0;
463
+ if (typeof dummy !== "string")
464
+ throw new SubstitutionError(`the paused body has no string field ${name} at ${describePath(path)}`);
465
+ if (!ciphertext.accepts(dummy))
466
+ throw new SubstitutionError(`the paused field ${name} is not ${ciphertext.label}`);
467
+ if (swaps.has(dummy))
468
+ throw new SubstitutionError("two paused fields carry the same ciphertext");
469
+ swaps.set(dummy, fields[name]);
470
+ }
471
+ const dummies = [...swaps.keys()];
472
+ if (new Set(values).size !== values.length || values.some((value) => swaps.has(value))) {
473
+ throw new SubstitutionError("two ciphertexts in this substitution are the same");
474
+ }
475
+ const texts = [...dummies, ...values];
476
+ for (const a of texts)
477
+ for (const b of texts)
478
+ if (a !== b && b.includes(a))
479
+ throw new SubstitutionError("one ciphertext is part of another");
480
+ if ((remove.length > 0 || set.length > 0) && !roundTrips(parsed, body)) {
481
+ throw new SubstitutionError("the paused body does not round-trip through JSON, so it cannot be edited");
482
+ }
483
+ for (const entry of set) {
484
+ const parent = jsonAt(parsed, entry.path.slice(0, -1));
485
+ if (!parent.found || !isPlainObject(parent.value)) {
486
+ throw new SubstitutionError(`the paused body has no object at ${describePath(entry.path.slice(0, -1))} to write a value in`);
487
+ }
488
+ const key = entry.path[entry.path.length - 1];
489
+ const current = Object.prototype.hasOwnProperty.call(parent.value, key) ? parent.value[key] : void 0;
490
+ if (current !== null && typeof current === "object") {
491
+ throw new SubstitutionError(`refusing to write over the object at ${describePath(entry.path)}`);
492
+ }
493
+ }
494
+ const seen = /* @__PURE__ */ new Set();
495
+ const pattern = new RegExp(dummies.map((text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|"), "g");
496
+ const swapped = body.replace(pattern, (text) => {
497
+ seen.add(text);
498
+ return swaps.get(text);
499
+ });
500
+ if (seen.size !== dummies.length)
501
+ throw new SubstitutionError("a paused field is not written verbatim in the body");
502
+ let out;
503
+ try {
504
+ out = JSON.parse(swapped);
505
+ }
506
+ catch {
507
+ throw new SubstitutionError("the substituted body is not JSON");
508
+ }
509
+ const written = jsonAt(out, path);
510
+ if (!written.found || !isPlainObject(written.value) || names.some((name) => written.value[name] !== fields[name]) || dummies.some((dummy) => swapped.includes(dummy))) {
511
+ throw new SubstitutionError(`the substitution did not land at ${describePath(path)}`);
512
+ }
513
+ if (remove.length === 0 && set.length === 0)
514
+ return swapped;
515
+ for (const key of remove)
516
+ if (Object.prototype.hasOwnProperty.call(written.value, key))
517
+ delete written.value[key];
518
+ for (const entry of set) {
519
+ const parent = jsonAt(out, entry.path.slice(0, -1));
520
+ if (!parent.found || !isPlainObject(parent.value))
521
+ throw new SubstitutionError(`the set entry at ${describePath(entry.path)} did not land`);
522
+ parent.value[entry.path[entry.path.length - 1]] = entry.value;
523
+ }
524
+ return JSON.stringify(out);
525
+ }
526
+ // src/tap-payments.js
527
+ var TAP_PAYMENTS_PSP = "tap_payments";
528
+ var TAP_PAYMENTS_CAPABILITY = "tap_card_sdk_token";
529
+ var TAP_PAYMENTS_OPERATION = "tap_payments.encrypted_card";
530
+ var TAP_PAYMENTS_SCHEME = "rsa-pkcs1v15";
531
+ var TAP_PAYMENTS_HOST = "sdk.tap.company";
532
+ var TAP_PAYMENTS_TOKEN_URL = "https://sdk.tap.company/v2/card/token";
533
+ var TAP_PAYMENTS_FIELD = "encryptedData";
534
+ var TAP_PAYMENTS_PURPOSES = /* @__PURE__ */ Object.freeze(["CHARGE", "AUTHORIZE"]);
535
+ var TAP_PAYMENTS_REFUSAL_CODES = /* @__PURE__ */ Object.freeze([
536
+ "tap_payments_url_refused",
537
+ "tap_payments_headers_refused",
538
+ "tap_payments_body_unsupported",
539
+ "tap_payments_keep_on_file",
540
+ "tap_payments_merchant_unreviewed",
541
+ "tap_payments_card_unsupported"
542
+ ]);
543
+ var MESSAGES = /* @__PURE__ */ Object.freeze({
544
+ tap_payments_url_refused: "Refusing to pay: this Tap card request does not go to Tap's card frame exactly as the frame sends it. Nothing was sent.",
545
+ tap_payments_headers_refused: "Refusing to pay: this Tap card request does not carry the frame's own headers. Nothing was sent.",
546
+ tap_payments_body_unsupported: "Refusing to pay: this is not the card request of Tap's card form. Nothing was sent.",
547
+ tap_payments_keep_on_file: "Refusing to pay: this Tap payment asks to keep the card on file. Nothing was sent.",
548
+ tap_payments_merchant_unreviewed: "Refusing to pay: Agentcard has not reviewed this Tap merchant. Nothing was sent.",
549
+ tap_payments_card_unsupported: "Could not encrypt this card for Tap. Nothing was sent."
550
+ });
551
+ function tapPaymentsRefusalMessage(code) {
552
+ return Object.prototype.hasOwnProperty.call(MESSAGES, code) ? MESSAGES[code] : MESSAGES.tap_payments_body_unsupported;
553
+ }
554
+ var TapPaymentsError = class extends Error {
555
+ constructor(code) {
556
+ const known = Object.prototype.hasOwnProperty.call(MESSAGES, code) ? code : "tap_payments_body_unsupported";
557
+ super(MESSAGES[known]);
558
+ this.name = "TapPaymentsError";
559
+ this.code = known;
560
+ }
561
+ };
562
+ var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
563
+ function isTapPaymentsTokenUrl(url) {
564
+ return url === TAP_PAYMENTS_TOKEN_URL;
565
+ }
566
+ var PUBLISHABLE_KEY = /^pk_(live|test)_[A-Za-z0-9]{16,64}$/;
567
+ function tapPaymentsKeyEnvironment(publishableKey) {
568
+ const match = typeof publishableKey === "string" ? PUBLISHABLE_KEY.exec(publishableKey) : null;
569
+ if (!match)
570
+ return null;
571
+ return match[1] === "live" ? "production" : "sandbox";
572
+ }
573
+ var pin = (fields) => Object.freeze({
574
+ ...fields,
575
+ origins: Object.freeze([...fields.origins]),
576
+ sessions: Object.freeze({ ...fields.sessions }),
577
+ key: Object.freeze({ ...fields.key })
578
+ });
579
+ var TAP_PAYMENTS_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
580
+ pin({
581
+ id: "casefilegame",
582
+ merchant: "Casefilegame",
583
+ tapMerchantId: "67977048",
584
+ publishableKey: "pk_live_ydlRjrWcLXaVvpsSBQKOie86",
585
+ environment: "production",
586
+ origins: ["https://checkout.tap.company"],
587
+ // The WooCommerce plugin's redirect (Plugin-WooCommerce-All-in-one tap.php 567-586, read 2026-10-17)
588
+ // creates the src_all charge with save_card false and names no agreement, subscription or destinations.
589
+ sessions: { saveCard: false, agreement: false, subscription: false, destinations: false },
590
+ key: {
591
+ spki: "MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAzja2vB+Iyafj2Mm3pFg65z7Yvj9ZeoFLdMBgWFyyjF020r5HSPKVhuZ39uJkjs0U/kWgEpKDzHZAKdtGv36dS33NjMAzYpgFkD8j+9/YWqpvAGRj5nv1b/q7NaiZk3b1wm7aXHJOx5L6rPQf2qDQxhcSNHocU+Uy8wGmGxRRu6QRKN3khaz4o4jJDzqxns4h/ShzHjdZeWIVfpCAyVoED0IESBYrvGEhJeyKnga5XdHdBU2yP8P1huO4RbSKcZv00ZgxVHAQQ9CqArW3TE8SyLLnJPkSpSHHBnIPSQS1z3ld1mImy/zqTd4ltkV6XHpYqVvoPmys2EuZX3pMvCcPGwIBEQ==",
592
+ sha256: "6eb4e89a1e05a06a39d631f6fb450c052a9cad9935edc1921e84e80207470552",
593
+ // The shared parser takes exponent 17 only under a pin that names it (rsa-pkcs1v15.js).
594
+ exponent: 17
595
+ }
596
+ })
597
+ ]);
598
+ var SESSION_REVIEW = /* @__PURE__ */ Object.freeze(["saveCard", "agreement", "subscription", "destinations"]);
599
+ var keepsNoCard = (entry) => record(entry.sessions) && SESSION_REVIEW.every((key) => entry.sessions[key] === false);
600
+ function tapPaymentsMerchantPin(publishableKey, pins = TAP_PAYMENTS_MERCHANT_PINS) {
601
+ const environment = tapPaymentsKeyEnvironment(publishableKey);
602
+ if (!environment || !Array.isArray(pins))
603
+ return null;
604
+ return pins.find((entry) => record(entry) && entry.publishableKey === publishableKey && entry.environment === environment && keepsNoCard(entry)) ?? null;
605
+ }
606
+ function tapPaymentsMerchantRefusal(environment, publishableKey, merchantOrigin, pins = TAP_PAYMENTS_MERCHANT_PINS) {
607
+ const found = tapPaymentsMerchantPin(publishableKey, pins);
608
+ if (!found || found.environment !== environment || typeof merchantOrigin !== "string" || !found.origins.includes(merchantOrigin)) {
609
+ return "tap_payments_merchant_unreviewed";
610
+ }
611
+ return null;
612
+ }
613
+ var BODY_LIMIT = 16384;
614
+ var ROOT_KEYS = /* @__PURE__ */ Object.freeze([
615
+ "encryptedData",
616
+ "purpose",
617
+ "customer",
618
+ "consent",
619
+ "merchant",
620
+ "order",
621
+ "payment_agreement",
622
+ "client_ip",
623
+ "device",
624
+ "browser",
625
+ "app"
626
+ ]);
627
+ var REQUIRED_KEYS = /* @__PURE__ */ Object.freeze(["encryptedData", "purpose", "order", "device", "browser", "app"]);
628
+ var SAVE_PURPOSES = /* @__PURE__ */ Object.freeze(["SAVE_TOKEN", "SAVE_AUTHENTICATED_TOKEN"]);
629
+ var ORDER_KEYS = /* @__PURE__ */ Object.freeze(["amount", "currency", "id", "description", "metadata", "reference"]);
630
+ var DEVICE_KEYS = /* @__PURE__ */ Object.freeze(["source", "ip"]);
631
+ var BROWSER_KEYS = /* @__PURE__ */ Object.freeze(["name", "id"]);
632
+ var APP_KEYS = /* @__PURE__ */ Object.freeze(["identifier", "name", "version", "iframe_version", "sdk_version"]);
633
+ var CIPHERTEXT_BYTES = /* @__PURE__ */ Object.freeze([128, 256, 384, 512]);
634
+ var BASE642 = /^[A-Za-z0-9+/]+={0,2}$/;
635
+ var CURRENCY = /^[A-Z]{3}$/;
636
+ var TEXT_LIMIT = 512;
637
+ var CONTROL = /[\u0000-\u001f\u007f]/;
638
+ var CARD_LONG_DIGITS = /(?:\p{Nd}[\s-]?){12}\p{Nd}/u;
639
+ var NESTING_LIMIT = 4;
640
+ var MEMBERS_LIMIT = 64;
641
+ var refuse2 = (code) => Object.freeze({ verdict: "refuse", code });
642
+ var CARD = /* @__PURE__ */ Object.freeze({ verdict: "card" });
643
+ function decodedBytes(value) {
644
+ if (typeof value !== "string" || value.length % 4 !== 0 || !BASE642.test(value))
645
+ return -1;
646
+ try {
647
+ if (btoa(atob(value)) !== value)
648
+ return -1;
649
+ }
650
+ catch {
651
+ return -1;
652
+ }
653
+ const pad = value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0;
654
+ return value.length / 4 * 3 - pad;
655
+ }
656
+ function isTapPaymentsCiphertext(value) {
657
+ return CIPHERTEXT_BYTES.includes(decodedBytes(value));
658
+ }
659
+ function readBody(body) {
660
+ if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT)
661
+ return null;
662
+ try {
663
+ const value = JSON.parse(body);
664
+ return record(value) && JSON.stringify(value) === body ? value : null;
665
+ }
666
+ catch {
667
+ return null;
668
+ }
669
+ }
670
+ var inOrder = (keys, order) => {
671
+ let at = -1;
672
+ for (const key of keys) {
673
+ const next = order.indexOf(key);
674
+ if (next <= at)
675
+ return false;
676
+ at = next;
677
+ }
678
+ return true;
679
+ };
680
+ var onlyKeys = (value, allowed) => record(value) && Object.keys(value).every((key) => allowed.includes(key));
681
+ var plainText = (value) => typeof value === "string" && value.length <= TEXT_LIMIT && !CONTROL.test(value) && !CARD_LONG_DIGITS.test(value);
682
+ var plainScalar = (value) => value === null || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value) && !CARD_LONG_DIGITS.test(String(value)) || plainText(value);
683
+ function plainJson(value, depth = 0, budget = { members: 0 }) {
684
+ if (depth > NESTING_LIMIT)
685
+ return false;
686
+ if (Array.isArray(value)) {
687
+ budget.members += value.length;
688
+ return budget.members <= MEMBERS_LIMIT && value.every((item) => plainJson(item, depth + 1, budget));
689
+ }
690
+ if (record(value)) {
691
+ const keys = Object.keys(value);
692
+ budget.members += keys.length;
693
+ return budget.members <= MEMBERS_LIMIT && keys.every((key) => plainText(key) && plainJson(value[key], depth + 1, budget));
694
+ }
695
+ return plainScalar(value);
696
+ }
697
+ function soundOrder(order) {
698
+ if (!onlyKeys(order, ORDER_KEYS) || !inOrder(Object.keys(order), ORDER_KEYS))
699
+ return false;
700
+ if ("amount" in order && !(typeof order.amount === "number" && Number.isFinite(order.amount) && order.amount >= 0 && !CARD_LONG_DIGITS.test(String(order.amount))))
701
+ return false;
702
+ if ("currency" in order && !(typeof order.currency === "string" && CURRENCY.test(order.currency)))
703
+ return false;
704
+ if ("id" in order && !plainText(order.id))
705
+ return false;
706
+ if ("description" in order && !plainText(order.description))
707
+ return false;
708
+ if ("metadata" in order && !plainJson(order.metadata))
709
+ return false;
710
+ return !("reference" in order) || plainJson(order.reference);
711
+ }
712
+ var soundDevice = (device) => onlyKeys(device, DEVICE_KEYS) && inOrder(Object.keys(device), DEVICE_KEYS) && (device.source === "web" || device.source === "app") && (!("ip" in device) || plainText(device.ip));
713
+ var soundBrowser = (browser) => onlyKeys(browser, BROWSER_KEYS) && inOrder(Object.keys(browser), BROWSER_KEYS) && (!("name" in browser) || plainText(browser.name)) && plainText(browser.id);
714
+ var versionValue = (value) => plainText(value) || typeof value === "number" && Number.isFinite(value) && !CARD_LONG_DIGITS.test(String(value));
715
+ var soundApp = (app) => onlyKeys(app, APP_KEYS) && inOrder(Object.keys(app), APP_KEYS) && app.identifier === "card_sdk" && app.name === "card_sdk" && ["version", "iframe_version", "sdk_version"].every((key) => !(key in app) || versionValue(app[key]));
716
+ function tapPaymentsBodyVerdict(body) {
717
+ const value = readBody(body);
718
+ if (value === null)
719
+ return refuse2("tap_payments_body_unsupported");
720
+ const keys = Object.keys(value);
721
+ if (!keys.every((key) => ROOT_KEYS.includes(key)) || !inOrder(keys, ROOT_KEYS) || !REQUIRED_KEYS.every((key) => keys.includes(key))) {
722
+ return refuse2("tap_payments_body_unsupported");
723
+ }
724
+ if (!isTapPaymentsCiphertext(value.encryptedData))
725
+ return refuse2("tap_payments_body_unsupported");
726
+ if (typeof value.purpose !== "string")
727
+ return refuse2("tap_payments_body_unsupported");
728
+ if (SAVE_PURPOSES.includes(value.purpose))
729
+ return refuse2("tap_payments_keep_on_file");
730
+ if (!TAP_PAYMENTS_PURPOSES.includes(value.purpose))
731
+ return refuse2("tap_payments_body_unsupported");
732
+ if ("payment_agreement" in value && value.payment_agreement !== null)
733
+ return refuse2("tap_payments_keep_on_file");
734
+ if ("consent" in value) {
735
+ const consent = value.consent;
736
+ if (!record(consent) || Object.keys(consent).length !== 1 || typeof consent.acknowledge !== "boolean")
737
+ return refuse2("tap_payments_body_unsupported");
738
+ if (consent.acknowledge)
739
+ return refuse2("tap_payments_keep_on_file");
740
+ }
741
+ if ("customer" in value && !(record(value.customer) && plainJson(value.customer)) || "merchant" in value && !(record(value.merchant) && plainJson(value.merchant)) || "client_ip" in value && value.client_ip !== null && !plainText(value.client_ip) || !soundOrder(value.order) || !soundDevice(value.device) || !soundBrowser(value.browser) || !soundApp(value.app)) {
742
+ return refuse2("tap_payments_body_unsupported");
743
+ }
744
+ return CARD;
745
+ }
746
+ function tapPaymentsOrderAmount(body) {
747
+ if (tapPaymentsBodyVerdict(body).verdict !== "card")
748
+ return null;
749
+ const order = JSON.parse(body).order;
750
+ return "amount" in order && "currency" in order ? Object.freeze({ amount: order.amount, currency: order.currency }) : null;
751
+ }
752
+ function headerValue(headers, name) {
753
+ const found = Object.keys(headers).filter((key) => key.toLowerCase() === name);
754
+ return found.length === 1 && typeof headers[found[0]] === "string" ? headers[found[0]] : null;
755
+ }
756
+ var JSON_TYPE = /^application\/json(?:\s*;\s*charset=utf-8)?$/i;
757
+ function tapPaymentsRequestKey(request) {
758
+ const headers = record(request) && record(request.headers) ? request.headers : {};
759
+ const authorization = headerValue(headers, "authorization");
760
+ return authorization !== null && tapPaymentsKeyEnvironment(authorization) ? authorization : null;
761
+ }
762
+ function namesPinnedMerchant(body, merchantPin) {
763
+ if (!("merchant" in body))
764
+ return true;
765
+ const keys = Object.keys(body.merchant);
766
+ if (keys.length === 0)
767
+ return true;
768
+ if (keys.length !== 1 || keys[0] !== "id")
769
+ return false;
770
+ const id = body.merchant.id;
771
+ return (typeof id === "number" && Number.isSafeInteger(id) ? String(id) : id) === merchantPin.tapMerchantId;
772
+ }
773
+ function tapPaymentsRequestRefusal(request) {
774
+ if (!record(request) || typeof request.method !== "string" || request.method.toUpperCase() !== "POST")
775
+ return "tap_payments_url_refused";
776
+ if (!isTapPaymentsTokenUrl(request.url))
777
+ return "tap_payments_url_refused";
778
+ const headers = record(request.headers) ? request.headers : {};
779
+ const contentType = headerValue(headers, "content-type");
780
+ const publishableKey = tapPaymentsRequestKey(request);
781
+ if (contentType === null || !JSON_TYPE.test(contentType.trim()) || publishableKey === null)
782
+ return "tap_payments_headers_refused";
783
+ const verdict = tapPaymentsBodyVerdict(request.body);
784
+ if (verdict.verdict !== "card")
785
+ return verdict.code;
786
+ const merchantPin = tapPaymentsMerchantPin(publishableKey);
787
+ return merchantPin && namesPinnedMerchant(JSON.parse(request.body), merchantPin) ? null : "tap_payments_merchant_unreviewed";
788
+ }
789
+ var NAME_LIMIT = 24;
790
+ var NETWORKS = /* @__PURE__ */ Object.freeze([
791
+ { network: "visa", test: /^4[0-9]{15}$/, cvc: /^[0-9]{3}$/ },
792
+ { network: "mastercard", test: /^(?:5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}$/, cvc: /^[0-9]{3}$/ },
793
+ { network: "amex", test: /^3[47][0-9]{13}$/, cvc: /^[0-9]{4}$/ }
794
+ ]);
795
+ function holderName(name) {
796
+ if (typeof name !== "string")
797
+ return "";
798
+ return name.normalize("NFKD").replace(/[^A-Za-z\s.'-]/g, "").replace(/\s+/g, " ").trim().toUpperCase().slice(0, NAME_LIMIT).trim();
799
+ }
800
+ function tapPaymentsPlaintext(card) {
801
+ if (!record(card))
802
+ throw new TapPaymentsError("tap_payments_card_unsupported");
803
+ const number = String(card.number ?? "").replace(/[\s-]/g, "");
804
+ const cvc = String(card.cvc ?? "");
805
+ const monthText = String(card.month ?? "");
806
+ const yearText = String(card.year ?? "");
807
+ const network = NETWORKS.find((entry) => entry.test.test(number));
808
+ const month = /^[0-9]{1,2}$/.test(monthText) ? Number(monthText) : 0;
809
+ const name = holderName(card.name);
810
+ if (!network || !network.cvc.test(cvc) || month < 1 || month > 12 || !/^(?:[0-9]{2}|[0-9]{4})$/.test(yearText) || name === "") {
811
+ throw new TapPaymentsError("tap_payments_card_unsupported");
812
+ }
813
+ return JSON.stringify({ cvc, exp_month: String(month).padStart(2, "0"), exp_year: yearText.slice(-2), name, number });
814
+ }
815
+ function base64(bytes) {
816
+ let binary = "";
817
+ for (let i = 0; i < bytes.length; i++)
818
+ binary += String.fromCharCode(bytes[i]);
819
+ return btoa(binary);
820
+ }
821
+ function encryptTapPaymentsCard(card, publishableKey, facilities = {}) {
822
+ const merchantPin = tapPaymentsMerchantPin(publishableKey);
823
+ if (!merchantPin)
824
+ throw new TapPaymentsError("tap_payments_merchant_unreviewed");
825
+ const message = new TextEncoder().encode(tapPaymentsPlaintext(card));
826
+ try {
827
+ return Object.freeze({ encryptedData: base64(rsaesPkcs1v15Encrypt(merchantPin.key, message, facilities.crypto ?? globalThis.crypto)) });
828
+ }
829
+ finally {
830
+ message.fill(0);
831
+ }
832
+ }
833
+ function ciphertextInteger(value) {
834
+ const binary = atob(value);
835
+ let hex = "";
836
+ for (let i = 0; i < binary.length; i++)
837
+ hex += binary.charCodeAt(i).toString(16).padStart(2, "0");
838
+ return BigInt(`0x${hex}`);
839
+ }
840
+ function isTapPaymentsCiphertextUnderPin(value, merchantPin) {
841
+ if (!record(merchantPin) || !record(merchantPin.key))
842
+ return false;
843
+ let parsed;
844
+ try {
845
+ parsed = parseRsaPublicKey(merchantPin.key);
846
+ }
847
+ catch {
848
+ return false;
849
+ }
850
+ if (decodedBytes(value) !== parsed.size)
851
+ return false;
852
+ const c = ciphertextInteger(value);
853
+ return c > 1n && c < parsed.n;
854
+ }
855
+ var TAP_CIPHERTEXT = /* @__PURE__ */ Object.freeze({ accepts: isTapPaymentsCiphertext, label: "a Tap ciphertext" });
856
+ function substitutionOf(substitution) {
857
+ if (!record(substitution))
858
+ return null;
859
+ const keys = Object.keys(substitution);
860
+ return keys.length === 1 && keys[0] === TAP_PAYMENTS_FIELD && typeof substitution.encryptedData === "string" ? substitution.encryptedData : null;
861
+ }
862
+ function substituteTapPayments(request, substitution) {
863
+ const refusal = tapPaymentsRequestRefusal(request);
864
+ if (refusal)
865
+ throw new SubstitutionError(tapPaymentsRefusalMessage(refusal));
866
+ const value = substitutionOf(substitution);
867
+ if (value === null)
868
+ throw new SubstitutionError("the substitution must carry exactly encryptedData");
869
+ const merchantPin = tapPaymentsMerchantPin(tapPaymentsRequestKey(request));
870
+ if (!isTapPaymentsCiphertextUnderPin(value, merchantPin)) {
871
+ throw new SubstitutionError("substitution for encryptedData does not have the size and range of the merchant's pinned key");
872
+ }
873
+ if (value === JSON.parse(request.body).encryptedData)
874
+ throw new SubstitutionError("the ciphertext in this substitution is already in the body");
875
+ const out = swappedBody(request.body, value);
876
+ if (out === null)
877
+ throw new SubstitutionError("the substitution did not land at encryptedData alone");
878
+ return out;
879
+ }
880
+ function swappedBody(body, value) {
881
+ let out;
882
+ try {
883
+ out = swapMerchantHostedFields(body, { path: [], fields: { encryptedData: value } }, TAP_CIPHERTEXT);
884
+ }
885
+ catch (error) {
886
+ if (error instanceof SubstitutionError)
887
+ return null;
888
+ throw error;
889
+ }
890
+ const paused = JSON.parse(body);
891
+ const written = tapPaymentsBodyVerdict(out).verdict === "card" ? JSON.parse(out) : null;
892
+ if (!written || written.encryptedData !== value || JSON.stringify({ ...written, encryptedData: "" }) !== JSON.stringify({ ...paused, encryptedData: "" })) {
893
+ return null;
894
+ }
895
+ return out;
896
+ }
897
+ function tapPaymentsSubstitutionsRefusal(template, substitution) {
898
+ const refuseWith = (message) => ({ code: "invalid_substitutions", message });
899
+ if (tapPaymentsRequestRefusal(template) !== null)
900
+ return refuseWith("This authorization is not the card request of a reviewed Tap merchant.");
901
+ const value = substitutionOf(substitution);
902
+ if (value === null)
903
+ return refuseWith("substitutions must carry exactly this field: encryptedData.");
904
+ if (!isTapPaymentsCiphertextUnderPin(value, tapPaymentsMerchantPin(tapPaymentsRequestKey(template)))) {
905
+ return refuseWith("substitutions.encryptedData does not have the size and range of the merchant's pinned key.");
906
+ }
907
+ if (value === JSON.parse(template.body).encryptedData)
908
+ return refuseWith("substitutions must be a new ciphertext, not the one in the paused request.");
909
+ if (swappedBody(template.body, value) === null)
910
+ return refuseWith("substitutions.encryptedData cannot be written at encryptedData alone in the paused request.");
911
+ return null;
912
+ }
913
+ function tapPaymentsKeyUsable(authorization) {
914
+ if (!record(authorization) || !record(authorization.cse))
915
+ return false;
916
+ const cse = authorization.cse;
917
+ if (cse.psp !== TAP_PAYMENTS_PSP || cse.scheme !== TAP_PAYMENTS_SCHEME)
918
+ return false;
919
+ if (cse.public_key != null || cse.client_key != null || Object.prototype.hasOwnProperty.call(cse, "merchant_hosted"))
920
+ return false;
921
+ if (!isTapPaymentsTokenUrl(authorization.url))
922
+ return false;
923
+ const merchantPin = tapPaymentsMerchantPin(cse.publishable_key);
924
+ if (!merchantPin || cse.environment !== merchantPin.environment || authorization.sandbox !== (merchantPin.environment === "sandbox"))
925
+ return false;
926
+ try {
927
+ return parseRsaPublicKey(merchantPin.key).size > 0;
928
+ }
929
+ catch {
930
+ return false;
931
+ }
932
+ }
933
+ var ANSWER_LIMIT = 65536;
934
+ var TOKEN_ID = /^tok_[A-Za-z0-9]{8,64}$/;
935
+ var REFUSAL_CODE = /^[A-Za-z0-9_.:-]{1,64}$/;
936
+ var MAX_CODE_DIGITS = 11;
937
+ function readAnswer(text) {
938
+ if (typeof text !== "string" || text === "" || text.length > ANSWER_LIMIT)
939
+ return null;
940
+ try {
941
+ const value = JSON.parse(text);
942
+ return record(value) ? value : null;
943
+ }
944
+ catch {
945
+ return null;
946
+ }
947
+ }
948
+ var boundedCode = (value) => typeof value === "string" && REFUSAL_CODE.test(value) && (value.match(/[0-9]/g) ?? []).length <= MAX_CODE_DIGITS ? value : null;
949
+ function tapPaymentsRefusalCode(text) {
950
+ const answer = readAnswer(text);
951
+ const first = answer && Array.isArray(answer.errors) && record(answer.errors[0]) ? answer.errors[0] : null;
952
+ if (!first)
953
+ return null;
954
+ const code = typeof first.code === "number" && Number.isSafeInteger(first.code) ? String(first.code) : first.code;
955
+ return boundedCode(code) ?? boundedCode(first.error);
956
+ }
957
+ function tapPaymentsAnswerOutcome(status, text, card) {
958
+ const unknown = (reason) => ({ outcome: "unknown", reason });
959
+ if (!Number.isInteger(status))
960
+ return unknown("tap_payments_unconfirmed");
961
+ if (status >= 500)
962
+ return unknown("server_error");
963
+ if (status >= 400)
964
+ return { outcome: "refused", code: tapPaymentsRefusalCode(text) ?? `http_${status}` };
965
+ if (status < 200 || status >= 300)
966
+ return unknown("tap_payments_unconfirmed");
967
+ const answer = readAnswer(text);
968
+ if (answer === null)
969
+ return unknown("tap_payments_unconfirmed");
970
+ if (Array.isArray(answer.errors) && answer.errors.length > 0) {
971
+ return { outcome: "refused", code: tapPaymentsRefusalCode(text) ?? "tap_payments_error" };
972
+ }
973
+ if (Object.prototype.hasOwnProperty.call(answer, "errors") && answer.errors !== null && !Array.isArray(answer.errors)) {
974
+ return unknown("tap_payments_unconfirmed");
975
+ }
976
+ if (typeof answer.id !== "string" || !TOKEN_ID.test(answer.id) || answer.object !== "token" || Object.prototype.hasOwnProperty.call(answer, "status") && answer.status !== "ACTIVE") {
977
+ return unknown("tap_payments_unconfirmed");
978
+ }
979
+ if (card) {
980
+ const number = String(card.number ?? "").replace(/[^0-9]/g, "");
981
+ if (number.length >= 12 && text.includes(number))
982
+ return unknown("tap_payments_unsafe_response");
983
+ const facts = record(answer.card) ? answer.card : null;
984
+ if (!facts || facts.last_four !== number.slice(-4) || Object.prototype.hasOwnProperty.call(facts, "first_six") && facts.first_six !== number.slice(0, 6)) {
985
+ return unknown("tap_payments_token_mismatch");
986
+ }
987
+ }
988
+ return { outcome: "approved" };
989
+ }
990
+ export { TAP_PAYMENTS_CAPABILITY, TAP_PAYMENTS_FIELD, TAP_PAYMENTS_HOST, TAP_PAYMENTS_MERCHANT_PINS, TAP_PAYMENTS_OPERATION, TAP_PAYMENTS_PSP, TAP_PAYMENTS_PURPOSES, TAP_PAYMENTS_REFUSAL_CODES, TAP_PAYMENTS_SCHEME, TAP_PAYMENTS_TOKEN_URL, TapPaymentsError, encryptTapPaymentsCard, isTapPaymentsCiphertext, isTapPaymentsCiphertextUnderPin, isTapPaymentsTokenUrl, substituteTapPayments, tapPaymentsAnswerOutcome, tapPaymentsBodyVerdict, tapPaymentsKeyEnvironment, tapPaymentsKeyUsable, tapPaymentsMerchantPin, tapPaymentsMerchantRefusal, tapPaymentsOrderAmount, tapPaymentsPlaintext, tapPaymentsRefusalCode, tapPaymentsRefusalMessage, tapPaymentsRequestKey, tapPaymentsRequestRefusal, tapPaymentsSubstitutionsRefusal };