Added timestamp property to payload.

This commit is contained in:
Mike Cao 2025-03-01 14:40:37 -08:00
parent 9a87442870
commit 65f18d12ab
6 changed files with 33 additions and 15 deletions

2
next-env.d.ts vendored
View file

@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" /> /// <reference types="next/image-types/global" />
// NOTE: This file should not be edited // NOTE: This file should not be edited
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

View file

@ -7,16 +7,16 @@ import { badRequest, json, forbidden, serverError } from '@/lib/response';
import { fetchSession, fetchWebsite } from '@/lib/load'; import { fetchSession, fetchWebsite } from '@/lib/load';
import { getClientInfo, hasBlockedIp } from '@/lib/detect'; import { getClientInfo, hasBlockedIp } from '@/lib/detect';
import { secret, uuid, visitSalt } from '@/lib/crypto'; import { secret, uuid, visitSalt } from '@/lib/crypto';
import { COLLECTION_TYPE, DOMAIN_REGEX } from '@/lib/constants'; import { COLLECTION_TYPE } from '@/lib/constants';
import { anyObjectParam, urlOrPathParam } from '@/lib/schema';
import { createSession, saveEvent, saveSessionData } from '@/queries'; import { createSession, saveEvent, saveSessionData } from '@/queries';
import { urlOrPathParam } from '@/lib/schema';
const schema = z.object({ const schema = z.object({
type: z.enum(['event', 'identify']), type: z.enum(['event', 'identify']),
payload: z.object({ payload: z.object({
website: z.string().uuid(), website: z.string().uuid(),
data: z.object({}).passthrough().optional(), data: anyObjectParam.optional(),
hostname: z.string().regex(DOMAIN_REGEX).max(100).optional(), hostname: z.string().max(100).optional(),
language: z.string().max(35).optional(), language: z.string().max(35).optional(),
referrer: urlOrPathParam.optional(), referrer: urlOrPathParam.optional(),
screen: z.string().max(11).optional(), screen: z.string().max(11).optional(),
@ -26,6 +26,7 @@ const schema = z.object({
tag: z.string().max(50).optional(), tag: z.string().max(50).optional(),
ip: z.string().ip().optional(), ip: z.string().ip().optional(),
userAgent: z.string().optional(), userAgent: z.string().optional(),
timestamp: z.coerce.number().int().optional(),
}), }),
}); });
@ -55,6 +56,7 @@ export async function POST(request: Request) {
data, data,
title, title,
tag, tag,
timestamp,
} = payload; } = payload;
// Cache check // Cache check
@ -88,6 +90,7 @@ export async function POST(request: Request) {
} }
const sessionId = uuid(websiteId, ip, userAgent); const sessionId = uuid(websiteId, ip, userAgent);
const createdAt = timestamp ? new Date(timestamp * 1000) : new Date();
// Find session // Find session
if (!clickhouse.enabled && !cache?.sessionId) { if (!clickhouse.enabled && !cache?.sessionId) {
@ -179,6 +182,7 @@ export async function POST(request: Request) {
subdivision2, subdivision2,
city, city,
tag, tag,
createdAt,
}); });
} }
@ -191,6 +195,7 @@ export async function POST(request: Request) {
websiteId, websiteId,
sessionId, sessionId,
sessionData: data, sessionData: data,
createdAt,
}); });
} }

View file

