aboutsummaryrefslogtreecommitdiff
path: root/scripts/seed/generators
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/seed/generators')
-rw-r--r--scripts/seed/generators/events.ts191
-rw-r--r--scripts/seed/generators/revenue.ts65
-rw-r--r--scripts/seed/generators/sessions.ts52
3 files changed, 308 insertions, 0 deletions
diff --git a/scripts/seed/generators/events.ts b/scripts/seed/generators/events.ts
new file mode 100644
index 0000000..7242906
--- /dev/null
+++ b/scripts/seed/generators/events.ts
@@ -0,0 +1,191 @@
+import { uuid, addSeconds, randomInt } from '../utils.js';
+import { getRandomReferrer } from '../distributions/referrers.js';
+import type { SessionData } from './sessions.js';
+
+export const EVENT_TYPE = {
+ pageView: 1,
+ customEvent: 2,
+} as const;
+
+export interface PageConfig {
+ path: string;
+ title: string;
+ weight: number;
+ avgTimeOnPage: number;
+}
+
+export interface CustomEventConfig {
+ name: string;
+ weight: number;
+ pages?: string[];
+ data?: Record<string, string[] | number[]>;
+}
+
+export interface JourneyConfig {
+ pages: string[];
+ weight: number;
+}
+
+export interface EventData {
+ id: string;
+ websiteId: string;
+ sessionId: string;
+ visitId: string;
+ eventType: number;
+ urlPath: string;
+ urlQuery: string | null;
+ pageTitle: string | null;
+ hostname: string;
+ referrerDomain: string | null;
+ referrerPath: string | null;
+ utmSource: string | null;
+ utmMedium: string | null;
+ utmCampaign: string | null;
+ utmContent: string | null;
+ utmTerm: string | null;
+ gclid: string | null;
+ fbclid: string | null;
+ eventName: string | null;
+ tag: string | null;
+ createdAt: Date;
+}
+
+export interface EventDataEntry {
+ id: string;
+ websiteId: string;
+ websiteEventId: string;
+ dataKey: string;
+ stringValue: string | null;
+ numberValue: number | null;
+ dateValue: Date | null;
+ dataType: number;
+ createdAt: Date;
+}
+
+export interface SiteConfig {
+ hostname: string;
+ pages: PageConfig[];
+ journeys: JourneyConfig[];
+ customEvents: CustomEventConfig[];
+}
+
+function getPageTitle(pages: PageConfig[], path: string): string | null {
+ const page = pages.find(p => p.path === path);
+ return page?.title ?? null;
+}
+
+function getPageTimeOnPage(pages: PageConfig[], path: string): number {
+ const page = pages.find(p => p.path === path);
+ return page?.avgTimeOnPage ?? 30;
+}
+
+export function generateEventsForSession(
+ session: SessionData,
+ siteConfig: SiteConfig,
+ journey: string[],
+): { events: EventData[]; eventDataEntries: EventDataEntry[] } {
+ const events: EventData[] = [];
+ const eventDataEntries: EventDataEntry[] = [];
+ const visitId = uuid();
+
+ let currentTime = session.createdAt;
+ const referrer = getRandomReferrer();
+
+ for (let i = 0; i < journey.length; i++) {
+ const pagePath = journey[i];
+ const isFirstPage = i === 0;
+
+ const eventId = uuid();
+ const pageTitle = getPageTitle(siteConfig.pages, pagePath);
+
+ events.push({
+ id: eventId,
+ websiteId: session.websiteId,
+ sessionId: session.id,
+ visitId,
+ eventType: EVENT_TYPE.pageView,
+ urlPath: pagePath,
+ urlQuery: null,
+ pageTitle,
+ hostname: siteConfig.hostname,
+ referrerDomain: isFirstPage ? referrer.domain : null,
+ referrerPath: isFirstPage ? referrer.path : null,
+ utmSource: isFirstPage ? referrer.utmSource : null,
+ utmMedium: isFirstPage ? referrer.utmMedium : null,
+ utmCampaign: isFirstPage ? referrer.utmCampaign : null,
+ utmContent: isFirstPage ? referrer.utmContent : null,
+ utmTerm: isFirstPage ? referrer.utmTerm : null,
+ gclid: isFirstPage ? referrer.gclid : null,
+ fbclid: isFirstPage ? referrer.fbclid : null,
+ eventName: null,
+ tag: null,
+ createdAt: currentTime,
+ });
+
+ // Check for custom events on this page
+ for (const customEvent of siteConfig.customEvents) {
+ // Check if this event can occur on this page
+ if (customEvent.pages && !customEvent.pages.includes(pagePath)) {
+ continue;
+ }
+
+ // Random chance based on weight
+ if (Math.random() < customEvent.weight) {
+ currentTime = addSeconds(currentTime, randomInt(2, 15));
+
+ const customEventId = uuid();
+ events.push({
+ id: customEventId,
+ websiteId: session.websiteId,
+ sessionId: session.id,
+ visitId,
+ eventType: EVENT_TYPE.customEvent,
+ urlPath: pagePath,
+ urlQuery: null,
+ pageTitle,
+ hostname: siteConfig.hostname,
+ referrerDomain: null,
+ referrerPath: null,
+ utmSource: null,
+ utmMedium: null,
+ utmCampaign: null,
+ utmContent: null,
+ utmTerm: null,
+ gclid: null,
+ fbclid: null,
+ eventName: customEvent.name,
+ tag: null,
+ createdAt: currentTime,
+ });
+
+ // Generate event data if configured
+ if (customEvent.data) {
+ for (const [key, values] of Object.entries(customEvent.data)) {
+ const value = values[Math.floor(Math.random() * values.length)];
+ const isNumber = typeof value === 'number';
+
+ eventDataEntries.push({
+ id: uuid(),
+ websiteId: session.websiteId,
+ websiteEventId: customEventId,
+ dataKey: key,
+ stringValue: isNumber ? null : String(value),
+ numberValue: isNumber ? value : null,
+ dateValue: null,
+ dataType: isNumber ? 2 : 1, // 1 = string, 2 = number
+ createdAt: currentTime,
+ });
+ }
+ }
+ }
+ }
+
+ // Time spent on page before navigating
+ const timeOnPage = getPageTimeOnPage(siteConfig.pages, pagePath);
+ const variance = Math.floor(timeOnPage * 0.5);
+ const actualTime = timeOnPage + randomInt(-variance, variance);
+ currentTime = addSeconds(currentTime, Math.max(5, actualTime));
+ }
+
+ return { events, eventDataEntries };
+}
diff --git a/scripts/seed/generators/revenue.ts b/scripts/seed/generators/revenue.ts
new file mode 100644
index 0000000..deea9e6
--- /dev/null
+++ b/scripts/seed/generators/revenue.ts
@@ -0,0 +1,65 @@
+import { uuid, randomFloat } from '../utils.js';
+import type { EventData } from './events.js';
+
+export interface RevenueConfig {
+ eventName: string;
+ minAmount: number;
+ maxAmount: number;
+ currency: string;
+ weight: number;
+}
+
+export interface RevenueData {
+ id: string;
+ websiteId: string;
+ sessionId: string;
+ eventId: string;
+ eventName: string;
+ currency: string;
+ revenue: number;
+ createdAt: Date;
+}
+
+export function generateRevenue(event: EventData, config: RevenueConfig): RevenueData | null {
+ if (event.eventName !== config.eventName) {
+ return null;
+ }
+
+ if (Math.random() > config.weight) {
+ return null;
+ }
+
+ const revenue = randomFloat(config.minAmount, config.maxAmount);
+
+ return {
+ id: uuid(),
+ websiteId: event.websiteId,
+ sessionId: event.sessionId,
+ eventId: event.id,
+ eventName: event.eventName!,
+ currency: config.currency,
+ revenue: Math.round(revenue * 100) / 100, // Round to 2 decimal places
+ createdAt: event.createdAt,
+ };
+}
+
+export function generateRevenueForEvents(
+ events: EventData[],
+ configs: RevenueConfig[],
+): RevenueData[] {
+ const revenueEntries: RevenueData[] = [];
+
+ for (const event of events) {
+ if (!event.eventName) continue;
+
+ for (const config of configs) {
+ const revenue = generateRevenue(event, config);
+ if (revenue) {
+ revenueEntries.push(revenue);
+ break; // Only one revenue per event
+ }
+ }
+ }
+
+ return revenueEntries;
+}
diff --git a/scripts/seed/generators/sessions.ts b/scripts/seed/generators/sessions.ts
new file mode 100644
index 0000000..1370511
--- /dev/null
+++ b/scripts/seed/generators/sessions.ts
@@ -0,0 +1,52 @@
+import { uuid } from '../utils.js';
+import { getRandomDevice } from '../distributions/devices.js';
+import { getRandomGeo, getRandomLanguage } from '../distributions/geographic.js';
+import { generateTimestampForDay } from '../distributions/temporal.js';
+
+export interface SessionData {
+ id: string;
+ websiteId: string;
+ browser: string;
+ os: string;
+ device: string;
+ screen: string;
+ language: string;
+ country: string;
+ region: string;
+ city: string;
+ createdAt: Date;
+}
+
+export function createSession(websiteId: string, day: Date): SessionData {
+ const deviceInfo = getRandomDevice();
+ const geo = getRandomGeo();
+ const language = getRandomLanguage();
+ const createdAt = generateTimestampForDay(day);
+
+ return {
+ id: uuid(),
+ websiteId,
+ browser: deviceInfo.browser,
+ os: deviceInfo.os,
+ device: deviceInfo.device,
+ screen: deviceInfo.screen,
+ language,
+ country: geo.country,
+ region: geo.region,
+ city: geo.city,
+ createdAt,
+ };
+}
+
+export function createSessions(websiteId: string, day: Date, count: number): SessionData[] {
+ const sessions: SessionData[] = [];
+
+ for (let i = 0; i < count; i++) {
+ sessions.push(createSession(websiteId, day));
+ }
+
+ // Sort by createdAt to maintain chronological order
+ sessions.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
+
+ return sessions;
+}