cdp-edge 2.2.5 → 2.3.1
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 +57 -2
- package/contracts/types.ts +81 -0
- package/docs/whatsapp-ctwa.md +3 -2
- package/package.json +7 -4
- package/server-edge-tracker/.client.env.example +14 -0
- package/server-edge-tracker/deploy-client.js +76 -0
- package/server-edge-tracker/{index.js → index.ts} +93 -84
- package/server-edge-tracker/modules/{db.js → db.ts} +117 -77
- package/server-edge-tracker/modules/dispatch/{ga4.js → ga4.ts} +12 -10
- package/server-edge-tracker/modules/dispatch/{meta.js → meta.ts} +35 -28
- package/server-edge-tracker/modules/dispatch/{platforms.js → platforms.ts} +58 -56
- package/server-edge-tracker/modules/dispatch/{tiktok.js → tiktok.ts} +22 -20
- package/server-edge-tracker/modules/dispatch/{whatsapp.js → whatsapp.ts} +74 -28
- package/server-edge-tracker/modules/{intelligence.js → intelligence.ts} +175 -60
- package/server-edge-tracker/modules/ml/{bidding.js → bidding.ts} +37 -35
- package/server-edge-tracker/modules/ml/{fraud.js → fraud.ts} +48 -40
- package/server-edge-tracker/modules/ml/{logistic.js → logistic.ts} +44 -19
- package/server-edge-tracker/modules/ml/{ltv.js → ltv.ts} +135 -90
- package/server-edge-tracker/modules/ml/{matchquality.js → matchquality.ts} +70 -26
- package/server-edge-tracker/modules/ml/{segmentation.js → segmentation.ts} +109 -48
- package/server-edge-tracker/modules/{utils.js → utils.ts} +41 -22
- package/server-edge-tracker/types.ts +255 -0
- package/server-edge-tracker/wrangler.toml +2 -2
- package/docs/PixelBuilder-Documentacao-Completa (2).docx +0 -0
package/README.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
**Padrão Quantum Tracking: 100% Cloudflare Edge.** Sem GTM. Sem Stape. Sem cookies de terceiros.
|
|
4
4
|
|
|
5
|
-
> **v2.
|
|
5
|
+
> **v2.3.1** — Hardening Enterprise · PII removido dos logs · Script de deploy seguro (`deploy-client.js`) · WhatsApp secrets alinhados à Meta Cloud API v22.0 · `api-versions.json` v1.1.0
|
|
6
|
+
|
|
7
|
+
> ⚠️ **REGRA DE OURO (SQUAD):** Todas as atualizações, correções ou novas features devem OBRIGATORIAMENTE ser documentadas de forma sincronizada neste `README.md`, no arquivo de instruções `CLAUDE.md` e no dossiê de diretoria `CDP-EDGE-BUSINESS-BOOK.md`. Nenhuma alteração passa sem esse tripé.
|
|
6
8
|
|
|
7
9
|
---
|
|
8
10
|
|
|
@@ -25,6 +27,59 @@ Meu ecossistema opera como um Cérebro de Conversão Privado na borda. Quando um
|
|
|
25
27
|
|
|
26
28
|
---
|
|
27
29
|
|
|
30
|
+
## 📋 CHANGELOG v2.3.1 — Hardening Enterprise (12 de Abril de 2026)
|
|
31
|
+
|
|
32
|
+
### 🔒 Segurança & Conformidade
|
|
33
|
+
|
|
34
|
+
- **PII removido dos logs:** `DeviceGraph` parou de logar `user_id` nos Workers logs — dados sensíveis nunca aparecem no Cloudflare dashboard
|
|
35
|
+
- **Deploy seguro:** novo `deploy-client.js` — lê credenciais de `.client.env` (gitignored), gera `wrangler.deploy.toml` temporário, faz deploy e autodestrói o arquivo. Credenciais de cliente nunca entram no repo
|
|
36
|
+
- **`.gitignore` reforçado:** `.client.env` e `wrangler.deploy.toml` explicitamente ignorados
|
|
37
|
+
- **WhatsApp secrets alinhados à Meta Cloud API v22.0:** `resolvePhoneNumberId()` e `resolveAccessToken()` com fallback canônico → legado — backwards compat garantido
|
|
38
|
+
- **`api-versions.json` v1.1.0:** metadata `updated_at` corrigido para `2026-04-12`
|
|
39
|
+
- **`/health` WhatsApp:** reflete corretamente secrets com nomes canônicos ou legados
|
|
40
|
+
|
|
41
|
+
### 🔧 Deploy de Cliente — Novo Fluxo
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
cd server-edge-tracker
|
|
45
|
+
cp .client.env.example .client.env
|
|
46
|
+
# preencher DATABASE_ID, SITE_DOMAIN, pixels
|
|
47
|
+
node deploy-client.js --dry-run # valida sem subir
|
|
48
|
+
node deploy-client.js # deploy real
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 📋 CHANGELOG v2.3.0 — TypeScript Nativo (12 de Abril de 2026)
|
|
54
|
+
|
|
55
|
+
### 🔷 Worker 100% TypeScript — Migração Completa
|
|
56
|
+
|
|
57
|
+
Todo o código server-side (`server-edge-tracker/`) foi migrado de JavaScript para **TypeScript nativo**. O Wrangler compila diretamente o `.ts` via esbuild — sem etapa de build separada, sem configuração extra.
|
|
58
|
+
|
|
59
|
+
**Por que TypeScript muda o jogo no CDP Edge:**
|
|
60
|
+
- **Env tipado** — typos em nomes de secrets (`META_ACCESS_TOKEN`, `GEO_CACHE`, `DB`) viram erros em build time, nunca em produção
|
|
61
|
+
- **TrackPayload contratado** — o shape do payload entre browser e Worker é garantido pelo compilador
|
|
62
|
+
- **Cloudflare types nativos** — D1, KV, R2, Workers AI com autocomplete e validação de métodos
|
|
63
|
+
- **Fraud Gate e ML seguros** — `checkFraudGate(env: Env, request: Request, payload: TrackPayload)` — nenhum `undefined` passa despercebido
|
|
64
|
+
- **Refatoração segura** — renomear qualquer campo do `TrackPayload` lista automaticamente todos os pontos de quebra
|
|
65
|
+
|
|
66
|
+
**Arquivos migrados (JS → TS) — 16 módulos:**
|
|
67
|
+
- `index.ts` — entry point do Worker
|
|
68
|
+
- `types.ts` — **novo** — contratos centralizados: `Env`, `TrackPayload`, `BehavioralData`, `HotmartWebhook`, `KiwifyWebhook`, `TictoWebhook`, `QueueMessage`, `PromiseResult<T>`
|
|
69
|
+
- `modules/utils.ts`, `modules/db.ts`, `modules/intelligence.ts`
|
|
70
|
+
- `modules/dispatch/` — `meta.ts`, `ga4.ts`, `tiktok.ts`, `platforms.ts`, `whatsapp.ts`
|
|
71
|
+
- `modules/ml/` — `ltv.ts`, `fraud.ts`, `bidding.ts`, `segmentation.ts`, `logistic.ts`, `matchquality.ts`
|
|
72
|
+
|
|
73
|
+
**Infraestrutura:**
|
|
74
|
+
- `tsconfig.json` — `target: ESNext`, `moduleResolution: "bundler"`, `strict: true`, `@cloudflare/workers-types`
|
|
75
|
+
- `wrangler.toml` — `main = "index.ts"` (TypeScript nativo via wrangler/esbuild)
|
|
76
|
+
- `contracts/types.ts` — tipos públicos exportados no pacote NPM: `QuantumEventPayload`, `AgencyContext`, `ApiVersionsConfig`
|
|
77
|
+
- `npm run typecheck` — `tsc --noEmit` (225 testes passando, zero erros de compilação)
|
|
78
|
+
|
|
79
|
+
**Breaking change:** nenhuma — API HTTP e comportamento em runtime são idênticos. TypeScript é invisível para o Cloudflare.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
28
83
|
## 📋 CHANGELOG v2.2.5 (11 de Abril de 2026)
|
|
29
84
|
|
|
30
85
|
### 🔧 Correção de Versão Dinâmica
|
|
@@ -65,7 +120,7 @@ Meu ecossistema opera como um Cérebro de Conversão Privado na borda. Quando um
|
|
|
65
120
|
- **YouTube events**: `video_milestone`/`video_progress_25/50/75` → `video_25`/`video_50`/`video_75` (alinhado ao VALID_EVENT_NAMES do worker)
|
|
66
121
|
- **LinkedIn CAPI**: endpoint `/rest/conversionEvents` + header `LinkedIn-Version: 202401` em `contracts/api-versions.json`
|
|
67
122
|
- **Workers AI model**: `llama-3-8b-instruct` → `@cf/meta/llama-3.1-8b-instruct`
|
|
68
|
-
- **
|
|
123
|
+
- **index.ts**: Content-Length guard (413 se > 64KB), payload validation (allowlist 19 events, 512 chars, value range), PII removido dos logs
|
|
69
124
|
- **Testes**: bugs críticos em `deduplication.test.js` corrigidos (template literals escapados, prefixo errado)
|
|
70
125
|
- **npm**: lodash 4.17.23 → 4.18.1, node-fetch removido
|
|
71
126
|
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// CDP Edge Premium - API Contracts & Typings
|
|
2
|
+
|
|
3
|
+
export interface QuantumEventPayload {
|
|
4
|
+
eventName: string;
|
|
5
|
+
eventId: string;
|
|
6
|
+
userId: string;
|
|
7
|
+
email?: string | null;
|
|
8
|
+
phone?: string | null;
|
|
9
|
+
firstName?: string | null;
|
|
10
|
+
lastName?: string | null;
|
|
11
|
+
city?: string | null;
|
|
12
|
+
state?: string | null;
|
|
13
|
+
zip?: string | null;
|
|
14
|
+
country?: string | null;
|
|
15
|
+
|
|
16
|
+
// Identifiers
|
|
17
|
+
fbp?: string | null;
|
|
18
|
+
fbc?: string | null;
|
|
19
|
+
ttp?: string | null;
|
|
20
|
+
gaClientId?: string | null;
|
|
21
|
+
|
|
22
|
+
// Parameters
|
|
23
|
+
value?: number | null;
|
|
24
|
+
currency?: string;
|
|
25
|
+
contentIds?: string[];
|
|
26
|
+
contentName?: string;
|
|
27
|
+
contentType?: string;
|
|
28
|
+
pageUrl?: string;
|
|
29
|
+
orderId?: string;
|
|
30
|
+
|
|
31
|
+
// Quantum Tracking Details
|
|
32
|
+
intentScoreNum?: number | null;
|
|
33
|
+
metaSignal?: number;
|
|
34
|
+
distanceBucket?: string;
|
|
35
|
+
funnelLevel?: string;
|
|
36
|
+
botScore?: number;
|
|
37
|
+
|
|
38
|
+
// Any extra params
|
|
39
|
+
[key: string]: any;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface AgencyContext {
|
|
43
|
+
// Required Env mappings for specialists
|
|
44
|
+
META_ACCESS_TOKEN?: string;
|
|
45
|
+
META_PIXEL_ID?: string;
|
|
46
|
+
GA4_API_SECRET?: string;
|
|
47
|
+
GA4_MEASUREMENT_ID?: string;
|
|
48
|
+
TIKTOK_ACCESS_TOKEN?: string;
|
|
49
|
+
TIKTOK_PIXEL_ID?: string;
|
|
50
|
+
PINTEREST_ACCESS_TOKEN?: string;
|
|
51
|
+
PINTEREST_AD_ACCOUNT_ID?: string;
|
|
52
|
+
REDDIT_ACCESS_TOKEN?: string;
|
|
53
|
+
REDDIT_AD_ACCOUNT_ID?: string;
|
|
54
|
+
LINKEDIN_ACCESS_TOKEN?: string;
|
|
55
|
+
LINKEDIN_AD_ACCOUNT_ID?: string;
|
|
56
|
+
SPOTIFY_ACCESS_TOKEN?: string;
|
|
57
|
+
SPOTIFY_AD_ACCOUNT_ID?: string;
|
|
58
|
+
|
|
59
|
+
// Databases and Stores
|
|
60
|
+
DB?: any; // D1 Database
|
|
61
|
+
GEO_CACHE?: any; // KV Namespace
|
|
62
|
+
RATE_LIMITER?: any;
|
|
63
|
+
SITE_DOMAIN?: string;
|
|
64
|
+
|
|
65
|
+
[key: string]: any;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface ApiVersionsConfig {
|
|
69
|
+
metadata: {
|
|
70
|
+
version: string;
|
|
71
|
+
};
|
|
72
|
+
meta: any;
|
|
73
|
+
google: any;
|
|
74
|
+
tiktok: any;
|
|
75
|
+
pinterest: any;
|
|
76
|
+
reddit: any;
|
|
77
|
+
linkedin: any;
|
|
78
|
+
bing: any;
|
|
79
|
+
youtube: any;
|
|
80
|
+
spotify: any;
|
|
81
|
+
}
|
package/docs/whatsapp-ctwa.md
CHANGED
|
@@ -199,11 +199,12 @@ fetch('https://SEU_WORKER.SEU_USUARIO.workers.dev/track', {
|
|
|
199
199
|
|
|
200
200
|
| Arquivo | Descrição |
|
|
201
201
|
|---------|-----------|
|
|
202
|
-
| `server-edge-tracker/
|
|
202
|
+
| `server-edge-tracker/modules/dispatch/whatsapp.ts` | Funções `processWhatsAppWebhook()`, `sendWhatsApp()`, `verifyHmac()` |
|
|
203
|
+
| `server-edge-tracker/index.ts` | Rotas `/webhook/whatsapp` (GET verify + POST mensagens) |
|
|
203
204
|
| `server-edge-tracker/migrate-v6.sql` | Migration que criou a tabela `whatsapp_contacts` |
|
|
204
205
|
| `server-edge-tracker/wrangler.toml` | Secret `WA_WEBHOOK_VERIFY_TOKEN` documentado |
|
|
205
206
|
| `server-edge-tracker/schema.sql` | Schema completo do D1 (referência) |
|
|
206
207
|
|
|
207
208
|
---
|
|
208
209
|
|
|
209
|
-
*Implementado em: 30 de março de 2026. CDP Edge v1.2 — WhatsApp CTWA Module.*
|
|
210
|
+
*Implementado em: 30 de março de 2026. CDP Edge v1.2 — WhatsApp CTWA Module. Migrado para TypeScript (`whatsapp.ts`) em 12 de abril de 2026 (v2.2.5+).*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cdp-edge",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
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",
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"agents:check": "node scripts/validate-agents.js",
|
|
35
35
|
"agents:sync": "node scripts/sync-agents.js",
|
|
36
36
|
"agents:sync:list": "node scripts/sync-agents.js --list",
|
|
37
|
-
"agents:sync:all": "node scripts/sync-agents.js --apply-all"
|
|
37
|
+
"agents:sync:all": "node scripts/sync-agents.js --apply-all",
|
|
38
|
+
"typecheck": "tsc --noEmit"
|
|
38
39
|
},
|
|
39
40
|
"keywords": [
|
|
40
41
|
"pixel",
|
|
@@ -71,12 +72,14 @@
|
|
|
71
72
|
"ora": "^8.0.0"
|
|
72
73
|
},
|
|
73
74
|
"devDependencies": {
|
|
75
|
+
"@cloudflare/workers-types": "^4.20260412.1",
|
|
74
76
|
"@semantic-release/changelog": "^6.0.3",
|
|
75
77
|
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
76
78
|
"@semantic-release/github": "^12.0.6",
|
|
77
79
|
"@semantic-release/npm": "^13.1.5",
|
|
78
80
|
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
79
|
-
"@types/node": "^20.
|
|
80
|
-
"semantic-release": "^25.0.3"
|
|
81
|
+
"@types/node": "^20.19.39",
|
|
82
|
+
"semantic-release": "^25.0.3",
|
|
83
|
+
"typescript": "^6.0.2"
|
|
81
84
|
}
|
|
82
85
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# CDP Edge — Variáveis do cliente para deploy
|
|
2
|
+
# Copie este arquivo para .client.env e preencha com os dados reais.
|
|
3
|
+
# .client.env é gitignored — NUNCA commitado.
|
|
4
|
+
|
|
5
|
+
# Cloudflare D1 — obter com: wrangler d1 list
|
|
6
|
+
DATABASE_ID=SEU_DATABASE_ID
|
|
7
|
+
|
|
8
|
+
# Domínio do projeto (sem https://)
|
|
9
|
+
SITE_DOMAIN=seudominio.com.br
|
|
10
|
+
|
|
11
|
+
# Pixels de rastreamento (opcional — deixar vazio se não usar)
|
|
12
|
+
META_PIXEL_ID=
|
|
13
|
+
GA4_MEASUREMENT_ID=
|
|
14
|
+
TIKTOK_PIXEL_ID=
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CDP Edge — deploy-client.js
|
|
4
|
+
*
|
|
5
|
+
* Deploy do Worker com variáveis reais do cliente, sem commitar credenciais no repo.
|
|
6
|
+
* Lê de .client.env (gitignored) e gera um wrangler.deploy.toml temporário.
|
|
7
|
+
*
|
|
8
|
+
* Uso:
|
|
9
|
+
* node deploy-client.js → deploy completo
|
|
10
|
+
* node deploy-client.js --dry-run → valida sem subir ao Cloudflare
|
|
11
|
+
*
|
|
12
|
+
* Setup:
|
|
13
|
+
* cp .client.env.example .client.env
|
|
14
|
+
* # edite .client.env com os valores do cliente
|
|
15
|
+
* node deploy-client.js
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
const { execSync } = require('child_process');
|
|
21
|
+
|
|
22
|
+
const ROOT = __dirname;
|
|
23
|
+
const TOML = path.join(ROOT, 'wrangler.toml');
|
|
24
|
+
const DEPLOY = path.join(ROOT, 'wrangler.deploy.toml');
|
|
25
|
+
const ENV = path.join(ROOT, '.client.env');
|
|
26
|
+
const DRY_RUN = process.argv.includes('--dry-run');
|
|
27
|
+
|
|
28
|
+
// ── Carregar .client.env ──────────────────────────────────────────────────────
|
|
29
|
+
if (!fs.existsSync(ENV)) {
|
|
30
|
+
console.error('\n❌ .client.env não encontrado.');
|
|
31
|
+
console.error(' cp .client.env.example .client.env e preencha os valores do cliente.\n');
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const env = {};
|
|
36
|
+
fs.readFileSync(ENV, 'utf8').split('\n').forEach(line => {
|
|
37
|
+
const trimmed = line.trim();
|
|
38
|
+
if (!trimmed || trimmed.startsWith('#')) return;
|
|
39
|
+
const [key, ...rest] = trimmed.split('=');
|
|
40
|
+
if (key) env[key.trim()] = rest.join('=').trim();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const required = ['DATABASE_ID', 'SITE_DOMAIN'];
|
|
44
|
+
const missing = required.filter(k => !env[k]);
|
|
45
|
+
if (missing.length > 0) {
|
|
46
|
+
console.error(`\n❌ Variáveis obrigatórias faltando no .client.env: ${missing.join(', ')}\n`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ── Substituir placeholders no wrangler.toml → wrangler.deploy.toml ───────────
|
|
51
|
+
let toml = fs.readFileSync(TOML, 'utf8');
|
|
52
|
+
|
|
53
|
+
toml = toml
|
|
54
|
+
.replace(/SEU_DATABASE_ID/g, env.DATABASE_ID)
|
|
55
|
+
.replace(/SEU_DOMINIO/g, env.SITE_DOMAIN)
|
|
56
|
+
.replace(/META_PIXEL_ID\s*=\s*""/, `META_PIXEL_ID = "${env.META_PIXEL_ID || ''}"`)
|
|
57
|
+
.replace(/GA4_MEASUREMENT_ID\s*=\s*""/, `GA4_MEASUREMENT_ID = "${env.GA4_MEASUREMENT_ID || ''}"`)
|
|
58
|
+
.replace(/TIKTOK_PIXEL_ID\s*=\s*""/, `TIKTOK_PIXEL_ID = "${env.TIKTOK_PIXEL_ID || ''}"`);
|
|
59
|
+
|
|
60
|
+
fs.writeFileSync(DEPLOY, toml);
|
|
61
|
+
|
|
62
|
+
// ── Executar wrangler deploy ──────────────────────────────────────────────────
|
|
63
|
+
const cmd = `wrangler deploy --config wrangler.deploy.toml${DRY_RUN ? ' --dry-run' : ''}`;
|
|
64
|
+
console.log(`\n🚀 ${DRY_RUN ? '[DRY-RUN] ' : ''}Deploying com config do cliente...\n`);
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
execSync(cmd, { stdio: 'inherit', cwd: ROOT });
|
|
68
|
+
console.log(`\n✅ Deploy ${DRY_RUN ? '(dry-run) ' : ''}concluído.\n`);
|
|
69
|
+
} catch (err) {
|
|
70
|
+
console.error('\n❌ Deploy falhou.\n');
|
|
71
|
+
process.exit(1);
|
|
72
|
+
} finally {
|
|
73
|
+
// sempre remove o arquivo temporário
|
|
74
|
+
if (fs.existsSync(DEPLOY)) fs.unlinkSync(DEPLOY);
|
|
75
|
+
console.log('🧹 wrangler.deploy.toml removido.\n');
|
|
76
|
+
}
|