@p2pdotme/sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +155 -0
- package/dist/fraud-engine.cjs +598 -0
- package/dist/fraud-engine.cjs.map +1 -0
- package/dist/fraud-engine.d.cts +194 -0
- package/dist/fraud-engine.d.ts +194 -0
- package/dist/fraud-engine.mjs +549 -0
- package/dist/fraud-engine.mjs.map +1 -0
- package/dist/index.cjs +75 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +49 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.mjs +46 -0
- package/dist/index.mjs.map +1 -0
- package/dist/order-routing.cjs +882 -0
- package/dist/order-routing.cjs.map +1 -0
- package/dist/order-routing.d.cts +68 -0
- package/dist/order-routing.d.ts +68 -0
- package/dist/order-routing.mjs +854 -0
- package/dist/order-routing.mjs.map +1 -0
- package/dist/payload.cjs +3164 -0
- package/dist/payload.cjs.map +1 -0
- package/dist/payload.d.cts +162 -0
- package/dist/payload.d.ts +162 -0
- package/dist/payload.mjs +3120 -0
- package/dist/payload.mjs.map +1 -0
- package/dist/profile.cjs +695 -0
- package/dist/profile.cjs.map +1 -0
- package/dist/profile.d.cts +133 -0
- package/dist/profile.d.ts +133 -0
- package/dist/profile.mjs +667 -0
- package/dist/profile.mjs.map +1 -0
- package/dist/qr-parsers.cjs +366 -0
- package/dist/qr-parsers.cjs.map +1 -0
- package/dist/qr-parsers.d.cts +41 -0
- package/dist/qr-parsers.d.ts +41 -0
- package/dist/qr-parsers.mjs +338 -0
- package/dist/qr-parsers.mjs.map +1 -0
- package/dist/react.cjs +4803 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +511 -0
- package/dist/react.d.ts +511 -0
- package/dist/react.mjs +4759 -0
- package/dist/react.mjs.map +1 -0
- package/dist/zkkyc.cjs +868 -0
- package/dist/zkkyc.cjs.map +1 -0
- package/dist/zkkyc.d.cts +230 -0
- package/dist/zkkyc.d.ts +230 -0
- package/dist/zkkyc.mjs +824 -0
- package/dist/zkkyc.mjs.map +1 -0
- package/package.json +130 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
// src/qr-parsers/errors.ts
|
|
2
|
+
var QRParserError = class extends Error {
|
|
3
|
+
code;
|
|
4
|
+
cause;
|
|
5
|
+
context;
|
|
6
|
+
constructor(message, options) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "QRParserError";
|
|
9
|
+
this.code = options.code;
|
|
10
|
+
this.cause = options.cause;
|
|
11
|
+
this.context = options.context;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// src/qr-parsers/types.ts
|
|
16
|
+
import { err, ok } from "neverthrow";
|
|
17
|
+
function success(data) {
|
|
18
|
+
return ok(data);
|
|
19
|
+
}
|
|
20
|
+
function failure(code, message, context) {
|
|
21
|
+
return err(new QRParserError(message, { code, context }));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// src/qr-parsers/utils/crc16.ts
|
|
25
|
+
function calculateCRC16(data) {
|
|
26
|
+
const payload = `${data}6304`;
|
|
27
|
+
const polynomial = 4129;
|
|
28
|
+
let result = 65535;
|
|
29
|
+
const encoder = new TextEncoder();
|
|
30
|
+
const bytes = encoder.encode(payload);
|
|
31
|
+
for (let offset = 0; offset < bytes.length; offset++) {
|
|
32
|
+
result ^= bytes[offset] << 8;
|
|
33
|
+
for (let bitwise = 0; bitwise < 8; bitwise++) {
|
|
34
|
+
result <<= 1;
|
|
35
|
+
if (result & 65536) {
|
|
36
|
+
result ^= polynomial;
|
|
37
|
+
}
|
|
38
|
+
result &= 65535;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return result.toString(16).toUpperCase().padStart(4, "0");
|
|
42
|
+
}
|
|
43
|
+
function verifyCRC16(qrData) {
|
|
44
|
+
if (!qrData || qrData.length < 8) {
|
|
45
|
+
return { valid: false, error: "QR data too short for CRC verification" };
|
|
46
|
+
}
|
|
47
|
+
const crcTagIndex = qrData.lastIndexOf("6304");
|
|
48
|
+
if (crcTagIndex === -1 || crcTagIndex + 8 !== qrData.length) {
|
|
49
|
+
return { valid: false, error: "Missing or misplaced CRC tag (6304)" };
|
|
50
|
+
}
|
|
51
|
+
const providedCrc = qrData.substring(crcTagIndex + 4, crcTagIndex + 8);
|
|
52
|
+
if (!/^[0-9A-Fa-f]{4}$/.test(providedCrc)) {
|
|
53
|
+
return { valid: false, error: "Invalid CRC hex format" };
|
|
54
|
+
}
|
|
55
|
+
const dataBeforeCrc = qrData.substring(0, crcTagIndex);
|
|
56
|
+
const calculatedCrc = calculateCRC16(dataBeforeCrc);
|
|
57
|
+
if (calculatedCrc !== providedCrc.toUpperCase()) {
|
|
58
|
+
return {
|
|
59
|
+
valid: false,
|
|
60
|
+
error: `CRC mismatch: expected ${calculatedCrc}, got ${providedCrc.toUpperCase()}`
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return { valid: true };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/qr-parsers/utils/tlv.ts
|
|
67
|
+
function parseTLV(data) {
|
|
68
|
+
const entries = [];
|
|
69
|
+
let pos = 0;
|
|
70
|
+
while (pos + 4 <= data.length) {
|
|
71
|
+
const tag = data.substring(pos, pos + 2);
|
|
72
|
+
const lengthStr = data.substring(pos + 2, pos + 4);
|
|
73
|
+
if (!/^[0-9]{2}$/.test(tag) || !/^[0-9]{2}$/.test(lengthStr)) {
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
const length = parseInt(lengthStr, 10);
|
|
77
|
+
if (pos + 4 + length > data.length) {
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
const value = data.substring(pos + 4, pos + 4 + length);
|
|
81
|
+
entries.push({ tag, value });
|
|
82
|
+
pos += 4 + length;
|
|
83
|
+
}
|
|
84
|
+
return entries;
|
|
85
|
+
}
|
|
86
|
+
function extractTags(data, tags) {
|
|
87
|
+
const result = {};
|
|
88
|
+
const tagSet = new Set(tags);
|
|
89
|
+
for (const entry of parseTLV(data)) {
|
|
90
|
+
if (tagSet.has(entry.tag)) {
|
|
91
|
+
result[entry.tag] = entry.value;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/qr-parsers/parsers/ars.ts
|
|
98
|
+
function parseMercadoPago(qrData, _sellPrice) {
|
|
99
|
+
if (!qrData || typeof qrData !== "string" || qrData.trim().length === 0) {
|
|
100
|
+
return failure("INVALID_QR", "QR data is empty or invalid");
|
|
101
|
+
}
|
|
102
|
+
const trimmed = qrData.trim();
|
|
103
|
+
const isARS = trimmed.includes("5303032");
|
|
104
|
+
const isAR = trimmed.includes("5802AR");
|
|
105
|
+
if (!isARS && !isAR) {
|
|
106
|
+
return failure("INVALID_QR", "Not an ARS/Argentina QR code");
|
|
107
|
+
}
|
|
108
|
+
const crc = verifyCRC16(trimmed);
|
|
109
|
+
if (!crc.valid) {
|
|
110
|
+
return failure("INVALID_QR", "Invalid QR checksum");
|
|
111
|
+
}
|
|
112
|
+
const tags = extractTags(trimmed, ["59"]);
|
|
113
|
+
const merchantName = tags["59"] || "Unknown";
|
|
114
|
+
return success({ paymentAddress: merchantName });
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/qr-parsers/parsers/brl.ts
|
|
118
|
+
import { err as err2, ok as ok2 } from "neverthrow";
|
|
119
|
+
|
|
120
|
+
// src/qr-parsers/utils/amount.ts
|
|
121
|
+
function parseAmount(amountStr, sellPrice) {
|
|
122
|
+
if (!amountStr || amountStr.trim() === "") return null;
|
|
123
|
+
const fiat = parseFloat(amountStr.trim());
|
|
124
|
+
if (Number.isNaN(fiat) || fiat <= 0) return null;
|
|
125
|
+
return { usdc: fiat / sellPrice, fiat };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/qr-parsers/parsers/brl.ts
|
|
129
|
+
var PIX_TAGS = {
|
|
130
|
+
PAYLOAD_FORMAT: "00",
|
|
131
|
+
PIX_KEY_INFO: "26",
|
|
132
|
+
AMOUNT: "54",
|
|
133
|
+
MERCHANT_NAME: "59",
|
|
134
|
+
CRC: "63"
|
|
135
|
+
};
|
|
136
|
+
function parsePIXKeyInfo(data) {
|
|
137
|
+
const result = { pixKey: null, location: null };
|
|
138
|
+
for (const entry of parseTLV(data)) {
|
|
139
|
+
if (entry.tag === "01") {
|
|
140
|
+
if (entry.value.includes("http") || entry.value.includes("://")) {
|
|
141
|
+
result.location = entry.value.startsWith("http") ? entry.value : `https://${entry.value}`;
|
|
142
|
+
} else {
|
|
143
|
+
result.pixKey = entry.value;
|
|
144
|
+
}
|
|
145
|
+
} else if (entry.tag === "25") {
|
|
146
|
+
result.location = entry.value.startsWith("http") ? entry.value : `https://${entry.value}`;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
function safeBase64Decode(base64String) {
|
|
152
|
+
if (typeof globalThis.atob === "function") {
|
|
153
|
+
return globalThis.atob(base64String);
|
|
154
|
+
}
|
|
155
|
+
throw new Error("No base64 decoder available");
|
|
156
|
+
}
|
|
157
|
+
function parseJWT(token) {
|
|
158
|
+
try {
|
|
159
|
+
const parts = token.trim().split(".");
|
|
160
|
+
if (parts.length !== 3 || !parts[0] || !parts[1] || !parts[2]) return null;
|
|
161
|
+
const json = safeBase64Decode(parts[1]);
|
|
162
|
+
return JSON.parse(json);
|
|
163
|
+
} catch {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function dynamicErr(code, message) {
|
|
168
|
+
return err2(new QRParserError(message, { code }));
|
|
169
|
+
}
|
|
170
|
+
async function fetchDynamicData(location, proxyUrl, orderId) {
|
|
171
|
+
try {
|
|
172
|
+
const url = new URL(`${proxyUrl}/pix`);
|
|
173
|
+
url.searchParams.set("locationUrl", location);
|
|
174
|
+
if (orderId) {
|
|
175
|
+
url.searchParams.set("orderId", orderId);
|
|
176
|
+
}
|
|
177
|
+
const response = await fetch(url, {
|
|
178
|
+
method: "GET",
|
|
179
|
+
headers: { Accept: "*/*" }
|
|
180
|
+
});
|
|
181
|
+
if (!response.ok) {
|
|
182
|
+
return dynamicErr("FETCH_FAILED", `Proxy error: ${response.status} ${response.statusText}`);
|
|
183
|
+
}
|
|
184
|
+
const jwtToken = await response.text();
|
|
185
|
+
const payload = parseJWT(jwtToken);
|
|
186
|
+
if (!payload) {
|
|
187
|
+
return dynamicErr("FETCH_FAILED", "Failed to parse dynamic PIX response");
|
|
188
|
+
}
|
|
189
|
+
return ok2({ dynamicAmount: payload.valor?.original });
|
|
190
|
+
} catch (error) {
|
|
191
|
+
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
192
|
+
return dynamicErr("FETCH_FAILED", `Failed to fetch dynamic PIX data: ${msg}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async function parsePIX(qrData, sellPrice, config) {
|
|
196
|
+
if (!qrData || typeof qrData !== "string" || qrData.trim().length === 0) {
|
|
197
|
+
return failure("INVALID_QR", "QR data is empty or invalid");
|
|
198
|
+
}
|
|
199
|
+
const trimmed = qrData.trim();
|
|
200
|
+
const crc = verifyCRC16(trimmed);
|
|
201
|
+
if (!crc.valid) {
|
|
202
|
+
return failure("INVALID_QR", "Invalid QR checksum");
|
|
203
|
+
}
|
|
204
|
+
const allTags = {};
|
|
205
|
+
for (const entry of parseTLV(trimmed)) {
|
|
206
|
+
allTags[entry.tag] = entry.value;
|
|
207
|
+
}
|
|
208
|
+
if (!allTags[PIX_TAGS.PAYLOAD_FORMAT]) {
|
|
209
|
+
return failure("INVALID_QR", "Invalid PIX QR format");
|
|
210
|
+
}
|
|
211
|
+
const merchantName = allTags[PIX_TAGS.MERCHANT_NAME] || "MERCHANT_NOT_FOUND";
|
|
212
|
+
let dynamicAmount;
|
|
213
|
+
const pixKeyData = allTags[PIX_TAGS.PIX_KEY_INFO];
|
|
214
|
+
if (pixKeyData) {
|
|
215
|
+
const { location } = parsePIXKeyInfo(pixKeyData);
|
|
216
|
+
if (location) {
|
|
217
|
+
if (!config.proxyUrl) {
|
|
218
|
+
return failure("FETCH_FAILED", "proxyUrl is required for dynamic PIX QR codes");
|
|
219
|
+
}
|
|
220
|
+
const dynamicResult = await fetchDynamicData(location, config.proxyUrl, config.orderId);
|
|
221
|
+
if (dynamicResult.isErr()) {
|
|
222
|
+
return err2(dynamicResult.error);
|
|
223
|
+
}
|
|
224
|
+
dynamicAmount = dynamicResult.value.dynamicAmount;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const fiatAmountStr = dynamicAmount || allTags[PIX_TAGS.AMOUNT];
|
|
228
|
+
const result = { paymentAddress: merchantName };
|
|
229
|
+
if (fiatAmountStr) {
|
|
230
|
+
const amount = parseAmount(fiatAmountStr, sellPrice);
|
|
231
|
+
if (amount) {
|
|
232
|
+
result.amount = amount;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return success(result);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// src/qr-parsers/parsers/idr.ts
|
|
239
|
+
var QRIS_TAGS = { AMOUNT: "54", MERCHANT_NAME: "59" };
|
|
240
|
+
function parseQRIS(qrData, sellPrice) {
|
|
241
|
+
if (!qrData || typeof qrData !== "string" || qrData.trim().length === 0) {
|
|
242
|
+
return failure("INVALID_QR", "QR data is empty or invalid");
|
|
243
|
+
}
|
|
244
|
+
const trimmed = qrData.trim();
|
|
245
|
+
const tags = extractTags(trimmed, [QRIS_TAGS.AMOUNT, QRIS_TAGS.MERCHANT_NAME]);
|
|
246
|
+
const merchantName = tags[QRIS_TAGS.MERCHANT_NAME];
|
|
247
|
+
if (!merchantName) {
|
|
248
|
+
return failure("INVALID_QR", "Missing merchant name");
|
|
249
|
+
}
|
|
250
|
+
const result = { paymentAddress: merchantName };
|
|
251
|
+
const amountStr = tags[QRIS_TAGS.AMOUNT];
|
|
252
|
+
if (amountStr) {
|
|
253
|
+
const amount = parseAmount(amountStr, sellPrice);
|
|
254
|
+
if (!amount) {
|
|
255
|
+
return failure("INVALID_AMOUNT", "Invalid amount in QR");
|
|
256
|
+
}
|
|
257
|
+
result.amount = amount;
|
|
258
|
+
}
|
|
259
|
+
return success(result);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// src/qr-parsers/parsers/inr.ts
|
|
263
|
+
var UPI_ID_REGEX = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+$/;
|
|
264
|
+
function parseUPI(qrData, sellPrice) {
|
|
265
|
+
if (!qrData || typeof qrData !== "string" || qrData.trim().length === 0) {
|
|
266
|
+
return failure("INVALID_QR", "QR data is empty or invalid");
|
|
267
|
+
}
|
|
268
|
+
const trimmed = qrData.trim();
|
|
269
|
+
let paramString;
|
|
270
|
+
if (trimmed.startsWith("upi://pay?")) {
|
|
271
|
+
paramString = trimmed.substring(10);
|
|
272
|
+
} else if (trimmed.includes("?")) {
|
|
273
|
+
paramString = trimmed.split("?")[1];
|
|
274
|
+
} else {
|
|
275
|
+
paramString = trimmed;
|
|
276
|
+
}
|
|
277
|
+
const params = new URLSearchParams(paramString);
|
|
278
|
+
const pa = params.get("pa");
|
|
279
|
+
if (!pa) {
|
|
280
|
+
return failure("INVALID_QR", "Missing UPI payment address");
|
|
281
|
+
}
|
|
282
|
+
if (!UPI_ID_REGEX.test(pa)) {
|
|
283
|
+
return failure("INVALID_QR", "Invalid UPI ID format");
|
|
284
|
+
}
|
|
285
|
+
const result = { paymentAddress: pa };
|
|
286
|
+
const amountStr = params.get("am");
|
|
287
|
+
if (amountStr) {
|
|
288
|
+
const amount = parseAmount(amountStr, sellPrice);
|
|
289
|
+
if (!amount) {
|
|
290
|
+
return failure("INVALID_AMOUNT", "Invalid amount in QR");
|
|
291
|
+
}
|
|
292
|
+
result.amount = amount;
|
|
293
|
+
}
|
|
294
|
+
return success(result);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// src/qr-parsers/parsers/ven.ts
|
|
298
|
+
function parsePagoMovil(qrData, _sellPrice) {
|
|
299
|
+
if (!qrData || typeof qrData !== "string" || qrData.trim().length === 0) {
|
|
300
|
+
return failure("INVALID_QR", "QR data is empty or invalid");
|
|
301
|
+
}
|
|
302
|
+
const trimmed = qrData.trim();
|
|
303
|
+
const qIdx = trimmed.indexOf("?");
|
|
304
|
+
if (qIdx === -1) {
|
|
305
|
+
return failure("INVALID_QR", "Not a valid Venezuelan QR code");
|
|
306
|
+
}
|
|
307
|
+
const payload = trimmed.substring(0, qIdx);
|
|
308
|
+
if (!payload || !/^[A-Za-z0-9+/=]+$/.test(payload)) {
|
|
309
|
+
return failure("INVALID_QR", "Not a valid Venezuelan QR code");
|
|
310
|
+
}
|
|
311
|
+
return success({ paymentAddress: trimmed });
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// src/qr-parsers/parse-qr.ts
|
|
315
|
+
async function parseQR(qrData, currency, sellPrice, config) {
|
|
316
|
+
if (!qrData || typeof qrData !== "string" || qrData.trim().length === 0) {
|
|
317
|
+
return failure("INVALID_QR", "QR data is empty or invalid");
|
|
318
|
+
}
|
|
319
|
+
switch (currency) {
|
|
320
|
+
case "INR":
|
|
321
|
+
return parseUPI(qrData, sellPrice);
|
|
322
|
+
case "IDR":
|
|
323
|
+
return parseQRIS(qrData, sellPrice);
|
|
324
|
+
case "BRL":
|
|
325
|
+
return parsePIX(qrData, sellPrice, config ?? {});
|
|
326
|
+
case "ARS":
|
|
327
|
+
return parseMercadoPago(qrData, sellPrice);
|
|
328
|
+
case "VEN":
|
|
329
|
+
return parsePagoMovil(qrData, sellPrice);
|
|
330
|
+
default:
|
|
331
|
+
return failure("INVALID_CURRENCY", `Currency "${currency}" is not supported`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
export {
|
|
335
|
+
QRParserError,
|
|
336
|
+
parseQR
|
|
337
|
+
};
|
|
338
|
+
//# sourceMappingURL=qr-parsers.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/qr-parsers/errors.ts","../src/qr-parsers/types.ts","../src/qr-parsers/utils/crc16.ts","../src/qr-parsers/utils/tlv.ts","../src/qr-parsers/parsers/ars.ts","../src/qr-parsers/parsers/brl.ts","../src/qr-parsers/utils/amount.ts","../src/qr-parsers/parsers/idr.ts","../src/qr-parsers/parsers/inr.ts","../src/qr-parsers/parsers/ven.ts","../src/qr-parsers/parse-qr.ts"],"sourcesContent":["export type QRParserErrorCode =\n\t| \"INVALID_QR\"\n\t| \"INVALID_CURRENCY\"\n\t| \"INVALID_AMOUNT\"\n\t| \"FETCH_FAILED\";\n\nexport class QRParserError extends Error {\n\treadonly code: QRParserErrorCode;\n\treadonly cause?: unknown;\n\treadonly context?: Record<string, unknown>;\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions: {\n\t\t\tcode: QRParserErrorCode;\n\t\t\tcause?: unknown;\n\t\t\tcontext?: Record<string, unknown>;\n\t\t},\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"QRParserError\";\n\t\tthis.code = options.code;\n\t\tthis.cause = options.cause;\n\t\tthis.context = options.context;\n\t}\n}\n","import { err, ok, type Result } from \"neverthrow\";\nimport { QRParserError, type QRParserErrorCode } from \"./errors\";\n\nexport type SupportedCurrency = \"INR\" | \"IDR\" | \"BRL\" | \"ARS\" | \"VEN\";\n\nexport interface ParseQRConfig {\n\tproxyUrl?: string;\n\torderId?: string;\n}\n\nexport interface ParsedQR {\n\tpaymentAddress: string;\n\tamount?: {\n\t\tusdc: number;\n\t\tfiat: number;\n\t};\n}\n\nexport type ParseResult = Result<ParsedQR, QRParserError>;\n\nexport function success(data: ParsedQR): ParseResult {\n\treturn ok(data);\n}\n\nexport function failure(\n\tcode: QRParserErrorCode,\n\tmessage: string,\n\tcontext?: Record<string, unknown>,\n): ParseResult {\n\treturn err(new QRParserError(message, { code, context }));\n}\n","/**\n * Calculate CRC-16-CCITT-FALSE checksum.\n * Polynomial 0x1021, initial value 0xFFFF.\n * Used by EMVCo-compliant QR codes (PIX, MercadoPago).\n */\nexport function calculateCRC16(data: string): string {\n\tconst payload = `${data}6304`;\n\tconst polynomial = 0x1021;\n\tlet result = 0xffff;\n\n\tconst encoder = new TextEncoder();\n\tconst bytes = encoder.encode(payload);\n\n\tfor (let offset = 0; offset < bytes.length; offset++) {\n\t\tresult ^= bytes[offset] << 8;\n\t\tfor (let bitwise = 0; bitwise < 8; bitwise++) {\n\t\t\tresult <<= 1;\n\t\t\tif (result & 0x10000) {\n\t\t\t\tresult ^= polynomial;\n\t\t\t}\n\t\t\tresult &= 0xffff;\n\t\t}\n\t}\n\n\treturn result.toString(16).toUpperCase().padStart(4, \"0\");\n}\n\n/**\n * Verify CRC-16 checksum of an EMVCo QR string.\n * Expects the string to end with \"6304\" + 4 hex CRC digits.\n */\nexport function verifyCRC16(qrData: string): { valid: boolean; error?: string } {\n\tif (!qrData || qrData.length < 8) {\n\t\treturn { valid: false, error: \"QR data too short for CRC verification\" };\n\t}\n\n\tconst crcTagIndex = qrData.lastIndexOf(\"6304\");\n\tif (crcTagIndex === -1 || crcTagIndex + 8 !== qrData.length) {\n\t\treturn { valid: false, error: \"Missing or misplaced CRC tag (6304)\" };\n\t}\n\n\tconst providedCrc = qrData.substring(crcTagIndex + 4, crcTagIndex + 8);\n\tif (!/^[0-9A-Fa-f]{4}$/.test(providedCrc)) {\n\t\treturn { valid: false, error: \"Invalid CRC hex format\" };\n\t}\n\n\tconst dataBeforeCrc = qrData.substring(0, crcTagIndex);\n\tconst calculatedCrc = calculateCRC16(dataBeforeCrc);\n\n\tif (calculatedCrc !== providedCrc.toUpperCase()) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: `CRC mismatch: expected ${calculatedCrc}, got ${providedCrc.toUpperCase()}`,\n\t\t};\n\t}\n\n\treturn { valid: true };\n}\n","/**\n * Parse a TLV (Tag-Length-Value) encoded string.\n * Tags are 2 digits, lengths are 2 digits (EMVCo standard).\n * Returns all parsed tag-value pairs. Stops gracefully on truncated data.\n */\nexport function parseTLV(data: string): { tag: string; value: string }[] {\n\tconst entries: { tag: string; value: string }[] = [];\n\tlet pos = 0;\n\n\twhile (pos + 4 <= data.length) {\n\t\tconst tag = data.substring(pos, pos + 2);\n\t\tconst lengthStr = data.substring(pos + 2, pos + 4);\n\n\t\tif (!/^[0-9]{2}$/.test(tag) || !/^[0-9]{2}$/.test(lengthStr)) {\n\t\t\tbreak;\n\t\t}\n\n\t\tconst length = parseInt(lengthStr, 10);\n\t\tif (pos + 4 + length > data.length) {\n\t\t\tbreak;\n\t\t}\n\n\t\tconst value = data.substring(pos + 4, pos + 4 + length);\n\t\tentries.push({ tag, value });\n\t\tpos += 4 + length;\n\t}\n\n\treturn entries;\n}\n\n/**\n * Extract specific tags from a TLV string.\n * Returns a record mapping tag IDs to their values.\n * Only includes tags present in the `tags` array.\n */\nexport function extractTags(data: string, tags: string[]): Record<string, string> {\n\tconst result: Record<string, string> = {};\n\tconst tagSet = new Set(tags);\n\n\tfor (const entry of parseTLV(data)) {\n\t\tif (tagSet.has(entry.tag)) {\n\t\t\tresult[entry.tag] = entry.value;\n\t\t}\n\t}\n\n\treturn result;\n}\n","import type { ParseResult } from \"../types\";\nimport { failure, success } from \"../types\";\nimport { verifyCRC16 } from \"../utils/crc16\";\nimport { extractTags } from \"../utils/tlv\";\n\nexport function parseMercadoPago(qrData: string, _sellPrice: number): ParseResult {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tconst trimmed = qrData.trim();\n\n\tconst isARS = trimmed.includes(\"5303032\");\n\tconst isAR = trimmed.includes(\"5802AR\");\n\tif (!isARS && !isAR) {\n\t\treturn failure(\"INVALID_QR\", \"Not an ARS/Argentina QR code\");\n\t}\n\n\tconst crc = verifyCRC16(trimmed);\n\tif (!crc.valid) {\n\t\treturn failure(\"INVALID_QR\", \"Invalid QR checksum\");\n\t}\n\n\tconst tags = extractTags(trimmed, [\"59\"]);\n\tconst merchantName = tags[\"59\"] || \"Unknown\";\n\n\treturn success({ paymentAddress: merchantName });\n}\n","import { err, ok, type Result } from \"neverthrow\";\nimport { QRParserError, type QRParserErrorCode } from \"../errors\";\nimport type { ParsedQR, ParseQRConfig, ParseResult } from \"../types\";\nimport { failure, success } from \"../types\";\nimport { parseAmount } from \"../utils/amount\";\nimport { verifyCRC16 } from \"../utils/crc16\";\nimport { parseTLV } from \"../utils/tlv\";\n\nconst PIX_TAGS = {\n\tPAYLOAD_FORMAT: \"00\",\n\tPIX_KEY_INFO: \"26\",\n\tAMOUNT: \"54\",\n\tMERCHANT_NAME: \"59\",\n\tCRC: \"63\",\n} as const;\n\nfunction parsePIXKeyInfo(data: string): { pixKey: string | null; location: string | null } {\n\tconst result = { pixKey: null as string | null, location: null as string | null };\n\n\tfor (const entry of parseTLV(data)) {\n\t\tif (entry.tag === \"01\") {\n\t\t\tif (entry.value.includes(\"http\") || entry.value.includes(\"://\")) {\n\t\t\t\tresult.location = entry.value.startsWith(\"http\") ? entry.value : `https://${entry.value}`;\n\t\t\t} else {\n\t\t\t\tresult.pixKey = entry.value;\n\t\t\t}\n\t\t} else if (entry.tag === \"25\") {\n\t\t\tresult.location = entry.value.startsWith(\"http\") ? entry.value : `https://${entry.value}`;\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction safeBase64Decode(base64String: string): string {\n\tif (typeof globalThis.atob === \"function\") {\n\t\treturn globalThis.atob(base64String);\n\t}\n\tthrow new Error(\"No base64 decoder available\");\n}\n\ninterface PIXJWTPayload {\n\tstatus?: string;\n\ttxid?: string;\n\tvalor?: { original?: string };\n\tcalendario?: { expiracao?: number };\n}\n\nfunction parseJWT(token: string): PIXJWTPayload | null {\n\ttry {\n\t\tconst parts = token.trim().split(\".\");\n\t\tif (parts.length !== 3 || !parts[0] || !parts[1] || !parts[2]) return null;\n\t\tconst json = safeBase64Decode(parts[1]);\n\t\treturn JSON.parse(json) as PIXJWTPayload;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction dynamicErr(\n\tcode: QRParserErrorCode,\n\tmessage: string,\n): Result<{ dynamicAmount?: string }, QRParserError> {\n\treturn err(new QRParserError(message, { code }));\n}\n\nasync function fetchDynamicData(\n\tlocation: string,\n\tproxyUrl: string,\n\torderId?: string,\n): Promise<Result<{ dynamicAmount?: string }, QRParserError>> {\n\ttry {\n\t\tconst url = new URL(`${proxyUrl}/pix`);\n\t\turl.searchParams.set(\"locationUrl\", location);\n\t\tif (orderId) {\n\t\t\turl.searchParams.set(\"orderId\", orderId);\n\t\t}\n\n\t\tconst response = await fetch(url, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: { Accept: \"*/*\" },\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\treturn dynamicErr(\"FETCH_FAILED\", `Proxy error: ${response.status} ${response.statusText}`);\n\t\t}\n\n\t\tconst jwtToken = await response.text();\n\t\tconst payload = parseJWT(jwtToken);\n\n\t\tif (!payload) {\n\t\t\treturn dynamicErr(\"FETCH_FAILED\", \"Failed to parse dynamic PIX response\");\n\t\t}\n\n\t\treturn ok({ dynamicAmount: payload.valor?.original });\n\t} catch (error) {\n\t\tconst msg = error instanceof Error ? error.message : \"Unknown error\";\n\t\treturn dynamicErr(\"FETCH_FAILED\", `Failed to fetch dynamic PIX data: ${msg}`);\n\t}\n}\n\nexport async function parsePIX(\n\tqrData: string,\n\tsellPrice: number,\n\tconfig: ParseQRConfig,\n): Promise<ParseResult> {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tconst trimmed = qrData.trim();\n\n\tconst crc = verifyCRC16(trimmed);\n\tif (!crc.valid) {\n\t\treturn failure(\"INVALID_QR\", \"Invalid QR checksum\");\n\t}\n\n\tconst allTags: Record<string, string> = {};\n\tfor (const entry of parseTLV(trimmed)) {\n\t\tallTags[entry.tag] = entry.value;\n\t}\n\n\tif (!allTags[PIX_TAGS.PAYLOAD_FORMAT]) {\n\t\treturn failure(\"INVALID_QR\", \"Invalid PIX QR format\");\n\t}\n\n\tconst merchantName = allTags[PIX_TAGS.MERCHANT_NAME] || \"MERCHANT_NOT_FOUND\";\n\n\tlet dynamicAmount: string | undefined;\n\tconst pixKeyData = allTags[PIX_TAGS.PIX_KEY_INFO];\n\tif (pixKeyData) {\n\t\tconst { location } = parsePIXKeyInfo(pixKeyData);\n\t\tif (location) {\n\t\t\tif (!config.proxyUrl) {\n\t\t\t\treturn failure(\"FETCH_FAILED\", \"proxyUrl is required for dynamic PIX QR codes\");\n\t\t\t}\n\t\t\tconst dynamicResult = await fetchDynamicData(location, config.proxyUrl, config.orderId);\n\t\t\tif (dynamicResult.isErr()) {\n\t\t\t\treturn err(dynamicResult.error);\n\t\t\t}\n\t\t\tdynamicAmount = dynamicResult.value.dynamicAmount;\n\t\t}\n\t}\n\n\tconst fiatAmountStr = dynamicAmount || allTags[PIX_TAGS.AMOUNT];\n\tconst result: ParsedQR = { paymentAddress: merchantName };\n\n\tif (fiatAmountStr) {\n\t\tconst amount = parseAmount(fiatAmountStr, sellPrice);\n\t\tif (amount) {\n\t\t\tresult.amount = amount;\n\t\t}\n\t}\n\n\treturn success(result);\n}\n","/**\n * Parse a fiat amount string and convert to usdc using sellPrice.\n * Returns null if the amount is not parseable or <= 0.\n */\nexport function parseAmount(\n\tamountStr: string,\n\tsellPrice: number,\n): { usdc: number; fiat: number } | null {\n\tif (!amountStr || amountStr.trim() === \"\") return null;\n\n\tconst fiat = parseFloat(amountStr.trim());\n\tif (Number.isNaN(fiat) || fiat <= 0) return null;\n\n\treturn { usdc: fiat / sellPrice, fiat };\n}\n","import type { ParsedQR, ParseResult } from \"../types\";\nimport { failure, success } from \"../types\";\nimport { parseAmount } from \"../utils/amount\";\nimport { extractTags } from \"../utils/tlv\";\n\nconst QRIS_TAGS = { AMOUNT: \"54\", MERCHANT_NAME: \"59\" } as const;\n\nexport function parseQRIS(qrData: string, sellPrice: number): ParseResult {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tconst trimmed = qrData.trim();\n\tconst tags = extractTags(trimmed, [QRIS_TAGS.AMOUNT, QRIS_TAGS.MERCHANT_NAME]);\n\n\tconst merchantName = tags[QRIS_TAGS.MERCHANT_NAME];\n\tif (!merchantName) {\n\t\treturn failure(\"INVALID_QR\", \"Missing merchant name\");\n\t}\n\n\tconst result: ParsedQR = { paymentAddress: merchantName };\n\n\tconst amountStr = tags[QRIS_TAGS.AMOUNT];\n\tif (amountStr) {\n\t\tconst amount = parseAmount(amountStr, sellPrice);\n\t\tif (!amount) {\n\t\t\treturn failure(\"INVALID_AMOUNT\", \"Invalid amount in QR\");\n\t\t}\n\t\tresult.amount = amount;\n\t}\n\n\treturn success(result);\n}\n","import type { ParsedQR, ParseResult } from \"../types\";\nimport { failure, success } from \"../types\";\nimport { parseAmount } from \"../utils/amount\";\n\nconst UPI_ID_REGEX = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+$/;\n\nexport function parseUPI(qrData: string, sellPrice: number): ParseResult {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tconst trimmed = qrData.trim();\n\n\tlet paramString: string;\n\tif (trimmed.startsWith(\"upi://pay?\")) {\n\t\tparamString = trimmed.substring(10);\n\t} else if (trimmed.includes(\"?\")) {\n\t\tparamString = trimmed.split(\"?\")[1];\n\t} else {\n\t\tparamString = trimmed;\n\t}\n\n\tconst params = new URLSearchParams(paramString);\n\tconst pa = params.get(\"pa\");\n\n\tif (!pa) {\n\t\treturn failure(\"INVALID_QR\", \"Missing UPI payment address\");\n\t}\n\n\tif (!UPI_ID_REGEX.test(pa)) {\n\t\treturn failure(\"INVALID_QR\", \"Invalid UPI ID format\");\n\t}\n\n\tconst result: ParsedQR = { paymentAddress: pa };\n\n\tconst amountStr = params.get(\"am\");\n\tif (amountStr) {\n\t\tconst amount = parseAmount(amountStr, sellPrice);\n\t\tif (!amount) {\n\t\t\treturn failure(\"INVALID_AMOUNT\", \"Invalid amount in QR\");\n\t\t}\n\t\tresult.amount = amount;\n\t}\n\n\treturn success(result);\n}\n","import type { ParseResult } from \"../types\";\nimport { failure, success } from \"../types\";\n\nexport function parsePagoMovil(qrData: string, _sellPrice: number): ParseResult {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tconst trimmed = qrData.trim();\n\n\tconst qIdx = trimmed.indexOf(\"?\");\n\tif (qIdx === -1) {\n\t\treturn failure(\"INVALID_QR\", \"Not a valid Venezuelan QR code\");\n\t}\n\n\tconst payload = trimmed.substring(0, qIdx);\n\n\tif (!payload || !/^[A-Za-z0-9+/=]+$/.test(payload)) {\n\t\treturn failure(\"INVALID_QR\", \"Not a valid Venezuelan QR code\");\n\t}\n\n\treturn success({ paymentAddress: trimmed });\n}\n","import { parseMercadoPago } from \"./parsers/ars\";\nimport { parsePIX } from \"./parsers/brl\";\nimport { parseQRIS } from \"./parsers/idr\";\nimport { parseUPI } from \"./parsers/inr\";\nimport { parsePagoMovil } from \"./parsers/ven\";\nimport type { ParseQRConfig, ParseResult, SupportedCurrency } from \"./types\";\nimport { failure } from \"./types\";\n\n/**\n * Parses a QR string for the given currency and returns the extracted payment data.\n *\n * This dispatcher is `async` because dynamic PIX (BRL) QRs store the amount\n * behind a location URL pointing at the issuing bank's PIX endpoint. The SDK\n * resolves that URL via a CORS-bypassing proxy (see `pix-proxy` / `config.proxyUrl`),\n * which returns a signed JWT whose `valor.original` field holds the amount.\n * All other parsers (UPI, QRIS, MercadoPago, PagoMovil) and static PIX are\n * synchronous and resolve immediately.\n */\nexport async function parseQR(\n\tqrData: string,\n\tcurrency: SupportedCurrency,\n\tsellPrice: number,\n\tconfig?: ParseQRConfig,\n): Promise<ParseResult> {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tswitch (currency) {\n\t\tcase \"INR\":\n\t\t\treturn parseUPI(qrData, sellPrice);\n\t\tcase \"IDR\":\n\t\t\treturn parseQRIS(qrData, sellPrice);\n\t\tcase \"BRL\":\n\t\t\treturn parsePIX(qrData, sellPrice, config ?? {});\n\t\tcase \"ARS\":\n\t\t\treturn parseMercadoPago(qrData, sellPrice);\n\t\tcase \"VEN\":\n\t\t\treturn parsePagoMovil(qrData, sellPrice);\n\t\tdefault:\n\t\t\treturn failure(\"INVALID_CURRENCY\", `Currency \"${currency}\" is not supported`);\n\t}\n}\n"],"mappings":"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","names":["err","ok","err","ok"]}
|