cdp-edge 2.0.1 → 2.0.2

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 (30) hide show
  1. package/contracts/api-versions.json +12 -8
  2. package/dist/commands/install.js +1 -1
  3. package/dist/commands/setup.js +1 -1
  4. package/extracted-skill/tracking-events-generator/agents/attribution-agent.md +23 -23
  5. package/extracted-skill/tracking-events-generator/agents/compliance-agent.md +20 -0
  6. package/extracted-skill/tracking-events-generator/agents/crm-integration-agent.md +48 -16
  7. package/extracted-skill/tracking-events-generator/agents/dashboard-agent.md +7 -7
  8. package/extracted-skill/tracking-events-generator/agents/database-agent.md +8 -8
  9. package/extracted-skill/tracking-events-generator/agents/debug-agent.md +13 -13
  10. package/extracted-skill/tracking-events-generator/agents/devops-agent.md +31 -7
  11. package/extracted-skill/tracking-events-generator/agents/email-agent.md +27 -0
  12. package/extracted-skill/tracking-events-generator/agents/fingerprint-agent.md +205 -0
  13. package/extracted-skill/tracking-events-generator/agents/intelligence-agent.md +6 -6
  14. package/extracted-skill/tracking-events-generator/agents/linkedin-agent.md +108 -0
  15. package/extracted-skill/tracking-events-generator/agents/ltv-predictor-agent.md +1 -1
  16. package/extracted-skill/tracking-events-generator/agents/master-feedback-loop.md +68 -8
  17. package/extracted-skill/tracking-events-generator/agents/master-orchestrator.md +61 -18
  18. package/extracted-skill/tracking-events-generator/agents/performance-agent.md +29 -19
  19. package/extracted-skill/tracking-events-generator/agents/performance-optimization-agent.md +11 -1
  20. package/extracted-skill/tracking-events-generator/agents/security-enterprise-agent.md +137 -28
  21. package/extracted-skill/tracking-events-generator/agents/server-tracking.md +7 -8
  22. package/extracted-skill/tracking-events-generator/agents/tiktok-agent.md +63 -0
  23. package/extracted-skill/tracking-events-generator/agents/tracking-plan-agent.md +100 -5
  24. package/extracted-skill/tracking-events-generator/agents/webhook-agent.md +58 -0
  25. package/extracted-skill/tracking-events-generator/agents/whatsapp-agent.md +58 -5
  26. package/extracted-skill/tracking-events-generator/agents/whatsapp-ctwa-setup-agent.md +16 -16
  27. package/extracted-skill/tracking-events-generator/agents/youtube-agent.md +140 -25
  28. package/extracted-skill/tracking-events-generator/contracts/api-versions.json +12 -8
  29. package/package.json +2 -2
  30. package/server-edge-tracker/worker.js +53 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdp-edge",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
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",
@@ -23,7 +23,7 @@
23
23
  "build": "node build.js",
24
24
  "dev": "node build.js --watch",
25
25
  "test": "node test.js",
26
- "test:unit": "node tests/unit/*.test.js",
26
+ "test:unit": "node tests/unit/normalization.test.js && node tests/unit/hashing.test.js && node tests/unit/deduplication.test.js && node tests/unit/payload-validation.test.js && node tests/unit/new-features.test.js",
27
27
  "test:unit:normalize": "node tests/unit/normalization.test.js",
28
28
  "test:unit:hash": "node tests/unit/hashing.test.js",
29
29
  "test:unit:dedup": "node tests/unit/deduplication.test.js",
