cdp-edge 1.0.2 → 1.0.4
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.
|
@@ -140,7 +140,8 @@ const _wbraid = _urlParams.get('wbraid') || ''; // Google Ads (iOS, web-to-app,
|
|
|
140
140
|
const _gbraid = _urlParams.get('gbraid') || ''; // Google Ads (app campaigns, privacy preserving)
|
|
141
141
|
|
|
142
142
|
// TikTok
|
|
143
|
-
const _ttclid
|
|
143
|
+
const _ttclid = _urlParams.get('ttclid') || ''; // TikTok Ads click ID → complementa cookie _ttp
|
|
144
|
+
const _msclkid = _urlParams.get('msclkid') || ''; // Microsoft Ads click ID
|
|
144
145
|
|
|
145
146
|
// UTMs — rastreamento interno de origem de tráfego (independente da atribuição das plataformas)
|
|
146
147
|
const _utms = {
|
|
@@ -217,7 +218,8 @@ const _getClickIDs = () => {
|
|
|
217
218
|
wbraid: _wbraid || undefined,
|
|
218
219
|
ttclid: _ttclid || undefined,
|
|
219
220
|
ttp: document.cookie.match(/_ttp=([^;]+)/)?.[1] || undefined, // TikTok Pixel cookie — EMQ TikTok
|
|
220
|
-
rclid:
|
|
221
|
+
rclid: _urlParams.get('rclid') || undefined,
|
|
222
|
+
msclkid: _msclkid || undefined,
|
|
221
223
|
};
|
|
222
224
|
};
|
|
223
225
|
|
package/package.json
CHANGED
|
@@ -389,7 +389,8 @@ export default {
|
|
|
389
389
|
if (!trackPayload.wbraid && c.wbraid) trackPayload.wbraid = c.wbraid;
|
|
390
390
|
if (!trackPayload.gbraid && c.gbraid) trackPayload.gbraid = c.gbraid;
|
|
391
391
|
if (!trackPayload.ttclid && c.ttclid) trackPayload.ttclid = c.ttclid;
|
|
392
|
-
if (!trackPayload.ttp
|
|
392
|
+
if (!trackPayload.ttp && c.ttp) trackPayload.ttp = c.ttp;
|
|
393
|
+
if (!trackPayload.msclkid && c.msclkid) trackPayload.msclkid = c.msclkid;
|
|
393
394
|
}
|
|
394
395
|
if (payload.utms && typeof payload.utms === 'object') {
|
|
395
396
|
const u = payload.utms as Record<string, string>;
|
|
@@ -761,6 +762,21 @@ export default {
|
|
|
761
762
|
ctx.waitUntil(resolveDeviceGraph(env.DB, payload.userId, payload.email, payload.phone));
|
|
762
763
|
}
|
|
763
764
|
|
|
765
|
+
// Deduplicação server-side — INSERT OR IGNORE retorna changes=0 para duplicatas
|
|
766
|
+
if (env.DB && payload.eventId) {
|
|
767
|
+
try {
|
|
768
|
+
const dedup = await env.DB.prepare(
|
|
769
|
+
`INSERT OR IGNORE INTO events (event_id, event_name, user_id, created_at)
|
|
770
|
+
VALUES (?, ?, ?, datetime('now'))`
|
|
771
|
+
).bind(payload.eventId, eventName, payload.userId || null).run();
|
|
772
|
+
if (dedup.meta.changes === 0) {
|
|
773
|
+
return new Response(JSON.stringify({ ok: true, skipped: 'duplicate' }), { status: 200, headers });
|
|
774
|
+
}
|
|
775
|
+
} catch {
|
|
776
|
+
// Tabela ausente ou erro de DB — não bloqueia o pipeline
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
764
780
|
// R2 Audit Log — background
|
|
765
781
|
ctx.waitUntil(writeAuditLog(env, eventName, payload, geoData));
|
|
766
782
|
|
|
@@ -115,6 +115,7 @@ export async function upsertProfile(env: Env, eventName: string, payload: TrackP
|
|
|
115
115
|
const {
|
|
116
116
|
userId, email, phone,
|
|
117
117
|
fbp, fbc, ttp, gclid, ttclid, gaClientId,
|
|
118
|
+
wbraid, gbraid, msclkid,
|
|
118
119
|
city, state, country,
|
|
119
120
|
engagementScore, userScore,
|
|
120
121
|
} = payload;
|
|
@@ -131,8 +132,9 @@ export async function upsertProfile(env: Env, eventName: string, payload: TrackP
|
|
|
131
132
|
await env.DB.prepare(`
|
|
132
133
|
INSERT INTO user_profiles
|
|
133
134
|
(user_id, email, phone, fbp, fbc, ttp, gclid, ttclid, ga_client_id,
|
|
135
|
+
wbraid, gbraid, msclkid,
|
|
134
136
|
city, state, country, score, cohort_label, created_at, updated_at)
|
|
135
|
-
VALUES (
|
|
137
|
+
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,datetime('now'),datetime('now'))
|
|
136
138
|
ON CONFLICT(user_id) DO UPDATE SET
|
|
137
139
|
email = COALESCE(excluded.email, user_profiles.email),
|
|
138
140
|
phone = COALESCE(excluded.phone, user_profiles.phone),
|
|
@@ -142,6 +144,9 @@ export async function upsertProfile(env: Env, eventName: string, payload: TrackP
|
|
|
142
144
|
gclid = COALESCE(excluded.gclid, user_profiles.gclid),
|
|
143
145
|
ttclid = COALESCE(excluded.ttclid, user_profiles.ttclid),
|
|
144
146
|
ga_client_id = COALESCE(excluded.ga_client_id, user_profiles.ga_client_id),
|
|
147
|
+
wbraid = COALESCE(excluded.wbraid, user_profiles.wbraid),
|
|
148
|
+
gbraid = COALESCE(excluded.gbraid, user_profiles.gbraid),
|
|
149
|
+
msclkid = COALESCE(excluded.msclkid, user_profiles.msclkid),
|
|
145
150
|
city = COALESCE(excluded.city, user_profiles.city),
|
|
146
151
|
state = COALESCE(excluded.state, user_profiles.state),
|
|
147
152
|
country = COALESCE(excluded.country, user_profiles.country),
|
|
@@ -158,6 +163,9 @@ export async function upsertProfile(env: Env, eventName: string, payload: TrackP
|
|
|
158
163
|
gclid || null,
|
|
159
164
|
ttclid || null,
|
|
160
165
|
gaClientId || null,
|
|
166
|
+
wbraid || null,
|
|
167
|
+
gbraid || null,
|
|
168
|
+
msclkid || null,
|
|
161
169
|
city || null,
|
|
162
170
|
state || null,
|
|
163
171
|
(country || (request as any).cf?.country || null),
|
|
@@ -79,6 +79,22 @@ CREATE INDEX IF NOT EXISTS idx_profiles_fbp ON user_profiles(fbp);
|
|
|
79
79
|
CREATE INDEX IF NOT EXISTS idx_profiles_msclkid ON user_profiles(msclkid);
|
|
80
80
|
CREATE INDEX IF NOT EXISTS idx_profiles_li_fat ON user_profiles(li_fat_id);
|
|
81
81
|
|
|
82
|
+
-- ── Tabela de Eventos (Deduplicação + Label ML) ──────────────────────────────
|
|
83
|
+
-- Registra cada evento processado com sucesso.
|
|
84
|
+
-- Duplo uso: (1) deduplicação server-side via event_id UNIQUE;
|
|
85
|
+
-- (2) label de LTV para treinamento ML (lead comprou depois?)
|
|
86
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
87
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
88
|
+
event_id TEXT UNIQUE, -- deduplicação: INSERT OR IGNORE descarta duplicatas
|
|
89
|
+
event_name TEXT NOT NULL,
|
|
90
|
+
user_id TEXT,
|
|
91
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
CREATE INDEX IF NOT EXISTS idx_events_user_id ON events(user_id);
|
|
95
|
+
CREATE INDEX IF NOT EXISTS idx_events_event_name ON events(event_name);
|
|
96
|
+
CREATE INDEX IF NOT EXISTS idx_events_created ON events(created_at);
|
|
97
|
+
|
|
82
98
|
-- ── Tabela de LOG de Webhooks Offline ─────────────────────────────────────────
|
|
83
99
|
CREATE TABLE IF NOT EXISTS webhook_events (
|
|
84
100
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|