@ar-agents/mercadopago 0.10.0 → 0.12.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/dist/index.js CHANGED
@@ -226,6 +226,23 @@ var DEFAULT_BASE_URL = "https://api.mercadopago.com";
226
226
  function sleep(ms) {
227
227
  return new Promise((resolve) => setTimeout(resolve, ms));
228
228
  }
229
+ function randomUuid() {
230
+ const c = globalThis.crypto;
231
+ if (c?.randomUUID) {
232
+ return c.randomUUID();
233
+ }
234
+ if (c?.getRandomValues) {
235
+ const bytes = new Uint8Array(16);
236
+ c.getRandomValues(bytes);
237
+ bytes[6] = bytes[6] & 15 | 64;
238
+ bytes[8] = bytes[8] & 63 | 128;
239
+ const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
240
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
241
+ }
242
+ throw new Error(
243
+ "MercadoPagoClient: no Web Crypto available for idempotency key generation. This shouldn't happen on Node 19+, Edge Runtime, or modern browsers."
244
+ );
245
+ }
229
246
  var MercadoPagoClient = class {
230
247
  accessToken;
231
248
  baseUrl;
@@ -269,8 +286,10 @@ var MercadoPagoClient = class {
269
286
  Authorization: `Bearer ${this.accessToken}`,
270
287
  "Content-Type": "application/json"
271
288
  };
272
- if (options?.idempotencyKey) {
273
- headers["X-Idempotency-Key"] = options.idempotencyKey;
289
+ const isMutatingPost = method === "POST";
290
+ const idempotencyKey = options?.idempotencyKey ?? (isMutatingPost ? randomUuid() : void 0);
291
+ if (idempotencyKey) {
292
+ headers["X-Idempotency-Key"] = idempotencyKey;
274
293
  }
275
294
  const trace = this.traceContext?.();
276
295
  if (trace?.traceId && trace?.spanId) {
@@ -2427,6 +2446,377 @@ function paginateSubscriptionPayments(client, preapprovalId, opts = {}) {
2427
2446
  );
2428
2447
  }
2429
2448
 
2449
+ // src/tax-id.ts
2450
+ function validateTaxId(input, type) {
2451
+ switch (type) {
2452
+ case "DNI":
2453
+ return validateAR_DNI(input);
2454
+ case "CUIT":
2455
+ case "CUIL":
2456
+ return validateAR_CUIT(input, type);
2457
+ case "CPF":
2458
+ return validateBR_CPF(input);
2459
+ case "CNPJ":
2460
+ return validateBR_CNPJ(input);
2461
+ case "RFC":
2462
+ return validateMX_RFC(input);
2463
+ case "RUT_CL":
2464
+ return validateCL_RUT(input);
2465
+ case "NIT":
2466
+ return validateCO_NIT(input);
2467
+ case "RUT_UY":
2468
+ return validateUY_RUT(input);
2469
+ case "RUC":
2470
+ return validatePE_RUC(input);
2471
+ }
2472
+ }
2473
+ function validateAR_DNI(input) {
2474
+ const normalized = (input ?? "").replace(/\D/g, "");
2475
+ if (normalized.length === 0) {
2476
+ return failure(normalized, "DNI", "AR", "DNI vac\xEDo.");
2477
+ }
2478
+ if (normalized.length < 7 || normalized.length > 8) {
2479
+ return failure(
2480
+ normalized,
2481
+ "DNI",
2482
+ "AR",
2483
+ `Debe tener 7 u 8 d\xEDgitos; recib\xED ${normalized.length}.`
2484
+ );
2485
+ }
2486
+ return {
2487
+ valid: true,
2488
+ normalized,
2489
+ formatted: normalized.replace(/^(\d{1,2})(\d{3})(\d{3})$/, "$1.$2.$3"),
2490
+ type: "DNI",
2491
+ country: "AR",
2492
+ error: null
2493
+ };
2494
+ }
2495
+ var AR_CHECK_WEIGHTS = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];
2496
+ function validateAR_CUIT(input, type) {
2497
+ const normalized = (input ?? "").replace(/\D/g, "");
2498
+ if (normalized.length !== 11) {
2499
+ return failure(
2500
+ normalized,
2501
+ type,
2502
+ "AR",
2503
+ `Debe tener 11 d\xEDgitos; recib\xED ${normalized.length}.`
2504
+ );
2505
+ }
2506
+ const sum = AR_CHECK_WEIGHTS.reduce(
2507
+ (acc, w, i) => acc + w * Number(normalized[i]),
2508
+ 0
2509
+ );
2510
+ const remainder = sum % 11;
2511
+ const expected = remainder === 0 ? 0 : remainder === 1 ? 9 : 11 - remainder;
2512
+ const actual = Number(normalized[10]);
2513
+ if (actual !== expected) {
2514
+ return failure(
2515
+ normalized,
2516
+ type,
2517
+ "AR",
2518
+ `D\xEDgito verificador inv\xE1lido. Esperado: ${expected}, recibido: ${actual}.`
2519
+ );
2520
+ }
2521
+ return {
2522
+ valid: true,
2523
+ normalized,
2524
+ formatted: `${normalized.slice(0, 2)}-${normalized.slice(2, 10)}-${normalized.slice(10)}`,
2525
+ type,
2526
+ country: "AR",
2527
+ error: null
2528
+ };
2529
+ }
2530
+ function validateBR_CPF(input) {
2531
+ const normalized = (input ?? "").replace(/\D/g, "");
2532
+ if (normalized.length !== 11) {
2533
+ return failure(
2534
+ normalized,
2535
+ "CPF",
2536
+ "BR",
2537
+ `Debe tener 11 d\xEDgitos; recib\xED ${normalized.length}.`
2538
+ );
2539
+ }
2540
+ if (/^(\d)\1{10}$/.test(normalized)) {
2541
+ return failure(normalized, "CPF", "BR", "CPF inv\xE1lido (todos los d\xEDgitos iguales).");
2542
+ }
2543
+ const computeDigit = (slice, weights) => {
2544
+ const sum = weights.reduce((acc, w, i) => acc + w * Number(slice[i]), 0);
2545
+ const r = sum * 10 % 11;
2546
+ return r === 10 ? 0 : r;
2547
+ };
2548
+ const d1 = computeDigit(normalized.slice(0, 9), [10, 9, 8, 7, 6, 5, 4, 3, 2]);
2549
+ const d2 = computeDigit(
2550
+ normalized.slice(0, 10),
2551
+ [11, 10, 9, 8, 7, 6, 5, 4, 3, 2]
2552
+ );
2553
+ if (d1 !== Number(normalized[9]) || d2 !== Number(normalized[10])) {
2554
+ return failure(normalized, "CPF", "BR", "D\xEDgitos verificadores inv\xE1lidos.");
2555
+ }
2556
+ return {
2557
+ valid: true,
2558
+ normalized,
2559
+ formatted: normalized.replace(
2560
+ /^(\d{3})(\d{3})(\d{3})(\d{2})$/,
2561
+ "$1.$2.$3-$4"
2562
+ ),
2563
+ type: "CPF",
2564
+ country: "BR",
2565
+ error: null
2566
+ };
2567
+ }
2568
+ function validateBR_CNPJ(input) {
2569
+ const normalized = (input ?? "").replace(/\D/g, "");
2570
+ if (normalized.length !== 14) {
2571
+ return failure(
2572
+ normalized,
2573
+ "CNPJ",
2574
+ "BR",
2575
+ `Debe tener 14 d\xEDgitos; recib\xED ${normalized.length}.`
2576
+ );
2577
+ }
2578
+ if (/^(\d)\1{13}$/.test(normalized)) {
2579
+ return failure(normalized, "CNPJ", "BR", "CNPJ inv\xE1lido (todos los d\xEDgitos iguales).");
2580
+ }
2581
+ const computeDigit = (slice, weights) => {
2582
+ const sum = weights.reduce((acc, w, i) => acc + w * Number(slice[i]), 0);
2583
+ const r = sum % 11;
2584
+ return r < 2 ? 0 : 11 - r;
2585
+ };
2586
+ const w1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
2587
+ const w2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
2588
+ const d1 = computeDigit(normalized.slice(0, 12), w1);
2589
+ const d2 = computeDigit(normalized.slice(0, 13), w2);
2590
+ if (d1 !== Number(normalized[12]) || d2 !== Number(normalized[13])) {
2591
+ return failure(normalized, "CNPJ", "BR", "D\xEDgitos verificadores inv\xE1lidos.");
2592
+ }
2593
+ return {
2594
+ valid: true,
2595
+ normalized,
2596
+ formatted: normalized.replace(
2597
+ /^(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})$/,
2598
+ "$1.$2.$3/$4-$5"
2599
+ ),
2600
+ type: "CNPJ",
2601
+ country: "BR",
2602
+ error: null
2603
+ };
2604
+ }
2605
+ function validateMX_RFC(input) {
2606
+ const normalized = (input ?? "").trim().toUpperCase().replace(/[\s-]/g, "");
2607
+ const pfPattern = /^[A-ZÑ&]{4}\d{6}[A-Z\d]{3}$/;
2608
+ const pmPattern = /^[A-ZÑ&]{3}\d{6}[A-Z\d]{3}$/;
2609
+ if (!pfPattern.test(normalized) && !pmPattern.test(normalized)) {
2610
+ return failure(
2611
+ normalized,
2612
+ "RFC",
2613
+ "MX",
2614
+ "RFC mal formado. Persona f\xEDsica: 4 letras + YYMMDD + 3 alfanum\xE9ricos. Persona moral: 3 letras + YYMMDD + 3 alfanum\xE9ricos."
2615
+ );
2616
+ }
2617
+ return {
2618
+ valid: true,
2619
+ normalized,
2620
+ formatted: normalized,
2621
+ type: "RFC",
2622
+ country: "MX",
2623
+ error: null
2624
+ };
2625
+ }
2626
+ function validateCL_RUT(input) {
2627
+ const cleaned = (input ?? "").replace(/[^0-9kK]/g, "").toUpperCase();
2628
+ if (cleaned.length < 2) {
2629
+ return failure(cleaned, "RUT_CL", "CL", "RUT vac\xEDo o muy corto.");
2630
+ }
2631
+ const body = cleaned.slice(0, -1);
2632
+ const dv = cleaned.slice(-1);
2633
+ if (!/^\d+$/.test(body)) {
2634
+ return failure(cleaned, "RUT_CL", "CL", "Cuerpo del RUT debe ser num\xE9rico.");
2635
+ }
2636
+ let sum = 0;
2637
+ let multiplier = 2;
2638
+ for (let i = body.length - 1; i >= 0; i--) {
2639
+ sum += Number(body[i]) * multiplier;
2640
+ multiplier = multiplier === 7 ? 2 : multiplier + 1;
2641
+ }
2642
+ const r = 11 - sum % 11;
2643
+ const expected = r === 11 ? "0" : r === 10 ? "K" : String(r);
2644
+ if (dv !== expected) {
2645
+ return failure(
2646
+ cleaned,
2647
+ "RUT_CL",
2648
+ "CL",
2649
+ `D\xEDgito verificador inv\xE1lido. Esperado: ${expected}, recibido: ${dv}.`
2650
+ );
2651
+ }
2652
+ return {
2653
+ valid: true,
2654
+ normalized: cleaned,
2655
+ formatted: `${formatThousands(body)}-${dv}`,
2656
+ type: "RUT_CL",
2657
+ country: "CL",
2658
+ error: null
2659
+ };
2660
+ }
2661
+ var CO_NIT_WEIGHTS = [3, 7, 13, 17, 19, 23, 29, 37, 41, 43, 47, 53, 59, 67, 71];
2662
+ function validateCO_NIT(input) {
2663
+ const cleaned = (input ?? "").replace(/[^0-9-]/g, "");
2664
+ const parts = cleaned.split("-");
2665
+ if (parts.length !== 2 || !/^\d+$/.test(parts[0]) || !/^\d$/.test(parts[1])) {
2666
+ return failure(
2667
+ cleaned,
2668
+ "NIT",
2669
+ "CO",
2670
+ "NIT debe tener formato: d\xEDgitos + '-' + d\xEDgito verificador."
2671
+ );
2672
+ }
2673
+ const body = parts[0];
2674
+ const dv = Number(parts[1]);
2675
+ if (body.length > CO_NIT_WEIGHTS.length) {
2676
+ return failure(cleaned, "NIT", "CO", "NIT excesivamente largo.");
2677
+ }
2678
+ let sum = 0;
2679
+ for (let i = 0; i < body.length; i++) {
2680
+ sum += Number(body[body.length - 1 - i]) * CO_NIT_WEIGHTS[i];
2681
+ }
2682
+ const r = sum % 11;
2683
+ const expected = r > 1 ? 11 - r : r;
2684
+ if (dv !== expected) {
2685
+ return failure(
2686
+ cleaned,
2687
+ "NIT",
2688
+ "CO",
2689
+ `D\xEDgito verificador inv\xE1lido. Esperado: ${expected}, recibido: ${dv}.`
2690
+ );
2691
+ }
2692
+ return {
2693
+ valid: true,
2694
+ normalized: body + parts[1],
2695
+ formatted: cleaned,
2696
+ type: "NIT",
2697
+ country: "CO",
2698
+ error: null
2699
+ };
2700
+ }
2701
+ var UY_RUT_WEIGHTS = [4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
2702
+ function validateUY_RUT(input) {
2703
+ const normalized = (input ?? "").replace(/\D/g, "");
2704
+ if (normalized.length !== 12) {
2705
+ return failure(
2706
+ normalized,
2707
+ "RUT_UY",
2708
+ "UY",
2709
+ `Debe tener 12 d\xEDgitos; recib\xED ${normalized.length}.`
2710
+ );
2711
+ }
2712
+ let sum = 0;
2713
+ for (let i = 0; i < 11; i++) {
2714
+ sum += Number(normalized[i]) * UY_RUT_WEIGHTS[i];
2715
+ }
2716
+ const r = sum % 11;
2717
+ const expected = r === 0 ? 0 : 11 - r;
2718
+ if (Number(normalized[11]) !== expected) {
2719
+ return failure(
2720
+ normalized,
2721
+ "RUT_UY",
2722
+ "UY",
2723
+ `D\xEDgito verificador inv\xE1lido. Esperado: ${expected}, recibido: ${normalized[11]}.`
2724
+ );
2725
+ }
2726
+ return {
2727
+ valid: true,
2728
+ normalized,
2729
+ formatted: normalized.replace(
2730
+ /^(\d{2})(\d{6})(\d{3})(\d{1})$/,
2731
+ "$1$2$3$4"
2732
+ ),
2733
+ type: "RUT_UY",
2734
+ country: "UY",
2735
+ error: null
2736
+ };
2737
+ }
2738
+ var PE_RUC_WEIGHTS = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];
2739
+ function validatePE_RUC(input) {
2740
+ const normalized = (input ?? "").replace(/\D/g, "");
2741
+ if (normalized.length !== 11) {
2742
+ return failure(
2743
+ normalized,
2744
+ "RUC",
2745
+ "PE",
2746
+ `Debe tener 11 d\xEDgitos; recib\xED ${normalized.length}.`
2747
+ );
2748
+ }
2749
+ const prefix = normalized.slice(0, 2);
2750
+ if (!["10", "15", "17", "20"].includes(prefix)) {
2751
+ return failure(
2752
+ normalized,
2753
+ "RUC",
2754
+ "PE",
2755
+ `Prefijo ${prefix} no v\xE1lido. Debe ser 10, 15, 17 o 20.`
2756
+ );
2757
+ }
2758
+ let sum = 0;
2759
+ for (let i = 0; i < 10; i++) {
2760
+ sum += Number(normalized[i]) * PE_RUC_WEIGHTS[i];
2761
+ }
2762
+ const r = 11 - sum % 11;
2763
+ const expected = r === 11 ? 0 : r === 10 ? 1 : r;
2764
+ if (Number(normalized[10]) !== expected) {
2765
+ return failure(
2766
+ normalized,
2767
+ "RUC",
2768
+ "PE",
2769
+ `D\xEDgito verificador inv\xE1lido. Esperado: ${expected}, recibido: ${normalized[10]}.`
2770
+ );
2771
+ }
2772
+ return {
2773
+ valid: true,
2774
+ normalized,
2775
+ formatted: normalized,
2776
+ type: "RUC",
2777
+ country: "PE",
2778
+ error: null
2779
+ };
2780
+ }
2781
+ function failure(normalized, type, country, error) {
2782
+ return {
2783
+ valid: false,
2784
+ normalized,
2785
+ formatted: null,
2786
+ type,
2787
+ country,
2788
+ error
2789
+ };
2790
+ }
2791
+ function formatThousands(s) {
2792
+ return s.replace(/\B(?=(\d{3})+(?!\d))/g, ".");
2793
+ }
2794
+ function detectAndValidate(input, country) {
2795
+ const cleaned = input.replace(/\D/g, "");
2796
+ switch (country) {
2797
+ case "AR": {
2798
+ if (cleaned.length === 7 || cleaned.length === 8) return validateTaxId(input, "DNI");
2799
+ if (cleaned.length === 11) return validateTaxId(input, "CUIT");
2800
+ return null;
2801
+ }
2802
+ case "BR": {
2803
+ if (cleaned.length === 11) return validateTaxId(input, "CPF");
2804
+ if (cleaned.length === 14) return validateTaxId(input, "CNPJ");
2805
+ return null;
2806
+ }
2807
+ case "MX":
2808
+ return validateTaxId(input, "RFC");
2809
+ case "CL":
2810
+ return validateTaxId(input, "RUT_CL");
2811
+ case "CO":
2812
+ return validateTaxId(input, "NIT");
2813
+ case "UY":
2814
+ return validateTaxId(input, "RUT_UY");
2815
+ case "PE":
2816
+ return validateTaxId(input, "RUC");
2817
+ }
2818
+ }
2819
+
2430
2820
  // src/test-cards.ts
