cdp-edge 2.5.9 → 2.6.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 (41) hide show
  1. package/README.md +238 -202
  2. package/bin/cdp-edge.js +1 -0
  3. package/dist/commands/infra.js +1 -1
  4. package/dist/commands/server.js +38 -33
  5. package/dist/commands/setup.js +3 -0
  6. package/dist/commands/validate.js +251 -236
  7. package/dist/sdk/cdpTrack.js +6 -4
  8. package/dist/sdk/cdpTrack.min.js +4 -4
  9. package/dist/sdk/install-snippet.html +1 -1
  10. package/extracted-skill/tracking-events-generator/INTEGRACAO-COMPLETA.md +4 -4
  11. package/extracted-skill/tracking-events-generator/Premium-Tracking-Intelligence-Resumo.md +3 -3
  12. package/extracted-skill/tracking-events-generator/agents/master-orchestrator.md +72 -23
  13. package/extracted-skill/tracking-events-generator/integration-test.js +3 -3
  14. package/extracted-skill/tracking-events-generator/knowledge-base.md +12 -12
  15. package/extracted-skill/tracking-events-generator/models/checkout-proprio.md +1 -1
  16. package/extracted-skill/tracking-events-generator/models/multi-step-checkout.md +4 -4
  17. package/extracted-skill/tracking-events-generator/models/reddit/conversions-api-template.js +1 -1
  18. package/extracted-skill/tracking-events-generator/models/scenarios/behavior-engine.js +1 -1
  19. package/extracted-skill/tracking-events-generator/models/scenarios/sales-page-logic.md +1 -1
  20. package/extracted-skill/tracking-events-generator/models/trafego-direto.md +7 -7
  21. package/package.json +2 -2
  22. package/server-edge-tracker/index.ts +1267 -1204
  23. package/server-edge-tracker/modules/db.ts +2 -2
  24. package/server-edge-tracker/modules/dispatch/meta.ts +3 -0
  25. package/server-edge-tracker/modules/dispatch/tiktok.ts +1 -0
  26. package/server-edge-tracker/modules/dispatch/whatsapp.ts +5 -2
  27. package/server-edge-tracker/modules/utils.ts +1 -1
  28. package/server-edge-tracker/types.ts +3 -0
  29. package/server-edge-tracker/wrangler.toml +2 -0
  30. package/templates/checkout-proprio.md +1 -1
  31. package/templates/install/CLAUDE.md +1 -1
  32. package/templates/multi-step-checkout.md +4 -4
  33. package/templates/reddit/conversions-api-template.js +1 -1
  34. package/templates/scenarios/behavior-engine.js +1 -1
  35. package/templates/scenarios/sales-page-logic.md +1 -1
  36. package/templates/trafego-direto.md +7 -7
  37. package/templates/vsl-page.md +2 -2
  38. package/server-edge-tracker/.client.env +0 -5
  39. package/server-edge-tracker/dist-check/README.md +0 -1
  40. package/server-edge-tracker/dist-check/index.js +0 -5164
  41. package/server-edge-tracker/dist-check/index.js.map +0 -8
@@ -55,7 +55,7 @@ export async function saveLead(env: Env, eventName: string, payload: TrackPayloa
55
55
  city, state, country,
56
56
  fbp, fbc, userId,
57
57
  utmSource, utmMedium, utmCampaign, utmContent, utmTerm,
58
- pageUrl, value, currency, eventId, botScore,
58
+ pageUrl, value, currency, eventId, event_id, botScore,
59
59
  engagementScore, intentionLevel, utmRestored,
60
60
  } = payload;
61
61
 
@@ -69,7 +69,7 @@ export async function saveLead(env: Env, eventName: string, payload: TrackPayloa
69
69
  ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,datetime('now'))
