cdp-edge 1.0.4 → 1.1.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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Padrão Quantum Tracking: 100% Cloudflare Edge.** Sem GTM. Sem Stape. Sem cookies de terceiros.
4
4
 
5
- > **v2.5.3** — Auditoria de Dependências + Sync de Agentes + Fix D1 (25 de Abril de 2026) 🔧
5
+ > **v2.5.4** — Auditoria de Dependências + Sync de Agentes + Fix D1 (25 de Abril de 2026) 🔧
6
6
 
7
7
  ---
8
8
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "_comment": "Fonte de verdade para versões dos agent files. Atualizar quando modules/ ou index.ts mudarem. Use scripts/validate-agents.js para detectar drifts.",
3
- "worker_version": "2.5.3",
4
- "worker_hash_date": "2026-04-15",
3
+ "worker_version": "2.5.4",
4
+ "worker_hash_date": "2026-04-25",
5
5
  "agents": {
6
6
  "master-orchestrator": {
7
7
  "version": "2.0.7",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdp-edge",
3
- "version": "1.0.4",
3
+ "version": "1.1.0",
4
4
  "description": "CDP Edge - Quantum Tracking - Sistema multi-agente para tracking digital Cloudflare Native (Workers + D1)",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -63,6 +63,9 @@ import {
63
63
  processWhatsAppWebhook,
64
64
  verifyHmac,
65
65
  } from './modules/dispatch/whatsapp';
66
+ import {
67
+ notifyEvolutionForm,
68
+ } from './modules/dispatch/crm';
66
69
 
67
70
  // ── ML — LTV + A/B Testing ────────────────────────────────────────────────────
68
71
  import {
@@ -239,6 +242,9 @@ export default {
239
242
  WA_NOTIFY_NUMBER: env.WA_NOTIFY_NUMBER ? 'set' : 'not set (optional - only for auto-reply)',
240
243
  TIKTOK_ACCESS_TOKEN: env.TIKTOK_ACCESS_TOKEN ? 'set' : 'not set (optional)',
241
244
  CALLMEBOT_PHONE: env.CALLMEBOT_PHONE ? 'set' : 'not set (optional)',
245
+ EVOLUTION_BASE_URL: env.EVOLUTION_BASE_URL ? 'set' : 'not set (optional - CRM Evolution)',
246
+ EVOLUTION_INSTANCE: env.EVOLUTION_INSTANCE ? 'set' : 'not set (optional - CRM Evolution)',
247
+ EVOLUTION_API_KEY: env.EVOLUTION_API_KEY ? 'set' : 'not set (optional - CRM Evolution)',
242
248
  };
243
249
 
244
250
  const hasMissing =
@@ -793,6 +799,25 @@ export default {
793
799
  : []),
794
800
  ]);
795
801
 
802
+ // ── Notifica o Evolution CRM (formulários de cadastro) ────────────────
803
+ // Ativo para Lead e Contact vindos de formulários (quando tem telefone).
804
+ // Silencioso se EVOLUTION_BASE_URL / EVOLUTION_INSTANCE / EVOLUTION_API_KEY
805
+ // não estiverem configurados — zero impacto no pipeline principal.
806
+ const EVOLUTION_FORM_EVENTS = ['Lead', 'Contact', 'CompleteRegistration'];
807
+ if (EVOLUTION_FORM_EVENTS.includes(eventName) && trackPayload.phone) {
808
+ ctx.waitUntil(
809
+ notifyEvolutionForm(env, {
810
+ phone: trackPayload.phone,
811
+ name: [trackPayload.firstName, trackPayload.lastName].filter(Boolean).join(' ') || null,
812
+ email: trackPayload.email || null,
813
+ formName: trackPayload.contentName || trackPayload.productName || eventName,
814
+ utmSource: trackPayload.utmSource || null,
815
+ utmCampaign: trackPayload.utmCampaign || null,
816
+ pageUrl: trackPayload.pageUrl || null,
817
+ })
818
+ );
819
+ }
820
+
796
821
  // Automação de mensagens
797
822
  const AUTOMATION_EVENTS = ['Lead', 'Purchase', 'InitiateCheckout'];
798
823
  if (AUTOMATION_EVENTS.includes(eventName) && env.DB) {
@@ -0,0 +1,116 @@
1
+ /**
2
+ * CDP Edge — Evolution GO Integration
3
+ * Encaminha leads para o Evolution GO, que dispara o webhook para o EVO CRM.
4
+ *
5
+ * Secrets necessários (wrangler secret put):
6
+ * EVOLUTION_BASE_URL → URL base (ex: https://go.arkitekt.space)
7
+ * EVOLUTION_INSTANCE → Nome da instância (ex: Ramon)
8
+ * EVOLUTION_API_KEY → API Key do Evolution GO
9
+ */
10
+
11
+ import { Env } from '../../types.js';
12
+
13
+ export interface CTWALeadData {
14
+ phone: string;
15
+ messageBody?: string;
16
+ ctwaClid?: string | null;
17
+ adId?: string | null;
18
+ sourceUrl?: string | null;
19
+ headline?: string | null;
20
+ wamid?: string | null;
21
+ }
22
+
23
+ export interface FormLeadData {
24
+ phone: string;
25
+ name?: string | null;
26
+ email?: string | null;
27
+ formName?: string | null;
28
+ utmSource?: string | null;
29
+ utmCampaign?: string | null;
30
+ pageUrl?: string | null;
31
+ }
32
+
33
+ // ── Helpers ──────────────────────────────────────────────────────────────────
34
+
35
+ function isEvolutionConfigured(env: Env): boolean {
36
+ return !!(env.EVOLUTION_BASE_URL && env.EVOLUTION_INSTANCE && env.EVOLUTION_API_KEY);
37
+ }
38
+
39
+ function evolutionHeaders(env: Env): Record<string, string> {
40
+ return {
41
+ 'Content-Type': 'application/json',
42
+ 'apikey': env.EVOLUTION_API_KEY!,
43
+ };
44
+ }
45
+
46
+ function normalizePhone(phone: string): string {
47
+ const digits = phone.replace(/\D/g, '');
48
+ if (digits.startsWith('55') && (digits.length === 12 || digits.length === 13)) return digits;
49
+ if (digits.length === 10 || digits.length === 11) return `55${digits}`;
50
+ return digits;
51
+ }
52
+
53
+ // ── Envio via Evolution GO /send/text ────────────────────────────────────────
54
+ // POST {EVOLUTION_BASE_URL}/send/text
55
+ // Body: { id: instanceName, number, text, delay }
56
+
57
+ async function sendEvolutionText(env: Env, phone: string, text: string): Promise<void> {
58
+ const number = normalizePhone(phone);
59
+ try {
60
+ const res = await fetch(`${env.EVOLUTION_BASE_URL}/send/text`, {
61
+ method: 'POST',
62
+ headers: evolutionHeaders(env),
63
+ body: JSON.stringify({
64
+ id: env.EVOLUTION_INSTANCE,
65
+ number,
66
+ text,
67
+ delay: 0,
68
+ }),
69
+ });
70
+ if (!res.ok) {
71
+ const err = await res.text();
72
+ console.warn('[Evolution] sendText non-ok:', res.status, err.slice(0, 200));
73
+ }
74
+ } catch (err: any) {
75
+ console.warn('[Evolution] sendText failed (non-critical):', err?.message || String(err));
76
+ }
77
+ }
78
+
79
+ // ── API Pública — CTWA ────────────────────────────────────────────────────────
80
+
81
+ export async function notifyEvolutionCTWA(env: Env, data: CTWALeadData): Promise<void> {
82
+ if (!isEvolutionConfigured(env)) return;
83
+
84
+ const { phone, messageBody, ctwaClid, adId, sourceUrl, headline } = data;
85
+
86
+ const linhas: string[] = [`🔔 *Novo Lead via WhatsApp (CTWA)*`, ``];
87
+ linhas.push(`📱 *Número:* ${phone}`);
88
+ if (messageBody) linhas.push(`💬 *Mensagem:* ${messageBody}`);
89
+ if (headline) linhas.push(`📢 *Anúncio:* ${headline}`);
90
+ if (sourceUrl) linhas.push(`🔗 *URL:* ${sourceUrl}`);
91
+ if (adId) linhas.push(`🆔 *Ad ID:* ${adId}`);
92
+ if (ctwaClid) linhas.push(`🧩 *CTWA ID:* ${ctwaClid}`);
93
+ linhas.push(``, `🕐 ${new Date().toLocaleString('pt-BR', { timeZone: 'America/Sao_Paulo' })}`);
94
+
95
+ await sendEvolutionText(env, phone, linhas.join('\n'));
96
+ }
97
+
98
+ // ── API Pública — Formulário ──────────────────────────────────────────────────
99
+
100
+ export async function notifyEvolutionForm(env: Env, data: FormLeadData): Promise<void> {
101
+ if (!isEvolutionConfigured(env)) return;
102
+
103
+ const { phone, name, email, formName, utmSource, utmCampaign, pageUrl } = data;
104
+
105
+ const linhas: string[] = [`📋 *Novo Lead via Formulário*`, ``];
106
+ if (name) linhas.push(`👤 *Nome:* ${name}`);
107
+ if (email) linhas.push(`📧 *E-mail:* ${email}`);
108
+ linhas.push( `📱 *Telefone:* ${phone}`);
109
+ if (formName) linhas.push(`📝 *Formulário:* ${formName}`);
110
+ if (utmSource) linhas.push(`🔗 *Fonte:* ${utmSource}`);
111
+ if (utmCampaign) linhas.push(`📣 *Campanha:* ${utmCampaign}`);
112
+ if (pageUrl) linhas.push(`🌐 *Página:* ${pageUrl}`);
113
+ linhas.push(``, `🕐 ${new Date().toLocaleString('pt-BR', { timeZone: 'America/Sao_Paulo' })}`);
114
+
115
+ await sendEvolutionText(env, phone, linhas.join('\n'));
116
+ }
@@ -7,6 +7,7 @@ import { sha256, normalizePhone } from '../utils.js';
7
7
  import { saveLead, logApiFailure } from '../db.js';
8
8
  import { Env, TrackPayload } from '../../types.js';
9
9
  import { ExecutionContext } from '@cloudflare/workers-types';
10
+ import { notifyEvolutionCTWA } from './crm.js';
10
11
 
11
12
  // ── Tipos ───────────────────────────────────────────────────────────────────────
12
13
  interface WhatsAppOptions {
@@ -248,6 +249,22 @@ export async function processWhatsAppWebhook(env: Env, body: any, request: Reque
248
249
  }, request, 'whatsapp')
249
250
  );
250
251
 
252
+ // ── Notifica o Evolution CRM sobre o novo lead CTWA ──────────────────────
253
+ // Cria/atualiza o contato no Evolution e abre a conversa para o vendedor.
254
+ // Silencioso se EVOLUTION_BASE_URL / EVOLUTION_INSTANCE / EVOLUTION_API_KEY
255
+ // não estiverem configurados.
256
+ ctx.waitUntil(
257
+ notifyEvolutionCTWA(env, {
258
+ phone: phoneNorm,
259
+ messageBody: messageBody || undefined,
260
+ ctwaClid,
261
+ adId,
262
+ sourceUrl,
263
+ headline,
264
+ wamid,
265
+ })
266
+ );
267
+
251
268
  results.push({ ok: true, phone: phoneNorm.slice(0, 4) + '****', ctwa_clid: ctwaClid ? 'present' : 'absent', event_id: eventId });
252
269
  }
