From a3733b0424727ebe02b97aecf732e3891d677b76 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Thu, 5 Feb 2026 21:25:46 -0800 Subject: [PATCH 1/4] Fix TypeScript type errors across multiple files --- .../[websiteId]/(reports)/funnels/Funnel.tsx | 2 +- .../(reports)/funnels/FunnelAddButton.tsx | 2 +- .../websites/[websiteId]/(reports)/goals/Goal.tsx | 2 +- .../(main)/websites/[websiteId]/WebsiteChart.tsx | 6 +++++- .../(main)/websites/[websiteId]/WebsiteMenu.tsx | 4 ++-- src/components/hooks/useMessages.ts | 10 +++++++--- src/components/input/LanguageButton.tsx | 2 +- src/declaration.d.ts | 15 +++++++++++++++ src/lib/db.ts | 2 +- src/lib/react.ts | 2 +- src/lib/request.ts | 2 +- src/queries/sql/reports/getJourney.ts | 4 ++-- 12 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx b/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx index e336a3db6..54b4cd0f9 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx @@ -42,7 +42,7 @@ export function Funnel({ id, name, type, parameters, websiteId }) { return ( diff --git a/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelAddButton.tsx b/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelAddButton.tsx index 29b548032..725262aac 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelAddButton.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelAddButton.tsx @@ -16,7 +16,7 @@ export function FunnelAddButton({ websiteId }: { websiteId: string }) { diff --git a/src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx b/src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx index b6c4a11d6..39eb34890 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx @@ -51,7 +51,7 @@ export function Goal({ id, name, type, parameters, websiteId, startDate, endDate return ( diff --git a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx index b2ea2a83e..165d2da21 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx @@ -22,7 +22,11 @@ export function WebsiteChart({ const chartData = useMemo(() => { if (data) { - const result = { + const result: { + pageviews: any[]; + sessions: any[]; + compare?: { pageviews: any[]; sessions: any[] }; + } = { pageviews, sessions, }; diff --git a/src/app/(main)/websites/[websiteId]/WebsiteMenu.tsx b/src/app/(main)/websites/[websiteId]/WebsiteMenu.tsx index 301895341..8025635a0 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteMenu.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteMenu.tsx @@ -10,7 +10,7 @@ import { } from '@umami/react-zen'; import { Fragment } from 'react'; import { useMessages, useNavigation } from '@/components/hooks'; -import { Edit, More, Share } from '@/components/icons'; +import { Edit, Ellipsis, Share } from '@/components/icons'; export function WebsiteMenu({ websiteId }: { websiteId: string }) { const { formatMessage, labels } = useMessages(); @@ -33,7 +33,7 @@ export function WebsiteMenu({ websiteId }: { websiteId: string }) { diff --git a/src/components/hooks/useMessages.ts b/src/components/hooks/useMessages.ts index d5bc2423d..c1bffa432 100644 --- a/src/components/hooks/useMessages.ts +++ b/src/components/hooks/useMessages.ts @@ -13,7 +13,7 @@ interface UseMessages { messages: typeof messages; labels: typeof labels; getMessage: (id: string) => string; - getErrorMessage: (error: ApiError) => string | undefined; + getErrorMessage: (error: string | Error | ApiError) => string | undefined; FormattedMessage: typeof FormattedMessage; } @@ -26,12 +26,16 @@ export function useMessages(): UseMessages { return message ? formatMessage(message) : id; }; - const getErrorMessage = (error: ApiError) => { + const getErrorMessage = (error: string | Error | ApiError) => { if (!error) { return undefined; } - const code = error?.code; + if (typeof error === 'string') { + return error; + } + + const code = (error as ApiError)?.code; return code ? getMessage(code) : error?.message || 'Unknown error'; }; diff --git a/src/components/input/LanguageButton.tsx b/src/components/input/LanguageButton.tsx index ac43dcb6b..fe4380d38 100644 --- a/src/components/input/LanguageButton.tsx +++ b/src/components/input/LanguageButton.tsx @@ -19,7 +19,7 @@ export function LanguageButton() { - + {items.map(({ value, label }) => { return ( diff --git a/src/declaration.d.ts b/src/declaration.d.ts index 14bae12ab..17acee2bb 100644 --- a/src/declaration.d.ts +++ b/src/declaration.d.ts @@ -16,3 +16,18 @@ declare module 'semver'; declare module 'tsup'; declare module 'uuid'; declare module '@umami/esbuild-plugin-css-modules'; + +interface UmamiTracker { + track: { + (): Promise; + (eventName: string): Promise; + (eventName: string, obj: Record): Promise; + (properties: Record): Promise; + (eventFunction: (props: Record) => Record): Promise; + }; + identify: (data: Record) => Promise; +} + +interface Window { + umami: UmamiTracker; +} diff --git a/src/lib/db.ts b/src/lib/db.ts index 7b6e8368b..7bee4816b 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -5,7 +5,7 @@ export const KAFKA = 'kafka'; export const KAFKA_PRODUCER = 'kafka-producer'; // Fixes issue with converting bigint values -BigInt.prototype.toJSON = function () { +(BigInt.prototype as any).toJSON = function () { return Number(this); }; diff --git a/src/lib/react.ts b/src/lib/react.ts index 668cdf1fb..5a7ce2012 100644 --- a/src/lib/react.ts +++ b/src/lib/react.ts @@ -10,7 +10,7 @@ import { export function getFragmentChildren(children: ReactNode) { return (children as ReactElement)?.type === Fragment - ? (children as ReactElement).props.children + ? (children as ReactElement<{ children: ReactNode }>).props.children : children; } diff --git a/src/lib/request.ts b/src/lib/request.ts index 42c449048..74ee432a3 100644 --- a/src/lib/request.ts +++ b/src/lib/request.ts @@ -16,7 +16,7 @@ export async function parseRequest( const url = new URL(request.url); let query = Object.fromEntries(url.searchParams); let body = await getJsonBody(request); - let error: () => undefined | undefined; + let error: (() => Response) | undefined; let auth = null; if (schema) { diff --git a/src/queries/sql/reports/getJourney.ts b/src/queries/sql/reports/getJourney.ts index 283e0fad4..362f7bdba 100644 --- a/src/queries/sql/reports/getJourney.ts +++ b/src/queries/sql/reports/getJourney.ts @@ -60,7 +60,7 @@ async function relationalQuery( endStepQuery: string; params: Record; } { - const params = {}; + const params: Record = {}; let sequenceQuery = ''; let startStepQuery = ''; let endStepQuery = ''; @@ -172,7 +172,7 @@ async function clickhouseQuery( endStepQuery: string; params: Record; } { - const params = {}; + const params: Record = {}; let sequenceQuery = ''; let startStepQuery = ''; let endStepQuery = ''; From 2260520ae58b7b79327f0f50e4d465931b07f41c Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 16 Feb 2026 16:20:04 -0800 Subject: [PATCH 2/4] Revert "Fix TypeScript type errors across multiple files" This reverts commit a3733b0424727ebe02b97aecf732e3891d677b76. --- .../[websiteId]/(reports)/funnels/Funnel.tsx | 2 +- .../(reports)/funnels/FunnelAddButton.tsx | 2 +- .../websites/[websiteId]/(reports)/goals/Goal.tsx | 2 +- .../(main)/websites/[websiteId]/WebsiteChart.tsx | 6 +----- .../(main)/websites/[websiteId]/WebsiteMenu.tsx | 4 ++-- src/components/hooks/useMessages.ts | 10 +++------- src/components/input/LanguageButton.tsx | 2 +- src/declaration.d.ts | 15 --------------- src/lib/db.ts | 2 +- src/lib/react.ts | 2 +- src/lib/request.ts | 2 +- src/queries/sql/reports/getJourney.ts | 4 ++-- 12 files changed, 15 insertions(+), 38 deletions(-) diff --git a/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx b/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx index 54b4cd0f9..e336a3db6 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx @@ -42,7 +42,7 @@ export function Funnel({ id, name, type, parameters, websiteId }) { return ( diff --git a/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelAddButton.tsx b/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelAddButton.tsx index 725262aac..29b548032 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelAddButton.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelAddButton.tsx @@ -16,7 +16,7 @@ export function FunnelAddButton({ websiteId }: { websiteId: string }) { diff --git a/src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx b/src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx index 39eb34890..b6c4a11d6 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx @@ -51,7 +51,7 @@ export function Goal({ id, name, type, parameters, websiteId, startDate, endDate return ( diff --git a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx index 165d2da21..b2ea2a83e 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx @@ -22,11 +22,7 @@ export function WebsiteChart({ const chartData = useMemo(() => { if (data) { - const result: { - pageviews: any[]; - sessions: any[]; - compare?: { pageviews: any[]; sessions: any[] }; - } = { + const result = { pageviews, sessions, }; diff --git a/src/app/(main)/websites/[websiteId]/WebsiteMenu.tsx b/src/app/(main)/websites/[websiteId]/WebsiteMenu.tsx index 8025635a0..301895341 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteMenu.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteMenu.tsx @@ -10,7 +10,7 @@ import { } from '@umami/react-zen'; import { Fragment } from 'react'; import { useMessages, useNavigation } from '@/components/hooks'; -import { Edit, Ellipsis, Share } from '@/components/icons'; +import { Edit, More, Share } from '@/components/icons'; export function WebsiteMenu({ websiteId }: { websiteId: string }) { const { formatMessage, labels } = useMessages(); @@ -33,7 +33,7 @@ export function WebsiteMenu({ websiteId }: { websiteId: string }) { diff --git a/src/components/hooks/useMessages.ts b/src/components/hooks/useMessages.ts index c1bffa432..d5bc2423d 100644 --- a/src/components/hooks/useMessages.ts +++ b/src/components/hooks/useMessages.ts @@ -13,7 +13,7 @@ interface UseMessages { messages: typeof messages; labels: typeof labels; getMessage: (id: string) => string; - getErrorMessage: (error: string | Error | ApiError) => string | undefined; + getErrorMessage: (error: ApiError) => string | undefined; FormattedMessage: typeof FormattedMessage; } @@ -26,16 +26,12 @@ export function useMessages(): UseMessages { return message ? formatMessage(message) : id; }; - const getErrorMessage = (error: string | Error | ApiError) => { + const getErrorMessage = (error: ApiError) => { if (!error) { return undefined; } - if (typeof error === 'string') { - return error; - } - - const code = (error as ApiError)?.code; + const code = error?.code; return code ? getMessage(code) : error?.message || 'Unknown error'; }; diff --git a/src/components/input/LanguageButton.tsx b/src/components/input/LanguageButton.tsx index fe4380d38..ac43dcb6b 100644 --- a/src/components/input/LanguageButton.tsx +++ b/src/components/input/LanguageButton.tsx @@ -19,7 +19,7 @@ export function LanguageButton() { - + {items.map(({ value, label }) => { return ( diff --git a/src/declaration.d.ts b/src/declaration.d.ts index 17acee2bb..14bae12ab 100644 --- a/src/declaration.d.ts +++ b/src/declaration.d.ts @@ -16,18 +16,3 @@ declare module 'semver'; declare module 'tsup'; declare module 'uuid'; declare module '@umami/esbuild-plugin-css-modules'; - -interface UmamiTracker { - track: { - (): Promise; - (eventName: string): Promise; - (eventName: string, obj: Record): Promise; - (properties: Record): Promise; - (eventFunction: (props: Record) => Record): Promise; - }; - identify: (data: Record) => Promise; -} - -interface Window { - umami: UmamiTracker; -} diff --git a/src/lib/db.ts b/src/lib/db.ts index 7bee4816b..7b6e8368b 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -5,7 +5,7 @@ export const KAFKA = 'kafka'; export const KAFKA_PRODUCER = 'kafka-producer'; // Fixes issue with converting bigint values -(BigInt.prototype as any).toJSON = function () { +BigInt.prototype.toJSON = function () { return Number(this); }; diff --git a/src/lib/react.ts b/src/lib/react.ts index 5a7ce2012..668cdf1fb 100644 --- a/src/lib/react.ts +++ b/src/lib/react.ts @@ -10,7 +10,7 @@ import { export function getFragmentChildren(children: ReactNode) { return (children as ReactElement)?.type === Fragment - ? (children as ReactElement<{ children: ReactNode }>).props.children + ? (children as ReactElement).props.children : children; } diff --git a/src/lib/request.ts b/src/lib/request.ts index 74ee432a3..42c449048 100644 --- a/src/lib/request.ts +++ b/src/lib/request.ts @@ -16,7 +16,7 @@ export async function parseRequest( const url = new URL(request.url); let query = Object.fromEntries(url.searchParams); let body = await getJsonBody(request); - let error: (() => Response) | undefined; + let error: () => undefined | undefined; let auth = null; if (schema) { diff --git a/src/queries/sql/reports/getJourney.ts b/src/queries/sql/reports/getJourney.ts index 362f7bdba..283e0fad4 100644 --- a/src/queries/sql/reports/getJourney.ts +++ b/src/queries/sql/reports/getJourney.ts @@ -60,7 +60,7 @@ async function relationalQuery( endStepQuery: string; params: Record; } { - const params: Record = {}; + const params = {}; let sequenceQuery = ''; let startStepQuery = ''; let endStepQuery = ''; @@ -172,7 +172,7 @@ async function clickhouseQuery( endStepQuery: string; params: Record; } { - const params: Record = {}; + const params = {}; let sequenceQuery = ''; let startStepQuery = ''; let endStepQuery = ''; From 3d8d5a7293329a3db62bc1774b464ad94c85d955 Mon Sep 17 00:00:00 2001 From: juanisidoro Date: Fri, 13 Feb 2026 08:39:05 +0100 Subject: [PATCH 3/4] fix: handle null referrer in pixel tracking route request.headers.get("referer") returns null when the header is absent (e.g. email clients). The Zod schema uses .optional() which accepts undefined but rejects null, causing silent validation failure and pixel events not being recorded. Fixes #4028 --- src/app/(collect)/p/[slug]/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/(collect)/p/[slug]/route.ts b/src/app/(collect)/p/[slug]/route.ts index 79d6faa5c..b1864d017 100644 --- a/src/app/(collect)/p/[slug]/route.ts +++ b/src/app/(collect)/p/[slug]/route.ts @@ -47,7 +47,7 @@ export async function GET(request: Request, { params }: { params: Promise<{ slug payload: { pixel: pixel.id, url: request.url, - referrer: request.headers.get('referer'), + referrer: request.headers.get("referer") || undefined, }, }; From c730442e5c72458c480d26817c76bdadf88a5a85 Mon Sep 17 00:00:00 2001 From: juanisidoro Date: Fri, 13 Feb 2026 09:23:15 +0100 Subject: [PATCH 4/4] fix: apply same null referrer fix to link tracking route The same bug exists in the link route (q/[slug]) where request.headers.get("referer") returns null for requests without a Referer header, causing silent Zod validation failure. --- src/app/(collect)/q/[slug]/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/(collect)/q/[slug]/route.ts b/src/app/(collect)/q/[slug]/route.ts index 24089bdb2..aa9c26f3f 100644 --- a/src/app/(collect)/q/[slug]/route.ts +++ b/src/app/(collect)/q/[slug]/route.ts @@ -45,7 +45,7 @@ export async function GET(request: Request, { params }: { params: Promise<{ slug payload: { link: link.id, url: request.url, - referrer: request.headers.get('referer'), + referrer: request.headers.get("referer") || undefined, }, };