70
70
  `).bind(
71
71
  eventName,
72
- eventId || null,
72
+ eventId || event_id || null,
73
73
  email || null,
74
74
  normalizePhone(phone) || null,
75
75
  firstName || null,
@@ -15,6 +15,9 @@ interface EnrichedPayload {
15
15
  }
16
16
 
17
17
  export async function sendMetaCapi(env: Env, eventName: string, payload: TrackPayload, request: Request | null, ctx: ExecutionContext | null): Promise<any> {
18
+ if (env.DISABLE_EXTERNAL_DISPATCH === '1') return { skipped: 'external dispatch disabled' };
19
+ if (!env.META_ACCESS_TOKEN) return { skipped: 'META_ACCESS_TOKEN not set' };
20
+
18
21
  // Auto-enriquecer payload com dados do Identity Graph antes do envio
19
22
  let recovered = { email: false, utm: false };
20
23
  if (env.DB && payload) {
@@ -9,6 +9,7 @@ import { Env, TrackPayload } from '../../types.js';
9
9
  import { ExecutionContext } from '@cloudflare/workers-types';
10
10
 
11
11
  export async function sendTikTokApi(env: Env, eventName: string, payload: TrackPayload, request: Request | null, ctx: ExecutionContext | null): Promise<any> {
12
+ if (env.DISABLE_EXTERNAL_DISPATCH === '1') return { skipped: 'external dispatch disabled' };
12
13
  if (!env.TIKTOK_ACCESS_TOKEN) return { skipped: 'TIKTOK_ACCESS_TOKEN not set' };
13
14
 
14
15
  const pixelId = env.TIKTOK_PIXEL_ID;
@@ -264,6 +264,9 @@ export async function processWhatsAppWebhook(env: Env, body: any, request: Reque
264
264
  export async function verifyHmac(secret: string, rawBody: string, receivedSignature: string): Promise<boolean> {
265
265
  if (!secret || !receivedSignature) return false;
266
266
  try {
267
+ const normalizedSignature = receivedSignature.startsWith('sha256=')
268
+ ? receivedSignature.slice('sha256='.length)
269
+ : receivedSignature;
267
270
  const key = await crypto.subtle.importKey(
268
271
  'raw',
269
272
  new TextEncoder().encode(secret),
@@ -273,10 +276,10 @@ export async function verifyHmac(secret: string, rawBody: string, receivedSignat
273
276
  );
274
277
  const sig = await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(rawBody));
275
278
  const computed = Array.from(new Uint8Array(sig)).map(b => b.toString(16).padStart(2, '0')).join('');
276
- if (computed.length !== receivedSignature.length) return false;
279
+ if (computed.length !== normalizedSignature.length) return false;
277
280
  let diff = 0;
278
281
  for (let i = 0; i < computed.length; i++) {
279
- diff |= computed.charCodeAt(i) ^ receivedSignature.charCodeAt(i);
282
+ diff |= computed.charCodeAt(i) ^ normalizedSignature.toLowerCase().charCodeAt(i);
280
283
  }
281
284
  return diff === 0;
282
285
  } catch {
@@ -36,7 +36,7 @@ export function corsHeaders(origin: string | null, siteDomain: string | null): R
36
36
  return {
37
37
  'Access-Control-Allow-Origin': allowed || '*',
38
38
  'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
39
- 'Access-Control-Allow-Headers': 'Content-Type, X-Requested-With',
39
+ 'Access-Control-Allow-Headers': 'Content-Type, X-Requested-With, Authorization',
40
40
  'Access-Control-Max-Age': '86400',
41
41
  };
42
42
  }
@@ -30,11 +30,14 @@ export interface Env {
30
30
  GA4_MEASUREMENT_ID?: string;
31
31
  TIKTOK_PIXEL_ID?: string;
32
32
  SITE_DOMAIN?: string;
33
+ DISABLE_EXTERNAL_DISPATCH?: string;
33
34
 
34
35
  // Secrets
36
+ ADMIN_API_TOKEN?: string;
35
37
  META_ACCESS_TOKEN?: string;
36
38
  GA4_API_SECRET?: string;
37
39
  TIKTOK_ACCESS_TOKEN?: string;
40
+ META_APP_SECRET?: string;
38
41
  WA_WEBHOOK_VERIFY_TOKEN?: string;
39
42
  // WhatsApp Cloud API — nomes canônicos (Meta Cloud API v25.0)
40
43
  WHATSAPP_ACCESS_TOKEN?: string; // canonical: Bearer token do System User
@@ -125,6 +125,7 @@ head_sampling_rate = 1
125
125
  # Só execute o comando abaixo se o secret ainda não existir:
126
126
  #
127
127
  # wrangler secret put META_ACCESS_TOKEN ← token Meta CAPI
128
+ # wrangler secret put ADMIN_API_TOKEN ← token Bearer para rotas /api/* administrativas
128
129
  # wrangler secret put GA4_API_SECRET ← secret GA4 Measurement Protocol
129
130
  # wrangler secret put TIKTOK_ACCESS_TOKEN ← token TikTok Events API (opcional)
130
131
  # wrangler secret put META_AD_ACCOUNT_ID ← ID da conta de anúncios Meta
@@ -134,6 +135,7 @@ head_sampling_rate = 1
134
135
  # wrangler secret put WA_PHONE_ID ← ID legado do número (compatibilidade)
135
136
  # wrangler secret put WA_NOTIFY_NUMBER ← Número que recebe alertas de venda/lead
136
137
  # wrangler secret put WA_WEBHOOK_VERIFY_TOKEN ← Token de verificação do webhook WhatsApp
138
+ # wrangler secret put META_APP_SECRET ← App Secret para validar x-hub-signature-256 do WhatsApp
137
139
  # wrangler secret put WEBHOOK_SECRET_TICTO ← HMAC-SHA256 Ticto
138
140
  # wrangler secret put CALLMEBOT_PHONE ← Número CallMeBot para alertas
139
141
  # wrangler secret put CALLMEBOT_APIKEY ← API Key CallMeBot
@@ -31,7 +31,7 @@ Este script captura dados à medida que o usuário preenche o formulário.
31
31
  ```javascript
