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,10 @@
1
+ export interface WhatsAppClientConfig {
2
+ accessToken: string;
3
+ phoneNumberId: string;
4
+ }
5
+ export declare class WhatsAppClient {
6
+ private accessToken;
7
+ private phoneNumberId;
8
+ constructor(config: WhatsAppClientConfig);
9
+ sendMessage(phoneNumber: string, message: string): Promise<unknown>;
10
+ }
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WhatsAppClient = void 0;
4
+ const GRAPH_API_BASE = "https://graph.facebook.com/v18.0";
5
+ class WhatsAppClient {
6
+ accessToken;
7
+ phoneNumberId;
8
+ constructor(config) {
9
+ if (!config.accessToken) {
10
+ throw new Error("WHATSAPP_ACCESS_TOKEN is required");
11
+ }
12
+ if (!config.phoneNumberId) {
13
+ throw new Error("WHATSAPP_PHONE_NUMBER_ID is required");
14
+ }
15
+ this.accessToken = config.accessToken;
16
+ this.phoneNumberId = config.phoneNumberId;
17
+ }
18
+ async sendMessage(phoneNumber, message) {
19
+ if (!phoneNumber) {
20
+ throw new Error("phoneNumber is required");
21
+ }
22
+ if (!message) {
23
+ throw new Error("message is required");
24
+ }
25
+ const url = `${GRAPH_API_BASE}/${this.phoneNumberId}/messages`;
26
+ const res = await fetch(url, {
27
+ method: "POST",
28
+ headers: {
29
+ Authorization: `Bearer ${this.accessToken}`,
30
+ "Content-Type": "application/json",
31
+ },
32
+ body: JSON.stringify({
33
+ messaging_product: "whatsapp",
34
+ to: phoneNumber,
35
+ type: "text",
36
+ text: { body: message },
37
+ }),
38
+ });
39
+ if (!res.ok) {
40
+ const body = await res.text();
41
+ throw new Error(`WhatsApp API error (${res.status}): ${body}`);
42
+ }
43
+ return res.json();
44
+ }
45
+ }
46
+ exports.WhatsAppClient = WhatsAppClient;
47
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/whatsapp/client.ts"],"names":[],"mappings":";;;AAAA,MAAM,cAAc,GAAG,kCAAkC,CAAC;AAO1D,MAAa,cAAc;IACjB,WAAW,CAAS;IACpB,aAAa,CAAS;IAE9B,YAAY,MAA4B;QACtC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QACD,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QACtC,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,WAAmB,EAAE,OAAe;QACpD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QACD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACzC,CAAC;QAED,MAAM,GAAG,GAAG,GAAG,cAAc,IAAI,IAAI,CAAC,aAAa,WAAW,CAAC;QAC/D,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAC3B,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,IAAI,CAAC,WAAW,EAAE;gBAC3C,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,iBAAiB,EAAE,UAAU;gBAC7B,EAAE,EAAE,WAAW;gBACf,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;aACxB,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,uBAAuB,GAAG,CAAC,MAAM,MAAM,IAAI,EAAE,CAAC,CAAC;QACjE,CAAC;QAED,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;CACF;AA7CD,wCA6CC"}
@@ -0,0 +1,11 @@
1
+ import { WhatsAppClient } from "./client.js";
2
+ import type { ParsedCommand } from "./message-parser.js";
3
+ export interface HandlersConfig {
4
+ mpAccessToken: string;
5
+ currency: string;
6
+ successUrl?: string;
7
+ }
8
+ export declare function createCommandHandlers(config: HandlersConfig): {
9
+ handleCommand: (wa: WhatsAppClient, phoneNumber: string, parsed: ParsedCommand) => Promise<void>;
10
+ };
11
+ export declare function createPaymentNotifier(wa: WhatsAppClient, notifyPhone: string): (payment: unknown) => Promise<void>;
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createCommandHandlers = createCommandHandlers;
4
+ exports.createPaymentNotifier = createPaymentNotifier;
5
+ const index_js_1 = require("../index.js");
6
+ const formatting_js_1 = require("../shared/formatting.js");
7
+ function createCommandHandlers(config) {
8
+ const mp = (0, index_js_1.createMercadoPagoTools)(config.mpAccessToken);
9
+ async function handleCommand(wa, phoneNumber, parsed) {
10
+ switch (parsed.command) {
11
+ case "ayuda":
12
+ return handleAyuda(wa, phoneNumber);
13
+ case "cobrar":
14
+ return handleCobrar(wa, phoneNumber, parsed.args);
15
+ case "pagos":
16
+ return handlePagos(wa, phoneNumber);
17
+ case "estado":
18
+ return handleEstado(wa, phoneNumber, parsed.args);
19
+ case "devolver":
20
+ return handleDevolver(wa, phoneNumber, parsed.args);
21
+ }
22
+ }
23
+ async function handleAyuda(wa, phone) {
24
+ await wa.sendMessage(phone, "Comandos disponibles:\n\n" +
25
+ "cobrar <monto> <descripcion>\n Genera un link de pago\n\n" +
26
+ "pagos\n Lista ultimos pagos\n\n" +
27
+ "estado <payment_id>\n Consulta estado de un pago\n\n" +
28
+ "devolver <payment_id> [monto]\n Devuelve un pago\n\n" +
29
+ "ayuda\n Muestra este mensaje");
30
+ }
31
+ async function handleCobrar(wa, phone, args) {
32
+ if (args.length < 2) {
33
+ await wa.sendMessage(phone, "Uso: cobrar <monto> <descripcion>\nEjemplo: cobrar 5000 curso python");
34
+ return;
35
+ }
36
+ const amount = Number(args[0]);
37
+ if (isNaN(amount) || amount <= 0) {
38
+ await wa.sendMessage(phone, "El monto debe ser un numero positivo.");
39
+ return;
40
+ }
41
+ const description = args.slice(1).join(" ");
42
+ try {
43
+ const backUrls = config.successUrl ? { success: config.successUrl } : undefined;
44
+ const result = (await mp.tools.create_payment_preference({
45
+ title: description,
46
+ quantity: 1,
47
+ currency: config.currency,
48
+ unit_price: amount,
49
+ back_urls: backUrls,
50
+ }));
51
+ await wa.sendMessage(phone, `\ud83d\udcb3 Link de pago generado\n\n` +
52
+ `${description}\n` +
53
+ `Monto: $${amount}\n\n` +
54
+ `${result.init_point}`);
55
+ }
56
+ catch (err) {
57
+ await wa.sendMessage(phone, (0, formatting_js_1.friendlyError)(err));
58
+ }
59
+ }
60
+ async function handlePagos(wa, phone) {
61
+ try {
62
+ const result = (await mp.tools.search_payments({ limit: 5 }));
63
+ if (!result.results || result.results.length === 0) {
64
+ await wa.sendMessage(phone, "No se encontraron pagos recientes.");
65
+ return;
66
+ }
67
+ const lines = result.results.map((p) => {
68
+ const emoji = (0, formatting_js_1.statusEmoji)(p.status);
69
+ const label = (0, formatting_js_1.statusLabel)(p.status);
70
+ return `${emoji} ${label}\n$${p.transaction_amount}\nID: ${p.id}`;
71
+ });
72
+ await wa.sendMessage(phone, `Ultimos pagos:\n\n${lines.join("\n\n")}`);
73
+ }
74
+ catch (err) {
75
+ await wa.sendMessage(phone, (0, formatting_js_1.friendlyError)(err));
76
+ }
77
+ }
78
+ async function handleEstado(wa, phone, args) {
79
+ if (args.length < 1) {
80
+ await wa.sendMessage(phone, "Uso: estado <payment_id>\nEjemplo: estado 123456789");
81
+ return;
82
+ }
83
+ try {
84
+ const payment = (await mp.tools.get_payment({ payment_id: args[0] }));
85
+ const emoji = (0, formatting_js_1.statusEmoji)(payment.status);
86
+ const label = (0, formatting_js_1.statusLabel)(payment.status);
87
+ await wa.sendMessage(phone, `Pago #${payment.id}\n\n` +
88
+ `Estado: ${emoji} ${label}\n` +
89
+ `Monto: $${payment.transaction_amount}\n` +
90
+ `Descripcion: ${payment.description ?? "Sin descripcion"}\n` +
91
+ `Pagador: ${payment.payer?.email ?? "No disponible"}\n` +
92
+ `Fecha: ${payment.date_created ?? "No disponible"}`);
93
+ }
94
+ catch (err) {
95
+ await wa.sendMessage(phone, (0, formatting_js_1.friendlyError)(err));
96
+ }
97
+ }
98
+ async function handleDevolver(wa, phone, args) {
99
+ if (args.length < 1) {
100
+ await wa.sendMessage(phone, "Uso: devolver <payment_id> [monto]\nEjemplo: devolver 123456789");
101
+ return;
102
+ }
103
+ const paymentId = args[0];
104
+ let amount;
105
+ if (args[1]) {
106
+ amount = Number(args[1]);
107
+ if (isNaN(amount) || amount <= 0) {
108
+ await wa.sendMessage(phone, "El monto debe ser un numero positivo.");
109
+ return;
110
+ }
111
+ }
112
+ try {
113
+ const result = (await mp.tools.create_refund({
114
+ payment_id: paymentId,
115
+ amount,
116
+ }));
117
+ const tipo = amount ? "parcial" : "total";
118
+ await wa.sendMessage(phone, `Devolucion ${tipo} realizada\n\n` +
119
+ `ID devolucion: ${result.id}\n` +
120
+ `Pago: #${paymentId}\n` +
121
+ `Monto devuelto: $${result.amount}`);
122
+ }
123
+ catch (err) {
124
+ await wa.sendMessage(phone, (0, formatting_js_1.friendlyError)(err));
125
+ }
126
+ }
127
+ return { handleCommand };
128
+ }
129
+ function createPaymentNotifier(wa, notifyPhone) {
130
+ return async (payment) => {
131
+ const p = payment;
132
+ if (p.status !== "approved")
133
+ return;
134
+ await wa.sendMessage(notifyPhone, `\u2705 Pago recibido\nMonto: $${p.transaction_amount}\nID: ${p.id}` +
135
+ (p.description ? `\nDescripcion: ${p.description}` : ""));
136
+ };
137
+ }
138
+ //# sourceMappingURL=handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/whatsapp/handlers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ export type CommandName = "cobrar" | "pagos" | "estado" | "devolver" | "ayuda";
2
+ export interface ParsedCommand {
3
+ command: CommandName;
4
+ args: string[];
5
+ }
6
+ export declare function parseMessage(text: string): ParsedCommand | null;
7
+ export interface IncomingWhatsAppMessage {
8
+ from: string;
9
+ text: string;
10
+ messageId: string;
11
+ timestamp: string;
12
+ }
13
+ interface WhatsAppWebhookEntry {
14
+ changes?: Array<{
15
+ value?: {
16
+ messages?: Array<{
17
+ from?: string;
18
+ id?: string;
19
+ timestamp?: string;
20
+ type?: string;
21
+ text?: {
22
+ body?: string;
23
+ };
24
+ }>;
25
+ };
26
+ }>;
27
+ }
28
+ interface WhatsAppWebhookPayload {
29
+ object?: string;
30
+ entry?: WhatsAppWebhookEntry[];
31
+ }
32
+ export declare function extractMessages(body: WhatsAppWebhookPayload): IncomingWhatsAppMessage[];
33
+ export {};
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseMessage = parseMessage;
4
+ exports.extractMessages = extractMessages;
5
+ const VALID_COMMANDS = new Set([
6
+ "cobrar",
7
+ "pagos",
8
+ "estado",
9
+ "devolver",
10
+ "ayuda",
11
+ "help",
12
+ ]);
13
+ function parseMessage(text) {
14
+ const trimmed = text.trim();
15
+ if (!trimmed)
16
+ return null;
17
+ const parts = trimmed.split(/\s+/);
18
+ const raw = parts[0].toLowerCase().replace(/^\//, "");
19
+ if (!VALID_COMMANDS.has(raw))
20
+ return null;
21
+ const command = raw === "help" ? "ayuda" : raw;
22
+ return { command, args: parts.slice(1) };
23
+ }
24
+ function extractMessages(body) {
25
+ const messages = [];
26
+ if (body.object !== "whatsapp_business_account")
27
+ return messages;
28
+ for (const entry of body.entry ?? []) {
29
+ for (const change of entry.changes ?? []) {
30
+ for (const msg of change.value?.messages ?? []) {
31
+ if (msg.type === "text" && msg.text?.body && msg.from && msg.id) {
32
+ messages.push({
33
+ from: msg.from,
34
+ text: msg.text.body,
35
+ messageId: msg.id,
36
+ timestamp: msg.timestamp ?? "",
37
+ });
38
+ }
39
+ }
40
+ }
41
+ }
42
+ return messages;
43
+ }
44
+ //# sourceMappingURL=message-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-parser.js","sourceRoot":"","sources":["../../src/whatsapp/message-parser.ts"],"names":[],"mappings":";;AAgBA,oCAWC;AA4BD,0CAqBC;AArED,MAAM,cAAc,GAAwB,IAAI,GAAG,CAAC;IAClD,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,UAAU;IACV,OAAO;IACP,MAAM;CACP,CAAC,CAAC;AAEH,SAAgB,YAAY,CAAC,IAAY;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAEtD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAE1C,MAAM,OAAO,GAAgB,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAkB,CAAC;IAC3E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3C,CAAC;AA4BD,SAAgB,eAAe,CAAC,IAA4B;IAC1D,MAAM,QAAQ,GAA8B,EAAE,CAAC;IAE/C,IAAI,IAAI,CAAC,MAAM,KAAK,2BAA2B;QAAE,OAAO,QAAQ,CAAC;IAEjE,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;QACrC,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;YACzC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,KAAK,EAAE,QAAQ,IAAI,EAAE,EAAE,CAAC;gBAC/C,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;oBAChE,QAAQ,CAAC,IAAI,CAAC;wBACZ,IAAI,EAAE,GAAG,CAAC,IAAI;wBACd,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI;wBACnB,SAAS,EAAE,GAAG,CAAC,EAAE;wBACjB,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,EAAE;qBAC/B,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,16 @@
1
+ export interface WhatsAppWebhookConfig {
2
+ waAccessToken: string;
3
+ waPhoneNumberId: string;
4
+ verifyToken: string;
5
+ mpAccessToken: string;
6
+ currency?: string;
7
+ successUrl?: string;
8
+ allowedPhones?: Set<string>;
9
+ }
10
+ export declare function createWhatsAppWebhookHandler(config: WhatsAppWebhookConfig): (request: Request) => Promise<Response>;
11
+ export { WhatsAppClient } from "./client.js";
12
+ export type { WhatsAppClientConfig } from "./client.js";
13
+ export { parseMessage, extractMessages } from "./message-parser.js";
14
+ export type { ParsedCommand, IncomingWhatsAppMessage, CommandName } from "./message-parser.js";
15
+ export { createCommandHandlers, createPaymentNotifier } from "./handlers.js";
16
+ export type { HandlersConfig } from "./handlers.js";
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createPaymentNotifier = exports.createCommandHandlers = exports.extractMessages = exports.parseMessage = exports.WhatsAppClient = void 0;
4
+ exports.createWhatsAppWebhookHandler = createWhatsAppWebhookHandler;
5
+ const client_js_1 = require("./client.js");
6
+ const message_parser_js_1 = require("./message-parser.js");
7
+ const handlers_js_1 = require("./handlers.js");
8
+ function createWhatsAppWebhookHandler(config) {
9
+ const wa = new client_js_1.WhatsAppClient({
10
+ accessToken: config.waAccessToken,
11
+ phoneNumberId: config.waPhoneNumberId,
12
+ });
13
+ const handlersConfig = {
14
+ mpAccessToken: config.mpAccessToken,
15
+ currency: config.currency ?? "ARS",
16
+ successUrl: config.successUrl,
17
+ };
18
+ const { handleCommand } = (0, handlers_js_1.createCommandHandlers)(handlersConfig);
19
+ return async (request) => {
20
+ // GET — Meta webhook verification challenge
21
+ if (request.method === "GET") {
22
+ const url = new URL(request.url);
23
+ const mode = url.searchParams.get("hub.mode");
24
+ const token = url.searchParams.get("hub.verify_token");
25
+ const challenge = url.searchParams.get("hub.challenge");
26
+ if (mode === "subscribe" && token === config.verifyToken) {
27
+ return new Response(challenge ?? "", { status: 200 });
28
+ }
29
+ return new Response("Forbidden", { status: 403 });
30
+ }
31
+ // POST — incoming messages
32
+ if (request.method === "POST") {
33
+ let body;
34
+ try {
35
+ body = await request.json();
36
+ }
37
+ catch {
38
+ return new Response("Bad request", { status: 400 });
39
+ }
40
+ const messages = (0, message_parser_js_1.extractMessages)(body);
41
+ for (const msg of messages) {
42
+ // Access control: if allowedPhones is set, only respond to those numbers
43
+ if (config.allowedPhones && !config.allowedPhones.has(msg.from)) {
44
+ continue;
45
+ }
46
+ const parsed = (0, message_parser_js_1.parseMessage)(msg.text);
47
+ if (parsed) {
48
+ try {
49
+ await handleCommand(wa, msg.from, parsed);
50
+ }
51
+ catch {
52
+ // Best-effort: don't fail the webhook on handler errors
53
+ }
54
+ }
55
+ }
56
+ // Always return 200 to acknowledge receipt (Meta requires this)
57
+ return new Response("OK", { status: 200 });
58
+ }
59
+ return new Response("Method not allowed", { status: 405 });
60
+ };
61
+ }
62
+ var client_js_2 = require("./client.js");
63
+ Object.defineProperty(exports, "WhatsAppClient", { enumerable: true, get: function () { return client_js_2.WhatsAppClient; } });
64
+ var message_parser_js_2 = require("./message-parser.js");
65
+ Object.defineProperty(exports, "parseMessage", { enumerable: true, get: function () { return message_parser_js_2.parseMessage; } });
66
+ Object.defineProperty(exports, "extractMessages", { enumerable: true, get: function () { return message_parser_js_2.extractMessages; } });
67
+ var handlers_js_2 = require("./handlers.js");
68
+ Object.defineProperty(exports, "createCommandHandlers", { enumerable: true, get: function () { return handlers_js_2.createCommandHandlers; } });
69
+ Object.defineProperty(exports, "createPaymentNotifier", { enumerable: true, get: function () { return handlers_js_2.createPaymentNotifier; } });
70
+ //# sourceMappingURL=webhook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../src/whatsapp/webhook.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "cobroya",
3
+ "version": "1.0.0",
4
+ "description": "Mercado Pago payment links from Telegram, WhatsApp, and AI agents. Cobra en 10 segundos.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "bin",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "bin": {
20
+ "cobroya-mcp": "./bin/mcp-server.mjs",
21
+ "cobroya-telegram": "./bin/telegram-bot.mjs",
22
+ "mercadopago-mcp": "./bin/mcp-server.mjs",
23
+ "mercadopago-telegram": "./bin/telegram-bot.mjs"
24
+ },
25
+ "keywords": [
26
+ "mercadopago",
27
+ "payments",
28
+ "telegram",
29
+ "whatsapp",
30
+ "mcp",
31
+ "ai-agents",
32
+ "argentina",
33
+ "latam",
34
+ "checkout"
35
+ ],
36
+ "author": "dan1d",
37
+ "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/dan1d/mercadopago-tool.git"
41
+ },
42
+ "homepage": "https://cobroya.app",
43
+ "scripts": {
44
+ "build": "tsc",
45
+ "test": "vitest run",
46
+ "test:watch": "vitest",
47
+ "integration": "tsx scripts/integration.ts",
48
+ "bot": "tsx src/telegram-bot.ts",
49
+ "whatsapp": "tsx scripts/whatsapp-server.ts",
50
+ "start": "node dist/server.js",
51
+ "dev:server": "tsx src/server.ts",
52
+ "docker:build": "docker build -t mercadopago-tool .",
53
+ "docker:run": "docker run --env-file .env -p 3000:3000 mercadopago-tool"
54
+ },
55
+ "devDependencies": {
56
+ "@types/node-telegram-bot-api": "^0.64.14",
57
+ "tsx": "^4.7.0",
58
+ "typescript": "^5.4.0",
59
+ "vitest": "^1.6.0"
60
+ },
61
+ "engines": {
62
+ "node": ">=18"
63
+ },
64
+ "dependencies": {
65
+ "@modelcontextprotocol/sdk": "^1.27.1",
66
+ "dotenv": "^17.3.1",
67
+ "node-telegram-bot-api": "^0.67.0",
68
+ "zod": "^4.3.6"
69
+ }
70
+ }