Files
stats/packages/trpc/src/routers/session.ts
2026-03-16 13:31:48 +01:00

89 lines
2.4 KiB
TypeScript

import {
getSessionDistinctValues,
getSessionList,
getSessionReplayChunksFrom,
SESSION_DISTINCT_FIELDS,
sessionService,
} from '@openpanel/db';
import { zChartEventFilter } from '@openpanel/validation';
import { z } from 'zod';
import { createTRPCRouter, protectedProcedure } from '../trpc';
export function encodeCursor(cursor: {
createdAt: string;
id: string;
}): string {
const json = JSON.stringify(cursor);
return Buffer.from(json, 'utf8').toString('base64url'); // URL-safe
}
export function decodeCursor(
encoded: string
): { createdAt: string; id: string } | null {
try {
const json = Buffer.from(encoded, 'base64url').toString('utf8');
const obj = JSON.parse(json);
if (typeof obj.createdAt === 'string' && typeof obj.id === 'string') {
return obj;
}
return null;
} catch {
return null;
}
}
export const sessionRouter = createTRPCRouter({
list: protectedProcedure
.input(
z.object({
projectId: z.string(),
profileId: z.string().optional(),
cursor: z.string().nullish(),
filters: z.array(zChartEventFilter).default([]),
startDate: z.date().optional(),
endDate: z.date().optional(),
search: z.string().optional(),
take: z.number().default(50),
minPageViews: z.number().nullish(),
maxPageViews: z.number().nullish(),
minEvents: z.number().nullish(),
maxEvents: z.number().nullish(),
})
)
.query(({ input }) => {
return getSessionList({
...input,
cursor: input.cursor ? new Date(input.cursor) : undefined,
});
}),
distinctValues: protectedProcedure
.input(
z.object({
projectId: z.string(),
field: z.enum(SESSION_DISTINCT_FIELDS),
})
)
.query(({ input }) => {
return getSessionDistinctValues(input.projectId, input.field);
}),
byId: protectedProcedure
.input(z.object({ sessionId: z.string(), projectId: z.string() }))
.query(({ input: { sessionId, projectId } }) => {
return sessionService.byId(sessionId, projectId);
}),
replayChunksFrom: protectedProcedure
.input(
z.object({
sessionId: z.string(),
projectId: z.string(),
fromIndex: z.number().int().min(0).default(0),
})
)
.query(({ input: { sessionId, projectId, fromIndex } }) => {
return getSessionReplayChunksFrom(sessionId, projectId, fromIndex);
}),
});