lytx 0.3.11 → 0.3.12
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 +0 -2
- package/index.d.ts +1 -2
- package/index.ts +1 -2
- package/package.json +1 -3
- package/src/api/tag_api.ts +15 -453
- package/src/api/tag_api_v2.ts +48 -2
- package/src/templates/script.ts +2 -2
- package/src/worker.tsx +1 -4
package/README.md
CHANGED
|
@@ -130,7 +130,6 @@ import {
|
|
|
130
130
|
userApiRoutes,
|
|
131
131
|
eventLabelsApi,
|
|
132
132
|
reportsApi,
|
|
133
|
-
legacyContainerRoute,
|
|
134
133
|
newSiteSetup,
|
|
135
134
|
lytxTag,
|
|
136
135
|
trackWebEvent,
|
|
@@ -168,7 +167,6 @@ const app = defineApp<AppRequestInfo>([
|
|
|
168
167
|
},
|
|
169
168
|
|
|
170
169
|
// ── Tag & event ingestion (unauthenticated) ──
|
|
171
|
-
legacyContainerRoute,
|
|
172
170
|
lytxTag(dbAdapter),
|
|
173
171
|
trackWebEvent(dbAdapter, "/trackWebEvent", { useQueue: true }),
|
|
174
172
|
eventsApi,
|
package/index.d.ts
CHANGED
|
@@ -32,8 +32,7 @@ export { aiChatRoute, aiConfigRoute, aiTagSuggestRoute } from "./src/api/ai_api"
|
|
|
32
32
|
export { resendVerificationEmailRoute, userApiRoutes } from "./src/api/auth_api";
|
|
33
33
|
export { eventLabelsApi } from "./src/api/event_labels_api";
|
|
34
34
|
export { reportsApi } from "./src/api/reports_api";
|
|
35
|
-
export {
|
|
36
|
-
export { lytxTag, trackWebEvent } from "./src/api/tag_api_v2";
|
|
35
|
+
export { lytxTag, newSiteSetup, trackWebEvent } from "./src/api/tag_api_v2";
|
|
37
36
|
export { handleQueueMessage } from "./src/api/queueWorker";
|
|
38
37
|
|
|
39
38
|
export { authMiddleware, sessionMiddleware } from "./src/api/authMiddleware";
|
package/index.ts
CHANGED
|
@@ -48,8 +48,7 @@ export { aiChatRoute, aiConfigRoute, aiTagSuggestRoute } from "./src/api/ai_api"
|
|
|
48
48
|
export { resendVerificationEmailRoute, userApiRoutes } from "./src/api/auth_api";
|
|
49
49
|
export { eventLabelsApi } from "./src/api/event_labels_api";
|
|
50
50
|
export { reportsApi } from "./src/api/reports_api";
|
|
51
|
-
export {
|
|
52
|
-
export { lytxTag, trackWebEvent } from "./src/api/tag_api_v2";
|
|
51
|
+
export { lytxTag, newSiteSetup, trackWebEvent } from "./src/api/tag_api_v2";
|
|
53
52
|
export { handleQueueMessage } from "./src/api/queueWorker";
|
|
54
53
|
|
|
55
54
|
// ── Middleware ───────────────────────────────────────────────────────────────
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lytx",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.12",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -87,7 +87,6 @@
|
|
|
87
87
|
"@tailwindcss/vite": "^4.1.8",
|
|
88
88
|
"@types/better-sqlite3": "^7.6.13",
|
|
89
89
|
"@types/bun": "^1.2.21",
|
|
90
|
-
"@types/mustache": "^4.2.2",
|
|
91
90
|
"@types/node": "^24.0.0",
|
|
92
91
|
"@types/react": "^19.1.7",
|
|
93
92
|
"@types/react-dom": "^19.1.6",
|
|
@@ -123,7 +122,6 @@
|
|
|
123
122
|
"esbuild": "^0.27.2",
|
|
124
123
|
"hono": "^4.11.7",
|
|
125
124
|
"modern-monaco": "^0.3.7",
|
|
126
|
-
"mustache": "^4.2.0",
|
|
127
125
|
"postgres": "^3.4.3",
|
|
128
126
|
"prism-react-renderer": "^2.4.1",
|
|
129
127
|
"react": "^19.3.0-canary-4fdf7cf2-20251003",
|
package/src/api/tag_api.ts
CHANGED
|
@@ -1,458 +1,20 @@
|
|
|
1
|
-
import { route } from "rwsdk/router";
|
|
2
|
-
import type { RequestInfo } from "rwsdk/worker";
|
|
3
|
-
import { env } from "cloudflare:workers";
|
|
4
|
-
import { IS_DEV } from "rwsdk/constants";
|
|
5
|
-
import { parseBrowser, parseOs, parseDeviceType, parseUserAgent } from "@/utilities/detector";
|
|
6
|
-
import type { AppContext } from "@/types/app-context";
|
|
7
|
-
import { type PageEvent, } from "@/templates/lytxpixel";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import { script_tag_manager, script_core } from "virtual:lytx-pixel-raw";
|
|
11
|
-
|
|
12
|
-
import { getSiteForTag, insertSiteEvent } from "@db/postgres/sites";
|
|
13
1
|
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
import Mustache from "mustache";
|
|
21
|
-
import { hashIpAddress } from "@/utilities";
|
|
22
|
-
import { createSite } from "@db/d1/sites";
|
|
23
|
-
import type { DBAdapter } from "@db/types";
|
|
24
|
-
|
|
25
|
-
// import { getClient } from "@db/client";
|
|
26
|
-
|
|
27
|
-
export const dataVariableName = "lytxDataLayer" as const;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
//WARNING: This only needs to be used on tag routes for third party sites
|
|
31
|
-
export function corsMiddleware({ request, response }: RequestInfo) {
|
|
32
|
-
const headers = response.headers;
|
|
33
|
-
// Allow all origins for embedding on third-party sites
|
|
34
|
-
headers.set("Access-Control-Allow-Origin", "*");
|
|
35
|
-
|
|
36
|
-
// Match your previous methods
|
|
37
|
-
headers.set("Access-Control-Allow-Methods", "POST, OPTIONS, GET");
|
|
38
|
-
|
|
39
|
-
// Include all headers from your previous setup
|
|
40
|
-
headers.set("Access-Control-Allow-Headers", "X-Custom-Header, Upgrade-Insecure-Requests, Content-Type");
|
|
41
|
-
|
|
42
|
-
// Match your previous exposed headers
|
|
43
|
-
headers.set("Access-Control-Expose-Headers", "Content-Length, X-Kuma-Revision");
|
|
44
|
-
|
|
45
|
-
// Match your previous max age
|
|
46
|
-
headers.set("Access-Control-Max-Age", "600");
|
|
47
|
-
|
|
48
|
-
// Match your previous credentials setting (false)
|
|
49
|
-
headers.set("Access-Control-Allow-Credentials", "false");
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
//TODO: Add CORS Middleware
|
|
54
|
-
// origin: "*",
|
|
55
|
-
// allowHeaders: ["X-Custom-Header", "Upgrade-Insecure-Requests"],
|
|
56
|
-
// allowMethods: ["POST", "OPTIONS", "GET"],
|
|
57
|
-
// exposeHeaders: ["Content-Length", "X-Kuma-Revision"],
|
|
58
|
-
// maxAge: 600,
|
|
59
|
-
// credentials: false,
|
|
2
|
+
corsMiddleware,
|
|
3
|
+
dataVariableName,
|
|
4
|
+
lytxTag,
|
|
5
|
+
newSiteSetup,
|
|
6
|
+
trackWebEvent,
|
|
7
|
+
} from "@/api/tag_api_v2";
|
|
60
8
|
|
|
61
9
|
/**
|
|
62
|
-
* @deprecated
|
|
63
|
-
* GET /container.js
|
|
64
|
-
*
|
|
65
|
-
* This is the legacy container.js endpoint
|
|
66
|
-
*/
|
|
67
|
-
export const legacyContainerRoute = route("/container.js", async ({ request }) => {
|
|
68
|
-
if (request.method != "GET") return new Response("Not Found.", { status: 404 });
|
|
69
|
-
return new Response(`console.log('This Script has been deprecated please migrate to lytx.js')`, {
|
|
70
|
-
headers: {
|
|
71
|
-
"Content-Type": "text/javascript",
|
|
72
|
-
},
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
*
|
|
79
|
-
* GET /lytx.js
|
|
10
|
+
* @deprecated Use `@/api/tag_api_v2` instead.
|
|
80
11
|
*
|
|
81
|
-
* This
|
|
12
|
+
* This module remains as a compatibility shim for existing imports.
|
|
82
13
|
*/
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const account = url.searchParams.get("account");
|
|
92
|
-
const platform = url.searchParams.get("platform") ?? "web";
|
|
93
|
-
|
|
94
|
-
const queryParams = url.searchParams;
|
|
95
|
-
//do this part from the parser
|
|
96
|
-
const queryParamsObj = Object.entries(queryParams).filter(
|
|
97
|
-
([key]) => key !== "account" && key !== "platform"
|
|
98
|
-
);
|
|
99
|
-
//do this part from the parser
|
|
100
|
-
const queryParamsStr = queryParamsObj
|
|
101
|
-
.map(([key, value]) => {
|
|
102
|
-
return `&${key}=${value.join("&")}`;
|
|
103
|
-
})
|
|
104
|
-
.join("");
|
|
105
|
-
|
|
106
|
-
let events: null | PageEvent[] = null;
|
|
107
|
-
const config = {
|
|
108
|
-
site: "",
|
|
109
|
-
tag: "",
|
|
110
|
-
track_web_events: false,
|
|
111
|
-
tag_manager: false,
|
|
112
|
-
gdpr: false,
|
|
113
|
-
autocapture: false,
|
|
114
|
-
event_load_strategy: "sdk" as "sdk" | "kv",
|
|
115
|
-
};
|
|
116
|
-
if (account) {
|
|
117
|
-
//TODO: Make function that reads from adapter
|
|
118
|
-
const checkAccouuntByTagId = await getSiteForTag(account);
|
|
119
|
-
|
|
120
|
-
let accountKey = null;
|
|
121
|
-
if (checkAccouuntByTagId) {
|
|
122
|
-
//console.log(checkAccouuntByTagId);
|
|
123
|
-
if (checkAccouuntByTagId.tag_id_override) {
|
|
124
|
-
//use override
|
|
125
|
-
accountKey = checkAccouuntByTagId.tag_id_override;
|
|
126
|
-
} else {
|
|
127
|
-
//use tag id
|
|
128
|
-
accountKey = checkAccouuntByTagId.tag_id;
|
|
129
|
-
}
|
|
130
|
-
config.site = checkAccouuntByTagId.domain ?? "";
|
|
131
|
-
config.tag = checkAccouuntByTagId.tag_id ?? "";
|
|
132
|
-
config.track_web_events = checkAccouuntByTagId.track_web_events;
|
|
133
|
-
// tag_manager may not exist in postgres schema (legacy), default to false
|
|
134
|
-
config.tag_manager = (checkAccouuntByTagId as any).tag_manager ?? false;
|
|
135
|
-
config.gdpr = checkAccouuntByTagId.gdpr ?? false;
|
|
136
|
-
// autocapture may not exist in postgres schema yet, default to false
|
|
137
|
-
config.autocapture = (checkAccouuntByTagId as any).autocapture ?? false;
|
|
138
|
-
config.event_load_strategy = (checkAccouuntByTagId.event_load_strategy ?? "sdk") as "sdk" | "kv";
|
|
139
|
-
} else {
|
|
140
|
-
//throw an error
|
|
141
|
-
if (IS_DEV) console.log('🔥🔥🔥 No account found for ', account);
|
|
142
|
-
}
|
|
143
|
-
if (accountKey && config.event_load_strategy !== "sdk") {
|
|
144
|
-
const checkKey = (await env.LYTX_EVENTS.get(accountKey, {
|
|
145
|
-
type: "json",
|
|
146
|
-
})) as unknown as PageEvent[];
|
|
147
|
-
//console.log(checkKey);
|
|
148
|
-
if (checkKey) events = checkKey;
|
|
149
|
-
else events = [];
|
|
150
|
-
} else {
|
|
151
|
-
//throw error
|
|
152
|
-
events = [];
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
if (events) {
|
|
157
|
-
const shouldLoadEvents = config.event_load_strategy !== "sdk";
|
|
158
|
-
const view = {
|
|
159
|
-
data: shouldLoadEvents ? events : [],
|
|
160
|
-
site: config.site,
|
|
161
|
-
tag: config.tag,
|
|
162
|
-
track_web_events: config.track_web_events,
|
|
163
|
-
macros: queryParamsStr,
|
|
164
|
-
platform: platform
|
|
165
|
-
};
|
|
166
|
-
return new Response(
|
|
167
|
-
Mustache.render(
|
|
168
|
-
//IIFE so varaibles & functions are not declared on the window object.
|
|
169
|
-
`//! Copyright ${new Date().getFullYear()} Lytx.io All rights reserved.
|
|
170
|
-
(function () {
|
|
171
|
-
${
|
|
172
|
-
//Below excludes third-party vendor scripts when tag_manager is disabled
|
|
173
|
-
config.tag_manager
|
|
174
|
-
? //Third-party vendor scripts enabled (tag_manager = true)
|
|
175
|
-
`
|
|
176
|
-
const ${dataVariableName} = [
|
|
177
|
-
{{#data}}
|
|
178
|
-
{
|
|
179
|
-
event_name: "{{{event_name}}}",
|
|
180
|
-
QuantcastPixelId:"{{QuantcastPixelId}}",
|
|
181
|
-
QuantCastPixelLabel:"{{QuantCastPixelLabel}}",
|
|
182
|
-
SimplfiPixelid:"{{SimplfiPixelid}}",
|
|
183
|
-
googleanalytics:"{{googleanalytics}}",
|
|
184
|
-
googleadsscript:"{{googleadsscript}}",
|
|
185
|
-
googleadsconversion:'{{{googleadsconversion}}}',
|
|
186
|
-
metaEvent:"{{metaEvent}}",
|
|
187
|
-
linkedinEvent:"{{linkedinEvent}}",
|
|
188
|
-
clickCease:"{{clickCease}}",
|
|
189
|
-
condition: "{{condition}}",
|
|
190
|
-
data_passback: "{{data_passback}}",
|
|
191
|
-
parameters: '{{{parameters}}}',
|
|
192
|
-
paramConfig:"{{paramConfig}}",
|
|
193
|
-
query_parameters:"{{query_parameters}}",
|
|
194
|
-
customScript:"{{customScript}}",
|
|
195
|
-
rules: "{{rules}}",
|
|
196
|
-
Notes:"{{Notes}}",
|
|
197
|
-
},
|
|
198
|
-
{{/data}}
|
|
199
|
-
];`
|
|
200
|
-
: //Third-party vendor scripts disabled (tag_manager = false)
|
|
201
|
-
`
|
|
202
|
-
const ${dataVariableName} = [
|
|
203
|
-
{{#data}}
|
|
204
|
-
{
|
|
205
|
-
event_name: "{{{event_name}}}",
|
|
206
|
-
condition: "{{condition}}",
|
|
207
|
-
data_passback: "{{data_passback}}",
|
|
208
|
-
parameters: '{{{parameters}}}',
|
|
209
|
-
paramConfig:"{{paramConfig}}",
|
|
210
|
-
query_parameters:"{{query_parameters}}",
|
|
211
|
-
rules: "{{rules}}",
|
|
212
|
-
Notes:"{{Notes}}",
|
|
213
|
-
},
|
|
214
|
-
{{/data}}
|
|
215
|
-
];
|
|
216
|
-
`}
|
|
217
|
-
if(window.${dataVariableName}){
|
|
218
|
-
window.${dataVariableName}.push(
|
|
219
|
-
{site:"{{site}}",tag:"{{tag}}",events:${dataVariableName},tracked:[]}
|
|
220
|
-
)
|
|
221
|
-
}else{
|
|
222
|
-
window.${dataVariableName} = [
|
|
223
|
-
{site:"{{site}}",tag:"{{tag}}",events:${dataVariableName},tracked:[]}
|
|
224
|
-
]
|
|
225
|
-
}
|
|
226
|
-
${config.tag_manager ? script_tag_manager : script_core}
|
|
227
|
-
|
|
228
|
-
parseData(${dataVariableName},{site:"{{site}}",tag:"{{tag}}"},${config.track_web_events},'{{platform}}');
|
|
229
|
-
|
|
230
|
-
${config.track_web_events ? `trackEvents("{{tag}}",'{{platform}}',null,'{{{macros}}}');` : ``}
|
|
231
|
-
})();
|
|
232
|
-
`,
|
|
233
|
-
view
|
|
234
|
-
),
|
|
235
|
-
{
|
|
236
|
-
headers: {
|
|
237
|
-
"Content-Type": "text/javascript",
|
|
238
|
-
},
|
|
239
|
-
});
|
|
240
|
-
} else {
|
|
241
|
-
return new Response("Not Found.", { status: 404 });
|
|
242
|
-
}
|
|
243
|
-
}]);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
*
|
|
248
|
-
* GET /trackWebEvent
|
|
249
|
-
*
|
|
250
|
-
* This is the track web event endpoint
|
|
251
|
-
*/
|
|
252
|
-
export const trackWebEvent = (adapter: DBAdapter) => route("/trackWebEvent", [corsMiddleware, async ({ request, cf }) => {
|
|
253
|
-
if (request.method != "POST") return new Response("Not Found.", { status: 404 });
|
|
254
|
-
const url = new URL(request.url);
|
|
255
|
-
const headers = request.headers;
|
|
256
|
-
const account = url.searchParams.get("account");
|
|
257
|
-
const platform = url.searchParams.get("platform") ?? "web";
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
// const account = c.req.query("account");
|
|
262
|
-
// const platform = c.req.query("platform");
|
|
263
|
-
//add zod
|
|
264
|
-
const data =
|
|
265
|
-
platform == "tv"
|
|
266
|
-
? ((await request.json()) as {
|
|
267
|
-
event: WebEvent["event"] | Record<"custom", string>;
|
|
268
|
-
custom_data: Record<string, string>;
|
|
269
|
-
client_page_url: string;
|
|
270
|
-
referer?: string;
|
|
271
|
-
screen_width?: number;
|
|
272
|
-
screen_height?: number;
|
|
273
|
-
browser?: string;
|
|
274
|
-
operating_system?: string;
|
|
275
|
-
rid?: string;
|
|
276
|
-
device_type?: string;
|
|
277
|
-
})
|
|
278
|
-
: ((await request.json()) as {
|
|
279
|
-
referer: string;
|
|
280
|
-
event: WebEvent["event"] | Record<"custom", string>;
|
|
281
|
-
client_page_url: string;
|
|
282
|
-
screen_width: number;
|
|
283
|
-
screen_height: number;
|
|
284
|
-
browser?: string;
|
|
285
|
-
operating_system?: string;
|
|
286
|
-
rid?: string;
|
|
287
|
-
device_type?: string;
|
|
288
|
-
custom_data?: Record<string, string>;
|
|
289
|
-
});
|
|
290
|
-
const eventName = typeof data.event == "object" ? data.event.custom : data.event;
|
|
291
|
-
const isRuleDefinitionEvent = eventName === "auto_capture" && data.custom_data?.type === "auto_capture";
|
|
292
|
-
if (isRuleDefinitionEvent) {
|
|
293
|
-
return new Response(JSON.stringify({ error: null, status: 200, rid: null, skipped: true }), {
|
|
294
|
-
headers: {
|
|
295
|
-
"Content-Type": "application/json",
|
|
296
|
-
},
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
//console.log(data);
|
|
300
|
-
//get tag id
|
|
301
|
-
if (account && platform) {
|
|
302
|
-
|
|
303
|
-
const checkAccouuntByTagId = await getSiteForTag(account);
|
|
304
|
-
|
|
305
|
-
if (checkAccouuntByTagId && checkAccouuntByTagId.track_web_events) {
|
|
306
|
-
const clientUrl = platform == "web" ? new URL(data.client_page_url) : data.client_page_url;
|
|
307
|
-
const queryParams: Record<string, string> = {};
|
|
308
|
-
|
|
309
|
-
if (platform == "web" && typeof clientUrl == "object") {
|
|
310
|
-
clientUrl.searchParams.forEach((value, key) => {
|
|
311
|
-
if (
|
|
312
|
-
!blockedQueryParams.find((query) =>
|
|
313
|
-
query.includes(key.toLowerCase())
|
|
314
|
-
)
|
|
315
|
-
) {
|
|
316
|
-
queryParams[key] = value;
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
const parsedDeviceData = parseUserAgent(headers.get("User-Agent")!);
|
|
322
|
-
|
|
323
|
-
const cf = request.cf as IncomingRequestCfProperties | undefined;
|
|
324
|
-
|
|
325
|
-
//WARNING: Forcing the type here until we migrate account --> team_id
|
|
326
|
-
const team_id = checkAccouuntByTagId.account_id!;
|
|
327
|
-
|
|
328
|
-
const recordData: WebEvent = {
|
|
329
|
-
page_url: headers.get("referer") ?? "Unknown",
|
|
330
|
-
referer: data.referer,
|
|
331
|
-
screen_height: data.screen_height,
|
|
332
|
-
screen_width: data.screen_width,
|
|
333
|
-
client_page_url:
|
|
334
|
-
platform == "web" ? (typeof clientUrl != "string" ? clientUrl.pathname : "") : data.client_page_url,
|
|
335
|
-
//!check platform here
|
|
336
|
-
browser:
|
|
337
|
-
platform == "tv"
|
|
338
|
-
? data.browser
|
|
339
|
-
: parseBrowser(parsedDeviceData, headers.get("User-Agent")!),
|
|
340
|
-
operating_system:
|
|
341
|
-
platform == "tv"
|
|
342
|
-
? data.operating_system
|
|
343
|
-
: parseOs(parsedDeviceData, headers.get("sec-ch-ua-platform")!),
|
|
344
|
-
device_type:
|
|
345
|
-
platform == "tv"
|
|
346
|
-
? data.device_type
|
|
347
|
-
: parseDeviceType(
|
|
348
|
-
parsedDeviceData,
|
|
349
|
-
headers.get("sec-ch-ua-mobile")!
|
|
350
|
-
),
|
|
351
|
-
bot_data:
|
|
352
|
-
(parsedDeviceData.bot as unknown as Record<string, string>) ??
|
|
353
|
-
undefined,
|
|
354
|
-
country: cf?.country ?? undefined,
|
|
355
|
-
region: cf?.region ?? undefined,
|
|
356
|
-
city: cf?.city ?? undefined,
|
|
357
|
-
postal: cf?.postalCode ?? undefined,
|
|
358
|
-
event: platform == "web" ? "page_view" : "screen_view",
|
|
359
|
-
tag_id: account,
|
|
360
|
-
//FIX: THIS IS TEMPORARY
|
|
361
|
-
account_id: team_id,
|
|
362
|
-
team_id: team_id,
|
|
363
|
-
site_id: checkAccouuntByTagId.site_id,
|
|
364
|
-
query_params: queryParams,
|
|
365
|
-
rid: platform == "tv" ? data.rid : null,
|
|
366
|
-
custom_data: data.custom_data,
|
|
367
|
-
};
|
|
368
|
-
|
|
369
|
-
// let lat = cf ? cf!.latitude as string : null
|
|
370
|
-
if (eventName) {
|
|
371
|
-
recordData.event = eventName as WebEvent["event"];
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
//console.log(recordData,checkAccouuntByTagId.data.gdpr);
|
|
375
|
-
|
|
376
|
-
if (checkAccouuntByTagId.gdpr) {
|
|
377
|
-
|
|
378
|
-
const newEvent = await insertSiteEvent(recordData);
|
|
379
|
-
return new Response(JSON.stringify({ error: null, status: 200 }), {
|
|
380
|
-
headers: {
|
|
381
|
-
"Content-Type": "application/json",
|
|
382
|
-
},
|
|
383
|
-
})
|
|
384
|
-
// c.json({ error: newEvent.error, status: newEvent.status });
|
|
385
|
-
} else {
|
|
386
|
-
//extra data allowed in non gdpr sites
|
|
387
|
-
//goes to us db
|
|
388
|
-
|
|
389
|
-
//TODO: Add cron to update salt
|
|
390
|
-
const ridVal = await hashIpAddress(headers.get("x-real-ip")!, checkAccouuntByTagId.rid_salt!)
|
|
391
|
-
recordData.rid = ridVal;
|
|
392
|
-
const newEvent = await insertSiteEvent(recordData);
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
return new Response(JSON.stringify({ error: null, status: 200, rid: ridVal }), {
|
|
396
|
-
headers: {
|
|
397
|
-
"Content-Type": "application/json",
|
|
398
|
-
},
|
|
399
|
-
});
|
|
400
|
-
// c.json({ error: newEvent.error, status: newEvent.status, rid: ridVal });
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
} else return new Response("Not Found.", { status: 404 });
|
|
404
|
-
} else return new Response("Not Found.", { status: 404 });
|
|
405
|
-
|
|
406
|
-
//sec-ch-ua-platform Windows
|
|
407
|
-
//user-agent
|
|
408
|
-
//sec-ch-ua-mobile
|
|
409
|
-
//referer PATH
|
|
410
|
-
|
|
411
|
-
}]);
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
/**
|
|
416
|
-
* POST /api/sites
|
|
417
|
-
*
|
|
418
|
-
* This is the new site setup endpoint
|
|
419
|
-
*/
|
|
420
|
-
export const newSiteSetup = (internal = true) =>
|
|
421
|
-
route("/sites", async ({ request, ctx }: RequestInfo<any, AppContext>) => {
|
|
422
|
-
|
|
423
|
-
let team_id: number | null = null;
|
|
424
|
-
if (!internal) {
|
|
425
|
-
//TODO: Grab api key from request
|
|
426
|
-
const apiKey = request.headers.get("x-api-key");
|
|
427
|
-
if (!apiKey) return new Response("Missing API Key", { status: 400 });
|
|
428
|
-
// team_id = await getTeamIdFromApiKey(apiKey);
|
|
429
|
-
if (!team_id) return new Response("Invalid API Key", { status: 400 });
|
|
430
|
-
} else team_id = ctx.team.id;
|
|
431
|
-
|
|
432
|
-
if (request.method !== "POST") return new Response("Method Not Allowed", { status: 405 });
|
|
433
|
-
// const site_stub = env.SITE_DURABLE_OBJECT.get(ctx.)
|
|
434
|
-
|
|
435
|
-
const body = await request.json() as {
|
|
436
|
-
name: string,
|
|
437
|
-
domain: string,
|
|
438
|
-
track_web_events: boolean,
|
|
439
|
-
gdpr: boolean,
|
|
440
|
-
autocapture?: boolean,
|
|
441
|
-
event_load_strategy?: "sdk" | "kv"
|
|
442
|
-
};
|
|
443
|
-
if (body.name && body.domain) {
|
|
444
|
-
const { name, domain, gdpr, track_web_events, autocapture, event_load_strategy } = body;
|
|
445
|
-
const site = await createSite({
|
|
446
|
-
name,
|
|
447
|
-
domain,
|
|
448
|
-
track_web_events,
|
|
449
|
-
gdpr,
|
|
450
|
-
autocapture: autocapture ?? true,
|
|
451
|
-
event_load_strategy: event_load_strategy ?? "sdk",
|
|
452
|
-
team_id: team_id ?? 0
|
|
453
|
-
});
|
|
454
|
-
return new Response(JSON.stringify(site), { status: 200 });
|
|
455
|
-
} else {
|
|
456
|
-
return new Response("Invalid request body.", { status: 400 });
|
|
457
|
-
}
|
|
458
|
-
});
|
|
14
|
+
export {
|
|
15
|
+
corsMiddleware,
|
|
16
|
+
dataVariableName,
|
|
17
|
+
lytxTag,
|
|
18
|
+
newSiteSetup,
|
|
19
|
+
trackWebEvent,
|
|
20
|
+
};
|
package/src/api/tag_api_v2.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { env } from "cloudflare:workers";
|
|
|
4
4
|
import type { PageEvent } from "@/templates/lytxpixel";
|
|
5
5
|
import { script_tag_manager, script_core } from "virtual:lytx-pixel-raw";
|
|
6
6
|
// import { getSiteForTag as getSiteForTagPg } from "@db/postgres/sites";
|
|
7
|
-
import { getSiteForTag as getSiteForTagD1, rotateSiteRidSalt } from "@db/d1/sites";
|
|
7
|
+
import { createSite, getSiteForTag as getSiteForTagD1, rotateSiteRidSalt } from "@db/d1/sites";
|
|
8
8
|
import { insertSiteEvents } from "@db/adapter";
|
|
9
9
|
import { enqueueSiteEventsForProcessing } from "@/api/queueWorker";
|
|
10
10
|
import { blockedQueryParams, WebEvent } from "@/templates/trackWebEvents";
|
|
@@ -13,6 +13,7 @@ import { hashIpAddress } from "@/utilities";
|
|
|
13
13
|
import type { DBAdapter } from "@db/types";
|
|
14
14
|
import { IS_DEV } from "rwsdk/constants";
|
|
15
15
|
import { SiteEventInput } from "@/session/siteSchema";
|
|
16
|
+
import type { AppContext } from "@/types/app-context";
|
|
16
17
|
|
|
17
18
|
export const dataVariableName = "lytxDataLayer" as const;
|
|
18
19
|
|
|
@@ -25,7 +26,52 @@ export function corsMiddleware({ response }: RequestInfo) {
|
|
|
25
26
|
headers.set("Access-Control-Max-Age", "600");
|
|
26
27
|
headers.set("Access-Control-Allow-Credentials", "false");
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* POST /sites
|
|
32
|
+
*
|
|
33
|
+
* Creates a new site for the current team.
|
|
34
|
+
*/
|
|
35
|
+
export const newSiteSetup = (internal = true) =>
|
|
36
|
+
route("/sites", async ({ request, ctx }: RequestInfo<any, AppContext>) => {
|
|
37
|
+
let team_id: number | null = null;
|
|
38
|
+
if (!internal) {
|
|
39
|
+
const apiKey = request.headers.get("x-api-key");
|
|
40
|
+
if (!apiKey) return new Response("Missing API Key", { status: 400 });
|
|
41
|
+
if (!team_id) return new Response("Invalid API Key", { status: 400 });
|
|
42
|
+
} else {
|
|
43
|
+
team_id = ctx.team.id;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (request.method !== "POST") return new Response("Method Not Allowed", { status: 405 });
|
|
47
|
+
|
|
48
|
+
const body = await request.json() as {
|
|
49
|
+
name: string;
|
|
50
|
+
domain: string;
|
|
51
|
+
track_web_events: boolean;
|
|
52
|
+
gdpr: boolean;
|
|
53
|
+
autocapture?: boolean;
|
|
54
|
+
event_load_strategy?: "sdk" | "kv";
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
if (!body.name || !body.domain) {
|
|
58
|
+
return new Response("Invalid request body.", { status: 400 });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const { name, domain, gdpr, track_web_events, autocapture, event_load_strategy } = body;
|
|
62
|
+
const site = await createSite({
|
|
63
|
+
name,
|
|
64
|
+
domain,
|
|
65
|
+
track_web_events,
|
|
66
|
+
gdpr,
|
|
67
|
+
autocapture: autocapture ?? true,
|
|
68
|
+
event_load_strategy: event_load_strategy ?? "sdk",
|
|
69
|
+
team_id: team_id ?? 0,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return new Response(JSON.stringify(site), { status: 200 });
|
|
73
|
+
});
|
|
74
|
+
//TODO: move to seprate
|
|
29
75
|
function checkIfTagManager(events: PageEvent[], allowed = false) {
|
|
30
76
|
const eventsMapped = [];
|
|
31
77
|
for (const ev of events) {
|
package/src/templates/script.ts
CHANGED
|
@@ -16,7 +16,7 @@ export const pageScript = `
|
|
|
16
16
|
window._lytxEvents = window._lytxEvents || [];
|
|
17
17
|
(function () {
|
|
18
18
|
const elem = document.createElement("script");
|
|
19
|
-
elem.src = "http://localhost:8787/
|
|
19
|
+
elem.src = "http://localhost:8787/lytx.js?account=test-account";
|
|
20
20
|
elem.async = true;
|
|
21
21
|
elem.type = "text/javascript";
|
|
22
22
|
const script = document.getElementsByTagName("script")[0];
|
|
@@ -28,4 +28,4 @@ window._lytxEvents.push({
|
|
|
28
28
|
labels: "lytx-main",
|
|
29
29
|
}
|
|
30
30
|
);
|
|
31
|
-
`;
|
|
31
|
+
`;
|
package/src/worker.tsx
CHANGED
|
@@ -13,10 +13,7 @@ import { aiChatRoute, aiConfigRoute, aiTagSuggestRoute, getAiConfig, setAiRuntim
|
|
|
13
13
|
import { resendVerificationEmailRoute, userApiRoutes } from "@api/auth_api";
|
|
14
14
|
import { eventLabelsApi } from "@api/event_labels_api";
|
|
15
15
|
import { reportsApi } from "@api/reports_api";
|
|
16
|
-
import {
|
|
17
|
-
newSiteSetup,
|
|
18
|
-
} from "@api/tag_api";
|
|
19
|
-
import { lytxTag, trackWebEvent } from "@api/tag_api_v2";
|
|
16
|
+
import { lytxTag, newSiteSetup, trackWebEvent } from "@api/tag_api_v2";
|
|
20
17
|
import { authMiddleware, sessionMiddleware } from "@api/authMiddleware";
|
|
21
18
|
import {
|
|
22
19
|
canRegisterEmail,
|