From ebdd9095ab137f1e0497631bc8df099d4fc1c17e Mon Sep 17 00:00:00 2001 From: Exlaso Date: Fri, 30 May 2025 11:14:03 +0530 Subject: [PATCH 1/4] fix: decode location fields in user detection --- src/lib/detect.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/detect.ts b/src/lib/detect.ts index a023d27d..4331a9a9 100644 --- a/src/lib/detect.ts +++ b/src/lib/detect.ts @@ -5,11 +5,11 @@ import ipaddr from 'ipaddr.js'; import maxmind from 'maxmind'; import { DESKTOP_OS, - MOBILE_OS, DESKTOP_SCREEN_WIDTH, - LAPTOP_SCREEN_WIDTH, - MOBILE_SCREEN_WIDTH, IP_ADDRESS_HEADERS, + LAPTOP_SCREEN_WIDTH, + MOBILE_OS, + MOBILE_SCREEN_WIDTH, } from './constants'; const MAXMIND = 'maxmind'; @@ -146,9 +146,9 @@ export async function getClientInfo(request: Request, payload: Record Date: Fri, 30 May 2025 11:19:19 +0530 Subject: [PATCH 2/4] fix: handle unknown location fields in user detection --- src/lib/detect.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/detect.ts b/src/lib/detect.ts index 4331a9a9..8712632a 100644 --- a/src/lib/detect.ts +++ b/src/lib/detect.ts @@ -146,9 +146,9 @@ export async function getClientInfo(request: Request, payload: Record Date: Wed, 4 Jun 2025 12:43:02 +0530 Subject: [PATCH 3/4] fix: use safeDecodeURIComponent for location fields in user detection --- src/lib/detect.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lib/detect.ts b/src/lib/detect.ts index 8712632a..2b1fe01d 100644 --- a/src/lib/detect.ts +++ b/src/lib/detect.ts @@ -11,6 +11,7 @@ import { MOBILE_OS, MOBILE_SCREEN_WIDTH, } from './constants'; +import { safeDecodeURIComponent } from '@/lib/url'; const MAXMIND = 'maxmind'; @@ -146,9 +147,9 @@ export async function getClientInfo(request: Request, payload: Record Date: Mon, 9 Jun 2025 12:06:42 +0200 Subject: [PATCH 4/4] improv: Improved performance of send due to slow session creation retrieving session every time. --- src/app/api/send/route.ts | 44 +++++++++------------ src/queries/sql/sessions/createSession.ts | 47 +++++++++++++++-------- 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/src/app/api/send/route.ts b/src/app/api/send/route.ts index 60d6f7af..16441efc 100644 --- a/src/app/api/send/route.ts +++ b/src/app/api/send/route.ts @@ -4,7 +4,7 @@ import { startOfHour, startOfMonth } from 'date-fns'; import clickhouse from '@/lib/clickhouse'; import { parseRequest } from '@/lib/request'; import { badRequest, json, forbidden, serverError } from '@/lib/response'; -import { fetchSession, fetchWebsite } from '@/lib/load'; +import { fetchWebsite } from '@/lib/load'; import { getClientInfo, hasBlockedIp } from '@/lib/detect'; import { createToken, parseToken } from '@/lib/jwt'; import { secret, uuid, hash } from '@/lib/crypto'; @@ -103,32 +103,24 @@ export async function POST(request: Request) { const sessionId = id ? uuid(websiteId, id) : uuid(websiteId, ip, userAgent, sessionSalt); - // Find session + // Create a session if not found if (!clickhouse.enabled && !cache?.sessionId) { - const session = await fetchSession(websiteId, sessionId); - - // Create a session if not found - if (!session) { - try { - await createSession({ - id: sessionId, - websiteId, - browser, - os, - device, - screen, - language, - country, - region, - city, - distinctId: id, - }); - } catch (e: any) { - if (!e.message.toLowerCase().includes('unique constraint')) { - return serverError(e); - } - } - } + await createSession( + { + id: sessionId, + websiteId, + browser, + os, + device, + screen, + language, + country, + region, + city, + distinctId: id, + }, + { skipDuplicates: true }, + ); } // Visit info diff --git a/src/queries/sql/sessions/createSession.ts b/src/queries/sql/sessions/createSession.ts index 9d1402b1..d2794c8f 100644 --- a/src/queries/sql/sessions/createSession.ts +++ b/src/queries/sql/sessions/createSession.ts @@ -1,7 +1,10 @@ import { Prisma } from '@prisma/client'; import prisma from '@/lib/prisma'; -export async function createSession(data: Prisma.SessionCreateInput) { +export async function createSession( + data: Prisma.SessionCreateInput, + options = { skipDuplicates: false }, +) { const { id, websiteId, @@ -16,19 +19,31 @@ export async function createSession(data: Prisma.SessionCreateInput) { distinctId, } = data; - return prisma.client.session.create({ - data: { - id, - websiteId, - browser, - os, - device, - screen, - language, - country, - region, - city, - distinctId, - }, - }); + try { + return await prisma.client.session.create({ + data: { + id, + websiteId, + browser, + os, + device, + screen, + language, + country, + region, + city, + distinctId, + }, + }); + } catch (e: any) { + // With skipDuplicates flag: ignore unique constraint error and return null + if ( + options.skipDuplicates && + e instanceof Prisma.PrismaClientKnownRequestError && + e.code === 'P2002' + ) { + return null; + } + throw e; + } }