@p2pdotme/sdk 1.2.19 → 1.2.21

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.
@@ -72,11 +72,25 @@ interface CountryOption {
72
72
  readonly uploadPaymentQR?: boolean;
73
73
  /** Structural check for a standalone QR payload (no `||` pack). */
74
74
  readonly validateQr?: (payload: string) => boolean;
75
+ /**
76
+ * PAY display: payload to re-draw a stored QR. May be looser than
77
+ * `validateQr` so old orders still render (e.g. Yape/Plin without CRC,
78
+ * Pago Móvil without `merchantId`). Scan & Pay uses `validateQr` /
79
+ * parsers, not this hook. Apps call `getPayQrPayload(currency, id)` —
80
+ * do not branch on currency.
81
+ */
82
+ readonly getPayQrPayload?: (paymentId: string) => string | null;
75
83
  /**
76
84
  * Fill catalog fields from a validated QR (e.g. Yape/Plin phone in EMVCo).
77
85
  * Only used when the typed fallback did not already set the key.
78
86
  */
79
87
  readonly hydrateFieldsFromQr?: (qr: string) => Partial<Record<string, string>>;
88
+ /**
89
+ * i18n key for a warning shown before the payer sends fiat (e.g. a bank
90
+ * outage). Apps call `getTransferWarning(currency)` — do not branch on
91
+ * currency. Omit when there is no warning.
92
+ */
93
+ readonly transferWarning?: string;
80
94
  }
81
95
 
82
96
  /** All supported countries with their currency metadata, payment methods, and display config. */
@@ -93,18 +107,23 @@ declare function uploadsPaymentQR(currency: CurrencyCode | null | undefined): bo
93
107
  */
94
108
  declare function usesPackedPaymentId(currency: CurrencyCode | null | undefined): boolean;
95
109
  /**
96
- * Apps mount the catalog form (PackedPaymentInput): QR upload and/or
97
- * more than one typed field.
110
+ * Apps mount the catalog form (PackedPaymentInput): QR upload and typed
111
+ * fields may both show — they are not exclusive.
98
112
  */
99
113
  declare function usesCatalogPaymentForm(currency: CurrencyCode | null | undefined): boolean;
114
+ /**
115
+ * i18n key for a warning shown before the payer sends fiat, or `null` when the
116
+ * currency has none. Apps translate with `t(key)` — do not branch on currency.
117
+ */
118
+ declare function getTransferWarning(currency: CurrencyCode | null | undefined): string | null;
100
119
 
101
120
  /** Payment ID field configuration for each supported currency. */
102
121
  declare const PAYMENT_ID_FIELDS: Record<CurrencyCode, PaymentIdFieldConfig[]>;
103
122
 
104
123
  /**
105
124
  * Yape/Plin EMVCo: country PE, currency 604, CRC-16/CCITT-FALSE.
106
- * CRC is required on upload so we never persist a truncated screenshot.
107
- * (PAY render in the merchant is looser; that path does not use this.)
125
+ * Same rule for SELL upload and Scan & Pay (`parsePeru`).
126
+ * `getPayQrPayload` may still re-draw a stored blob whose CRC later fails.
108
127
  */
109
128
  declare function validatePeruvianQr(payload: string): boolean;
110
129
  /**
@@ -118,7 +137,8 @@ declare function validateBolivianQr(payload: string): boolean;
118
137
  * Suiche 7B / Pago Móvil collection QR: `base64?merchantId=NNNN&…`.
119
138
  * The base64 is bank AES — we cannot decode phone/RIF from it, only the
120
139
  * envelope. Reject packed `||` IDs so a stored compound string is never
121
- * treated as a QR. Scan & Pay uses the looser `isPagoMovilQr` envelope.
140
+ * treated as a QR. Same rule for SELL upload and Scan & Pay (`parsePagoMovil`).
141
+ * `getPayQrPayload` may still re-draw a stored blob without `merchantId`.
122
142
  */
123
143
  declare function validateVenezuelanQr(payload: string): boolean;
124
144
 
@@ -138,7 +158,7 @@ type PeruvianPaymentIdParts = {
138
158
  phone: string | null;
139
159
  cci: string | null;
140
160
  };
141
- /** QR payload and/or CCI and/or Yape/Plin phone. */
161
+ /** QR payload and/or CCI and/or Yape/Plin phone. A packed rest must be valid typed fields. */
142
162
  declare function validatePeruvianPaymentId(value: string): boolean;
