cdp-edge 2.3.9 → 2.5.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 +33 -3
- package/bin/cdp-edge.js +3 -2
- package/dist/commands/validate.js +248 -84
- package/dist/sdk/cdpTrack.js +2095 -0
- package/dist/sdk/cdpTrack.min.js +64 -0
- package/dist/sdk/install-snippet.html +10 -0
- package/extracted-skill/tracking-events-generator/anti-blocking.js +1 -1
- package/extracted-skill/tracking-events-generator/cdpTrack.js +0 -10
- package/extracted-skill/tracking-events-generator/engagement-scoring.js +2 -2
- package/extracted-skill/tracking-events-generator/micro-events.js +1 -1
- package/extracted-skill/tracking-events-generator/tracking.config.js +3 -3
- package/package.json +5 -1
- package/scripts/build-sdk.js +106 -0
- package/server-edge-tracker/index.ts +93 -0
package/README.md
CHANGED
|
@@ -2,13 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
**Padrão Quantum Tracking: 100% Cloudflare Edge.** Sem GTM. Sem Stape. Sem cookies de terceiros.
|
|
4
4
|
|
|
5
|
-
> **v2.5.
|
|
6
|
-
> **v2.
|
|
5
|
+
> **v2.5.1** — SDK Bundle + Diagnóstico Pós-Deploy + Gap Fixes (15 de Abril de 2026) 🛠️
|
|
6
|
+
> **v2.3.9** — Quiz Scoring Engine + Sales Engine (14 de Abril de 2026) 🤖💰
|
|
7
7
|
> **v2.3.8** — Fix Definitivo: api-versions.json (14 de Abril de 2026) 🔒
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## 📋 CHANGELOG v2.5.
|
|
11
|
+
## 📋 CHANGELOG v2.5.1 — SDK Bundle + Diagnóstico Pós-Deploy + Gap Fixes (15 de Abril de 2026) 🛠️
|
|
12
|
+
|
|
13
|
+
### SDK Bundle — cdpTrack.min.js pronto para `<script src="">`
|
|
14
|
+
- `npm run sdk:build` → `dist/sdk/cdpTrack.min.js` (41.6 kB, IIFE, `window.cdpTrack`)
|
|
15
|
+
- Um único arquivo sem dependências externas — cola no site e funciona
|
|
16
|
+
- `dist/sdk/install-snippet.html` com snippet pronto para antes do `</body>`
|
|
17
|
+
|
|
18
|
+
### Diagnóstico Pós-Deploy — `cdp-edge validate <url>`
|
|
19
|
+
```bash
|
|
20
|
+
cdp-edge validate https://meusite.com.br
|
|
21
|
+
cdp-edge validate https://meusite.com.br --worker https://worker.meusite.workers.dev
|
|
22
|
+
```
|
|
23
|
+
Verifica automaticamente:
|
|
24
|
+
- Página carrega `cdpTrack.min.js` e Meta Pixel
|
|
25
|
+
- Worker `/health` (D1, KV, AI, secrets)
|
|
26
|
+
- Worker `/validate-install` (D1 write+read, KV, AI, secrets críticos)
|
|
27
|
+
- `POST /track` aceita evento sintético → 200
|
|
28
|
+
|
|
29
|
+
### Gap Fixes Críticos
|
|
30
|
+
- **Endpoint**: `/api/tracking` → `/track` em todos os módulos SDK
|
|
31
|
+
- **utm_term**: injetado pelo Worker após quiz scoring (nunca pelo cliente)
|
|
32
|
+
- **TikTok ttp**: cookie `_ttp` capturado e enviado ao Worker
|
|
33
|
+
- **ROAS por origem**: segmentado por `utm_content` (quiz_* vs video_* vs landing_* vs ctwa_*)
|
|
34
|
+
|
|
35
|
+
### Novos Agentes
|
|
36
|
+
- `lead-scoring-agent.md` — quiz de qualificação + análise dimensional Granite
|
|
37
|
+
- `match-quality-agent.md` — guardião EMQ com cron 2h e alerta CallMeBot
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 📋 CHANGELOG v2.3.9 — Quiz Scoring Engine + Sales Engine (14 de Abril de 2026) 🤖💰
|
|
12
42
|
|
|
13
43
|
### O que foi adicionado
|
|
14
44
|
|
package/bin/cdp-edge.js
CHANGED
|
@@ -51,8 +51,9 @@ program
|
|
|
51
51
|
.action(runServer);
|
|
52
52
|
|
|
53
53
|
program
|
|
54
|
-
.command('validate <
|
|
55
|
-
.description('
|
|
54
|
+
.command('validate <url>')
|
|
55
|
+
.description('Diagnóstico pós-deploy — verifica se o tracking está funcionando de ponta a ponta')
|
|
56
|
+
.option('--worker <url>', 'URL do Worker se diferente do site (ex: https://worker.meusite.workers.dev)')
|
|
56
57
|
.action(runValidate);
|
|
57
58
|
|
|
58
59
|
program
|
|
@@ -1,84 +1,248 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
async function
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
//
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
1
|
+
/**
|
|
2
|
+
* CDP Edge — validate <url>
|
|
3
|
+
*
|
|
4
|
+
* Diagnóstico pós-deploy. Verifica se o tracking está funcionando de ponta a ponta:
|
|
5
|
+
* 1. Página carrega cdpTrack.min.js e tem Meta Pixel
|
|
6
|
+
* 2. Worker /health responde (D1, KV, AI, secrets)
|
|
7
|
+
* 3. Worker /validate-install passa todos os checks internos
|
|
8
|
+
* 4. POST /track aceita evento sintético e retorna 200
|
|
9
|
+
*
|
|
10
|
+
* Uso:
|
|
11
|
+
* cdp-edge validate https://meusite.com.br
|
|
12
|
+
* cdp-edge validate https://meusite.com.br --worker https://worker.meusite.workers.dev
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import chalk from 'chalk';
|
|
16
|
+
import ora from 'ora';
|
|
17
|
+
|
|
18
|
+
// ── Helpers de output ─────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
function ok(label, detail = '') {
|
|
21
|
+
console.log(` ${chalk.green('✓')} ${chalk.bold(label)}${detail ? chalk.gray(' — ' + detail) : ''}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function fail(label, detail = '') {
|
|
25
|
+
console.log(` ${chalk.red('✗')} ${chalk.bold(label)}${detail ? chalk.red(' — ' + detail) : ''}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function warn(label, detail = '') {
|
|
29
|
+
console.log(` ${chalk.yellow('⚠')} ${chalk.bold(label)}${detail ? chalk.yellow(' — ' + detail) : ''}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function section(title) {
|
|
33
|
+
console.log('\n' + chalk.cyan.bold(`── ${title} ──────────────────────────────`));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ── Fetch com timeout ─────────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
async function fetchWithTimeout(url, options = {}, timeoutMs = 10000) {
|
|
39
|
+
const controller = new AbortController();
|
|
40
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
41
|
+
try {
|
|
42
|
+
return await fetch(url, { ...options, signal: controller.signal });
|
|
43
|
+
} finally {
|
|
44
|
+
clearTimeout(timer);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ── Check 1: Página HTML ──────────────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
async function checkPage(siteUrl) {
|
|
51
|
+
section('Página HTML');
|
|
52
|
+
const results = { ok: true };
|
|
53
|
+
|
|
54
|
+
let html = '';
|
|
55
|
+
try {
|
|
56
|
+
const res = await fetchWithTimeout(siteUrl, {
|
|
57
|
+
headers: { 'User-Agent': 'CDP-Edge-Validator/1.0' },
|
|
58
|
+
});
|
|
59
|
+
if (!res.ok) {
|
|
60
|
+
fail('Página acessível', `HTTP ${res.status}`);
|
|
61
|
+
results.ok = false;
|
|
62
|
+
return results;
|
|
63
|
+
}
|
|
64
|
+
ok('Página acessível', `HTTP ${res.status}`);
|
|
65
|
+
html = await res.text();
|
|
66
|
+
} catch (err) {
|
|
67
|
+
fail('Página acessível', err.message);
|
|
68
|
+
results.ok = false;
|
|
69
|
+
return results;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// cdpTrack.min.js
|
|
73
|
+
if (html.includes('cdpTrack.min.js') || html.includes('cdpTrack.js')) {
|
|
74
|
+
ok('cdpTrack.min.js referenciado na página');
|
|
75
|
+
} else {
|
|
76
|
+
fail('cdpTrack.min.js NÃO encontrado na página', 'adicionar <script src="/cdpTrack.min.js">');
|
|
77
|
+
results.ok = false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Meta Pixel (fbq)
|
|
81
|
+
if (html.includes('fbq(') || html.includes("fbq('init'") || html.includes('connect.facebook.net')) {
|
|
82
|
+
ok('Meta Pixel (fbq) detectado');
|
|
83
|
+
} else {
|
|
84
|
+
warn('Meta Pixel não detectado no HTML', 'pode estar em script externo — verificar manualmente');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Google tag
|
|
88
|
+
if (html.includes('gtag(') || html.includes('googletagmanager.com') || html.includes('G-')) {
|
|
89
|
+
ok('Google Tag detectado');
|
|
90
|
+
} else {
|
|
91
|
+
warn('Google Tag não detectado no HTML', 'opcional — verificar se GA4 está habilitado');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return results;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ── Check 2: Worker /health ───────────────────────────────────────────────────
|
|
98
|
+
|
|
99
|
+
async function checkWorkerHealth(workerUrl) {
|
|
100
|
+
section('Worker /health');
|
|
101
|
+
const results = { ok: true };
|
|
102
|
+
|
|
103
|
+
let data;
|
|
104
|
+
try {
|
|
105
|
+
const res = await fetchWithTimeout(`${workerUrl}/health`);
|
|
106
|
+
data = await res.json();
|
|
107
|
+
} catch (err) {
|
|
108
|
+
fail('Worker acessível', err.message);
|
|
109
|
+
results.ok = false;
|
|
110
|
+
return results;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
ok('Worker acessível', `status: ${data.status}`);
|
|
114
|
+
|
|
115
|
+
// Bindings
|
|
116
|
+
for (const [key, val] of Object.entries(data.bindings || {})) {
|
|
117
|
+
if (val === 'ok') ok(`Binding ${key}`);
|
|
118
|
+
else { fail(`Binding ${key}`, val); results.ok = false; }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Vars
|
|
122
|
+
for (const [key, val] of Object.entries(data.vars || {})) {
|
|
123
|
+
if (val === 'set') ok(`Var ${key}`);
|
|
124
|
+
else { fail(`Var ${key}`, 'MISSING — configurar no wrangler.toml'); results.ok = false; }
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Secrets críticos
|
|
128
|
+
const criticalSecrets = ['META_ACCESS_TOKEN', 'GA4_API_SECRET'];
|
|
129
|
+
for (const [key, val] of Object.entries(data.secrets || {})) {
|
|
130
|
+
if (criticalSecrets.includes(key)) {
|
|
131
|
+
if (val === 'set') ok(`Secret ${key}`);
|
|
132
|
+
else { fail(`Secret ${key}`, 'MISSING — wrangler secret put ' + key); results.ok = false; }
|
|
133
|
+
} else {
|
|
134
|
+
if (val === 'set') ok(`Secret ${key}`);
|
|
135
|
+
else warn(`Secret ${key}`, val);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return results;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ── Check 3: /validate-install ────────────────────────────────────────────────
|
|
143
|
+
|
|
144
|
+
async function checkValidateInstall(workerUrl) {
|
|
145
|
+
section('Worker /validate-install (checks internos)');
|
|
146
|
+
const results = { ok: true };
|
|
147
|
+
|
|
148
|
+
let data;
|
|
149
|
+
try {
|
|
150
|
+
const res = await fetchWithTimeout(`${workerUrl}/validate-install`, {
|
|
151
|
+
headers: { 'CDP-Validate': '1' },
|
|
152
|
+
});
|
|
153
|
+
data = await res.json();
|
|
154
|
+
} catch (err) {
|
|
155
|
+
fail('validate-install acessível', err.message);
|
|
156
|
+
results.ok = false;
|
|
157
|
+
return results;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
for (const [key, check] of Object.entries(data.checks || {})) {
|
|
161
|
+
if (check.ok) ok(key, check.detail);
|
|
162
|
+
else { fail(key, check.detail); results.ok = false; }
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return results;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ── Check 4: POST /track com evento sintético ─────────────────────────────────
|
|
169
|
+
|
|
170
|
+
async function checkTrackEndpoint(workerUrl) {
|
|
171
|
+
section('POST /track (evento sintético)');
|
|
172
|
+
const results = { ok: true };
|
|
173
|
+
|
|
174
|
+
const testEvent = {
|
|
175
|
+
eventName: 'PageView',
|
|
176
|
+
userId: `__cdp_validate_${Date.now()}__`,
|
|
177
|
+
pageUrl: workerUrl + '/',
|
|
178
|
+
userAgent: 'CDP-Edge-Validator/1.0',
|
|
179
|
+
utmSource: 'cdp_validate',
|
|
180
|
+
utmMedium: 'cli',
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
let res, data;
|
|
184
|
+
try {
|
|
185
|
+
res = await fetchWithTimeout(`${workerUrl}/track`, {
|
|
186
|
+
method: 'POST',
|
|
187
|
+
headers: { 'Content-Type': 'application/json' },
|
|
188
|
+
body: JSON.stringify(testEvent),
|
|
189
|
+
});
|
|
190
|
+
data = await res.json().catch(() => ({}));
|
|
191
|
+
} catch (err) {
|
|
192
|
+
fail('POST /track', err.message);
|
|
193
|
+
results.ok = false;
|
|
194
|
+
return results;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (res.ok) {
|
|
198
|
+
ok('POST /track', `HTTP ${res.status} — evento aceito`);
|
|
199
|
+
if (data.event_id) ok('event_id retornado', data.event_id);
|
|
200
|
+
if (data.ltv) ok('LTV Prediction', `${data.ltv?.class || ''} (score: ${data.ltv?.score ?? '?'})`);
|
|
201
|
+
if (data.fraud_score !== undefined) {
|
|
202
|
+
data.fraud_score < 50
|
|
203
|
+
? ok('Fraud Gate', `score ${data.fraud_score} — passou`)
|
|
204
|
+
: warn('Fraud Gate', `score ${data.fraud_score} — CLI pode ter sido flagrado como bot`);
|
|
205
|
+
}
|
|
206
|
+
} else {
|
|
207
|
+
fail('POST /track', `HTTP ${res.status} — ${data?.error || 'erro desconhecido'}`);
|
|
208
|
+
results.ok = false;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return results;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// ── Entry point ───────────────────────────────────────────────────────────────
|
|
215
|
+
|
|
216
|
+
export async function runValidate(urlArg, options = {}) {
|
|
217
|
+
// Normaliza URLs
|
|
218
|
+
const siteUrl = urlArg?.startsWith('http') ? urlArg.replace(/\/$/, '') : `https://${urlArg}`;
|
|
219
|
+
const workerUrl = options.worker
|
|
220
|
+
? options.worker.replace(/\/$/, '')
|
|
221
|
+
: siteUrl; // assume Worker no mesmo domínio (Custom Domain)
|
|
222
|
+
|
|
223
|
+
console.log(chalk.cyan.bold('\n CDP Edge — Diagnóstico Pós-Deploy\n'));
|
|
224
|
+
console.log(` Site: ${chalk.white(siteUrl)}`);
|
|
225
|
+
console.log(` Worker: ${chalk.white(workerUrl)}`);
|
|
226
|
+
|
|
227
|
+
const spinner = ora('Iniciando diagnóstico...').start();
|
|
228
|
+
spinner.stop();
|
|
229
|
+
|
|
230
|
+
let allOk = true;
|
|
231
|
+
const pageResult = await checkPage(siteUrl);
|
|
232
|
+
const healthResult = await checkWorkerHealth(workerUrl);
|
|
233
|
+
const validateResult = await checkValidateInstall(workerUrl);
|
|
234
|
+
const trackResult = await checkTrackEndpoint(workerUrl);
|
|
235
|
+
|
|
236
|
+
allOk = pageResult.ok && healthResult.ok && validateResult.ok && trackResult.ok;
|
|
237
|
+
|
|
238
|
+
// ── Resultado final ───────────────────────────────────────────────────────
|
|
239
|
+
console.log('\n' + chalk.cyan.bold('── Resultado ─────────────────────────────'));
|
|
240
|
+
if (allOk) {
|
|
241
|
+
console.log(`\n ${chalk.green.bold('✅ TUDO OK — tracking funcionando de ponta a ponta.')}`);
|
|
242
|
+
console.log(chalk.gray(' Eventos chegando ao Worker, D1 operacional, secrets configurados.\n'));
|
|
243
|
+
} else {
|
|
244
|
+
console.log(`\n ${chalk.red.bold('❌ FALHAS DETECTADAS — resolver antes de ir ao ar.')}`);
|
|
245
|
+
console.log(chalk.gray(' Corrija os itens marcados com ✗ acima e rode novamente.\n'));
|
|
246
|
+
process.exitCode = 1;
|
|
247
|
+
}
|
|
248
|
+
}
|