From 6180c6622c88ca33d0d387a50be9036429281598 Mon Sep 17 00:00:00 2001 From: Mohamed Bassem Date: Sat, 6 Dec 2025 16:07:11 +0000 Subject: chore: add benchmarks (#2229) * chore: add benchmarks * upgrade deps * fixes * lint --- packages/benchmarks/src/seed.ts | 171 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 packages/benchmarks/src/seed.ts (limited to 'packages/benchmarks/src/seed.ts') diff --git a/packages/benchmarks/src/seed.ts b/packages/benchmarks/src/seed.ts new file mode 100644 index 00000000..286a1f66 --- /dev/null +++ b/packages/benchmarks/src/seed.ts @@ -0,0 +1,171 @@ +import pLimit from "p-limit"; + +import type { ZBookmarkList } from "@karakeep/shared/types/lists"; +import type { ZTagBasic } from "@karakeep/shared/types/tags"; +import { BookmarkTypes } from "@karakeep/shared/types/bookmarks"; + +import { logInfo, logStep, logSuccess } from "./log"; +import { getTrpcClient, TrpcClient } from "./trpc"; +import { waitUntil } from "./utils"; + +export interface SeedConfig { + bookmarkCount: number; + tagCount: number; + listCount: number; + concurrency: number; +} + +export interface SeededBookmark { + id: string; + tags: ZTagBasic[]; + listId?: string; + title: string | null | undefined; +} + +export interface SeedResult { + apiKey: string; + trpc: TrpcClient; + tags: ZTagBasic[]; + lists: ZBookmarkList[]; + bookmarks: SeededBookmark[]; + searchTerm: string; +} + +const TOPICS = [ + "performance", + "search", + "reading", + "workflow", + "api", + "workers", + "backend", + "frontend", + "productivity", + "cli", +]; + +export async function seedData(config: SeedConfig): Promise { + const authlessClient = getTrpcClient(); + const email = `benchmarks+${Date.now()}@example.com`; + const password = "benchmarks1234"; + + logStep("Creating benchmark user and API key"); + await authlessClient.users.create.mutate({ + name: "Benchmark User", + email, + password, + confirmPassword: password, + }); + const { key } = await authlessClient.apiKeys.exchange.mutate({ + email, + password, + keyName: "benchmark-key", + }); + + const trpc = getTrpcClient(key); + logSuccess("User ready"); + + logStep(`Creating ${config.tagCount} tags`); + const tags: ZTagBasic[] = []; + for (let i = 0; i < config.tagCount; i++) { + const tag = await trpc.tags.create.mutate({ + name: `topic-${i + 1}`, + }); + tags.push(tag); + } + logSuccess("Tags created"); + + logStep(`Creating ${config.listCount} lists`); + const lists: ZBookmarkList[] = []; + for (let i = 0; i < config.listCount; i++) { + const list = await trpc.lists.create.mutate({ + name: `List ${i + 1}`, + description: `Auto-generated benchmark list #${i + 1}`, + icon: "bookmark", + }); + lists.push(list); + } + logSuccess("Lists created"); + + logStep(`Creating ${config.bookmarkCount} bookmarks`); + const limit = pLimit(config.concurrency); + const bookmarks: SeededBookmark[] = []; + + await Promise.all( + Array.from({ length: config.bookmarkCount }).map((_, index) => + limit(async () => { + const topic = TOPICS[index % TOPICS.length]; + const createdAt = new Date(Date.now() - index * 3000); + const bookmark = await trpc.bookmarks.createBookmark.mutate({ + type: BookmarkTypes.LINK, + url: `https://example.com/${topic}/${index}`, + title: `Benchmark ${topic} article ${index}`, + source: "api", + summary: `Benchmark dataset entry about ${topic} performance and organization.`, + favourited: index % 7 === 0, + archived: false, + createdAt, + }); + + const primaryTag = tags[index % tags.length]; + const secondaryTag = tags[(index + 5) % tags.length]; + const attachedTags = [primaryTag, secondaryTag]; + await trpc.bookmarks.updateTags.mutate({ + bookmarkId: bookmark.id, + attach: attachedTags.map((tag) => ({ + tagId: tag.id, + tagName: tag.name, + })), + detach: [], + }); + + let listId: string | undefined; + if (lists.length > 0) { + const list = lists[index % lists.length]; + await trpc.lists.addToList.mutate({ + listId: list.id, + bookmarkId: bookmark.id, + }); + listId = list.id; + } + + bookmarks.push({ + id: bookmark.id, + tags: attachedTags, + listId, + title: bookmark.title, + }); + }), + ), + ); + logSuccess("Bookmarks created"); + + const searchTerm = "benchmark"; + logStep("Waiting for search index to be ready"); + await waitUntil( + async () => { + const results = await trpc.bookmarks.searchBookmarks.query({ + text: searchTerm, + limit: 1, + }); + return results.bookmarks.length > 0; + }, + "search data to be indexed", + 120_000, + 2_000, + ); + logSuccess("Search index warmed up"); + + logInfo( + `Seeded ${bookmarks.length} bookmarks across ${tags.length} tags and ${lists.length} lists`, + ); + + return { + apiKey: key, + trpc, + tags, + lists, + bookmarks, + searchTerm, + }; +} -- cgit v1.2.3-70-g09d2