143
163
 
144
164
  /**
@@ -159,7 +179,8 @@ type VenezuelanPaymentIdParts = {
159
179
  };
160
180
  /**
161
181
  * Accepts a Suiche 7B QR payload, the typed `phone|rif|bank` fallback,
162
- * or both packed as `qr||phone|rif|bank`.
182
+ * or both packed as `qr||phone|rif|bank`. A non-empty packed rest must be a
183
+ * valid compound — QR does not mask an incomplete trio.
163
184
  */
164
185
  declare function validateVenezuelanPaymentId(value: string): boolean;
165
186
 
@@ -278,10 +299,21 @@ declare function unpackPackedPaymentId(paymentId: string): {
278
299
  * QR blob from a stored payment ID, or `null` if none / invalid.
279
300
  */
280
301
  declare function getStoredQrPayload(currency: CurrencyCode | null | undefined, paymentId: string | null | undefined): string | null;
302
+ /**
303
+ * Payload to feed `QRCodeSVG` for a PAY (or packed SELL) order.
304
+ * Tries strict `getStoredQrPayload` first, then the country's PAY hook.
305
+ */
306
+ declare function getPayQrPayload(currency: CurrencyCode | null | undefined, paymentId: string | null | undefined): string | null;
281
307
  /**
282
308
  * Builds a stored payment ID: optional validated QR packed with catalog fields.
283
309
  */
284
310
  declare function packStoredPaymentId(currency: CurrencyCode, qr: string | null | undefined, fieldValues: Record<string, string>): string;
311
+ /**
312
+ * Catalog payment form draft: optional QR and/or typed fields may coexist.
313
+ * Neither path is required relative to the other. If any typed field has text,
314
+ * non-optional fields must all be present and valid (`optional` on the catalog).
315
+ */
316
+ declare function validateCatalogPaymentDraft(currency: CurrencyCode, qr: string | null | undefined, fieldValues: Record<string, string>): boolean;
285
317
  /**
286
318
  * Validates a stored payment ID: optional packed QR, then catalog fields.
287
319
  * QR-only is valid when the country exposes `validateQr`.
@@ -298,4 +330,4 @@ declare function assignStoredPaymentIdToFieldValues(currency: CurrencyCode, paym
298
330
  */
299
331
  declare function formatStoredPaymentIdForDisplay(currency: CurrencyCode, paymentId: string): string;
300
332
 
301
- export { COUNTRY_OPTIONS, CURRENCY, CURRENCY_CODES, type CountryOption, type CurrencyCode, PACKED_PAYMENT_ID_SEP, PAYMENT_ID_FIELDS, type PaymentIdFieldConfig, type PeruvianPaymentIdParts, type VenezuelanPaymentIdParts, assignPaymentIdToFieldValues, assignStoredPaymentIdToFieldValues, deserializeCompoundPaymentId, formatCompoundPaymentIdForDisplay, formatStoredPaymentIdForDisplay, getCountryOption, getStoredQrPayload, packStoredPaymentId, serializeCompoundPaymentId, unpackPackedPaymentId, uploadsPaymentQR, usesCatalogPaymentForm, usesPackedPaymentId, validateArgentinePaymentId, validateBolivianAccount, validateBolivianQr, validateColombianPaymentId, validateCubanCardNumber, validateCubanPhoneNumber, validateEcuadorianAccountName, validateEcuadorianAccountNumber, validateEcuadorianCedula, validateIndonesianPhoneNumber, validateMexicanPaymentId, validateNigerianAccountName, validateNigerianAccountNumber, validatePIXId, validatePaymentIdFields, validatePeruvianCci, validatePeruvianPaymentId, validatePeruvianPaymentKey, validatePeruvianPhone, validatePeruvianQr, validatePhilippinePhoneNumber, validateRevolutId, validateStoredPaymentId, validateUPIId, validateVenezuelanPaymentId, validateVenezuelanPhoneNumber, validateVenezuelanQr, validateVenezuelanRif };
333
+ export { COUNTRY_OPTIONS, CURRENCY, CURRENCY_CODES, type CountryOption, type CurrencyCode, PACKED_PAYMENT_ID_SEP, PAYMENT_ID_FIELDS, type PaymentIdFieldConfig, type PeruvianPaymentIdParts, type VenezuelanPaymentIdParts, assignPaymentIdToFieldValues, assignStoredPaymentIdToFieldValues, deserializeCompoundPaymentId, formatCompoundPaymentIdForDisplay, formatStoredPaymentIdForDisplay, getCountryOption, getPayQrPayload, getStoredQrPayload, getTransferWarning, packStoredPaymentId, serializeCompoundPaymentId, unpackPackedPaymentId, uploadsPaymentQR, usesCatalogPaymentForm, usesPackedPaymentId, validateArgentinePaymentId, validateBolivianAccount, validateBolivianQr, validateCatalogPaymentDraft, validateColombianPaymentId, validateCubanCardNumber, validateCubanPhoneNumber, validateEcuadorianAccountName, validateEcuadorianAccountNumber, validateEcuadorianCedula, validateIndonesianPhoneNumber, validateMexicanPaymentId, validateNigerianAccountName, validateNigerianAccountNumber, validatePIXId, validatePaymentIdFields, validatePeruvianCci, validatePeruvianPaymentId, validatePeruvianPaymentKey, validatePeruvianPhone, validatePeruvianQr, validatePhilippinePhoneNumber, validateRevolutId, validateStoredPaymentId, validateUPIId, validateVenezuelanPaymentId, validateVenezuelanPhoneNumber, validateVenezuelanQr, validateVenezuelanRif };
package/dist/country.d.ts CHANGED
@@ -72,11 +72,25 @@ interface CountryOption {
72
72
  readonly uploadPaymentQR?: boolean;
73
73
  /** Structural check for a standalone QR payload (no `||` pack). */
74
74
  readonly validateQr?: (payload: string) => boolean;
75
+ /**
76
+ * PAY display: payload to re-draw a stored QR. May be looser than
77
+ * `validateQr` so old orders still render (e.g. Yape/Plin without CRC,
78
+ * Pago Móvil without `merchantId`). Scan & Pay uses `validateQr` /
79
+ * parsers, not this hook. Apps call `getPayQrPayload(currency, id)` —
80
+ * do not branch on currency.
81
+ */
82
+ readonly getPayQrPayload?: (paymentId: string) => string | null;
75
83
  /**
76
84
  * Fill catalog fields from a validated QR (e.g. Yape/Plin phone in EMVCo).
77
85
  * Only used when the typed fallback did not already set the key.
78
86
  */
79
87
  readonly hydrateFieldsFromQr?: (qr: string) => Partial<Record<string, string>>;
88
+ /**
89
+ * i18n key for a warning shown before the payer sends fiat (e.g. a bank
90
+ * outage). Apps call `getTransferWarning(currency)` — do not branch on
91
+ * currency. Omit when there is no warning.
92
+ */
93
+ readonly transferWarning?: string;
80
94
  }
81
95
 
82
96
  /** All supported countries with their currency metadata, payment methods, and display config. */
@@ -93,18 +107,23 @@ declare function uploadsPaymentQR(currency: CurrencyCode | null | undefined): bo
93
107
  */
94
108
  declare function usesPackedPaymentId(currency: CurrencyCode | null | undefined): boolean;
95
109
  /**
96
- * Apps mount the catalog form (PackedPaymentInput): QR upload and/or
97
- * more than one typed field.
110
+ * Apps mount the catalog form (PackedPaymentInput): QR upload and typed
111
+ * fields may both show — they are not exclusive.
98
112
  */
99
113
  declare function usesCatalogPaymentForm(currency: CurrencyCode | null | undefined): boolean;
114
+ /**
115
+ * i18n key for a warning shown before the payer sends fiat, or `null` when the
116
+ * currency has none. Apps translate with `t(key)` — do not branch on currency.
117
+ */
118
+ declare function getTransferWarning(currency: CurrencyCode | null | undefined): string | null;
100
119
 
101
120
  /** Payment ID field configuration for each supported currency. */
102
121
  declare const PAYMENT_ID_FIELDS: Record<CurrencyCode, PaymentIdFieldConfig[]>;
103
122
 
104
123
  /**
105
124
  * Yape/Plin EMVCo: country PE, currency 604, CRC-16/CCITT-FALSE.
106
- * CRC is required on upload so we never persist a truncated screenshot.
107
- * (PAY render in the merchant is looser; that path does not use this.)
125
+ * Same rule for SELL upload and Scan & Pay (`parsePeru`).
126
+ * `getPayQrPayload` may still re-draw a stored blob whose CRC later fails.
108
127
  */
109
128
  declare function validatePeruvianQr(payload: string): boolean;
110
129
  /**
@@ -118,7 +137,8 @@ declare function validateBolivianQr(payload: string): boolean;
118
137
  * Suiche 7B / Pago Móvil collection QR: `base64?merchantId=NNNN&…`.
119
138
  * The base64 is bank AES — we cannot decode phone/RIF from it, only the
120
139
  * envelope. Reject packed `||` IDs so a stored compound string is never
121
- * treated as a QR. Scan & Pay uses the looser `isPagoMovilQr` envelope.
140
+ * treated as a QR. Same rule for SELL upload and Scan & Pay (`parsePagoMovil`).
141
+ * `getPayQrPayload` may still re-draw a stored blob without `merchantId`.
122
142
  */
123
143
  declare function validateVenezuelanQr(payload: string): boolean;
124
144
 
@@ -138,7 +158,7 @@ type PeruvianPaymentIdParts = {
138
158
  phone: string | null;
139
159
  cci: string | null;
140
160
  };
141
- /** QR payload and/or CCI and/or Yape/Plin phone. */
161
+ /** QR payload and/or CCI and/or Yape/Plin phone. A packed rest must be valid typed fields. */
142
162
  declare function validatePeruvianPaymentId(value: string): boolean;
143
163
 
144
164
  /**
@@ -159,7 +179,8 @@ type VenezuelanPaymentIdParts = {
159
179
  };
160
180
  /**
161
181
  * Accepts a Suiche 7B QR payload, the typed `phone|rif|bank` fallback,
162
- * or both packed as `qr||phone|rif|bank`.
182
+ * or both packed as `qr||phone|rif|bank`. A non-empty packed rest must be a
183
+ * valid compound — QR does not mask an incomplete trio.
163
184
  */
164
185
  declare function validateVenezuelanPaymentId(value: string): boolean;
165
186
 
@@ -278,10 +299,21 @@ declare function unpackPackedPaymentId(paymentId: string): {
278
299
  * QR blob from a stored payment ID, or `null` if none / invalid.
279
300
  */
280
301
  declare function getStoredQrPayload(currency: CurrencyCode | null | undefined, paymentId: string | null | undefined): string | null;
302
+ /**
303
+ * Payload to feed `QRCodeSVG` for a PAY (or packed SELL) order.
304
+ * Tries strict `getStoredQrPayload` first, then the country's PAY hook.
305
+ */
306
+ declare function getPayQrPayload(currency: CurrencyCode | null | undefined, paymentId: string | null | undefined): string | null;
281
307
  /**
282
308
  * Builds a stored payment ID: optional validated QR packed with catalog fields.
283
309
  */
284
310
  declare function packStoredPaymentId(currency: CurrencyCode, qr: string | null | undefined, fieldValues: Record<string, string>): string;
311
+ /**
312
+ * Catalog payment form draft: optional QR and/or typed fields may coexist.
313
+ * Neither path is required relative to the other. If any typed field has text,
314
+ * non-optional fields must all be present and valid (`optional` on the catalog).
315
+ */
316
+ declare function validateCatalogPaymentDraft(currency: CurrencyCode, qr: string | null | undefined, fieldValues: Record<string, string>): boolean;
285
317
  /**
286
318
  * Validates a stored payment ID: optional packed QR, then catalog fields.
287
319
  * QR-only is valid when the country exposes `validateQr`.
@@ -298,4 +330,4 @@ declare function assignStoredPaymentIdToFieldValues(currency: CurrencyCode, paym
298
330
  */
299
331
  declare function formatStoredPaymentIdForDisplay(currency: CurrencyCode, paymentId: string): string;
300
332
 
301
- export { COUNTRY_OPTIONS, CURRENCY, CURRENCY_CODES, type CountryOption, type CurrencyCode, PACKED_PAYMENT_ID_SEP, PAYMENT_ID_FIELDS, type PaymentIdFieldConfig, type PeruvianPaymentIdParts, type VenezuelanPaymentIdParts, assignPaymentIdToFieldValues, assignStoredPaymentIdToFieldValues, deserializeCompoundPaymentId, formatCompoundPaymentIdForDisplay, formatStoredPaymentIdForDisplay, getCountryOption, getStoredQrPayload, packStoredPaymentId, serializeCompoundPaymentId, unpackPackedPaymentId, uploadsPaymentQR, usesCatalogPaymentForm, usesPackedPaymentId, validateArgentinePaymentId, validateBolivianAccount, validateBolivianQr, validateColombianPaymentId, validateCubanCardNumber, validateCubanPhoneNumber, validateEcuadorianAccountName, validateEcuadorianAccountNumber, validateEcuadorianCedula, validateIndonesianPhoneNumber, validateMexicanPaymentId, validateNigerianAccountName, validateNigerianAccountNumber, validatePIXId, validatePaymentIdFields, validatePeruvianCci, validatePeruvianPaymentId, validatePeruvianPaymentKey, validatePeruvianPhone, validatePeruvianQr, validatePhilippinePhoneNumber, validateRevolutId, validateStoredPaymentId, validateUPIId, validateVenezuelanPaymentId, validateVenezuelanPhoneNumber, validateVenezuelanQr, validateVenezuelanRif };
333
+ export { COUNTRY_OPTIONS, CURRENCY, CURRENCY_CODES, type CountryOption, type CurrencyCode, PACKED_PAYMENT_ID_SEP, PAYMENT_ID_FIELDS, type PaymentIdFieldConfig, type PeruvianPaymentIdParts, type VenezuelanPaymentIdParts, assignPaymentIdToFieldValues, assignStoredPaymentIdToFieldValues, deserializeCompoundPaymentId, formatCompoundPaymentIdForDisplay, formatStoredPaymentIdForDisplay, getCountryOption, getPayQrPayload, getStoredQrPayload, getTransferWarning, packStoredPaymentId, serializeCompoundPaymentId, unpackPackedPaymentId, uploadsPaymentQR, usesCatalogPaymentForm, usesPackedPaymentId, validateArgentinePaymentId, validateBolivianAccount, validateBolivianQr, validateCatalogPaymentDraft, validateColombianPaymentId, validateCubanCardNumber, validateCubanPhoneNumber, validateEcuadorianAccountName, validateEcuadorianAccountNumber, validateEcuadorianCedula, validateIndonesianPhoneNumber, validateMexicanPaymentId, validateNigerianAccountName, validateNigerianAccountNumber, validatePIXId, validatePaymentIdFields, validatePeruvianCci, validatePeruvianPaymentId, validatePeruvianPaymentKey, validatePeruvianPhone, validatePeruvianQr, validatePhilippinePhoneNumber, validateRevolutId, validateStoredPaymentId, validateUPIId, validateVenezuelanPaymentId, validateVenezuelanPhoneNumber, validateVenezuelanQr, validateVenezuelanRif };
package/dist/country.mjs CHANGED
@@ -148,6 +148,39 @@ function validateVenezuelanQr(payload) {
148
148
  if (!/^[A-Za-z0-9+/=]+$/.test(blob)) return false;
149
149
  return /(?:^|[?&])merchantId=\d{3,4}(?:&|$)/.test(trimmed.substring(qIdx));
150
150
  }
151
+ function payQrCandidate(paymentId) {
152
+ const trimmed = paymentId.trim();
153
+ const sep = trimmed.indexOf(PACKED_PAYMENT_ID_SEP);
154
+ return (sep >= 0 ? trimmed.slice(0, sep) : trimmed).trim();
155
+ }
156
+ function isPeruvianPayQr(payload) {
157
+ if (!payload.startsWith("0002")) return false;
158
+ return payload.includes("5802PE") && payload.includes("5303604");
159
+ }
160
+ function isVenezuelanPayQr(payload) {
161
+ if (!payload || payload.includes(PACKED_PAYMENT_ID_SEP)) return false;
162
+ const qIdx = payload.indexOf("?");
163
+ if (qIdx === -1) return false;
164
+ const blob = payload.slice(0, qIdx);
165
+ return blob.length > 0 && /^[A-Za-z0-9+/=]+$/.test(blob);
166
+ }
167
+ function isPhilippinePayQr(payload) {
168
+ if (!payload.startsWith("0002")) return false;
169
+ return payload.includes("5802PH") && payload.includes("5303608");
170
+ }
171
+ function isBolivianPayQr(payload) {
172
+ if (!payload || payload.includes(PACKED_PAYMENT_ID_SEP)) return false;
173
+ if (payload.startsWith("0002") && payload.includes("5802BO") && payload.includes("5303068")) {
174
+ return true;
175
+ }
176
+ const sep = payload.lastIndexOf("|");
177
+ if (sep < 40) return false;
178
+ const blob = payload.slice(0, sep);
179
+ const tag = payload.slice(sep + 1);
180
+ if (blob.length % 4 !== 0) return false;
181
+ if (!/^[A-Za-z0-9+/]+={0,2}$/.test(blob)) return false;
182
+ return /^[0-9A-Fa-f]{16,64}$/.test(tag);
183
+ }
151
184
 
152
185
  // src/country/currencies/bob.ts
153
186
  var BOB_PLACEHOLDER = "Bank account number (8\u201320 digits)";
@@ -180,7 +213,7 @@ var BOB_COUNTRY_OPTION = {
180
213
  flag: "\u{1F1E7}\u{1F1F4}",
181
214
  flagUrl: "https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f1e7-1f1f4.png",
182
215
  phoneCode: "+591",
183
- telegramSupportChannel: "https://t.me/p2pmebolivia",
216
+ telegramSupportChannel: "https://t.me/p2pme_bolivia_merchants",
184
217
  twitterUsername: "p2pmebolivia",
185
218
  smsCountryCodes: ["BO"],
186
219
  precision: 2,
@@ -188,7 +221,11 @@ var BOB_COUNTRY_OPTION = {
188
221
  disabled: false,
189
222
  disabledPaymentTypes: [],
190
223
  uploadPaymentQR: true,
191
- validateQr: validateBolivianQr
224
+ validateQr: validateBolivianQr,
225
+ getPayQrPayload: (paymentId) => {
226
+ const candidate = payQrCandidate(paymentId);
227
+ return isBolivianPayQr(candidate) ? candidate : null;
228
+ }
192
229
  };
193
230
 
194
231
  // src/country/currencies/brl.ts
@@ -371,7 +408,8 @@ var CUP_COUNTRY_OPTION = {
371
408
  precision: 2,
372
409
  isAlpha: true,
373
410
  disabled: false,
374
- disabledPaymentTypes: []
411
+ disabledPaymentTypes: [],
412
+ transferWarning: "CUP_BANDEC_WARNING"
375
413
  };
376
414
 
377
415
  // src/country/currencies/ecu.ts
@@ -768,54 +806,24 @@ function extractPeruvianPhoneFromQr(payload) {
768
806
  }
769
807
  return null;
770
808
  }
771
- function parsePeruvianFallback(value) {
772
- const trimmed = value.trim();
773
- if (!trimmed) return { phone: null, cci: null };
774
- const tokens = trimmed.split("|").map((token) => token.trim()).filter(Boolean);
775
- let phone = null;
776
- let cci = null;
777
- for (const token of tokens) {
778
- if (!phone && validatePeruvianPhone(token)) {
779
- phone = normalizePeruvianPaymentKey(token);
780
- continue;
781
- }
782
- if (!cci && validatePeruvianCci(token)) {
783
- cci = normalizePeruvianPaymentKey(token);
784
- }
785
- }
786
- return { phone, cci };
809
+ function isValidPeruvianTypedRest(value) {
810
+ const nonempty = value.split("|").map((token) => token.trim()).filter((token) => token.length > 0);
811
+ if (nonempty.length === 0) return false;
812
+ return nonempty.every((token) => validatePeruvianPhone(token) || validatePeruvianCci(token));
787
813
  }
788
- function parsePeruvianPaymentId(value) {
789
- if (!value || typeof value !== "string") {
790
- return { qr: null, phone: null, cci: null };
791
- }
814
+ function validatePeruvianPaymentId(value) {
815
+ if (!value || typeof value !== "string") return false;
792
816
  const trimmed = value.trim();
793
817
  const sep = trimmed.indexOf(PACKED_PAYMENT_ID_SEP);
794
818
  if (sep >= 0) {
795
819
  const left = trimmed.slice(0, sep);
796
820
  const right = trimmed.slice(sep + PACKED_PAYMENT_ID_SEP.length);
797
- const fallback2 = parsePeruvianFallback(right);
798
- const qr = validatePeruvianQr(left) ? left : null;
799
- return {
800
- qr,
801
- phone: fallback2.phone ?? (qr ? extractPeruvianPhoneFromQr(qr) : null),
802
- cci: fallback2.cci
803
- };
804
- }
805
- if (validatePeruvianQr(trimmed)) {
806
- return {
807
- qr: trimmed,
808
- phone: extractPeruvianPhoneFromQr(trimmed),
809
- cci: null
810
- };
821
+ const qrOk = validatePeruvianQr(left);
822
+ if (right.trim()) return qrOk && isValidPeruvianTypedRest(right);
823
+ return qrOk;
811
824
  }
812
- const fallback = parsePeruvianFallback(trimmed);
813
- return { qr: null, phone: fallback.phone, cci: fallback.cci };
814
- }
815
- function validatePeruvianPaymentId(value) {
816
- if (!value || typeof value !== "string") return false;
817
- const { qr, phone, cci } = parsePeruvianPaymentId(value);
818
- return Boolean(qr || phone || cci);
825
+ if (validatePeruvianQr(trimmed)) return true;
826
+ return isValidPeruvianTypedRest(trimmed);
819
827
  }
820
828
  var PEN_PAYMENT_FIELDS = [
821
829
  {
@@ -858,6 +866,10 @@ var PEN_COUNTRY_OPTION = {
858
866
  disabledPaymentTypes: [],
859
867
  uploadPaymentQR: true,
860
868
  validateQr: validatePeruvianQr,
869
+ getPayQrPayload: (paymentId) => {
870
+ const candidate = payQrCandidate(paymentId);
871
+ return isPeruvianPayQr(candidate) ? candidate : null;
872
+ },
861
873
  hydrateFieldsFromQr: (qr) => {
862
874
  const phone = extractPeruvianPhoneFromQr(qr);
863
875
  return phone ? { phone } : {};
@@ -914,7 +926,11 @@ var PHP_COUNTRY_OPTION = {
914
926
  precision: 2,
915
927
  isAlpha: true,
916
928
  disabled: false,
917
- disabledPaymentTypes: []
929
+ disabledPaymentTypes: [],
930
+ getPayQrPayload: (paymentId) => {
931
+ const candidate = payQrCandidate(paymentId);
932
+ return isPhilippinePayQr(candidate) ? candidate : null;
933
+ }
918
934
  };
919
935
 
920
936
  // src/country/currencies/usd.ts
@@ -993,7 +1009,16 @@ function parseVenezuelanPaymentId(value) {
993
1009
  }
994
1010
  function validateVenezuelanPaymentId(value) {
995
1011
  if (!value || typeof value !== "string") return false;
996
- const { qr, compound } = parseVenezuelanPaymentId(value);
1012
+ const trimmed = value.trim();
1013
+ const sep = trimmed.indexOf(PACKED_PAYMENT_ID_SEP);
1014
+ if (sep >= 0) {
1015
+ const left = trimmed.slice(0, sep);
1016
+ const right = trimmed.slice(sep + PACKED_PAYMENT_ID_SEP.length);
1017
+ const qrOk = validateVenezuelanQr(left);
1018
+ if (right.trim()) return qrOk && isValidVenezuelanCompound(right);
1019
+ return qrOk;
1020
+ }
1021
+ const { qr, compound } = parseVenezuelanPaymentId(trimmed);
997
1022
  return qr !== null || compound !== null;
998
1023
  }
999
1024
  var VEN_PAYMENT_FIELDS = [
@@ -1043,7 +1068,11 @@ var VEN_COUNTRY_OPTION = {
1043
1068
  disabled: false,
1044
1069
  disabledPaymentTypes: [],
1045
1070
  uploadPaymentQR: true,
1046
- validateQr: validateVenezuelanQr
1071
+ validateQr: validateVenezuelanQr,
1072
+ getPayQrPayload: (paymentId) => {
1073
+ const candidate = payQrCandidate(paymentId);
1074
+ return isVenezuelanPayQr(candidate) ? candidate : null;
1075
+ }
1047
1076
  };
1048
1077
 
1049
1078
  // src/country/payment-fields.ts
@@ -1097,6 +1126,9 @@ function usesCatalogPaymentForm(currency) {
1097
1126
  if (!currency) return false;
1098
1127
  return uploadsPaymentQR(currency) || (PAYMENT_ID_FIELDS[currency]?.length ?? 0) > 1;
1099
1128
  }
1129
+ function getTransferWarning(currency) {
1130
+ return getCountryOption(currency)?.transferWarning ?? null;
1131
+ }
1100
1132
 
1101
1133
  // src/country/validators.ts
1102
1134
  function serializeCompoundPaymentId(...fields) {
@@ -1179,12 +1211,14 @@ function getStoredQrPayload(currency, paymentId) {
1179
1211
  if (isStandaloneQr(option.validateQr, trimmed)) return trimmed;
1180
1212
  return null;
1181
1213
  }
1214
+ function getPayQrPayload(currency, paymentId) {
1215
+ if (!currency || !paymentId) return null;
1216
+ const stored = getStoredQrPayload(currency, paymentId);
1217
+ if (stored) return stored;
1218
+ return getCountryOption(currency)?.getPayQrPayload?.(paymentId.trim()) ?? null;
1219
+ }
1182
1220
  function packedTypedRest(fields, fieldValues) {
1183
- const parts = fields.map((field) => {
1184
- const value = (fieldValues[field.key] ?? "").trim();
1185
- if (!value) return "";
1186
- return field.validate(value) ? value : "";
1187
- });
1221
+ const parts = fields.map((field) => (fieldValues[field.key] ?? "").trim());
1188
1222
  if (!parts.some((part) => part.length > 0)) return "";
1189
1223
  return serializeCompoundPaymentId(...parts);
1190
1224
  }
@@ -1200,11 +1234,16 @@ function packStoredPaymentId(currency, qr, fieldValues) {
1200
1234
  function fieldsMatchStoredId(fields, paymentId) {
1201
1235
  if (validatePaymentIdFields(fields, paymentId)) return true;
1202
1236
  const assigned = assignPaymentIdToFieldValues(fields, paymentId);
1203
- const filled = fields.filter((field) => (assigned[field.key] || "").trim().length > 0);
1204
- if (filled.length === 0) return false;
1205
- return fields.every(
1206
- (field) => field.optional === true || (assigned[field.key] || "").trim().length > 0
1207
- );
1237
+ const values = fields.map((field) => (assigned[field.key] || "").trim());
1238
+ if (!values.some((value) => value.length > 0)) return false;
1239
+ return fields.every((field, i) => {
1240
+ const value = values[i];
1241
+ if (!value) return field.optional === true;
1242
+ return field.validate(value);
1243
+ });
1244
+ }
1245
+ function validateCatalogPaymentDraft(currency, qr, fieldValues) {
1246
+ return validateStoredPaymentId(currency, packStoredPaymentId(currency, qr, fieldValues));
1208
1247
  }
1209
1248
  function validateStoredPaymentId(currency, paymentId) {
1210
1249
  if (!paymentId || paymentId.trim().length === 0) return false;
@@ -1233,6 +1272,12 @@ function assignStoredPaymentIdToFieldValues(currency, paymentId) {
1233
1272
  } else if (isStandaloneQr(option?.validateQr, trimmed)) {
1234
1273
  qrPayload = trimmed;
1235
1274
  typed = "";
1275
+ } else {
1276
+ const payQr = option?.getPayQrPayload?.(trimmed);
1277
+ if (payQr) {
1278
+ qrPayload = payQr;
1279
+ typed = qr && payQr === qr ? rest.trim() : "";
1280
+ }
1236
1281
  }
1237
1282
  const values = assignPaymentIdToFieldValues(fields, typed);
1238
1283
  if (qrPayload && option?.hydrateFieldsFromQr) {
@@ -1265,7 +1310,9 @@ export {
1265
1310
  formatCompoundPaymentIdForDisplay,
1266
1311
  formatStoredPaymentIdForDisplay,
1267
1312
  getCountryOption,
1313
+ getPayQrPayload,
1268
1314
  getStoredQrPayload,
1315
+ getTransferWarning,
1269
1316
  packStoredPaymentId,
1270
1317
  serializeCompoundPaymentId,
1271
1318
  unpackPackedPaymentId,
@@ -1275,6 +1322,7 @@ export {
1275
1322
  validateArgentinePaymentId,
1276
1323
  validateBolivianAccount,
1277
1324
  validateBolivianQr,
1325
+ validateCatalogPaymentDraft,
1278
1326
  validateColombianPaymentId,
1279
1327
  validateCubanCardNumber,
1280
1328
  validateCubanPhoneNumber,