diff options
| author | Fuwn <[email protected]> | 2026-01-24 13:09:50 +0000 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-01-24 13:09:50 +0000 |
| commit | 396acf3bbbe00a192cb0ea0a9ccf91b1d8d2850b (patch) | |
| tree | b9df4ca6a70db45cfffbae6fdd7252e20fb8e93c /src/queries/sql/events/saveEvent.ts | |
| download | umami-main.tar.xz umami-main.zip | |
Created from https://vercel.com/new
Diffstat (limited to 'src/queries/sql/events/saveEvent.ts')
| -rw-r--r-- | src/queries/sql/events/saveEvent.ts | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/src/queries/sql/events/saveEvent.ts b/src/queries/sql/events/saveEvent.ts new file mode 100644 index 0000000..7313fe4 --- /dev/null +++ b/src/queries/sql/events/saveEvent.ts @@ -0,0 +1,249 @@ +import clickhouse from '@/lib/clickhouse'; +import { EVENT_NAME_LENGTH, PAGE_TITLE_LENGTH, URL_LENGTH } from '@/lib/constants'; +import { uuid } from '@/lib/crypto'; +import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; +import kafka from '@/lib/kafka'; +import prisma from '@/lib/prisma'; +import { saveEventData } from './saveEventData'; +import { saveRevenue } from './saveRevenue'; + +export interface SaveEventArgs { + websiteId: string; + sessionId: string; + visitId: string; + eventType: number; + createdAt?: Date; + + // Page + pageTitle?: string; + hostname?: string; + urlPath: string; + urlQuery?: string; + referrerPath?: string; + referrerQuery?: string; + referrerDomain?: string; + + // Session + distinctId?: string; + browser?: string; + os?: string; + device?: string; + screen?: string; + language?: string; + country?: string; + region?: string; + city?: string; + + // Events + eventName?: string; + eventData?: any; + tag?: string; + + // UTM + utmSource?: string; + utmMedium?: string; + utmCampaign?: string; + utmContent?: string; + utmTerm?: string; + + // Click IDs + gclid?: string; + fbclid?: string; + msclkid?: string; + ttclid?: string; + lifatid?: string; + twclid?: string; +} + +export async function saveEvent(args: SaveEventArgs) { + return runQuery({ + [PRISMA]: () => relationalQuery(args), + [CLICKHOUSE]: () => clickhouseQuery(args), + }); +} + +async function relationalQuery({ + websiteId, + sessionId, + visitId, + eventType, + createdAt, + pageTitle, + hostname, + urlPath, + urlQuery, + referrerPath, + referrerQuery, + referrerDomain, + eventName, + eventData, + tag, + utmSource, + utmMedium, + utmCampaign, + utmContent, + utmTerm, + gclid, + fbclid, + msclkid, + ttclid, + lifatid, + twclid, +}: SaveEventArgs) { + const websiteEventId = uuid(); + + await prisma.client.websiteEvent.create({ + data: { + id: websiteEventId, + websiteId, + sessionId, + visitId, + urlPath: urlPath?.substring(0, URL_LENGTH), + urlQuery: urlQuery?.substring(0, URL_LENGTH), + utmSource, + utmMedium, + utmCampaign, + utmContent, + utmTerm, + referrerPath: referrerPath?.substring(0, URL_LENGTH), + referrerQuery: referrerQuery?.substring(0, URL_LENGTH), + referrerDomain: referrerDomain?.substring(0, URL_LENGTH), + pageTitle: pageTitle?.substring(0, PAGE_TITLE_LENGTH), + gclid, + fbclid, + msclkid, + ttclid, + lifatid, + twclid, + eventType, + eventName: eventName ? eventName?.substring(0, EVENT_NAME_LENGTH) : null, + tag, + hostname, + createdAt, + }, + }); + + if (eventData) { + await saveEventData({ + websiteId, + sessionId, + eventId: websiteEventId, + urlPath: urlPath?.substring(0, URL_LENGTH), + eventName: eventName?.substring(0, EVENT_NAME_LENGTH), + eventData, + createdAt, + }); + + const { revenue, currency } = eventData; + + if (revenue > 0 && currency) { + await saveRevenue({ + websiteId, + sessionId, + eventId: websiteEventId, + eventName: eventName?.substring(0, EVENT_NAME_LENGTH), + currency, + revenue, + createdAt, + }); + } + } +} + +async function clickhouseQuery({ + websiteId, + sessionId, + visitId, + eventType, + createdAt, + pageTitle, + hostname, + urlPath, + urlQuery, + referrerPath, + referrerQuery, + referrerDomain, + distinctId, + browser, + os, + device, + screen, + language, + country, + region, + city, + eventName, + eventData, + tag, + utmSource, + utmMedium, + utmCampaign, + utmContent, + utmTerm, + gclid, + fbclid, + msclkid, + ttclid, + lifatid, + twclid, +}: SaveEventArgs) { + const { insert, getUTCString } = clickhouse; + const { sendMessage } = kafka; + const eventId = uuid(); + + const message = { + website_id: websiteId, + session_id: sessionId, + visit_id: visitId, + event_id: eventId, + country: country, + region: country && region ? (region.includes('-') ? region : `${country}-${region}`) : null, + city: city, + url_path: urlPath?.substring(0, URL_LENGTH), + url_query: urlQuery?.substring(0, URL_LENGTH), + utm_source: utmSource, + utm_medium: utmMedium, + utm_campaign: utmCampaign, + utm_content: utmContent, + utm_term: utmTerm, + referrer_path: referrerPath?.substring(0, URL_LENGTH), + referrer_query: referrerQuery?.substring(0, URL_LENGTH), + referrer_domain: referrerDomain?.substring(0, URL_LENGTH), + page_title: pageTitle?.substring(0, PAGE_TITLE_LENGTH), + gclid: gclid, + fbclid: fbclid, + msclkid: msclkid, + ttclid: ttclid, + li_fat_id: lifatid, + twclid: twclid, + event_type: eventType, + event_name: eventName ? eventName?.substring(0, EVENT_NAME_LENGTH) : null, + tag: tag, + distinct_id: distinctId, + created_at: getUTCString(createdAt), + browser, + os, + device, + screen, + language, + hostname, + }; + + if (kafka.enabled) { + await sendMessage('event', message); + } else { + await insert('website_event', [message]); + } + + if (eventData) { + await saveEventData({ + websiteId, + sessionId, + eventId, + urlPath: urlPath?.substring(0, URL_LENGTH), + eventName: eventName?.substring(0, EVENT_NAME_LENGTH), + eventData, + createdAt, + }); + } +} |