cobroya 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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +231 -0
  3. package/bin/mcp-server.mjs +2 -0
  4. package/bin/telegram-bot.mjs +2 -0
  5. package/dist/actions.d.ts +7 -0
  6. package/dist/actions.js +74 -0
  7. package/dist/actions.js.map +1 -0
  8. package/dist/client.d.ts +10 -0
  9. package/dist/client.js +49 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/errors.d.ts +10 -0
  12. package/dist/errors.js +28 -0
  13. package/dist/errors.js.map +1 -0
  14. package/dist/index.d.ts +133 -0
  15. package/dist/index.js +42 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/landing.d.ts +1 -0
  18. package/dist/landing.js +256 -0
  19. package/dist/landing.js.map +1 -0
  20. package/dist/mcp-server.d.ts +1 -0
  21. package/dist/mcp-server.js +95 -0
  22. package/dist/mcp-server.js.map +1 -0
  23. package/dist/schemas.d.ts +258 -0
  24. package/dist/schemas.js +80 -0
  25. package/dist/schemas.js.map +1 -0
  26. package/dist/server.d.ts +1 -0
  27. package/dist/server.js +181 -0
  28. package/dist/server.js.map +1 -0
  29. package/dist/shared/formatting.d.ts +4 -0
  30. package/dist/shared/formatting.js +51 -0
  31. package/dist/shared/formatting.js.map +1 -0
  32. package/dist/telegram-bot.d.ts +3 -0
  33. package/dist/telegram-bot.js +194 -0
  34. package/dist/telegram-bot.js.map +1 -0
  35. package/dist/webhook.d.ts +6 -0
  36. package/dist/webhook.js +77 -0
  37. package/dist/webhook.js.map +1 -0
  38. package/dist/whatsapp/client.d.ts +10 -0
  39. package/dist/whatsapp/client.js +47 -0
  40. package/dist/whatsapp/client.js.map +1 -0
  41. package/dist/whatsapp/handlers.d.ts +11 -0
  42. package/dist/whatsapp/handlers.js +138 -0
  43. package/dist/whatsapp/handlers.js.map +1 -0
  44. package/dist/whatsapp/message-parser.d.ts +33 -0
  45. package/dist/whatsapp/message-parser.js +44 -0
  46. package/dist/whatsapp/message-parser.js.map +1 -0
  47. package/dist/whatsapp/webhook.d.ts +16 -0
  48. package/dist/whatsapp/webhook.js +70 -0
  49. package/dist/whatsapp/webhook.js.map +1 -0
  50. package/package.json +70 -0
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.allSchemas = exports.getMerchantInfoSchema = exports.searchPaymentsSchema = exports.createRefundSchema = exports.getPaymentSchema = exports.createPaymentPreferenceSchema = void 0;
4
+ exports.createPaymentPreferenceSchema = {
5
+ name: "create_payment_preference",
6
+ description: "Creates a Mercado Pago checkout payment preference (payment link). Returns init_point URL for redirecting buyers.",
7
+ parameters: {
8
+ type: "object",
9
+ required: ["title", "quantity", "currency", "unit_price"],
10
+ properties: {
11
+ title: { type: "string", description: "Product or service title" },
12
+ quantity: { type: "number", description: "Quantity of items" },
13
+ currency: { type: "string", description: "Currency ID (e.g. ARS, BRL, MXN, CLP, COP, UYU, PEN)" },
14
+ unit_price: { type: "number", description: "Unit price of the item" },
15
+ back_urls: {
16
+ type: "object",
17
+ description: "URLs to redirect the buyer after payment",
18
+ properties: {
19
+ success: { type: "string", description: "URL on approved payment" },
20
+ failure: { type: "string", description: "URL on rejected payment" },
21
+ pending: { type: "string", description: "URL on pending payment" },
22
+ },
23
+ },
24
+ notification_url: { type: "string", description: "Webhook URL for payment notifications (IPN)" },
25
+ },
26
+ },
27
+ };
28
+ exports.getPaymentSchema = {
29
+ name: "get_payment",
30
+ description: "Retrieve a payment by its ID. Returns full payment details including status, amount, payer info.",
31
+ parameters: {
32
+ type: "object",
33
+ required: ["payment_id"],
34
+ properties: {
35
+ payment_id: { type: "string", description: "The payment ID to look up" },
36
+ },
37
+ },
38
+ };
39
+ exports.createRefundSchema = {
40
+ name: "create_refund",
41
+ description: "Refund a payment fully or partially. Omit amount for full refund.",
42
+ parameters: {
43
+ type: "object",
44
+ required: ["payment_id"],
45
+ properties: {
46
+ payment_id: { type: "string", description: "The payment ID to refund" },
47
+ amount: { type: "number", description: "Partial refund amount. Omit for full refund." },
48
+ },
49
+ },
50
+ };
51
+ exports.searchPaymentsSchema = {
52
+ name: "search_payments",
53
+ description: "Search recent payments for the authenticated merchant. Supports filtering by status.",
54
+ parameters: {
55
+ type: "object",
56
+ properties: {
57
+ status: { type: "string", description: "Filter by status: approved, pending, rejected, refunded, cancelled" },
58
+ sort: { type: "string", description: "Sort field (e.g. date_created)" },
59
+ criteria: { type: "string", description: "Sort order: asc or desc" },
60
+ limit: { type: "number", description: "Max results (default 30, max 100)" },
61
+ offset: { type: "number", description: "Pagination offset" },
62
+ },
63
+ },
64
+ };
65
+ exports.getMerchantInfoSchema = {
66
+ name: "get_merchant_info",
67
+ description: "Retrieve the authenticated merchant's user profile including ID, nickname, and site.",
68
+ parameters: {
69
+ type: "object",
70
+ properties: {},
71
+ },
72
+ };
73
+ exports.allSchemas = [
74
+ exports.createPaymentPreferenceSchema,
75
+ exports.getPaymentSchema,
76
+ exports.createRefundSchema,
77
+ exports.searchPaymentsSchema,
78
+ exports.getMerchantInfoSchema,
79
+ ];
80
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":";;;AAkCa,QAAA,6BAA6B,GAAG;IAC3C,IAAI,EAAE,2BAA2B;IACjC,WAAW,EAAE,mHAAmH;IAChI,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,CAAC;QACzD,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0BAA0B,EAAE;YAClE,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mBAAmB,EAAE;YAC9D,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,sDAAsD,EAAE;YACjG,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,wBAAwB,EAAE;YACrE,SAAS,EAAE;gBACT,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,0CAA0C;gBACvD,UAAU,EAAE;oBACV,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,yBAAyB,EAAE;oBACnE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,yBAAyB,EAAE;oBACnE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,wBAAwB,EAAE;iBACnE;aACF;YACD,gBAAgB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,6CAA6C,EAAE;SACjG;KACF;CACO,CAAC;AAEE,QAAA,gBAAgB,GAAG;IAC9B,IAAI,EAAE,aAAa;IACnB,WAAW,EAAE,kGAAkG;IAC/G,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,CAAC,YAAY,CAAC;QACxB,UAAU,EAAE;YACV,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,2BAA2B,EAAE;SACzE;KACF;CACO,CAAC;AAEE,QAAA,kBAAkB,GAAG;IAChC,IAAI,EAAE,eAAe;IACrB,WAAW,EAAE,mEAAmE;IAChF,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,CAAC,YAAY,CAAC;QACxB,UAAU,EAAE;YACV,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0BAA0B,EAAE;YACvE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,8CAA8C,EAAE;SACxF;KACF;CACO,CAAC;AAEE,QAAA,oBAAoB,GAAG;IAClC,IAAI,EAAE,iBAAiB;IACvB,WAAW,EAAE,sFAAsF;IACnG,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oEAAoE,EAAE;YAC7G,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,gCAAgC,EAAE;YACvE,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,yBAAyB,EAAE;YACpE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mCAAmC,EAAE;YAC3E,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mBAAmB,EAAE;SAC7D;KACF;CACO,CAAC;AAEE,QAAA,qBAAqB,GAAG;IACnC,IAAI,EAAE,mBAAmB;IACzB,WAAW,EAAE,sFAAsF;IACnG,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE,EAAE;KACf;CACO,CAAC;AAEE,QAAA,UAAU,GAAG;IACxB,qCAA6B;IAC7B,wBAAgB;IAChB,0BAAkB;IAClB,4BAAoB;IACpB,6BAAqB;CACtB,CAAC"}
@@ -0,0 +1 @@
1
+ import "dotenv/config";
package/dist/server.js ADDED
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ require("dotenv/config");
4
+ /**
5
+ * Unified production server.
6
+ *
7
+ * Runs in a single process:
8
+ * - Telegram bot (polling)
9
+ * - WhatsApp webhook (POST /whatsapp)
10
+ * - Mercado Pago IPN webhook (POST /mp-webhook)
11
+ * - Health check (GET /health)
12
+ *
13
+ * Deploy this on Railway, Fly.io, Render, or any VPS.
14
+ */
15
+ const node_http_1 = require("node:http");
16
+ const telegram_bot_js_1 = require("./telegram-bot.js");
17
+ const webhook_js_1 = require("./whatsapp/webhook.js");
18
+ const webhook_js_2 = require("./webhook.js");
19
+ const client_js_1 = require("./whatsapp/client.js");
20
+ const handlers_js_1 = require("./whatsapp/handlers.js");
21
+ const landing_js_1 = require("./landing.js");
22
+ const PORT = Number(process.env.PORT ?? 3000);
23
+ const MP_TOKEN = process.env.MERCADO_PAGO_ACCESS_TOKEN ?? "";
24
+ const MP_WEBHOOK_SECRET = process.env.MERCADO_PAGO_WEBHOOK_SECRET;
25
+ // ─── Telegram Bot ─────────────────────────────────────────
26
+ const TELEGRAM_ENABLED = !!process.env.TELEGRAM_BOT_TOKEN;
27
+ const TELEGRAM_NOTIFY_CHAT_ID = process.env.TELEGRAM_NOTIFY_CHAT_ID;
28
+ let telegramBot = null;
29
+ if (TELEGRAM_ENABLED) {
30
+ try {
31
+ telegramBot = (0, telegram_bot_js_1.startBot)();
32
+ }
33
+ catch (err) {
34
+ console.error("Telegram bot failed to start:", err);
35
+ }
36
+ }
37
+ // ─── WhatsApp Webhook ─────────────────────────────────────
38
+ const WA_ENABLED = !!process.env.WHATSAPP_ACCESS_TOKEN &&
39
+ !!process.env.WHATSAPP_PHONE_NUMBER_ID &&
40
+ !!process.env.WHATSAPP_VERIFY_TOKEN;
41
+ const WA_ALLOWED_PHONES = process.env.WHATSAPP_ALLOWED_PHONES
42
+ ? new Set(process.env.WHATSAPP_ALLOWED_PHONES.split(",").map((p) => p.trim()))
43
+ : undefined;
44
+ const waHandler = WA_ENABLED
45
+ ? (0, webhook_js_1.createWhatsAppWebhookHandler)({
46
+ waAccessToken: process.env.WHATSAPP_ACCESS_TOKEN,
47
+ waPhoneNumberId: process.env.WHATSAPP_PHONE_NUMBER_ID,
48
+ verifyToken: process.env.WHATSAPP_VERIFY_TOKEN,
49
+ mpAccessToken: MP_TOKEN,
50
+ currency: process.env.MP_CURRENCY ?? "ARS",
51
+ successUrl: process.env.MP_SUCCESS_URL,
52
+ allowedPhones: WA_ALLOWED_PHONES,
53
+ })
54
+ : null;
55
+ // ─── MP IPN Webhook + Notifications ──────────────────────
56
+ // If WhatsApp is enabled and a notify phone is set, forward approved payments
57
+ const WA_NOTIFY_PHONE = process.env.WA_NOTIFY_PHONE;
58
+ const paymentCallbacks = [];
59
+ // WhatsApp notification
60
+ if (WA_ENABLED && WA_NOTIFY_PHONE) {
61
+ const waClient = new client_js_1.WhatsAppClient({
62
+ accessToken: process.env.WHATSAPP_ACCESS_TOKEN,
63
+ phoneNumberId: process.env.WHATSAPP_PHONE_NUMBER_ID,
64
+ });
65
+ paymentCallbacks.push((0, handlers_js_1.createPaymentNotifier)(waClient, WA_NOTIFY_PHONE));
66
+ }
67
+ // Telegram notification
68
+ if (telegramBot && TELEGRAM_NOTIFY_CHAT_ID) {
69
+ const chatId = Number(TELEGRAM_NOTIFY_CHAT_ID);
70
+ paymentCallbacks.push(async (payment) => {
71
+ const p = payment;
72
+ if (p.status !== "approved")
73
+ return;
74
+ await telegramBot.sendMessage(chatId, `Pago recibido\nMonto: $${p.transaction_amount}\nID: ${p.id}` +
75
+ (p.description ? `\nDescripcion: ${p.description}` : ""));
76
+ });
77
+ }
78
+ // Console log (always)
79
+ paymentCallbacks.push(async (payment) => {
80
+ const p = payment;
81
+ console.log(`[PAYMENT] #${p.id} — ${p.status} — $${p.transaction_amount}`);
82
+ });
83
+ const mpWebhookHandler = MP_TOKEN
84
+ ? (0, webhook_js_2.createWebhookHandler)({
85
+ accessToken: MP_TOKEN,
86
+ secret: MP_WEBHOOK_SECRET,
87
+ onPayment: async (payment) => {
88
+ await Promise.allSettled(paymentCallbacks.map((cb) => cb(payment)));
89
+ },
90
+ })
91
+ : null;
92
+ // ─── HTTP Server ──────────────────────────────────────────
93
+ async function nodeToWebRequest(req, url) {
94
+ const body = await new Promise((resolve, reject) => {
95
+ let data = "";
96
+ req.on("data", (chunk) => {
97
+ data += chunk.toString();
98
+ });
99
+ req.on("end", () => resolve(data));
100
+ req.on("error", reject);
101
+ });
102
+ return new Request(url.toString(), {
103
+ method: req.method,
104
+ headers: req.headers,
105
+ body: req.method === "GET" ? undefined : body,
106
+ });
107
+ }
108
+ async function webToNodeResponse(webRes, res) {
109
+ const text = await webRes.text();
110
+ res.writeHead(webRes.status).end(text);
111
+ }
112
+ const server = (0, node_http_1.createServer)(async (req, res) => {
113
+ const url = new URL(req.url ?? "/", `http://localhost:${PORT}`);
114
+ const path = url.pathname;
115
+ // OG Image (SVG)
116
+ if (path === "/og.svg") {
117
+ const svg = `<svg width="1200" height="630" xmlns="http://www.w3.org/2000/svg">
118
+ <rect width="1200" height="630" fill="#09090b"/>
119
+ <rect x="0" y="0" width="1200" height="4" fill="url(#g)"/>
120
+ <defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="0"><stop offset="0%" stop-color="#3b82f6"/><stop offset="100%" stop-color="#8b5cf6"/></linearGradient></defs>
121
+ <text x="100" y="200" font-family="system-ui,sans-serif" font-size="72" font-weight="800" fill="#fafafa">CobroYa</text>
122
+ <text x="100" y="300" font-family="system-ui,sans-serif" font-size="42" fill="#a1a1aa">Cobra con Mercado Pago</text>
123
+ <text x="100" y="360" font-family="system-ui,sans-serif" font-size="42" fill="#a1a1aa">en 10 segundos</text>
124
+ <text x="100" y="460" font-family="system-ui,sans-serif" font-size="28" fill="#3b82f6">Telegram</text>
125
+ <text x="310" y="460" font-family="system-ui,sans-serif" font-size="28" fill="#27272a">|</text>
126
+ <text x="350" y="460" font-family="system-ui,sans-serif" font-size="28" fill="#22c55e">WhatsApp</text>
127
+ <text x="590" y="460" font-family="system-ui,sans-serif" font-size="28" fill="#27272a">|</text>
128
+ <text x="630" y="460" font-family="system-ui,sans-serif" font-size="28" fill="#8b5cf6">AI Agents</text>
129
+ <text x="100" y="550" font-family="system-ui,sans-serif" font-size="22" fill="#52525b">cobroya.app</text>
130
+ </svg>`;
131
+ res.writeHead(200, { "Content-Type": "image/svg+xml", "Cache-Control": "public, max-age=86400" });
132
+ res.end(svg);
133
+ return;
134
+ }
135
+ // Landing page
136
+ if (path === "/") {
137
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
138
+ res.end(landing_js_1.landingHTML);
139
+ return;
140
+ }
141
+ // Health check
142
+ if (path === "/health") {
143
+ const status = {
144
+ ok: true,
145
+ telegram: TELEGRAM_ENABLED,
146
+ whatsapp: WA_ENABLED,
147
+ mp_webhook: !!mpWebhookHandler,
148
+ uptime: process.uptime(),
149
+ };
150
+ res.writeHead(200, { "Content-Type": "application/json" });
151
+ res.end(JSON.stringify(status));
152
+ return;
153
+ }
154
+ // WhatsApp webhook
155
+ if (path.startsWith("/whatsapp") && waHandler) {
156
+ const webReq = await nodeToWebRequest(req, url);
157
+ const webRes = await waHandler(webReq);
158
+ await webToNodeResponse(webRes, res);
159
+ return;
160
+ }
161
+ // Mercado Pago IPN webhook
162
+ if (path.startsWith("/mp-webhook") && mpWebhookHandler) {
163
+ const webReq = await nodeToWebRequest(req, url);
164
+ const webRes = await mpWebhookHandler(webReq);
165
+ await webToNodeResponse(webRes, res);
166
+ return;
167
+ }
168
+ res.writeHead(404).end("Not Found");
169
+ });
170
+ server.listen(PORT, () => {
171
+ console.log(`\n=== mercadopago-tool server ===`);
172
+ console.log(`Port: ${PORT}`);
173
+ console.log(`Telegram: ${TELEGRAM_ENABLED ? "ON" : "OFF"}`);
174
+ console.log(`WhatsApp: ${WA_ENABLED ? "ON" : "OFF"}`);
175
+ console.log(`MP Webhook: ${mpWebhookHandler ? "ON" : "OFF"}`);
176
+ if (WA_NOTIFY_PHONE)
177
+ console.log(`WA Notifications: ${WA_NOTIFY_PHONE}`);
178
+ console.log(`Health: http://localhost:${PORT}/health`);
179
+ console.log(`================================\n`);
180
+ });
181
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";;AAAA,yBAAuB;AAEvB;;;;;;;;;;GAUG;AAEH,yCAAyC;AACzC,uDAA6C;AAC7C,sDAAqE;AACrE,6CAAoD;AACpD,oDAAsD;AACtD,wDAA+D;AAC/D,6CAA2C;AAE3C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,EAAE,CAAC;AAC7D,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC;AAElE,6DAA6D;AAC7D,MAAM,gBAAgB,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;AAC1D,MAAM,uBAAuB,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC;AACpE,IAAI,WAAW,GAAuC,IAAI,CAAC;AAE3D,IAAI,gBAAgB,EAAE,CAAC;IACrB,IAAI,CAAC;QACH,WAAW,GAAG,IAAA,0BAAQ,GAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,GAAG,CAAC,CAAC;IACtD,CAAC;AACH,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,GACd,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB;IACnC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB;IACtC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;AAEtC,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB;IAC3D,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9E,CAAC,CAAC,SAAS,CAAC;AAEd,MAAM,SAAS,GAAG,UAAU;IAC1B,CAAC,CAAC,IAAA,yCAA4B,EAAC;QAC3B,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAsB;QACjD,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAyB;QACtD,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAsB;QAC/C,aAAa,EAAE,QAAQ;QACvB,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,KAAK;QAC1C,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;QACtC,aAAa,EAAE,iBAAiB;KACjC,CAAC;IACJ,CAAC,CAAC,IAAI,CAAC;AAET,4DAA4D;AAC5D,8EAA8E;AAC9E,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;AAEpD,MAAM,gBAAgB,GAA+C,EAAE,CAAC;AAExE,wBAAwB;AACxB,IAAI,UAAU,IAAI,eAAe,EAAE,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAI,0BAAc,CAAC;QAClC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAsB;QAC/C,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAyB;KACrD,CAAC,CAAC;IACH,gBAAgB,CAAC,IAAI,CAAC,IAAA,mCAAqB,EAAC,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC;AAC1E,CAAC;AAED,wBAAwB;AACxB,IAAI,WAAW,IAAI,uBAAuB,EAAE,CAAC;IAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,uBAAuB,CAAC,CAAC;IAC/C,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAgB,EAAE,EAAE;QAC/C,MAAM,CAAC,GAAG,OAA2F,CAAC;QACtG,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU;YAAE,OAAO;QACpC,MAAM,WAAY,CAAC,WAAW,CAC5B,MAAM,EACN,0BAA0B,CAAC,CAAC,kBAAkB,SAAS,CAAC,CAAC,EAAE,EAAE;YAC3D,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAC3D,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,uBAAuB;AACvB,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAgB,EAAE,EAAE;IAC/C,MAAM,CAAC,GAAG,OAAqE,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,MAAM,OAAO,CAAC,CAAC,kBAAkB,EAAE,CAAC,CAAC;AAC7E,CAAC,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,QAAQ;IAC/B,CAAC,CAAC,IAAA,iCAAoB,EAAC;QACnB,WAAW,EAAE,QAAQ;QACrB,MAAM,EAAE,iBAAiB;QACzB,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YAC3B,MAAM,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACtE,CAAC;KACF,CAAC;IACJ,CAAC,CAAC,IAAI,CAAC;AAET,6DAA6D;AAC7D,KAAK,UAAU,gBAAgB,CAC7B,GAAwC,EACxC,GAAQ;IAER,MAAM,IAAI,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACzD,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YAC/B,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC3B,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACnC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;QACjC,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,OAAO,EAAE,GAAG,CAAC,OAAiC;QAC9C,IAAI,EAAE,GAAG,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI;KAC9C,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,iBAAiB,CAC9B,MAAgB,EAChB,GAAuC;IAEvC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACjC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,MAAM,GAAG,IAAA,wBAAY,EAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;IAC7C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,oBAAoB,IAAI,EAAE,CAAC,CAAC;IAChE,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC;IAE1B,iBAAiB;IACjB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG;;;;;;;;;;;;;WAaL,CAAC;QACR,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,EAAE,uBAAuB,EAAE,CAAC,CAAC;QAClG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACb,OAAO;IACT,CAAC;IAED,eAAe;IACf,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;QACjB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,CAAC,CAAC;QACnE,GAAG,CAAC,GAAG,CAAC,wBAAW,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,eAAe;IACf,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG;YACb,EAAE,EAAE,IAAI;YACR,QAAQ,EAAE,gBAAgB;YAC1B,QAAQ,EAAE,UAAU;YACpB,UAAU,EAAE,CAAC,CAAC,gBAAgB;YAC9B,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE;SACzB,CAAC;QACF,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QAChC,OAAO;IACT,CAAC;IAED,mBAAmB;IACnB,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,SAAS,EAAE,CAAC;QAC9C,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACrC,OAAO;IACT,CAAC;IAED,2BAA2B;IAC3B,IAAI,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,IAAI,gBAAgB,EAAE,CAAC;QACvD,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAC9C,MAAM,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACrC,OAAO;IACT,CAAC;IAED,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AACtC,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;IACvB,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IAC7B,OAAO,CAAC,GAAG,CAAC,aAAa,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,aAAa,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,eAAe,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IAC9D,IAAI,eAAe;QAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB,eAAe,EAAE,CAAC,CAAC;IACzE,OAAO,CAAC,GAAG,CAAC,4BAA4B,IAAI,SAAS,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;AACpD,CAAC,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function statusEmoji(status: string): string;
2
+ export declare function statusLabel(status: string): string;
3
+ export declare function formatMoney(amount: number, currency: string): string;
4
+ export declare function friendlyError(err: unknown): string;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.statusEmoji = statusEmoji;
4
+ exports.statusLabel = statusLabel;
5
+ exports.formatMoney = formatMoney;
6
+ exports.friendlyError = friendlyError;
7
+ const errors_js_1 = require("../errors.js");
8
+ function statusEmoji(status) {
9
+ switch (status) {
10
+ case "approved": return "\u2705";
11
+ case "pending":
12
+ case "in_process":
13
+ case "in_mediation": return "\u23f3";
14
+ case "rejected":
15
+ case "cancelled": return "\u274c";
16
+ case "refunded":
17
+ case "charged_back": return "\ud83d\udd04";
18
+ default: return "\u2753";
19
+ }
20
+ }
21
+ function statusLabel(status) {
22
+ const labels = {
23
+ approved: "Aprobado",
24
+ pending: "Pendiente",
25
+ in_process: "En proceso",
26
+ in_mediation: "En mediacion",
27
+ rejected: "Rechazado",
28
+ cancelled: "Cancelado",
29
+ refunded: "Devuelto",
30
+ charged_back: "Contracargo",
31
+ };
32
+ return labels[status] ?? status;
33
+ }
34
+ function formatMoney(amount, currency) {
35
+ return `$${amount.toLocaleString("es-AR", { minimumFractionDigits: 2, maximumFractionDigits: 2 })} ${currency}`;
36
+ }
37
+ function friendlyError(err) {
38
+ if (err instanceof errors_js_1.MercadoPagoError) {
39
+ if (err.isUnauthorized)
40
+ return "Error de autenticacion. Verifica el token de Mercado Pago.";
41
+ if (err.isNotFound)
42
+ return "No se encontro el recurso solicitado. Verifica el ID ingresado.";
43
+ if (err.isRateLimited)
44
+ return "Demasiadas solicitudes. Intenta de nuevo en unos minutos.";
45
+ return `Error de Mercado Pago (${err.status}): ${err.body}`;
46
+ }
47
+ if (err instanceof Error)
48
+ return `Error: ${err.message}`;
49
+ return "Ocurrio un error inesperado. Intenta de nuevo.";
50
+ }
51
+ //# sourceMappingURL=formatting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatting.js","sourceRoot":"","sources":["../../src/shared/formatting.ts"],"names":[],"mappings":";;AAEA,kCAYC;AAED,kCAYC;AAED,kCAEC;AAED,sCASC;AA3CD,4CAAgD;AAEhD,SAAgB,WAAW,CAAC,MAAc;IACxC,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,UAAU,CAAC,CAAC,OAAO,QAAQ,CAAC;QACjC,KAAK,SAAS,CAAC;QACf,KAAK,YAAY,CAAC;QAClB,KAAK,cAAc,CAAC,CAAC,OAAO,QAAQ,CAAC;QACrC,KAAK,UAAU,CAAC;QAChB,KAAK,WAAW,CAAC,CAAC,OAAO,QAAQ,CAAC;QAClC,KAAK,UAAU,CAAC;QAChB,KAAK,cAAc,CAAC,CAAC,OAAO,cAAc,CAAC;QAC3C,OAAO,CAAC,CAAC,OAAO,QAAQ,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,SAAgB,WAAW,CAAC,MAAc;IACxC,MAAM,MAAM,GAA2B;QACrC,QAAQ,EAAE,UAAU;QACpB,OAAO,EAAE,WAAW;QACpB,UAAU,EAAE,YAAY;QACxB,YAAY,EAAE,cAAc;QAC5B,QAAQ,EAAE,WAAW;QACrB,SAAS,EAAE,WAAW;QACtB,QAAQ,EAAE,UAAU;QACpB,YAAY,EAAE,aAAa;KAC5B,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC;AAClC,CAAC;AAED,SAAgB,WAAW,CAAC,MAAc,EAAE,QAAgB;IAC1D,OAAO,IAAI,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,qBAAqB,EAAE,CAAC,EAAE,qBAAqB,EAAE,CAAC,EAAE,CAAC,IAAI,QAAQ,EAAE,CAAC;AAClH,CAAC;AAED,SAAgB,aAAa,CAAC,GAAY;IACxC,IAAI,GAAG,YAAY,4BAAgB,EAAE,CAAC;QACpC,IAAI,GAAG,CAAC,cAAc;YAAE,OAAO,4DAA4D,CAAC;QAC5F,IAAI,GAAG,CAAC,UAAU;YAAE,OAAO,iEAAiE,CAAC;QAC7F,IAAI,GAAG,CAAC,aAAa;YAAE,OAAO,2DAA2D,CAAC;QAC1F,OAAO,0BAA0B,GAAG,CAAC,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9D,CAAC;IACD,IAAI,GAAG,YAAY,KAAK;QAAE,OAAO,UAAU,GAAG,CAAC,OAAO,EAAE,CAAC;IACzD,OAAO,gDAAgD,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,3 @@
1
+ import "dotenv/config";
2
+ import TelegramBot from "node-telegram-bot-api";
3
+ export declare function startBot(): TelegramBot;
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.startBot = startBot;
7
+ require("dotenv/config");
8
+ const node_telegram_bot_api_1 = __importDefault(require("node-telegram-bot-api"));
9
+ const index_js_1 = require("./index.js");
10
+ const formatting_js_1 = require("./shared/formatting.js");
11
+ const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN ?? "";
12
+ const MP_ACCESS_TOKEN = process.env.MERCADO_PAGO_ACCESS_TOKEN ?? "";
13
+ const MP_CURRENCY = process.env.MP_CURRENCY ?? "ARS";
14
+ const MP_SUCCESS_URL = process.env.MP_SUCCESS_URL ?? "";
15
+ // Access control: comma-separated list of allowed Telegram chat IDs
16
+ const ALLOWED_CHAT_IDS = process.env.TELEGRAM_ALLOWED_CHAT_IDS
17
+ ? new Set(process.env.TELEGRAM_ALLOWED_CHAT_IDS.split(",").map((id) => Number(id.trim())))
18
+ : null;
19
+ function startBot() {
20
+ if (!TELEGRAM_BOT_TOKEN) {
21
+ throw new Error("TELEGRAM_BOT_TOKEN es requerido. Configuralo en las variables de entorno.");
22
+ }
23
+ if (!MP_ACCESS_TOKEN) {
24
+ throw new Error("MERCADO_PAGO_ACCESS_TOKEN es requerido. Configuralo en las variables de entorno.");
25
+ }
26
+ const mp = (0, index_js_1.createMercadoPagoTools)(MP_ACCESS_TOKEN);
27
+ const bot = new node_telegram_bot_api_1.default(TELEGRAM_BOT_TOKEN, { polling: true });
28
+ function isAuthorized(chatId) {
29
+ if (!ALLOWED_CHAT_IDS)
30
+ return true; // No whitelist = allow all (dev mode)
31
+ return ALLOWED_CHAT_IDS.has(chatId);
32
+ }
33
+ bot.onText(/\/start(?:\s|$)/, (msg) => {
34
+ const chatId = msg.chat.id;
35
+ if (!isAuthorized(chatId)) {
36
+ bot.sendMessage(chatId, `No autorizado. Tu chat ID es: ${chatId}`);
37
+ return;
38
+ }
39
+ bot.sendMessage(chatId, "Hola! Soy tu bot de cobros con Mercado Pago.\n\n" +
40
+ "Puedo generar links de pago, consultar pagos y hacer devoluciones.\n\n" +
41
+ "Usa /help para ver los comandos disponibles.");
42
+ });
43
+ bot.onText(/\/help(?:\s|$)/, (msg) => {
44
+ const chatId = msg.chat.id;
45
+ if (!isAuthorized(chatId))
46
+ return;
47
+ bot.sendMessage(chatId, "Comandos disponibles:\n\n" +
48
+ "/cobrar <monto> <descripcion> - Genera un link de pago\n" +
49
+ " Ejemplo: /cobrar 5000 Servicio de diseno\n\n" +
50
+ "/pagos - Lista los ultimos 5 pagos\n\n" +
51
+ "/estado <payment_id> - Consulta el estado de un pago\n\n" +
52
+ "/devolver <payment_id> [monto] - Devuelve un pago (total o parcial)\n\n" +
53
+ "/help - Muestra este mensaje");
54
+ });
55
+ bot.onText(/\/cobrar(?:\s+(.*))?$/, async (msg, match) => {
56
+ const chatId = msg.chat.id;
57
+ if (!isAuthorized(chatId))
58
+ return;
59
+ const args = match?.[1]?.trim();
60
+ if (!args) {
61
+ bot.sendMessage(chatId, "Uso: /cobrar <monto> <descripcion>\nEjemplo: /cobrar 5000 Servicio de diseno");
62
+ return;
63
+ }
64
+ const spaceIndex = args.indexOf(" ");
65
+ if (spaceIndex === -1) {
66
+ bot.sendMessage(chatId, "Debes incluir un monto y una descripcion.\nEjemplo: /cobrar 5000 Servicio de diseno");
67
+ return;
68
+ }
69
+ const amountStr = args.substring(0, spaceIndex);
70
+ const description = args.substring(spaceIndex + 1).trim();
71
+ const amount = Number(amountStr);
72
+ if (isNaN(amount) || amount <= 0) {
73
+ bot.sendMessage(chatId, "El monto debe ser un numero positivo.\nEjemplo: /cobrar 5000 Servicio de diseno");
74
+ return;
75
+ }
76
+ if (!description) {
77
+ bot.sendMessage(chatId, "Debes incluir una descripcion.\nEjemplo: /cobrar 5000 Servicio de diseno");
78
+ return;
79
+ }
80
+ try {
81
+ const backUrls = MP_SUCCESS_URL
82
+ ? { success: MP_SUCCESS_URL }
83
+ : undefined;
84
+ const result = (await mp.tools.create_payment_preference({
85
+ title: description,
86
+ quantity: 1,
87
+ currency: MP_CURRENCY,
88
+ unit_price: amount,
89
+ back_urls: backUrls,
90
+ }));
91
+ bot.sendMessage(chatId, `Link de pago creado!\n\n` +
92
+ `Descripcion: ${description}\n` +
93
+ `Monto: ${(0, formatting_js_1.formatMoney)(amount, MP_CURRENCY)}\n\n` +
94
+ `Link de pago:\n${result.init_point}`);
95
+ }
96
+ catch (err) {
97
+ bot.sendMessage(chatId, (0, formatting_js_1.friendlyError)(err));
98
+ }
99
+ });
100
+ bot.onText(/\/pagos(?:\s|$)/, async (msg) => {
101
+ const chatId = msg.chat.id;
102
+ if (!isAuthorized(chatId))
103
+ return;
104
+ try {
105
+ const result = (await mp.tools.search_payments({ limit: 5 }));
106
+ if (!result.results || result.results.length === 0) {
107
+ bot.sendMessage(chatId, "No se encontraron pagos recientes.");
108
+ return;
109
+ }
110
+ const lines = result.results.map((p) => {
111
+ const emoji = (0, formatting_js_1.statusEmoji)(p.status);
112
+ const label = (0, formatting_js_1.statusLabel)(p.status);
113
+ const money = (0, formatting_js_1.formatMoney)(p.transaction_amount, p.currency_id ?? MP_CURRENCY);
114
+ const desc = p.description ?? "Sin descripcion";
115
+ return `${emoji} #${p.id} - ${label}\n ${money} - ${desc}`;
116
+ });
117
+ bot.sendMessage(chatId, `Ultimos pagos:\n\n${lines.join("\n\n")}`);
118
+ }
119
+ catch (err) {
120
+ bot.sendMessage(chatId, (0, formatting_js_1.friendlyError)(err));
121
+ }
122
+ });
123
+ bot.onText(/\/estado(?:\s+(\S+))?$/, async (msg, match) => {
124
+ const chatId = msg.chat.id;
125
+ if (!isAuthorized(chatId))
126
+ return;
127
+ const paymentId = match?.[1]?.trim();
128
+ if (!paymentId) {
129
+ bot.sendMessage(chatId, "Uso: /estado <payment_id>\nEjemplo: /estado 123456789");
130
+ return;
131
+ }
132
+ try {
133
+ const payment = (await mp.tools.get_payment({ payment_id: paymentId }));
134
+ const emoji = (0, formatting_js_1.statusEmoji)(payment.status);
135
+ const label = (0, formatting_js_1.statusLabel)(payment.status);
136
+ const money = (0, formatting_js_1.formatMoney)(payment.transaction_amount, payment.currency_id ?? MP_CURRENCY);
137
+ const payerEmail = payment.payer?.email ?? "No disponible";
138
+ bot.sendMessage(chatId, `Pago #${payment.id}\n\n` +
139
+ `Estado: ${emoji} ${label}\n` +
140
+ `Monto: ${money}\n` +
141
+ `Descripcion: ${payment.description ?? "Sin descripcion"}\n` +
142
+ `Pagador: ${payerEmail}\n` +
143
+ `Fecha: ${payment.date_created ?? "No disponible"}`);
144
+ }
145
+ catch (err) {
146
+ bot.sendMessage(chatId, (0, formatting_js_1.friendlyError)(err));
147
+ }
148
+ });
149
+ bot.onText(/\/devolver(?:\s+(\S+)(?:\s+(\S+))?)?$/, async (msg, match) => {
150
+ const chatId = msg.chat.id;
151
+ if (!isAuthorized(chatId))
152
+ return;
153
+ const paymentId = match?.[1]?.trim();
154
+ if (!paymentId) {
155
+ bot.sendMessage(chatId, "Uso: /devolver <payment_id> [monto]\n" +
156
+ "Ejemplo devolucion total: /devolver 123456789\n" +
157
+ "Ejemplo devolucion parcial: /devolver 123456789 1500");
158
+ return;
159
+ }
160
+ const amountStr = match?.[2]?.trim();
161
+ let amount;
162
+ if (amountStr) {
163
+ amount = Number(amountStr);
164
+ if (isNaN(amount) || amount <= 0) {
165
+ bot.sendMessage(chatId, "El monto de devolucion debe ser un numero positivo.");
166
+ return;
167
+ }
168
+ }
169
+ try {
170
+ const result = (await mp.tools.create_refund({
171
+ payment_id: paymentId,
172
+ amount,
173
+ }));
174
+ const refundType = amount ? "parcial" : "total";
175
+ bot.sendMessage(chatId, `Devolucion ${refundType} realizada!\n\n` +
176
+ `ID de devolucion: ${result.id}\n` +
177
+ `Pago: #${paymentId}\n` +
178
+ `Monto devuelto: $${result.amount}`);
179
+ }
180
+ catch (err) {
181
+ bot.sendMessage(chatId, (0, formatting_js_1.friendlyError)(err));
182
+ }
183
+ });
184
+ console.log("Bot de Telegram iniciado correctamente.");
185
+ return bot;
186
+ }
187
+ // Auto-start when run directly
188
+ const isMain = typeof require !== "undefined"
189
+ ? require.main === module
190
+ : process.argv[1]?.includes("telegram-bot");
191
+ if (isMain) {
192
+ startBot();
193
+ }
194
+ //# sourceMappingURL=telegram-bot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram-bot.js","sourceRoot":"","sources":["../src/telegram-bot.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export interface WebhookConfig {
2
+ accessToken: string;
3
+ onPayment: (payment: unknown) => void | Promise<void>;
4
+ secret?: string;
5
+ }
6
+ export declare function createWebhookHandler(config: WebhookConfig): (request: Request) => Promise<Response>;
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createWebhookHandler = createWebhookHandler;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const client_js_1 = require("./client.js");
6
+ function validateSignature(secret, dataId, xSignature, xRequestId) {
7
+ const parts = xSignature.split(",");
8
+ let ts = "";
9
+ let hash = "";
10
+ for (const part of parts) {
11
+ const [key, value] = part.trim().split("=", 2);
12
+ if (key === "ts") {
13
+ ts = value;
14
+ }
15
+ else if (key === "v1") {
16
+ hash = value;
17
+ }
18
+ }
19
+ if (!ts || !hash) {
20
+ return false;
21
+ }
22
+ const template = `id:${dataId};request-id:${xRequestId};ts:${ts};`;
23
+ const expected = (0, node_crypto_1.createHmac)("sha256", secret).update(template).digest("hex");
24
+ try {
25
+ return (0, node_crypto_1.timingSafeEqual)(Buffer.from(expected, "hex"), Buffer.from(hash, "hex"));
26
+ }
27
+ catch {
28
+ return false;
29
+ }
30
+ }
31
+ function createWebhookHandler(config) {
32
+ const client = new client_js_1.MercadoPagoClient(config.accessToken);
33
+ return async (request) => {
34
+ if (request.method !== "POST") {
35
+ return new Response("Method not allowed", { status: 405 });
36
+ }
37
+ let body;
38
+ try {
39
+ body = (await request.json());
40
+ }
41
+ catch {
42
+ return new Response("Bad request: invalid JSON", { status: 400 });
43
+ }
44
+ if (!body || typeof body !== "object") {
45
+ return new Response("Bad request: expected JSON object", { status: 400 });
46
+ }
47
+ // Non-payment notification types are acknowledged but ignored
48
+ if (body.type !== "payment") {
49
+ return new Response("OK", { status: 200 });
50
+ }
51
+ const dataId = body.data?.id;
52
+ if (!dataId || typeof dataId !== "string") {
53
+ return new Response("Bad request: missing data.id", { status: 400 });
54
+ }
55
+ // Validate signature if secret is configured
56
+ if (config.secret) {
57
+ const xSignature = request.headers.get("x-signature") ?? "";
58
+ const xRequestId = request.headers.get("x-request-id") ?? "";
59
+ if (!xSignature || !validateSignature(config.secret, dataId, xSignature, xRequestId)) {
60
+ return new Response("Invalid signature", { status: 401 });
61
+ }
62
+ }
63
+ try {
64
+ if (!/^\d+$/.test(dataId)) {
65
+ return new Response("Bad request: invalid payment ID format", { status: 400 });
66
+ }
67
+ const payment = await client.get(`/v1/payments/${dataId}`);
68
+ await config.onPayment(payment);
69
+ return new Response("OK", { status: 200 });
70
+ }
71
+ catch (error) {
72
+ console.error("[webhook] Error processing payment:", error);
73
+ return new Response("Internal server error", { status: 500 });
74
+ }
75
+ };
76
+ }
77
+ //# sourceMappingURL=webhook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook.js","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"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"}