@ -36,6 +36,8 @@ export const unitParam = z.string().refine(value => UNIT_TYPES.includes(value),
export const roleParam = z.enum(['team-member', 'team-view-only', 'team-manager']); export const roleParam = z.enum(['team-member', 'team-view-only', 'team-manager']);
export const anyObjectParam = z.object({}).passthrough();
export const urlOrPathParam = z.string().refine( export const urlOrPathParam = z.string().refine(
value => { value => {
try { try {

View file

@ -29,6 +29,7 @@ export async function saveEvent(args: {
subdivision2?: string; subdivision2?: string;
city?: string; city?: string;
tag?: string; tag?: string;
createdAt?: Date;
}) { }) {
return runQuery({ return runQuery({
[PRISMA]: () => relationalQuery(args), [PRISMA]: () => relationalQuery(args),
@ -49,6 +50,7 @@ async function relationalQuery(data: {
eventName?: string; eventName?: string;
eventData?: any; eventData?: any;
tag?: string; tag?: string;
createdAt?: Date;
}) { }) {
const { const {
websiteId, websiteId,
@ -63,6 +65,7 @@ async function relationalQuery(data: {
eventData, eventData,
pageTitle, pageTitle,
tag, tag,
createdAt,
} = data; } = data;
const websiteEventId = uuid(); const websiteEventId = uuid();
@ -81,6 +84,7 @@ async function relationalQuery(data: {
eventType: eventName ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView, eventType: eventName ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
eventName: eventName ? eventName?.substring(0, EVENT_NAME_LENGTH) : null, eventName: eventName ? eventName?.substring(0, EVENT_NAME_LENGTH) : null,
tag, tag,
createdAt,
}, },
}); });
@ -92,6 +96,7 @@ async function relationalQuery(data: {
urlPath: urlPath?.substring(0, URL_LENGTH), urlPath: urlPath?.substring(0, URL_LENGTH),
eventName: eventName?.substring(0, EVENT_NAME_LENGTH), eventName: eventName?.substring(0, EVENT_NAME_LENGTH),
eventData, eventData,
createdAt,
}); });
} }
@ -121,6 +126,7 @@ async function clickhouseQuery(data: {
subdivision2?: string; subdivision2?: string;
city?: string; city?: string;
tag?: string; tag?: string;
createdAt?: Date;
}) { }) {
const { const {
websiteId, websiteId,
@ -139,12 +145,12 @@ async function clickhouseQuery(data: {
subdivision2, subdivision2,
city, city,
tag, tag,
createdAt,
...args ...args
} = data; } = data;
const { insert, getUTCString } = clickhouse; const { insert, getUTCString } = clickhouse;
const { sendMessage } = kafka; const { sendMessage } = kafka;
const eventId = uuid(); const eventId = uuid();
const createdAt = getUTCString();
const message = { const message = {
...args, ...args,
@ -170,7 +176,7 @@ async function clickhouseQuery(data: {
event_type: eventName ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView, event_type: eventName ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
event_name: eventName ? eventName?.substring(0, EVENT_NAME_LENGTH) : null, event_name: eventName ? eventName?.substring(0, EVENT_NAME_LENGTH) : null,
tag: tag, tag: tag,
created_at: createdAt, created_at: getUTCString(createdAt),
}; };
if (kafka.enabled) { if (kafka.enabled) {

View file

@ -15,7 +15,7 @@ export async function saveEventData(data: {
urlPath?: string; urlPath?: string;
eventName?: string; eventName?: string;
eventData: DynamicData; eventData: DynamicData;
createdAt?: string; createdAt?: Date;
}) { }) {
return runQuery({ return runQuery({
[PRISMA]: () => relationalQuery(data), [PRISMA]: () => relationalQuery(data),
@ -27,8 +27,9 @@ async function relationalQuery(data: {
websiteId: string; websiteId: string;
eventId: string; eventId: string;
eventData: DynamicData; eventData: DynamicData;
createdAt?: Date;
}): Promise<Prisma.BatchPayload> { }): Promise<Prisma.BatchPayload> {
const { websiteId, eventId, eventData } = data; const { websiteId, eventId, eventData, createdAt } = data;
const jsonKeys = flattenJSON(eventData); const jsonKeys = flattenJSON(eventData);
@ -42,6 +43,7 @@ async function relationalQuery(data: {
numberValue: a.dataType === DATA_TYPE.number ? a.value : null, numberValue: a.dataType === DATA_TYPE.number ? a.value : null,
dateValue: a.dataType === DATA_TYPE.date ? new Date(a.value) : null, dateValue: a.dataType === DATA_TYPE.date ? new Date(a.value) : null,
dataType: a.dataType, dataType: a.dataType,
createdAt,
})); }));
return prisma.client.eventData.createMany({ return prisma.client.eventData.createMany({
@ -56,7 +58,7 @@ async function clickhouseQuery(data: {
urlPath?: string; urlPath?: string;
eventName?: string; eventName?: string;
eventData: DynamicData; eventData: DynamicData;
createdAt?: string; createdAt?: Date;
}) { }) {
const { websiteId, sessionId, eventId, urlPath, eventName, eventData, createdAt } = data; const { websiteId, sessionId, eventId, urlPath, eventName, eventData, createdAt } = data;
@ -77,7 +79,7 @@ async function clickhouseQuery(data: {
string_value: getStringValue(value, dataType), string_value: getStringValue(value, dataType),
number_value: dataType === DATA_TYPE.number ? value : null, number_value: dataType === DATA_TYPE.number ? value : null,
date_value: dataType === DATA_TYPE.date ? getUTCString(value) : null, date_value: dataType === DATA_TYPE.date ? getUTCString(value) : null,
created_at: createdAt, created_at: getUTCString(createdAt),
}; };
}); });

View file

@ -11,6 +11,7 @@ export async function saveSessionData(data: {
websiteId: string; websiteId: string;
sessionId: string; sessionId: string;
sessionData: DynamicData; sessionData: DynamicData;
createdAt?: Date;
}) { }) {
return runQuery({ return runQuery({
[PRISMA]: () => relationalQuery(data), [PRISMA]: () => relationalQuery(data),
@ -22,9 +23,10 @@ export async function relationalQuery(data: {
websiteId: string; websiteId: string;
sessionId: string; sessionId: string;
sessionData: DynamicData; sessionData: DynamicData;
createdAt?: Date;
}) { }) {
const { client } = prisma; const { client } = prisma;
const { websiteId, sessionId, sessionData } = data; const { websiteId, sessionId, sessionData, createdAt } = data;
const jsonKeys = flattenJSON(sessionData); const jsonKeys = flattenJSON(sessionData);
@ -37,6 +39,7 @@ export async function relationalQuery(data: {
numberValue: a.dataType === DATA_TYPE.number ? a.value : null, numberValue: a.dataType === DATA_TYPE.number ? a.value : null,
dateValue: a.dataType === DATA_TYPE.date ? new Date(a.value) : null, dateValue: a.dataType === DATA_TYPE.date ? new Date(a.value) : null,
dataType: a.dataType, dataType: a.dataType,
createdAt,
})); }));
const existing = await client.sessionData.findMany({ const existing = await client.sessionData.findMany({
@ -77,12 +80,12 @@ async function clickhouseQuery(data: {
websiteId: string; websiteId: string;
sessionId: string; sessionId: string;
sessionData: DynamicData; sessionData: DynamicData;
createdAt?: Date;
}) { }) {
const { websiteId, sessionId, sessionData } = data; const { websiteId, sessionId, sessionData, createdAt } = data;
const { insert, getUTCString } = clickhouse; const { insert, getUTCString } = clickhouse;
const { sendMessage } = kafka; const { sendMessage } = kafka;
const createdAt = getUTCString();
const jsonKeys = flattenJSON(sessionData); const jsonKeys = flattenJSON(sessionData);
@ -95,7 +98,7 @@ async function clickhouseQuery(data: {
string_value: getStringValue(value, dataType), string_value: getStringValue(value, dataType),
number_value: dataType === DATA_TYPE.number ? value : null, number_value: dataType === DATA_TYPE.number ? value : null,
date_value: dataType === DATA_TYPE.date ? getUTCString(value) : null, date_value: dataType === DATA_TYPE.date ? getUTCString(value) : null,
created_at: createdAt, created_at: getUTCString(createdAt),
}; };
}); });