From 2c5ca8adec1ee1211a5043ebfedd86d20cc745a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl-Gerhard=20Lindesva=CC=88rd?= Date: Wed, 21 Jan 2026 11:33:15 +0100 Subject: [PATCH] fix: validate revenue payload (must be int) --- packages/validation/src/track.validation.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/validation/src/track.validation.ts b/packages/validation/src/track.validation.ts index 409a70ff..18520f52 100644 --- a/packages/validation/src/track.validation.ts +++ b/packages/validation/src/track.validation.ts @@ -5,13 +5,25 @@ import { RESERVED_EVENT_NAMES } from '@openpanel/constants'; export const zTrackPayload = z .object({ name: z.string().min(1), - properties: z.record(z.unknown()).optional(), + properties: z.record(z.string(), z.unknown()).optional(), profileId: z.string().or(z.number()).optional(), }) .refine((data) => !RESERVED_EVENT_NAMES.includes(data.name as any), { message: `Event name cannot be one of the reserved names: ${RESERVED_EVENT_NAMES.join(', ')}`, path: ['name'], - }); + }) + .refine( + (data) => { + if (data.name !== 'revenue') return true; + const revenue = data.properties?.__revenue; + if (revenue === undefined) return true; + return Number.isInteger(revenue); + }, + { + message: '__revenue must be an integer (no floats or strings)', + path: ['properties', '__revenue'], + }, + ); export const zIdentifyPayload = z.object({ profileId: z.string().min(1),