32
32
  <script>
33
33
  (function() {
34
- const WORKER_URL = 'https://api.seusite.com/api/tracking';
34
+ const WORKER_URL = 'https://api.seusite.com/track';
35
35
 
36
36
  // Atualização de identidade ao sair do campo (Blur Event)
37
37
  const inputs = document.querySelectorAll('input[type="email"], input[type="tel"]');
@@ -58,7 +58,7 @@ cdp-edge/
58
58
 
59
59
  ## Regras obrigatórias (CDP Edge)
60
60
 
61
- - **Nunca usar GTM, Stape.io ou VPS** sempre Cloudflare Native
61
+ - **Arquitetura Cloudflare Native** — Workers, D1, KV, Queues e rotas same-domain
62
62
  - **Same-domain only** — o Worker deve rodar no domínio do funil
63
63
  - **SHA256 no Worker** — nunca hashar no browser
64
64
  - **event_id idêntico** entre browser e server para deduplicação
@@ -50,7 +50,7 @@ Step 4: Confirmação / Obrigado
50
50
  <script src="/js/cdpTrack.js" async></script>
51
51
  <script>
52
52
  window.cdpConfig = {
53
- workerUrl: '/api/tracking', // Same-Domain (furtivo)
53
+ workerUrl: '/track', // Same-Domain (furtivo)
54
54
  metaId: 'SEU_PIXEL_ID',
55
55
  ga4Id: 'G-XXXXXXXX',
56
56
  tiktokId: 'C4XXXXXXXXXXXXXXX',
@@ -204,7 +204,7 @@ document.addEventListener('visibilitychange', async () => {
204
204
  const cdp_uid = document.cookie.match(/cdp_uid=([^;]+)/)?.[1] || '';
205
205
 
206
206
  // Usa navigator.sendBeacon para garantir envio mesmo se browser encerrar
207
- navigator.sendBeacon('/api/tracking', JSON.stringify({
207
+ navigator.sendBeacon('/track', JSON.stringify({
208
208
  event_name: 'CheckoutAbandonment',
209
209
  cdp_uid,
210
210
  step: checkoutState.step,
@@ -236,7 +236,7 @@ export default {
236
236
  return new Response(null, { headers: cors });
237
237
  }
238
238
 
239
- if (url.pathname === '/api/tracking') {
239
+ if (url.pathname === '/track') {
240
240
  return handleTracking(request, env, ctx);
241
241
  }
242
242
 
@@ -589,7 +589,7 @@ CREATE INDEX IF NOT EXISTS idx_events_created ON events_log(created_at);
589
589
  - [ ] CheckoutAbandonment usa `navigator.sendBeacon` para garantir envio
590
590
 
591
591
  ### Cloudflare Worker
592
- - [ ] Endpoint `/api/tracking` configurado como Route no Cloudflare
592
+ - [ ] Endpoint `/track` configurado como Route no Cloudflare
593
593
  - [ ] Identity Graph atualizado progressivamente conforme usuário preenche campos
594
594
  - [ ] Meta CAPI v25.0 endpoint correto
595
595
  - [ ] TikTok Events API v1.3 endpoint correto
@@ -183,7 +183,7 @@ function generateEventId() {
183
183
  * @param {Object} data - Dados completos do evento
184
184
  */
185
185
  async function sendToServer(eventName, data) {
186
- const serverUrl = '/api/track'; // ou URL configurada
186
+ const serverUrl = '/track'; // ou URL configurada
187
187
 
188
188
  await fetch(serverUrl, {
189
189
  method: 'POST',
@@ -299,7 +299,7 @@ const BehaviorEngine = {
299
299
  fields_count: formInteracted.size,
300
300
  meta_intensity: 'medium',
301
301
  });
302
- navigator.sendBeacon('/api/tracking', new Blob([data], { type: 'application/json' }));
302
+ navigator.sendBeacon('/track', new Blob([data], { type: 'application/json' }));
303
303
  }
304
304
  }
305
305
  });
@@ -19,7 +19,7 @@ Mede a eficácia do vídeo de vendas antes do botão de compra aparecer.
19
19
  * **Ação**: Disparar `ViewContent` (25/50/75) e `AddToCart` (100% ou clique no botão).
20
20
 
21
21
  ### 3. Adblock Immunity (Stealth Tracking)
22
- Utiliza rotas no mesmo domínio (ex: `/api/tracking`) para garantir que o script de rastreamento não seja bloqueado por uBlock ou Ghostery.
22
+ Utiliza rotas no mesmo domínio (ex: `/track`) para garantir que o script de rastreamento não seja bloqueado por uBlock ou Ghostery.
23
23
 
24
24
  ---
25
25
 
@@ -34,7 +34,7 @@
34
34
  ┌─────────────────────────────────────────────────────────────┐
35
35
  │ Cloudflare Worker (Quantum Tier) │
36
36
 
37
- │ Endpoint: /api/tracking (Same-Domain) │
37
+ │ Endpoint: /track (Same-Domain) │
38
38
  │ - Recebe eventos do browser │
39
39
  │ - Salva sessão no D1 (fbp, fbc, ttp, UTMs) │
40
40
  │ - Despacha para APIs: Meta, GA4, TikTok │
@@ -78,7 +78,7 @@
78
78
  <script src="/js/cdpTrack.js" async></script>
79
79
  <script>
80
80
  window.cdpConfig = {
81
- workerUrl: '/api/tracking', // Same-Domain (furtivo)
81
+ workerUrl: '/track', // Same-Domain (furtivo)
82
82
  metaId: 'SEU_PIXEL_ID',
83
83
  ga4Id: 'G-XXXXXXXX',
84
84
  tiktokId: 'C4XXXXXXXXXXXXXXX',
@@ -182,7 +182,7 @@ export default {
182
182
  }
183
183
 
184
184
  // Endpoint principal de tracking
185
- if (url.pathname === '/api/tracking') {
185
+ if (url.pathname === '/track') {
186
186
  return handleTracking(request, env, ctx);
187
187
  }
188
188
 
@@ -500,13 +500,13 @@ CREATE INDEX IF NOT EXISTS idx_fbc ON identity_graph(fbc);
500
500
 
501
501
  ### Browser
502
502
  - [ ] cdp_uid gerado no primeiro acesso e persistido por 1 ano
503
- - [ ] PageView disparado via Fetch para `/api/tracking`
503
+ - [ ] PageView disparado via Fetch para `/track`
504
504
  - [ ] InitiateCheckout disparado antes do redirecionamento
505
505
  - [ ] cdp_uid injetado na URL do checkout (xcod/sck/src)
506
506
  - [ ] UTMs capturados e salvos no D1
507
507
 
508
508
  ### Cloudflare Worker
509
- - [ ] Endpoint `/api/tracking` configurado como Route no Cloudflare
509
+ - [ ] Endpoint `/track` configurado como Route no Cloudflare
510
510
  - [ ] Endpoint `/api/wh/{plataforma}` para webhooks
511
511
  - [ ] Salvar sessão no D1 com todos os cookies
512
512
  - [ ] D1 lookup pelo cdp_uid ao receber webhook
@@ -527,13 +527,13 @@ CREATE INDEX IF NOT EXISTS idx_fbc ON identity_graph(fbc);
527
527
  ```
528
528
  1. Visitante acessa a página de vendas
529
529
  └── JS: gera cdp_uid → salva cookie (1 ano)
530
- └── JS: dispara PageView → /api/tracking
530
+ └── JS: dispara PageView → /track
531
531
  └── Worker: salva sessão no D1 (fbp, fbc, ttp, UTMs, IP)
532
532
  └── Worker: dispatch → Meta, GA4, TikTok (PageView)
533
533
 
534
534
  2. Visitante clica no botão de compra
535
535
  └── JS: intercepta clique → previne redirecionamento
536
- └── JS: dispara InitiateCheckout → /api/tracking
536
+ └── JS: dispara InitiateCheckout → /track
537
537
  └── Worker: atualiza sessão no D1
538
538
  └── Worker: dispatch → Meta, GA4, TikTok (InitiateCheckout)
539
539
  └── JS: injeta cdp_uid na URL (xcod/sck/src)
@@ -35,7 +35,7 @@
35
35
  ┌─────────────────────────────────────────────────────────────────┐
36
36
  │ Cloudflare Worker │
37
37
  │ │
38
- │ /api/tracking: │
38
+ │ /track: │
39
39
  │ VideoProgress 75% → Meta: ViewContent + TikTok: ViewContent │
40
40
  │ Lead → Meta: Lead + GA4: generate_lead + TikTok: SubmitForm │
41
41
  │ InitiateCheckout → Meta + GA4 + TikTok │
@@ -175,7 +175,7 @@ function dispatchEvent(eventName, data = {}) {
175
175
  ### Configurar no Worker (`worker.js`) — handler de VideoProgress:
176
176
 
177
177
  ```javascript
178
- // Dentro do handler /api/tracking, adicionar case para VideoProgress
178
+ // Dentro do handler /track, adicionar case para VideoProgress
179
179
  case 'VideoProgress':
180
180
  const vp = payload.behavioral_data?.progress_percent || 0;
181
181
  // Só disparar plataformas em thresholds significativos
@@ -1,5 +0,0 @@
1
- DATABASE_ID=
2
- SITE_DOMAIN=
3
- META_PIXEL_ID=
4
- GA4_MEASUREMENT_ID=
5
- TIKTOK_PIXEL_ID=
@@ -1 +0,0 @@
1
- This folder contains the built output assets for the worker "server-edge-tracker" generated at 2026-04-14T21:31:47.480Z.