@p2pdotme/sdk 1.2.16 → 1.2.18

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 (58) hide show
  1. package/README.md +1 -1
  2. package/dist/country.cjs +480 -62
  3. package/dist/country.cjs.map +1 -1
  4. package/dist/country.d.cts +144 -27
  5. package/dist/country.d.ts +144 -27
  6. package/dist/country.mjs +460 -62
  7. package/dist/country.mjs.map +1 -1
  8. package/dist/fraud-engine.cjs +1 -0
  9. package/dist/fraud-engine.cjs.map +1 -1
  10. package/dist/fraud-engine.mjs +1 -0
  11. package/dist/fraud-engine.mjs.map +1 -1
  12. package/dist/index.cjs +2 -1
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.cts +1 -0
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.mjs +2 -1
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/orders.cjs +1 -0
  19. package/dist/orders.cjs.map +1 -1
  20. package/dist/orders.d.cts +2 -0
  21. package/dist/orders.d.ts +2 -0
  22. package/dist/orders.mjs +1 -0
  23. package/dist/orders.mjs.map +1 -1
  24. package/dist/prices.cjs +1 -0
  25. package/dist/prices.cjs.map +1 -1
  26. package/dist/prices.d.cts +1 -0
  27. package/dist/prices.d.ts +1 -0
  28. package/dist/prices.mjs +1 -0
  29. package/dist/prices.mjs.map +1 -1
  30. package/dist/profile.cjs +1 -0
  31. package/dist/profile.cjs.map +1 -1
  32. package/dist/profile.d.cts +2 -0
  33. package/dist/profile.d.ts +2 -0
  34. package/dist/profile.mjs +1 -0
  35. package/dist/profile.mjs.map +1 -1
  36. package/dist/qr-parsers.cjs +205 -11
  37. package/dist/qr-parsers.cjs.map +1 -1
  38. package/dist/qr-parsers.d.cts +9 -1
  39. package/dist/qr-parsers.d.ts +9 -1
  40. package/dist/qr-parsers.mjs +204 -11
  41. package/dist/qr-parsers.mjs.map +1 -1
  42. package/dist/react.cjs +1 -0
  43. package/dist/react.cjs.map +1 -1
  44. package/dist/react.d.cts +6 -0
  45. package/dist/react.d.ts +6 -0
  46. package/dist/react.mjs +1 -0
  47. package/dist/react.mjs.map +1 -1
  48. package/dist/stake.cjs +1 -0
  49. package/dist/stake.cjs.map +1 -1
  50. package/dist/stake.d.cts +1 -0
  51. package/dist/stake.d.ts +1 -0
  52. package/dist/stake.mjs +1 -0
  53. package/dist/stake.mjs.map +1 -1
  54. package/dist/zkkyc.cjs +1 -0
  55. package/dist/zkkyc.cjs.map +1 -1
  56. package/dist/zkkyc.mjs +1 -0
  57. package/dist/zkkyc.mjs.map +1 -1
  58. package/package.json +1 -1