@@ -151,7 +151,7 @@ async function sendMetaCapi(env, eventName, payload, request, ctx) {
151
151
  if (!res.ok) {
152
152
  const errorCode = data.error?.code || String(res.status);
153
153
  const errorMessage = data.error?.message || data.error?.error_user_msg || 'Unknown error';
154
- console.error('Meta CAPI error:', JSON.stringify(data));
154
+ console.error('Meta CAPI error:', res.status, data.error?.message || data.error?.error_user_msg || 'unknown');
155
155
 
156
156
  // Log de falha para Feedback Loop
157
157
  if (env.DB) {
@@ -802,7 +802,7 @@ async function sendTikTokApi(env, eventName, payload, request, ctx) {
802
802
 
803
803
  const data = await res.json();
804
804
  if (!res.ok || data.code !== 0) {
805
- console.error('TikTok Events API error:', JSON.stringify(data));
805
+ console.error('TikTok Events API error:', res.status, data.message || data.code || 'unknown');
806
806
 
807
807
  // Log de falha para Feedback Loop
808
808
  if (env.DB && ctx) {
@@ -907,8 +907,9 @@ async function sendPinterestCapi(env, eventName, payload, request, ctx) {
907
907
  );
908
908
  const data = await res.json();
909
909
  if (!res.ok) {
910
- console.error('Pinterest CAPI error:', JSON.stringify(data));
911
- if (env.DB && ctx) ctx.waitUntil(logApiFailure(env.DB, 'pinterest', eventName, String(res.status), JSON.stringify(data), body.data[0].event_id, JSON.stringify(body)));
910
+ const pinterestErrMsg = data.message || data.code || String(res.status);
911
+ console.error('Pinterest CAPI error:', res.status, pinterestErrMsg);
912
+ if (env.DB && ctx) ctx.waitUntil(logApiFailure(env.DB, 'pinterest', eventName, String(res.status), pinterestErrMsg, body.data[0].event_id, JSON.stringify(body)));
912
913
  }
913
914
  return data;
914
915
  } catch (err) {
@@ -1306,7 +1307,7 @@ async function _sendWARequest(env, body) {
1306
1307
  body: JSON.stringify(body),
1307
1308
  });
1308
1309
  const data = await res.json();
1309
- if (!res.ok) console.error('WhatsApp Meta API error:', JSON.stringify(data));
1310
+ if (!res.ok) console.error('WhatsApp Meta API error:', res.status, data.error?.message || 'unknown');
1310
1311
  return { ok: res.ok, status: res.status, data };
1311
1312
  } catch (err) {
1312
1313
  console.error('WhatsApp Meta API failed:', err.message);
@@ -1452,7 +1453,7 @@ async function processWhatsAppWebhook(env, body, request, ctx) {
1452
1453
  'UPDATE whatsapp_contacts SET capi_sent = 1 WHERE wamid = ?'
1453
1454
  ).bind(wamid).run();
1454
1455
  } else if (!res.ok) {
1455
- console.error('[CTWA] Meta CAPI error:', JSON.stringify(data));
1456
+ console.error('[CTWA] Meta CAPI error:', res.status, data.error?.message || 'unknown');
1456
1457
  if (env.DB) {
1457
1458
  await logApiFailure(env.DB, 'meta', 'Contact', data.error?.code || res.status,
1458
1459
  data.error?.message || 'CTWA CAPI error', eventId, JSON.stringify(requestBody));
@@ -1931,7 +1932,7 @@ async function runIntelligenceAgent(env, runType) {
1931
1932
 
1932
1933
  // 5. Customer Match — sync semanal D1 → Meta Custom Audience
1933
1934
  const cmResult = await syncMetaCustomAudience(env);
1934
- console.log(`[Intelligence Agent] Customer Match Meta: ${JSON.stringify(cmResult)}`);
1935
+ console.log(`[Intelligence Agent] Customer Match Meta: sent=${cmResult?.sent ?? 0}, received=${cmResult?.num_received ?? 0}`);
1935
1936
 
1936
1937
  console.log(`[Intelligence Agent] ${runType} concluído`);
1937
1938
  }
@@ -2000,7 +2001,7 @@ async function syncMetaCustomAudience(env) {
2000
2001
  const result = await res.json();
2001
2002
 
2002
2003
  if (!res.ok) {
2003
- console.error('[CustomerMatch] Meta erro:', JSON.stringify(result));
2004
+ console.error('[CustomerMatch] Meta erro:', res.status, result.error?.message || 'unknown');
2004
2005
  return { error: result.error?.message, sent: 0 };
2005
2006
  }
2006
2007
 
@@ -3508,6 +3509,12 @@ export default {
3508
3509
 
3509
3510
  // ── POST /track — evento do browser ───────────────────────────────────────
3510
3511
  if (request.method === 'POST' && url.pathname === '/track') {
3512
+ // Reject oversized payloads before reading body (64 KB limit)
3513
+ const contentLength = parseInt(request.headers.get('Content-Length') || '0', 10);
3514
+ if (contentLength > 65536) {
3515
+ return new Response(JSON.stringify({ error: 'Payload muito grande' }), { status: 413, headers });
3516
+ }
3517
+
3511
3518
  let body;
3512
3519
  try {
3513
3520
  body = await request.json();
@@ -3518,6 +3525,22 @@ export default {
3518
3525
  );
3519
3526
  }
3520
3527
 
3528
+ // ── Payload validation ────────────────────────────────────────────────────
3529
+ // Reject non-object bodies and oversized string fields to prevent injection
3530
+ if (typeof body !== 'object' || Array.isArray(body) || body === null) {
3531
+ return new Response(JSON.stringify({ error: 'Payload inválido' }), { status: 400, headers });
3532
+ }
3533
+
3534
+ const VALID_EVENT_NAMES = new Set([
3535
+ 'PageView','ViewContent','Lead','Purchase','InitiateCheckout',
3536
+ 'AddToCart','CompleteRegistration','Contact','Schedule',
3537
+ 'StartTrial','Subscribe','SubmitApplication','Search',
3538
+ 'video_start','video_25','video_50','video_75','video_complete'
3539
+ ]);
3540
+ const STR_FIELDS = ['email','phone','firstName','lastName','city','state','zip','userId',
3541
+ 'utmSource','utmMedium','utmCampaign','utmContent','utmTerm',
3542
+ 'fbclid','ttclid','gclid','transactionId','productName','currency'];
3543
+
3521
3544
  const { eventName, behavioral_data, ...payload } = body;
3522
3545
 
3523
3546
  if (!eventName) {
@@ -3527,6 +3550,28 @@ export default {
3527
3550
  );
3528
3551
  }
3529
3552
 
3553
+ if (typeof eventName !== 'string' || eventName.length > 64 || !VALID_EVENT_NAMES.has(eventName)) {
3554
+ return new Response(JSON.stringify({ error: `eventName desconhecido: ${eventName.slice(0, 64)}` }), { status: 400, headers });
3555
+ }
3556
+
3557
+ // Enforce max string length on known PII/UTM fields to block injection payloads
3558
+ for (const field of STR_FIELDS) {
3559
+ if (payload[field] !== undefined && payload[field] !== null) {
3560
+ if (typeof payload[field] !== 'string' || payload[field].length > 512) {
3561
+ return new Response(JSON.stringify({ error: `Campo inválido: ${field}` }), { status: 400, headers });
3562
+ }
3563
+ }
3564
+ }
3565
+
3566
+ // value must be a non-negative number when present
3567
+ if (payload.value !== undefined && payload.value !== null) {
3568
+ const v = Number(payload.value);
3569
+ if (isNaN(v) || v < 0 || v > 9_999_999) {
3570
+ return new Response(JSON.stringify({ error: 'value fora do intervalo permitido' }), { status: 400, headers });
3571
+ }
3572
+ payload.value = v;
3573
+ }
3574
+
3530
3575
  // ── Extrair dados comportamentais do browser ──────────────────────────────
3531
3576
  // behavioral_data vem do engagement-scoring.js (engagement_score 0-5, intention_level)
3532
3577
  // e do BehaviorEngine (user_score 0-100)