2431
2821
  var TEST_CARDS_AR = {
2432
2822
  VISA_CREDIT: {
@@ -2746,7 +3136,9 @@ var DEFAULT_DESCRIPTIONS = {
2746
3136
  confirm_3ds_challenge: "After the buyer completes a 3DS challenge (redirected back from challengeUrl), call this to poll MP and confirm whether the payment is now resolved. Polls get_payment up to N times with exponential backoff. Returns { payment, threeDs, resolved, attempts }. USE THIS as the FINAL step in the 3DS flow (after analyze_payment_3ds detected a challenge_required). Without confirming, the payment stays in 'pending' indefinitely from the buyer's perspective.",
2747
3137
  // ── v0.10 — Auto-paginate variants ──────────────────────────────────────
2748
3138
  search_payments_all: "Collect ALL payments matching a filter \u2014 auto-paginates under the hood. Returns an array (NOT paginated) so the agent doesn't have to manage offset/limit loops manually. SAFETY: pass `max_items` to cap; without it, MP traversal is bounded by the toolkit's internal max (10,000 items) to prevent runaway iterations. USE WHEN the agent needs to enumerate everything (e.g., monthly reconciliation 'all approved payments in March'). For agent flows that only need 'first N matches', pass `max_items` directly.",
2749
- list_settlements_all: "Collect ALL settlements matching a filter \u2014 auto-paginates. Pass `max_items` to cap. Use for monthly bank-conciliation reports."
3139
+ list_settlements_all: "Collect ALL settlements matching a filter \u2014 auto-paginates. Pass `max_items` to cap. Use for monthly bank-conciliation reports.",
3140
+ // ── v0.11 — TaxID validation cross-LATAM (pure) ──────────────────────────
3141
+ validate_tax_id: "PURE HELPER (no network, sub-ms) \u2014 validates a tax ID against the appropriate country algorithm. Supports AR (DNI/CUIT/CUIL with modulo-11), BR (CPF/CNPJ with two-step weighted modulo), MX (RFC structure), CL (RUT with K digit), CO (NIT modulo-11), UY (RUT 12-digit checksum), PE (RUC 11-digit + prefix validation). Returns { valid, normalized, formatted, type, country, error }. USE THIS BEFORE submitting buyer identification to MP \u2014 invalid tax IDs cause 4xx rejections. Surface the Spanish error verbatim."
2750
3142
  };
2751
3143
  function mercadoPagoTools(client, options) {
2752
3144
  const desc = (name) => options.descriptions?.[name] ?? DEFAULT_DESCRIPTIONS[name];
@@ -2874,7 +3266,45 @@ function mercadoPagoTools(client, options) {
2874
3266
  type: z.enum(["DNI", "CUIT", "CUIL"]),
2875
3267
  number: z.string()
2876
3268
  }).optional().describe("Payer identification \u2014 required for some payment types in AR"),
2877
- statement_descriptor: z.string().max(13).optional().describe("Shows on buyer's card statement (max 13 chars)")
3269
+ statement_descriptor: z.string().max(13).optional().describe("Shows on buyer's card statement (max 13 chars)"),
3270
+ // v0.11 — fraud scoring enrichment fields
3271
+ additional_info: z.object({
3272
+ ip_address: z.string().optional().describe(
3273
+ "Buyer's IP address (from req.headers X-Forwarded-For). STRONGLY RECOMMENDED for card payments \u2014 improves MP fraud scoring confidence and reduces false-positive rejections (3-5x lower per RG 5286/2023)."
3274
+ ),
3275
+ referral_url: z.string().url().optional().describe("Page the buyer came from"),
3276
+ payer: z.object({
3277
+ first_name: z.string().optional(),
3278
+ last_name: z.string().optional(),
3279
+ phone: z.object({ area_code: z.string().optional(), number: z.string().optional() }).optional(),
3280
+ address: z.object({
3281
+ zip_code: z.string().optional(),
3282
+ street_name: z.string().optional(),
3283
+ street_number: z.number().optional()
3284
+ }).optional(),
3285
+ registration_date: z.string().optional().describe("ISO 8601 \u2014 when the buyer registered on YOUR platform"),
3286
+ authentication_type: z.string().optional(),
3287
+ is_prime_user: z.boolean().optional(),
3288
+ is_first_purchase_online: z.boolean().optional(),
3289
+ last_purchase: z.string().optional()
3290
+ }).optional(),
3291
+ shipments: z.object({
3292
+ receiver_address: z.object({
3293
+ zip_code: z.string().optional(),
3294
+ street_name: z.string().optional(),
3295
+ street_number: z.number().optional(),
3296
+ floor: z.string().optional(),
3297
+ apartment: z.string().optional(),
3298
+ city_name: z.string().optional(),
3299
+ state_name: z.string().optional(),
3300
+ country_name: z.string().optional()
3301
+ }).optional(),
3302
+ express_shipment: z.boolean().optional(),
3303
+ local_pickup: z.boolean().optional()
3304
+ }).optional()
3305
+ }).optional().describe(
3306
+ "Fraud scoring enrichment. Pass IP address + payer profile + shipping address for materially better approval rates on card payments."
3307
+ )
2878
3308
  }),