@@ -20,6 +20,7 @@ var CURRENCY = {
20
20
  ARS: "ARS",
21
21
  MEX: "MEX",
22
22
  VEN: "VEN",
23
+ BOB: "BOB",
23
24
  EUR: "EUR",
24
25
  NGN: "NGN",
25
26
  USD: "USD",
@@ -53,6 +54,98 @@ var ARS_COUNTRY_OPTION = {
53
54
  disabledPaymentTypes: []
54
55
  };
55
56
 
57
+ // src/country/types.ts
58
+ var PACKED_PAYMENT_ID_SEP = "||";
59
+
60
+ // src/country/qr-validator.ts
61
+ function crc16ccitt(s) {
62
+ let crc = 65535;
63
+ for (let i = 0; i < s.length; i++) {
64
+ crc ^= s.charCodeAt(i) << 8;
65
+ for (let j = 0; j < 8; j++) {
66
+ crc = crc & 32768 ? crc << 1 ^ 4129 : crc << 1;
67
+ crc &= 65535;
68
+ }
69
+ }
70
+ return crc.toString(16).toUpperCase().padStart(4, "0");
71
+ }
72
+ function validateEmvcoQr(payload, country, currency) {
73
+ if (!payload || payload.trim().length === 0) return false;
74
+ const data = payload.trim();
75
+ const tags = {};
76
+ let pos = 0;
77
+ while (pos + 4 <= data.length) {
78
+ const tag = data.substring(pos, pos + 2);
79
+ const lengthStr = data.substring(pos + 2, pos + 4);
80
+ if (!/^[0-9]{2}$/.test(tag) || !/^[0-9]{2}$/.test(lengthStr)) break;
81
+ const length = Number.parseInt(lengthStr, 10);
82
+ if (pos + 4 + length > data.length) break;
83
+ tags[tag] = data.substring(pos + 4, pos + 4 + length);
84
+ pos += 4 + length;
85
+ }
86
+ if (tags["58"] !== country) return false;
87
+ if (tags["53"] !== currency) return false;
88
+ const crcTag = tags["63"];
89
+ if (!crcTag) return false;
90
+ const marker = data.lastIndexOf("6304");
91
+ if (marker === -1) return false;
92
+ const expected = crc16ccitt(data.substring(0, marker + 4));
93
+ return expected.toUpperCase() === crcTag.toUpperCase();
94
+ }
95
+ function validatePeruvianQr(payload) {
96
+ return validateEmvcoQr(payload, "PE", "604");
97
+ }
98
+ function isBolivianEncryptedQr(payload) {
99
+ const trimmed = payload.trim();
100
+ if (trimmed.includes(PACKED_PAYMENT_ID_SEP)) return false;
101
+ const sep = trimmed.lastIndexOf("|");
102
+ if (sep < 40) return false;
103
+ const blob = trimmed.slice(0, sep);
104
+ const tag = trimmed.slice(sep + 1);
105
+ if (blob.length % 4 !== 0) return false;
106
+ if (!/^[A-Za-z0-9+/]+={0,2}$/.test(blob)) return false;
107
+ return /^(?:[0-9A-Fa-f]{24}|[0-9A-Fa-f]{32})$/.test(tag);
108
+ }
109
+ function validateBolivianQr(payload) {
110
+ if (!payload || payload.trim().length === 0) return false;
111
+ return isBolivianEncryptedQr(payload) || validateEmvcoQr(payload, "BO", "068");
112
+ }
113
+ function validateVenezuelanQr(payload) {
114
+ if (!payload || typeof payload !== "string") return false;
115
+ const trimmed = payload.trim();
116
+ if (trimmed.includes(PACKED_PAYMENT_ID_SEP)) return false;
117
+ const qIdx = trimmed.indexOf("?");
118
+ if (qIdx < 40) return false;
119
+ const blob = trimmed.substring(0, qIdx);
120
+ if (!/^[A-Za-z0-9+/=]+$/.test(blob)) return false;
121
+ return /(?:^|[?&])merchantId=\d{3,4}(?:&|$)/.test(trimmed.substring(qIdx));
122
+ }
123
+
124
+ // src/country/currencies/bob.ts
125
+ var BOB_COUNTRY_OPTION = {
126
+ country: "Bolivia",
127
+ currency: CURRENCY.BOB,
128
+ internationalFormat: "BOB",
129
+ symbolNative: "Bs.",
130
+ locale: "es-BO",
131
+ paymentMethod: "QR_SIMPLE",
132
+ paymentAddressName: "QR_SIMPLE_DETAILS",
133
+ timezone: "America/La_Paz",
134
+ timezone_name: "BOT",
135
+ flag: "\u{1F1E7}\u{1F1F4}",
136
+ flagUrl: "https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f1e7-1f1f4.png",
137
+ phoneCode: "+591",
138
+ telegramSupportChannel: "https://t.me/p2pmebolivia",
139
+ twitterUsername: "p2pmebolivia",
140
+ smsCountryCodes: ["BO"],
141
+ precision: 2,
142
+ isAlpha: true,
143
+ disabled: false,
144
+ disabledPaymentTypes: [],
145
+ uploadPaymentQR: true,
146
+ validateQr: validateBolivianQr
147
+ };
148
+
56
149
  // src/country/currencies/brl.ts
57
150
  var BRL_COUNTRY_OPTION = {
58
151
  country: "Brazil",
@@ -254,6 +347,55 @@ var NGN_COUNTRY_OPTION = {
254
347
  };
255
348
 
256
349
  // src/country/currencies/pen.ts
350
+ function validatePeruvianPhone(value) {
351
+ if (!value || value.trim().length === 0) return false;
352
+ const phone = value.trim().replace(/\s+/g, "").replace(/^\+?51/, "");
353
+ return /^9\d{8}$/.test(phone);
354
+ }
355
+ function normalizePeruvianPaymentKey(value) {
356
+ const trimmed = value.trim();
357
+ const cci = trimmed.replace(/\s+/g, "");
358
+ if (/^\d{20}$/.test(cci)) return cci;
359
+ const phone = trimmed.replace(/\s+/g, "").replace(/^\+?51/, "");
360
+ if (/^9\d{8}$/.test(phone)) return phone;
361
+ return cci;
362
+ }
363
+ function looksLikeTlv(value) {
364
+ if (value.length < 5 || !/^\d{4}/.test(value)) return false;
365
+ const len = Number.parseInt(value.slice(2, 4), 10);
366
+ return !Number.isNaN(len) && len >= 0 && 4 + len <= value.length;
367
+ }
368
+ function phoneFromTlvValue(value) {
369
+ const trimmed = value.trim();
370
+ if (!trimmed) return null;
371
+ if (validatePeruvianPhone(trimmed)) return normalizePeruvianPaymentKey(trimmed);
372
+ if (/^[0-9a-f]+$/i.test(trimmed) && /[a-f]/i.test(trimmed)) return null;
373
+ const match = trimmed.match(/(^|[^0-9])(\+?51)?(9\d{8})(?![0-9])/);
374
+ if (!match) return null;
375
+ const candidate = `${match[2] ?? ""}${match[3]}`;
376
+ return validatePeruvianPhone(candidate) ? normalizePeruvianPaymentKey(candidate) : null;
377
+ }
378
+ function extractPeruvianPhoneFromQr(payload) {
379
+ let pos = 0;
380
+ while (pos + 4 <= payload.length) {
381
+ const tag = payload.slice(pos, pos + 2);
382
+ const len = Number.parseInt(payload.slice(pos + 2, pos + 4), 10);
383
+ if (Number.isNaN(len) || len < 0 || pos + 4 + len > payload.length) break;
384
+ const value = payload.slice(pos + 4, pos + 4 + len);
385
+ const direct = phoneFromTlvValue(value);
386
+ if (direct) return direct;
387
+ if (tag >= "02" && tag <= "51" || tag === "62" || tag === "64" || looksLikeTlv(value)) {
388
+ const nested = extractPeruvianPhoneFromQr(value);
389
+ if (nested) return nested;
390
+ }
391
+ pos += 4 + len;
392
+ }
393
+ const glued = payload.match(/\+51\s*9\d{8}/);
394
+ if (glued && validatePeruvianPhone(glued[0])) {
395
+ return normalizePeruvianPaymentKey(glued[0]);
396
+ }
397
+ return null;
398
+ }
257
399
  var PEN_COUNTRY_OPTION = {
258
400
  country: "Peru",
259
401
  currency: CURRENCY.PEN,
@@ -272,7 +414,13 @@ var PEN_COUNTRY_OPTION = {
272
414
  precision: 2,
273
415
  isAlpha: true,
274
416
  disabled: false,
275
- disabledPaymentTypes: []
417
+ disabledPaymentTypes: [],
418
+ uploadPaymentQR: true,
419
+ validateQr: validatePeruvianQr,
420
+ hydrateFieldsFromQr: (qr) => {
421
+ const phone = extractPeruvianPhoneFromQr(qr);
422
+ return phone ? { phone } : {};
423
+ }
276
424
  };
277
425
 
278
426
  // src/country/currencies/php.ts
@@ -339,7 +487,9 @@ var VEN_COUNTRY_OPTION = {
339
487
  precision: 2,
340
488
  isAlpha: false,
341
489
  disabled: false,
342
- disabledPaymentTypes: []
490
+ disabledPaymentTypes: [],
491
+ uploadPaymentQR: true,
492
+ validateQr: validateVenezuelanQr
343
493
  };
344
494
 
345
495
  // src/country/countries.ts
@@ -350,6 +500,7 @@ var COUNTRY_OPTIONS = [
350
500
  ARS_COUNTRY_OPTION,
351
501
  MEX_COUNTRY_OPTION,
352
502
  VEN_COUNTRY_OPTION,
503
+ BOB_COUNTRY_OPTION,
353
504
  NGN_COUNTRY_OPTION,
354
505
  COP_COUNTRY_OPTION,
355
506
  CUP_COUNTRY_OPTION,
@@ -465,9 +616,6 @@ function parseMercadoPago(qrData, _sellPrice) {
465
616
  return success({ paymentAddress: merchantName });
466
617
  }
467
618
 
468
- // src/qr-parsers/parsers/brl.ts
469
- import { err as err2, ok as ok2 } from "neverthrow";
470
-
471
619
  // src/qr-parsers/utils/amount.ts
472
620
  var DECIMAL_AMOUNT = /^\d+(\.\d+)?$/;
473
621
  function parseAmount(amountStr, sellPrice) {
@@ -480,7 +628,44 @@ function parseAmount(amountStr, sellPrice) {
480
628
  return { usdc: fiat / sellPrice, fiat };
481
629
  }
482
630
 
631
+ // src/qr-parsers/parsers/bob.ts
632
+ var BOB_TAGS = { AMOUNT: "54", CURRENCY: "53", COUNTRY: "58" };
633
+ function isBolivianEncryptedQr2(payload) {
634
+ if (payload.includes("||")) return false;
635
+ const sep = payload.lastIndexOf("|");
636
+ if (sep < 40) return false;
637
+ const blob = payload.slice(0, sep);
638
+ const tag = payload.slice(sep + 1);
639
+ if (blob.length % 4 !== 0) return false;
640
+ if (!/^[A-Za-z0-9+/]+={0,2}$/.test(blob)) return false;
641
+ return /^(?:[0-9A-Fa-f]{24}|[0-9A-Fa-f]{32})$/.test(tag);
642
+ }
643
+ function parseBolivia(qrData, sellPrice) {
644
+ if (!qrData || typeof qrData !== "string" || qrData.trim().length === 0) {
645
+ return failure("INVALID_QR", "QR data is empty or invalid");
646
+ }
647
+ const trimmed = qrData.trim();
648
+ if (isBolivianEncryptedQr2(trimmed)) {
649
+ return success({ paymentAddress: trimmed });
650
+ }
651
+ const tags = extractTags(trimmed, [BOB_TAGS.AMOUNT, BOB_TAGS.CURRENCY, BOB_TAGS.COUNTRY]);
652
+ if (tags[BOB_TAGS.COUNTRY] !== "BO" || tags[BOB_TAGS.CURRENCY] !== "068") {
653
+ return failure("INVALID_QR", "Not a valid Bolivia QR Simple QR");
654
+ }
655
+ const result = { paymentAddress: trimmed };
656
+ const amountStr = tags[BOB_TAGS.AMOUNT];
657
+ if (amountStr) {
658
+ const amount = parseAmount(amountStr, sellPrice);
659
+ if (!amount) {
660
+ return failure("INVALID_AMOUNT", "Invalid amount in QR");
661
+ }
662
+ result.amount = amount;
663
+ }
664
+ return success(result);
665
+ }
666
+
483
667
  // src/qr-parsers/parsers/brl.ts
668
+ import { err as err2, ok as ok2 } from "neverthrow";
484
669
  var PIX_TAGS = {
485
670
  PAYLOAD_FORMAT: "00",
486
671
  PIX_KEY_INFO: "26",
@@ -900,17 +1085,22 @@ function parseQRPh(qrData, sellPrice) {
900
1085
  }
901
1086
 
902
1087
  // src/qr-parsers/parsers/ven.ts
903
- function parsePagoMovil(qrData, _sellPrice) {
1088
+ function isPagoMovilQr(qrData) {
904
1089
  if (!qrData || typeof qrData !== "string" || qrData.trim().length === 0) {
905
- return failure("INVALID_QR", "QR data is empty or invalid");
1090
+ return false;
906
1091
  }
907
1092
  const trimmed = qrData.trim();
908
1093
  const qIdx = trimmed.indexOf("?");
909
- if (qIdx === -1) {
910
- return failure("INVALID_QR", "Not a valid Venezuelan QR code");
911
- }
1094
+ if (qIdx === -1) return false;
912
1095
  const payload = trimmed.substring(0, qIdx);
913
- if (!payload || !/^[A-Za-z0-9+/=]+$/.test(payload)) {
1096
+ return !!payload && /^[A-Za-z0-9+/=]+$/.test(payload);
1097
+ }
1098
+ function parsePagoMovil(qrData, _sellPrice) {
1099
+ if (!qrData || typeof qrData !== "string" || qrData.trim().length === 0) {
1100
+ return failure("INVALID_QR", "QR data is empty or invalid");
1101
+ }
1102
+ const trimmed = qrData.trim();
1103
+ if (!isPagoMovilQr(trimmed)) {
914
1104
  return failure("INVALID_QR", "Not a valid Venezuelan QR code");
915
1105
  }
916
1106
  return success({ paymentAddress: trimmed });
@@ -933,6 +1123,8 @@ async function parseQR(params) {
933
1123
  return parseMercadoPago(qrData, sellPrice);
934
1124
  case CURRENCY.VEN:
935
1125
  return parsePagoMovil(qrData, sellPrice);
1126
+ case CURRENCY.BOB:
1127
+ return parseBolivia(qrData, sellPrice);
936
1128
  case CURRENCY.NGN:
937
1129
  return parseNGN(qrData, sellPrice);
938
1130
  case CURRENCY.COP:
@@ -951,6 +1143,7 @@ async function parseQR(params) {
951
1143
  }
952
1144
  export {
953
1145
  QRParserError,
1146
+ isPagoMovilQr,
954
1147
  parseQR
955
1148
  };
956
1149
  //# sourceMappingURL=qr-parsers.mjs.map