253
270
 
@@ -64,6 +64,11 @@ export interface Env {
64
64
  RESEND_API_KEY?: string;
65
65
  RESEND_FROM_EMAIL?: string;
66
66
  CALLMEBOT_APIKEY?: string;
67
+
68
+ // Evolution API CRM
69
+ EVOLUTION_BASE_URL?: string; // URL base do servidor Evolution (ex: https://evolution.suaempresa.com)
70
+ EVOLUTION_INSTANCE?: string; // Nome da instância WhatsApp no Evolution
71
+ EVOLUTION_API_KEY?: string; // Chave de autenticação da API Evolution
67
72
  }
68
73
 
69
74
  // ── Event Payload Types ───────────────────────────────────────────────────────
@@ -16,13 +16,13 @@ workers_dev = true
16
16
  # pattern = "*.SEU_DOMINIO/track*"
17
17
  # zone_name = "SEU_DOMINIO"
18
18
 
19
- [[routes]]
20
- pattern = "SEU_DOMINIO/track*"
21
- zone_name = "SEU_DOMINIO"
22
-
23
- [[routes]]
24
- pattern = "*.SEU_DOMINIO/track*"
25
- zone_name = "SEU_DOMINIO"
19
+ # [[routes]]
20
+ # pattern = "lancamentosabc.com.br/track*"
21
+ # zone_name = "lancamentosabc.com.br"
22
+ #
23
+ # [[routes]]
24
+ # pattern = "*.lancamentosabc.com.br/track*"
25
+ # zone_name = "lancamentosabc.com.br"
26
26
 
27
27
  # ── Variáveis públicas (não são segredos) ─────────────────────────────────────
28
28
  [vars]
@@ -134,3 +134,6 @@ head_sampling_rate = 1
134
134
  # wrangler secret put LINKEDIN_AD_ACCOUNT_ID ← ID da conta de anúncios LinkedIn
135
135
  # wrangler secret put SPOTIFY_ACCESS_TOKEN ← Bearer token Spotify Advertising API
136
136
  # wrangler secret put SPOTIFY_AD_ACCOUNT_ID ← ID da conta de anúncios Spotify Ads
137
+ # wrangler secret put EVOLUTION_BASE_URL ← URL base do Evolution API (ex: https://evolution.suaempresa.com)
138
+ # wrangler secret put EVOLUTION_INSTANCE ← Nome da instância WhatsApp no Evolution
139
+ # wrangler secret put EVOLUTION_API_KEY ← Chave de autenticação do Evolution API