2879
3309
  execute: async (input) => {
2880
3310
  const payment = await client.createPayment({
@@ -2887,6 +3317,7 @@ function mercadoPagoTools(client, options) {
2887
3317
  ...input.external_reference !== void 0 ? { externalReference: input.external_reference } : {},
2888
3318
  ...input.identification !== void 0 ? { identification: input.identification } : {},
2889
3319
  ...input.statement_descriptor !== void 0 ? { statementDescriptor: input.statement_descriptor } : {},
3320
+ ...input.additional_info !== void 0 ? { additionalInfo: input.additional_info } : {},
2890
3321
  ...options.notificationUrl !== void 0 ? { notificationUrl: options.notificationUrl } : {},
2891
3322
  // Deterministic idempotency key — safe to retry, same inputs always
2892
3323
  // produce the same key (MP dedupes on its side).
@@ -4640,6 +5071,34 @@ function mercadoPagoTools(client, options) {
4640
5071
  const all = await collect(paginateSettlements(client, filterClean, opts));
4641
5072
  return { ok: true, count: all.length, settlements: all };
4642
5073
  }
5074
+ }),
5075
+ // ─────────────────────────────────────────────────────────────────────
5076
+ // v0.11 — TaxID validation cross-LATAM (pure)
5077
+ // ─────────────────────────────────────────────────────────────────────
5078
+ validate_tax_id: tool({
5079
+ description: desc("validate_tax_id"),
5080
+ inputSchema: z.object({
5081
+ tax_id: z.string().min(1).describe(
5082
+ "The tax ID to validate. Accepts any format with or without separators (20-41758101-5, 20.41758101.5, 20417581015 all work for AR CUIT)."
5083
+ ),
5084
+ type: z.enum([
5085
+ "DNI",
5086
+ "CUIT",
5087
+ "CUIL",
5088
+ "CPF",
5089
+ "CNPJ",
5090
+ "RFC",
5091
+ "RUT_CL",
5092
+ "NIT",
5093
+ "RUT_UY",
5094
+ "RUC"
5095
+ ]).describe(
5096
+ "TaxID type. AR: DNI/CUIT/CUIL. BR: CPF (persona f\xEDsica) / CNPJ (persona jur\xEDdica). MX: RFC. CL: RUT_CL. CO: NIT. UY: RUT_UY. PE: RUC."
5097
+ )
5098
+ }),
5099
+ execute: async ({ tax_id, type }) => {
5100
+ return validateTaxId(tax_id, type);
5101
+ }
4643
5102
  })
4644
5103
  };
4645
5104
  }
@@ -5150,6 +5609,123 @@ function sleep2(ms) {
5150
5609
  return new Promise((resolve) => setTimeout(resolve, ms));
5151
5610
  }
5152
5611
 
5153
- export { AHORA_PROGRAM_PROMOS, AR_ISSUER_PROMOS, AuditLogger, CircuitBreaker, CircuitOpenError, InMemoryAuditLog, InMemoryIdempotencyCache, InMemoryOAuthTokenStore, InMemoryStateAdapter, MercadoPagoAccountTypeMismatchError, MercadoPagoAuthError, MercadoPagoAuthorizeForbiddenError, MercadoPagoBackUrlInvalidError, MercadoPagoClient, MercadoPagoError, MercadoPagoOverloadedError, MercadoPagoPaymentRejectedError, MercadoPagoRateLimitError, MercadoPagoSelfPaymentError, MercadoPagoTimeoutError, RateLimitTimeoutError, TEST_CARDS_AR, TEST_PAYERS_AR, TokenBucketRateLimiter, WebhookDedup, analyze3DS, buildAuthorizeUrl, buildTestCardScenario, classifyError, collect, computeMarketplaceFee, confirmChallengeAndPoll, exchangeCodeForToken, expirationTimeMs, explainPaymentStatus, findApplicablePromos, isExpiringSoon, mercadoPagoTools, paginate, paginateAccountMovements, paginateMerchantOrders, paginatePayments, paginateSettlements, paginateSubscriptionPayments, paginateSubscriptionPlans, paginateSubscriptions, parseWebhookEvent, refreshAccessToken, verifyWebhookSignature };
5612
+ // src/middleware.ts
5613
+ function compose(...middlewares) {
5614
+ return (tool2) => {
5615
+ return middlewares.reduceRight((wrapped, mw) => mw(wrapped), tool2);
5616
+ };
5617
+ }
5618
+ function withAuditLog(logger, operation, actor) {
5619
+ return (tool2) => {
5620
+ const original = tool2.execute;
5621
+ if (!original) return tool2;
5622
+ return {
5623
+ ...tool2,
5624
+ execute: (async (input, opts) => {
5625
+ return logger.record({
5626
+ operation,
5627
+ input,
5628
+ ...actor !== void 0 ? { actor } : {},
5629
+ fn: () => original(input, opts)
5630
+ });
5631
+ })
5632
+ };
5633
+ };
5634
+ }
5635
+ function withRateLimit(limiter) {
5636
+ return (tool2) => {
5637
+ const original = tool2.execute;
5638
+ if (!original) return tool2;
5639
+ return {
5640
+ ...tool2,
5641
+ execute: (async (input, opts) => {
5642
+ await limiter.acquire();
5643
+ return original(input, opts);
5644
+ })
5645
+ };
5646
+ };
5647
+ }
5648
+ function withMetrics(toolName, hook) {
5649
+ return (tool2) => {
5650
+ const original = tool2.execute;
5651
+ if (!original) return tool2;
5652
+ return {
5653
+ ...tool2,
5654
+ execute: (async (input, opts) => {
5655
+ const t0 = Date.now();
5656
+ try {
5657
+ const result = await original(input, opts);
5658
+ hook.onMetric({
5659
+ toolName,
5660
+ durationMs: Date.now() - t0,
5661
+ success: true
5662
+ });
5663
+ return result;
5664
+ } catch (err) {
5665
+ hook.onMetric({
5666
+ toolName,
5667
+ durationMs: Date.now() - t0,
5668
+ success: false,
5669
+ errorCode: extractErrorCode2(err)
5670
+ });
5671
+ throw err;
5672
+ }
5673
+ })
5674
+ };
5675
+ };
5676
+ }
5677
+ var defaultShouldRetry = (err) => {
5678
+ if (err && typeof err === "object" && "status" in err) {
5679
+ const status = err.status;
5680
+ if (typeof status === "number" && status >= 400 && status < 500) {
5681
+ return false;
5682
+ }
5683
+ }
5684
+ return true;
5685
+ };
5686
+ function withRetry(opts = {}) {
5687
+ const maxAttempts = opts.maxAttempts ?? 3;
5688
+ const baseBackoff = opts.baseBackoffMs ?? 250;
5689
+ const shouldRetry = opts.shouldRetry ?? defaultShouldRetry;
5690
+ return (tool2) => {
5691
+ const original = tool2.execute;
5692
+ if (!original) return tool2;
5693
+ return {
5694
+ ...tool2,
5695
+ execute: (async (input, opts2) => {
5696
+ let attempt = 0;
5697
+ while (true) {
5698
+ try {
5699
+ return await original(input, opts2);
5700
+ } catch (err) {
5701
+ attempt++;
5702
+ if (attempt >= maxAttempts || !shouldRetry(err, attempt)) {
5703
+ throw err;
5704
+ }
5705
+ const delayMs = baseBackoff * Math.pow(2, attempt - 1);
5706
+ opts.onRetry?.({ attempt, error: err, delayMs });
5707
+ await new Promise((r) => setTimeout(r, delayMs));
5708
+ }
5709
+ }
5710
+ })
5711
+ };
5712
+ };
5713
+ }
5714
+ function applyToAllTools(tools, middleware) {
5715
+ const out = {};
5716
+ for (const [name, tool2] of Object.entries(tools)) {
5717
+ out[name] = middleware(tool2);
5718
+ }
5719
+ return out;
5720
+ }
5721
+ function extractErrorCode2(err) {
5722
+ if (err && typeof err === "object") {
5723
+ const e = err;
5724
+ return e.code ?? e.name ?? "unknown_error";
5725
+ }
5726
+ return "unknown_error";
5727
+ }
5728
+
5729
+ export { AHORA_PROGRAM_PROMOS, AR_ISSUER_PROMOS, AuditLogger, CircuitBreaker, CircuitOpenError, InMemoryAuditLog, InMemoryIdempotencyCache, InMemoryOAuthTokenStore, InMemoryStateAdapter, MercadoPagoAccountTypeMismatchError, MercadoPagoAuthError, MercadoPagoAuthorizeForbiddenError, MercadoPagoBackUrlInvalidError, MercadoPagoClient, MercadoPagoError, MercadoPagoOverloadedError, MercadoPagoPaymentRejectedError, MercadoPagoRateLimitError, MercadoPagoSelfPaymentError, MercadoPagoTimeoutError, RateLimitTimeoutError, TEST_CARDS_AR, TEST_PAYERS_AR, TokenBucketRateLimiter, WebhookDedup, analyze3DS, applyToAllTools, buildAuthorizeUrl, buildTestCardScenario, classifyError, collect, compose, computeMarketplaceFee, confirmChallengeAndPoll, detectAndValidate, exchangeCodeForToken, expirationTimeMs, explainPaymentStatus, findApplicablePromos, isExpiringSoon, mercadoPagoTools, paginate, paginateAccountMovements, paginateMerchantOrders, paginatePayments, paginateSettlements, paginateSubscriptionPayments, paginateSubscriptionPlans, paginateSubscriptions, parseWebhookEvent, refreshAccessToken, validateTaxId, verifyWebhookSignature, withAuditLog, withMetrics, withRateLimit, withRetry };
5154
5730
  //# sourceMappingURL=index.js.map
5155
5731
  //# sourceMappingURL=index.js.map