Conversation
Co-authored-by: eassanassar <eassanassar@gmail.com>
|
Cursor Agent can help with this pull request. Just |
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
WalkthroughAdds a new Reference Documentation section and multiple detailed reference pages under docs/reference covering HTTP API, SDK, Auth, DB, Redis, RPC, Mapper, Shared utilities, and Validation. Content includes endpoints, public APIs, usage examples, and notes. No source code changes; one doc notes newly documented Redis exports. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Client
participant API as HTTP API
participant DB as Database
participant CH as ClickHouse
participant Redis
Client->>API: GET /health
API->>DB: Check connection
API->>CH: Check connection
API->>Redis: Check connection
API-->>Client: Status report
Client->>API: POST /v1/query/compile (query)
API-->>Client: Compiled query / validation result
Client->>API: POST /v1/query (batch/single)
API->>CH: Execute compiled query
CH-->>API: Result rows
API-->>Client: Query response
sequenceDiagram
autonumber
participant Client
participant API as Assistant Stream
participant Model as LLM
Client->>API: POST /v1/assistant/stream {message, website_id, model, context}
API->>Model: Stream generate(message, context)
Model-->>API: Stream chunks
API-->>Client: SSE/stream chunks
Client->>Client: ReadableStream consumption
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
There was a problem hiding this comment.
Actionable comments posted: 43
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these settings in your CodeRabbit configuration.
📒 Files selected for processing (10)
docs/reference/README.md(1 hunks)docs/reference/api.md(1 hunks)docs/reference/auth.md(1 hunks)docs/reference/db.md(1 hunks)docs/reference/mapper.md(1 hunks)docs/reference/redis.md(1 hunks)docs/reference/rpc.md(1 hunks)docs/reference/sdk.md(1 hunks)docs/reference/shared.md(1 hunks)docs/reference/validation.md(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-29T15:42:16.889Z
Learnt from: CR
PR: databuddy-analytics/Databuddy#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-07-29T15:42:16.889Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Do not use `ioredis`; use `Bun.redis` for Redis
Applied to files:
docs/reference/redis.md
🪛 LanguageTool
docs/reference/auth.md
[grammar] ~1-~1: Use correct spacing
Context: ## @databuddy/auth ### Overview - Wraps better-auth with Driz...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~7-~7: Use colons correctly
Context: ...n({ headers }), etc.) - websitesApi: { hasPermission: auth.api.hasPermission } - Types:User, Session` - Permissions...
(QB_NEW_EN_OTHER_ERROR_IDS_30)
[grammar] ~8-~8: Use correct spacing
Context: ...api.hasPermission } - Types:User, Session` - Permissions/roles helpers ### Getting t...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~9-~9: Use correct spacing
Context: ... Session - Permissions/roles helpers ### Getting the current session (server) ```...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~11-~11: Use correct spacing
Context: ...### Getting the current session (server) ts import { auth } from '@databuddy/auth'; const session = await auth.api.getSession({ headers: request.headers }); if (!session?.user) { // not authenticated } ### Checking website permissions ```ts impor...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~21-~21: Use correct spacing
Context: ... } ### Checking website permissionsts import { websitesApi } from '@databuddy/auth'; const { success } = await websitesApi.hasPermission({ headers: request.headers, body: { permissions: { website: ['read'] } }, }); ``` ### Notes - The package configures email del...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
docs/reference/mapper.md
[grammar] ~1-~1: Use correct spacing
Context: ## @databuddy/mapper ### Overview - Normalizes third-party analyt...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~3-~3: There might be a mistake here.
Context: ## @databuddy/mapper ### Overview - Normalizes third-party analytics export ...
(QB_NEW_EN)
[grammar] ~4-~4: Use proper capitalization
Context: ... third-party analytics export rows into Databuddy AnalyticsEvent objects. - Exports: ...
(QB_NEW_EN_OTHER_ERROR_IDS_6)
[grammar] ~4-~4: There might be a mistake here.
Context: ...into Databuddy AnalyticsEvent objects. - Exports: - mapEvents(adapter, rows) ...
(QB_NEW_EN)
[grammar] ~5-~5: Use correct spacing
Context: ...ddy AnalyticsEvent objects. - Exports: - mapEvents(adapter, rows) - adapters.umami(clientId) and AnalyticsEventAdapter type ### U...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~7-~7: Use correct spacing
Context: ...entId)andAnalyticsEventAdapter` type ### Umami Adapter ```ts import { adapters, m...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~9-~9: Use correct spacing
Context: ...icsEventAdaptertype ### Umami Adapter ```ts import { adapters, mapEvents } from '@databuddy/mapper'; const adapter = adapters.umami('YOUR_CLIENT_ID'); const events = mapEvents(adapter, umamiCsvRows); // events: AnalyticsEvent[] ready for ingestion ``` The adapter maps fields likesession_id...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
docs/reference/db.md
[grammar] ~1-~1: Use correct spacing
Context: ## @databuddy/db ### Overview - Exposes Drizzle ORM (`export ...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~5-~5: Use correct spacing
Context: ...lations` so you can write typed queries. ### Usage ```ts import { db, eq, websites } ...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~7-~7: Use correct spacing
Context: ... you can write typed queries. ### Usage ts import { db, eq, websites } from '@databuddy/db'; const list = await db.query.websites.findMany({ where: eq(websites.userId, userId), limit: 20, }); ### Environment - Requires DATABASE_URL to...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
docs/reference/README.md
[grammar] ~1-~1: Use correct spacing
Context: ## Reference Documentation - SDK: sdk.md - HTTP API...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
docs/reference/api.md
[grammar] ~1-~1: Use correct spacing
Context: ## HTTP API Base URL examples: - Production: `https:...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~3-~3: There might be a mistake here.
Context: ## HTTP API Base URL examples: - Production: https://api.databuddy.cc -...
(QB_NEW_EN)
[grammar] ~4-~4: There might be a mistake here.
Context: ...P API Base URL examples: - Production: https://api.databuddy.cc - Local dev: your apps/api server (defau...
(QB_NEW_EN)
[grammar] ~5-~5: Use correct spacing
Context: ...ur apps/api server (default port 3001) Authentication: - Most routes require ei...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~7-~7: There might be a mistake here.
Context: ...ver (default port 3001) Authentication: - Most routes require either a logged-in s...
(QB_NEW_EN)
[grammar] ~8-~8: Use correct spacing
Context: ...x-api-keyheader scoped to the website. ### Health - **GET**/health` - Returns ser...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~13-~13: Use correct spacing
Context: ...ckHouse, Database, and Redis. - Example: bash curl -s https://api.databuddy.cc/health | jq ### Query API (analytics) - Prefix: `/v1...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~20-~20: Use correct spacing
Context: ... authenticated (session or x-api-key). - GET `/v1/query/types?include_meta=true...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~24-~24: Use correct spacing
Context: ..., defaults, optional meta). - Example: bash curl -s "https://api.databuddy.cc/v1/query/types?include_meta=true" \ -H "cookie: ...session..." | jq - POST /v1/query/compile - Validates...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~32-~32: Use correct spacing
Context: ...t without executing it. - Body fields: - projectId (string), type (string), from (ISO d...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~33-~33: There might be a mistake here.
Context: ...ing), from (ISO date), to (ISO date) - Optional: timeUnit, filters[], `grou...
(QB_NEW_EN)
[grammar] ~34-~34: Use commas correctly
Context: ...ters[], groupBy[], orderBy, limit, offset` - Example: ```bash curl -s -X POST https:/...
(QB_NEW_EN_OTHER_ERROR_IDS_33)
[grammar] ~35-~35: Use correct spacing
Context: ...orderBy, limit, offset - Example: ```bash curl -s -X POST https://api.databuddy.cc/v1/query/compile?website_id=WEBSITE_ID \ -H "content-type: application/json" \ -H "cookie: ...session..." \ -d '{ "projectId": "WEBSITE_ID", "type": "summary_overview", "from": "2025-01-01", "to": "2025-01-31", "timeUnit": "day", "limit": 100 }' | jq ``` - **POST**/v1/query` - Executes one or m...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~52-~52: Use colons correctly
Context: ...nput (array). - Body (single request): - parameters: Array of strings or objects `{ name, st...
(QB_NEW_EN_OTHER_ERROR_IDS_30)
[grammar] ~53-~53: There might be a mistake here.
Context: ...parameters: Array of strings or objects { name, start_date?, end_date?, granularity?, id? } - Optional:limit, page, filters[]`, ...
(QB_NEW_EN_OTHER)
[grammar] ~54-~54: There might be a mistake here.
Context: ...rity, groupBy, startDate, endDate, timeZone` - Example (single): ```bash curl -s -X POS...
(QB_NEW_EN_OTHER)
[grammar] ~55-~55: Use correct spacing
Context: ...dDate, timeZone` - Example (single): bash curl -s -X POST "https://api.databuddy.cc/v1/query?website_id=WEBSITE_ID" \ -H "content-type: application/json" \ -H "x-api-key: YOUR_WEBSITE_API_KEY" \ -d '{ "parameters": ["summary_overview"], "limit": 50, "granularity": "daily" }' | jq - Example (batch): ```bash curl -s -X POST...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~66-~66: Use correct spacing
Context: ...aily" }' | jq - Example (batch):bash curl -s -X POST "https://api.databuddy.cc/v1/query?website_id=WEBSITE_ID" \ -H "content-type: application/json" \ -H "cookie: ...session..." \ -d '[ { "parameters": ["summary_overview"], "granularity": "daily" }, { "parameters": [{ "name": "pages_top", "start_date": "2025-01-01", "end_date": "2025-01-31" }] } ]' | jq ``` ### Assistant API (streaming) - Prefix: ...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~81-~81: There might be a mistake here.
Context: ... a given website and message. - Body: { message: string, website_id: string, model?: 'chat'|'agent'|'agent-max', context?: { previousMessages?: { role?: string, content: string }[] } } - Example (fetch streaming): ```ts async f...
(QB_NEW_EN)
[grammar] ~82-~82: Use correct spacing
Context: ... }[] } }` - Example (fetch streaming): ts async function streamAssistant() { const res = await fetch('https://api.databuddy.cc/v1/assistant/stream?website_id=WEBSITE_ID', { method: 'POST', headers: { 'content-type': 'application/json', 'cookie': '...session...' }, body: JSON.stringify({ message: 'Show sessions trend', website_id: 'WEBSITE_ID' }) }); const reader = res.body!.getReader(); const decoder = new TextDecoder(); while (true) { const { value, done } = await reader.read(); if (done) break; console.log(decoder.decode(value)); // streaming updates } } ### Authentication Notes - Routes enforce we...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
docs/reference/shared.md
[grammar] ~1-~1: Use correct spacing
Context: ## @databuddy/shared ### Utilities #### Date Utilities - `format...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~3-~3: Use correct spacing
Context: ## @databuddy/shared ### Utilities #### Date Utilities - `formatDate(date, optio...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~5-~5: Use correct spacing
Context: ...ared ### Utilities #### Date Utilities - formatDate(date, options?): string - Options: timezone, dateFormat, `time...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~7-~7: Insert the missing word
Context: ..., dateFormat, timeFormat, showTime, customFormat. ```ts import { formatDa...
(QB_NEW_EN_OTHER_ERROR_IDS_32)
[grammar] ~7-~7: Use correct spacing
Context: ...timeFormat, showTime, customFormat. ```ts import { formatDate, convertToTimezone, formatRelativeTime } from '@databuddy/shared'; formatDate('2025-01-01', { timezone: 'UTC' }); formatDate(Date.now(), { showTime: true }); convertToTimezone('2025-01-01T00:00:00Z', 'America/New_York'); formatRelativeTime(Date.now() - 3600_000); // "an hour ago" ``` - getBrowserTimezone(): string-findTimezoneByRegion(region: string) #### ID Utility -createId(type?: 'UUID' | '...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~20-~20: Use correct spacing
Context: ...Region(region: string) #### ID Utility -createId(type?: 'UUID' | 'NANOID'): string```ts import { createId } from '@databuddy/shared'; createId(); // UUID v4 createId('NANOID'); // 10-char nanoid ``` #### Discord Webhook Utilities -initializeD...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~29-~29: Use correct spacing
Context: ...noid ``` #### Discord Webhook Utilities - initializeDiscordWebhook(url, options?) => DiscordWebhook - `initializeErrorWebhook(url) => DiscordWebhook` - `initializeActivityWebhook(url) => DiscordWebhook` - `getDefaultWebhook() | getErrorWebhook() | getActivityWebhook()` - `discord` convenience object - `logger` pre-confi...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~34-~34: Use correct spacing
Context: ...ebhook()-discordconvenience object -logger` pre-configured instance Example: ```ts ...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~35-~35: Use correct spacing
Context: ...bject - logger pre-configured instance Example: ```ts import { initializeDiscor...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~37-~37: There might be a problem here.
Context: ...oggerpre-configured instance Example: ```ts import { initializeDiscordWebhook, discord, logger } from '@databuddy/shared'; initializeDiscordWebhook(process.env.DISCORD_WEBHOOK_URL!); await discord.log.success('Deployment', 'New version deployed', { version: '1.2.3' }); try { throw new Error('Boom'); } catch (e) { logger.exception(e as Error, { service: 'api' }); } ``` ### Lists -filterOptions`: array of allowed filter fields for quer...
(QB_NEW_EN_MERGED_MATCH)
[grammar] ~52-~52: There might be a mistake here.
Context: ...owed filter fields for query UI and API. - TIMEZONES, bots, referrers: curated datasets ...
(QB_NEW_EN)
[grammar] ~53-~53: Use correct spacing
Context: ...rrers`: curated datasets for enrichment. ### Types - Various types for metrics, pages...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~55-~55: There might be a mistake here.
Context: ...ated datasets for enrichment. ### Types - Various types for metrics, pages, journe...
(QB_NEW_EN)
[grammar] ~56-~56: There might be a mistake here.
Context: ...ages, journeys, errors, website models, realtime payloads, etc. Import from `@databuddy/...
(QB_NEW_EN_OTHER)
docs/reference/validation.md
[grammar] ~1-~1: There might be a problem here.
Context: ## @databuddy/validation ### Constants - MAX_FUTURE_MS, MIN_TIMESTAMP - VALIDATION_LIMITS: field length and range limits used acro...
(QB_NEW_EN_MERGED_MATCH)
[grammar] ~5-~5: Use correct spacing
Context: ...and range limits used across validation. ### Regexes - RESOLUTION_REGEX, `RESOLUTIO...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~7-~7: There might be a mistake here.
Context: ...its used across validation. ### Regexes - RESOLUTION_REGEX, RESOLUTION_SIMPLE_REGEX - `LANGUAGE_...
(QB_NEW_EN_OTHER)
[grammar] ~8-~8: There might be a mistake here.
Context: ...ion. ### Regexes - RESOLUTION_REGEX, RESOLUTION_SIMPLE_REGEX - LANGUAGE_REGEX, TIMEZONE_REGEX, SESSION_ID_REGEX - ...
(QB_NEW_EN)
[grammar] ~9-~9: There might be a mistake here.
Context: ...-LANGUAGE_REGEX, TIMEZONE_REGEX, SESSION_ID_REGEX-LOCALHOST_URL_REGEX, DURATION_REGEX-WEBSITE_NAME_REGEX, DOMAIN_REGEX, SUBDOMAIN_REGEX` ### ...
(QB_NEW_EN_OTHER)
[grammar] ~11-~11: Use commas correctly
Context: ...-WEBSITE_NAME_REGEX, DOMAIN_REGEX, SUBDOMAIN_REGEX ### Utilities -parseDurationToSeconds(dur...
(QB_NEW_EN_OTHER_ERROR_IDS_33)
[grammar] ~13-~13: Use correct spacing
Context: ...REGEX, SUBDOMAIN_REGEX ### Utilities -parseDurationToSeconds(duration: string): number```ts parseDurationToSeconds('15s'); // 15 parseDurationToSeconds('2m'); // 120 parseDurationToSeconds('1h'); // 3600 parseDurationToSeconds('1d'); // 86400 ``` -sanitizeString(input: unknown, maxLength?: number): string` - Trims, removes control chars and HTML sp...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~24-~24: Insert the missing word
Context: ... removes control chars and HTML specials, collapses whitespace. - `validateTimez...
(QB_NEW_EN_OTHER_ERROR_IDS_32)
[grammar] ~24-~24: Use correct spacing
Context: ...and HTML specials, collapses whitespace. - validateTimezone(value: unknown): string - validateTimezoneOffset(value: unknown): number | null - validateLanguage(value: unknown): string - validateSessionId(value: unknown): string - validateUtmParameter(value: unknown): string - validateNumeric(value: unknown, min?: number, max?: number): number | null - validateUrl(value: unknown): string - filterSafeHeaders(headers: Record<string, string|string[]|undefined>): Record<string, string> - validateProperties(properties: unknown): Record<string, unknown> - validatePayloadSize(data: unknown, maxSizeBytes = 1_048_576): boolean - validatePerformanceMetric(value: unknown): number | undefined - validateScreenResolution(value: unknown): string - validateViewportSize(value: unknown): string - validateScrollDepth(value: unknown): number | null - validatePageCount(value: unknown): number | null - validateInteractionCount(value: unknown): number | null - validateExitIntent(value: unknown): number Example: ```ts import { validateUrl, ...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~44-~44: Use correct spacing
Context: ...ntent(value: unknown): number Example: ```ts import { validateUrl, validateLanguage, validateProperties, filterSafeHeaders, } from '@databuddy/validation'; const url = validateUrl('https://example.com/path?x=1'); const lang = validateLanguage('en-US'); const props = validateProperties({ name: ' Alice ', score: '42', active: true, unset: undefined }); // props -> { name: 'Alice', score: 42, active: true, unset: null } const safe = filterSafeHeaders({ 'User-Agent': 'X', 'X-Secret': 'hidden' }); // safe -> { 'user-agent': 'X' } ``` ### Schemas (zod) -analyticsEventSchema` -...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~62-~62: Use correct spacing
Context: ...ser-agent': 'X' } ``` ### Schemas (zod) - analyticsEventSchema - `batchAnalyticsEventSchema`, `batchAnalyticsEventsSchema` - `emailE...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~64-~64: There might be a mistake here.
Context: ...tSchema-batchAnalyticsEventSchema, batchAnalyticsEventsSchema-emailEventSchema, batchEmailEventSchema-errorEventS...
(QB_NEW_EN)
[grammar] ~65-~65: There might be a problem here.
Context: ...ticsEventsSchema-emailEventSchema, batchEmailEventSchema-errorEventSchema-webVitalsEventSchema-websiteNameSchema, domainSchema, subdomainSchema, cre...
(QB_NEW_EN_MERGED_MATCH)
[grammar] ~68-~68: Use correct spacing
Context: ...eWebsiteSchema, updateWebsiteSchema, transferWebsiteSchema` Usage: ```ts import { analyticsEventSche...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~70-~70: Use correct spacing
Context: ...Schema, transferWebsiteSchema` Usage: ts import { analyticsEventSchema } from '@databuddy/validation'; const parsed = analyticsEventSchema.parse(input);
(QB_NEW_EN_OTHER_ERROR_IDS_5)
docs/reference/sdk.md
[grammar] ~1-~1: Use correct spacing
Context: ## @databuddy/sdk ### Installation ```bash bun add @databuddy...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~3-~3: Use correct spacing
Context: ## @databuddy/sdk ### Installation bash bun add @databuddy/sdk # or npm install @databuddy/sdk ### React Component: Databuddy - Import...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~11-~11: Use correct spacing
Context: .../sdk ### React Component: Databuddy - **Import**:tsx import { Databuddy } fr...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~13-~13: Use correct spacing
Context: ...eact Component: Databuddy - Import: tsx import { Databuddy } from '@databuddy/sdk'; - Usage (Next.js root layout): ```tsx ex...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~17-~17: Use correct spacing
Context: ...; - **Usage (Next.js root layout)**:tsx export default function RootLayout({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` - Props: See DatabuddyConfig below. Th...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~37-~37: Use correct spacing
Context: ...ersiondefaults to the package version. ### Types -DatabuddyConfig`: Full configu...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~39-~39: Use correct spacing
Context: ...aults to the package version. ### Types - DatabuddyConfig: Full configuration for the component a...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~42-~42: Use correct spacing
Context: ...and property shapes used by the tracker. ### Tracker APIs - `isTrackerAvailable(): b...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~44-~44: Use correct spacing
Context: ...s used by the tracker. ### Tracker APIs - isTrackerAvailable(): boolean - Returns true if window.databuddy or `w...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~48-~48: Use correct spacing
Context: ....dbexists in the browser. - Example: ```ts import { isTrackerAvailable } from '@databuddy/sdk'; if (isTrackerAvailable()) { console.log('Databuddy tracker ready'); } ``` -getTracker(): DatabuddyTracker | null` - Returns the global tracker instance if a...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~59-~59: Use correct spacing
Context: ...cker instance if available. - Example: ts import { getTracker } from '@databuddy/sdk'; const tracker = getTracker(); tracker?.screenView('/pricing'); - track<T extends EventName>(eventName: T, properties?: PropertiesForEvent<T>): Promise<void> - Type-safe event tracking helper that pro...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~69-~69: Use correct spacing
Context: ...r window.databuddy.track. - Example: ts import { track } from '@databuddy/sdk'; await track('screen_view', { scroll_depth: 80, is_bounce: 0 }); await track('error', { message: 'Oops', error_type: 'NetworkError' }); - trackError(message: string, properties?: { filename?; lineno?; colno?; stack?; error_type?; [k: string]: any }): Promise<void> - Convenience wrapper around `track('error...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~78-~78: Use correct spacing
Context: ...ce wrapper around track('error', ...). - clear(): void - Clears the current session via `window.d...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~81-~81: Use correct spacing
Context: ....clear()orwindow.databuddy.clear(). - flush(): void` - Flushes any queued events. ### Global W...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~84-~84: Use correct spacing
Context: ...(): void - Flushes any queued events. ### Global Window Shorthands -window.db.t...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~86-~86: There might be a problem here.
Context: ...ed events. ### Global Window Shorthands - window.db.track(...), window.db.screenView(...), `window.db...
(QB_NEW_EN_MERGED_MATCH)
[grammar] ~88-~88: Insert the missing word
Context: ...db.screenView(...), window.db.clear(), window.db.flush()` are supported by th...
(QB_NEW_EN_OTHER_ERROR_IDS_32)
[grammar] ~88-~88: Use correct spacing
Context: ...ers above proxy to these when available. ### Example: Custom Interaction Tracking ```...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~90-~90: Use correct spacing
Context: ...### Example: Custom Interaction Tracking ts import { track } from '@databuddy/sdk'; function SignupButton() { return ( <button onClick={() => track('button_click', { button_text: 'Sign up', button_id: 'signup-cta' })} > Sign up </button> ); }
(QB_NEW_EN_OTHER_ERROR_IDS_5)
docs/reference/rpc.md
[grammar] ~1-~1: Use correct spacing
Context: ## @databuddy/rpc ### Overview - Uses tRPC for type-safe serve...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~5-~5: There might be a mistake here.
Context: ... type-safe server procedures. - Exports: - appRouter, type AppRouter - `createTRPCContex...
(QB_NEW_EN)
[grammar] ~6-~6: There might be a mistake here.
Context: ...procedures. - Exports: - appRouter, type AppRouter - createTRPCContext, createTRPCRouter, publicProcedure,...
(QB_NEW_EN)
[grammar] ~7-~7: There might be a mistake here.
Context: ...dure, rateLimitedProtectedProcedure, rateLimitedAdminProcedure -getRateLimitIdentifier, rateLimiters` ### Context ```ts impo...
(QB_NEW_EN)
[grammar] ~8-~8: Use correct spacing
Context: ...rocedure -getRateLimitIdentifier, rateLimiters` ### Context ```ts import { createTRPCContext...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~10-~10: Use correct spacing
Context: ...Identifier, rateLimiters` ### Context ts import { createTRPCContext } from '@databuddy/rpc'; // Called per request (headers required) const ctx = await createTRPCContext({ headers: request.headers }); // ctx = { db, auth, session, user, headers } ### Routers ```ts import { createTRPCRouter,...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~19-~19: Use correct spacing
Context: ...ession, user, headers } ### Routersts import { createTRPCRouter, publicProcedure, protectedProcedure } from '@databuddy/rpc'; export const exampleRouter = createTRPCRouter({ hello: publicProcedure.query(() => 'world'), me: protectedProcedure.query(({ ctx }) => ctx.user), }); ``` The appRouter mounts feature routers l...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~29-~29: Insert the missing word
Context: ...ces, goals, autocomplete, apikeys, experiments`. ### Rate Limiting Utili...
(QB_NEW_EN_OTHER_ERROR_IDS_32)
[grammar] ~29-~29: Use correct spacing
Context: ...autocomplete, apikeys, experiments. ### Rate Limiting Utilities - getRateLimitI...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[uncategorized] ~31-~31: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...mplete, apikeys, experiments. ### Rate Limiting Utilities - getRateLimitIdentifier(use...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
[grammar] ~31-~31: Use correct spacing
Context: ...periments. ### Rate Limiting Utilities - getRateLimitIdentifier(userId?: string, headers?: Headers): string-RateLimiterclass with methods: -checkLimit(ide...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~33-~33: Use correct spacing
Context: ...ing-RateLimiterclass with methods: -checkLimit(identifier: string): Promise<{ success; limit; remaining; reset; }> -getStatus(identifier: string) -reset(identifier: string)- Built-inrateLimiters: api, auth`, ...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~37-~37: Use correct spacing
Context: ... auth, expensive, admin, public. Use within procedures via `rateLimitedPr...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~39-~39: Use correct spacing
Context: ... or in HTTP middleware (see apps/api). ### Referrer Utilities - `parseReferrer(refe...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~41-~41: Use correct spacing
Context: ...see apps/api). ### Referrer Utilities - parseReferrer(referrerUrl: string | null | undefined, currentDomain?: string): { type; name; url; domain } - categorizeReferrer(info): string - isInternalReferrer(referrerUrl: string, websiteHostname?: string): boolean Example: ```ts import { parseReferrer, c...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~46-~46: Use correct spacing
Context: ...teHostname?: string): boolean Example: ```ts import { parseReferrer, categorizeReferrer } from '@databuddy/rpc/utils/referrer'; const info = parseReferrer('https://www.google.com/search?q=databuddy', 'example.com'); // { type: 'search', name: 'www.google.com', ... } const category = categorizeReferrer(info); // 'Search Engine' ``` ### Auth Utilities -authorizeWebsiteAccess...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~55-~55: Use correct spacing
Context: ... 'Search Engine' ``` ### Auth Utilities - authorizeWebsiteAccess(ctx, websiteId, permission: 'read'|'update'|'delete'|'transfer') - Ensures the current user (from tRPC cont...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~57-~57: Use correct spacing
Context: ...rmissions; throws TRPCError otherwise. ts import { authorizeWebsiteAccess } from '@databuddy/rpc/utils/auth'; export const websitesRouter = createTRPCRouter({ get: protectedProcedure.input(z.string()).query(async ({ ctx, input }) => { const site = await authorizeWebsiteAccess(ctx, input, 'read'); return site; }) }); ### Billing Utilities - `checkAndTrackWebsit...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~69-~69: Use correct spacing
Context: ...ite; }) }); ``` ### Billing Utilities - checkAndTrackWebsiteCreation(customerId: string) → `{ allowed: boolean, error?: string }`...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~70-~70: Use correct spacing
Context: ...kWebsiteCreation(customerId: string)→{ allowed: boolean, error?: string }-trackWebsiteUsage(customerId: string, value: number)→{ success: boolean }-getBillingC...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~71-~71: Use correct spacing
Context: ...e(customerId: string, value: number)→{ success: boolean }-getBillingCustomerId(userId: string, organizationId?: string|null): Promise ```ts import { getBillingCustomerId, checkAndTrackWebsiteCreation } from '@databuddy/rpc/utils/billing'; const customerId = await getBillingCustomerId(ctx.user.id, ctx.user.organizationId); const { allowed } = await checkAndTrackWebsiteCreation(customerId); if (!allowed) throw new TRPCError({ code: 'FORBIDDEN' }); ``` ### Cache Invalidation Helpers -invalidate...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~82-~82: Use correct spacing
Context: ... }); ### Cache Invalidation Helpers - `invalidateBasicWebsiteCaches(websiteId, websiteCache)` - `invalidateWebsiteCaches(websiteId, userId, reason?)` ts import { createDrizzleCache, redis } from '@databuddy/redis'; import { invalidateBasicWebsiteCaches, invalidateWebsiteCaches } from '@databuddy/rpc/utils/cache-invalidation'; const websiteCache = createDrizzleCache({ redis, namespace: 'websites' }); await invalidateBasicWebsiteCaches(websiteId, websiteCache); await invalidateWebsiteCaches(websiteId, ctx.user.id, 'website updated'); ```
(QB_NEW_EN_OTHER_ERROR_IDS_5)
docs/reference/redis.md
[grammar] ~1-~1: Use correct spacing
Context: ## @databuddy/redis ### Redis Client - redis: a singleton iore...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~3-~3: There might be a mistake here.
Context: ## @databuddy/redis ### Redis Client - redis: a singleton ioredis client (JSON helpe...
(QB_NEW_EN_OTHER)
[grammar] ~4-~4: There might be a mistake here.
Context: ...n ioredis client (JSON helpers included) - getRedisCache(): returns the singleton client (throws i...
(QB_NEW_EN)
[grammar] ~5-~5: Insert the missing word
Context: ...returns the singleton client (throws if REDIS_URL missing) - getRawRedis(): returns a n...
(QB_NEW_EN_OTHER_ERROR_IDS_32)
[grammar] ~5-~5: There might be a mistake here.
Context: ...n client (throws if REDIS_URL missing) - getRawRedis(): returns a non-extended raw client - `g...
(QB_NEW_EN)
[grammar] ~6-~6: Use correct spacing
Context: ...is(): returns a non-extended raw client - getJson(key): Promise<T|null>andsetJson(key, value, expireInSec)...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~7-~7: There might be a mistake here.
Context: ...ue, expireInSec)on the extended client - Lock helpers:getLock(key, value, timeo...
(QB_NEW_EN)
[grammar] ~8-~8: Use correct spacing
Context: ...ock(key, value), isRedisConnected(), disconnectRedis()` ts import { redis, getLock, releaseLock } from '@databuddy/redis'; await redis.set('hello', 'world'); const got = await redis.get('hello'); const ok = await getLock('my-lock', 'job-123', 10_000); if (ok) { try { // do work } finally { await releaseLock('my-lock', 'job-123'); } } ### cacheable(fn, options) - Memoizes async ...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~29-~29: Insert the missing word
Context: ...tKey(...), .clear(...), .clearAll(), .invalidate(...)`. ```ts import { cac...
(QB_NEW_EN_OTHER_ERROR_IDS_32)
[grammar] ~29-~29: Use correct spacing
Context: .....), .clearAll(), .invalidate(...)`. ts import { cacheable } from '@databuddy/redis'; const getUser = cacheable(async (id: string) => { // fetch from DB return { id, name: 'Ada' }; }, { expireInSec: 300, prefix: 'user', staleWhileRevalidate: true, staleTime: 30 }); const u = await getUser('123'); await getUser.clear('123'); ### getCache(key, options, fn) - Low-level h...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~43-~43: There might be a mistake here.
Context: ...3'); ``` ### getCache(key, options, fn) - Low-level helper to read-through cache a...
(QB_NEW_EN)
[grammar] ~44-~44: Use correct spacing
Context: ...o read-through cache a promise with SWR. ts import { getCache } from '@databuddy/redis'; const data = await getCache('stats:today', { expireInSec: 60 }, async () => { // compute expensive stats return { sessions: 42 }; }); ### Drizzle Cache - `createDrizzleCache({ re...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~55-~55: Use correct spacing
Context: ...ssions: 42 }; }); ``` ### Drizzle Cache - createDrizzleCache({ redis, namespace? }) provides: - `withCache({ key, ttl?, ta...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~56-~56: Use correct spacing
Context: ...eCache({ redis, namespace? })provides: -withCache({ key, ttl?, tables?, tag?, autoInvalidate?, queryFn }) -invalidateByTables(tables: string[]), invalidateByTags(tags: string[]), i...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~58-~58: Use correct spacing
Context: ...), invalidateByTags(tags: string[]), invalidateByKey(key: string) -cleanupDeps()` Example: ```ts import { createDrizzleCac...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~61-~61: Use correct spacing
Context: ...: string) -cleanupDeps()` Example: ts import { createDrizzleCache, redis } from '@databuddy/redis'; const websiteCache = createDrizzleCache({ redis, namespace: 'websites' }); const site = await websiteCache.withCache({ key: 'getById:abc', ttl: 600, tables: ['websites'], queryFn: () => db.query.websites.findFirst({ where: eq(websites.id, 'abc') }) });
(QB_NEW_EN_OTHER_ERROR_IDS_5)
🪛 markdownlint-cli2 (0.17.2)
docs/reference/auth.md
1-1: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
5-5: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
6-6: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
7-7: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
8-8: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
20-20: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
21-21: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
21-21: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
22-22: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
29-29: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
30-30: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
docs/reference/mapper.md
1-1: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
3-3: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
4-4: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
9-9: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
10-10: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
18-18: Files should end with a single newline character
(MD047, single-trailing-newline)
docs/reference/README.md
1-1: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
11-11: Files should end with a single newline character
(MD047, single-trailing-newline)
docs/reference/api.md
1-1: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
3-3: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
4-4: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
7-7: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
8-8: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
15-15: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
16-16: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
45-45: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
62-62: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
63-63: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
71-71: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
75-75: Files should end with a single newline character
(MD047, single-trailing-newline)
docs/reference/rpc.md
1-1: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
13-13: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
14-14: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
16-16: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
17-17: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
17-17: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
18-18: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
48-48: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
49-49: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
59-59: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
60-60: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
69-69: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
70-70: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
90-90: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
91-91: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
docs/reference/redis.md
1-1: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
3-3: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
4-4: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
26-26: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
27-27: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
43-43: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
44-44: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
55-55: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
56-56: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
62-62: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
72-72: Files should end with a single newline character
(MD047, single-trailing-newline)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (javascript-typescript)
| ## HTTP API | ||
|
|
||
| Base URL examples: | ||
| - Production: `https://api.databuddy.cc` | ||
| - Local dev: your `apps/api` server (default port 3001) | ||
|
|
||
| Authentication: | ||
| - Most routes require either a logged-in session cookie or an `x-api-key` header scoped to the website. | ||
|
|
||
| ### Health | ||
| - **GET** `/health` | ||
| - Returns service status for ClickHouse, Database, and Redis. | ||
| - Example: | ||
| ```bash | ||
| curl -s https://api.databuddy.cc/health | jq | ||
| ``` | ||
|
|
||
| ### Query API (analytics) | ||
| - **Prefix**: `/v1/query` | ||
| - Applies website authentication middleware. If `website_id` is required and the site is not public, you must be authenticated (session or `x-api-key`). | ||
|
|
||
| - **GET** `/v1/query/types?include_meta=true` | ||
| - Returns available query types and configuration (allowed filters, defaults, optional meta). | ||
| - Example: | ||
| ```bash | ||
| curl -s "https://api.databuddy.cc/v1/query/types?include_meta=true" \ | ||
| -H "cookie: ...session..." | jq | ||
| ``` | ||
|
|
||
| - **POST** `/v1/query/compile` | ||
| - Validates and compiles a query request without executing it. | ||
| - Body fields: | ||
| - `projectId` (string), `type` (string), `from` (ISO date), `to` (ISO date) | ||
| - Optional: `timeUnit`, `filters[]`, `groupBy[]`, `orderBy`, `limit`, `offset` | ||
| - Example: | ||
| ```bash | ||
| curl -s -X POST https://api.databuddy.cc/v1/query/compile?website_id=WEBSITE_ID \ | ||
| -H "content-type: application/json" \ | ||
| -H "cookie: ...session..." \ | ||
| -d '{ | ||
| "projectId": "WEBSITE_ID", | ||
| "type": "summary_overview", | ||
| "from": "2025-01-01", | ||
| "to": "2025-01-31", | ||
| "timeUnit": "day", | ||
| "limit": 100 | ||
| }' | jq | ||
| ``` | ||
|
|
||
| - **POST** `/v1/query` | ||
| - Executes one or more dynamic query requests. Supports batch input (array). | ||
| - Body (single request): | ||
| - `parameters`: Array of strings or objects `{ name, start_date?, end_date?, granularity?, id? }` | ||
| - Optional: `limit`, `page`, `filters[]`, `granularity`, `groupBy`, `startDate`, `endDate`, `timeZone` | ||
| - Example (single): | ||
| ```bash | ||
| curl -s -X POST "https://api.databuddy.cc/v1/query?website_id=WEBSITE_ID" \ | ||
| -H "content-type: application/json" \ | ||
| -H "x-api-key: YOUR_WEBSITE_API_KEY" \ | ||
| -d '{ | ||
| "parameters": ["summary_overview"], | ||
| "limit": 50, | ||
| "granularity": "daily" | ||
| }' | jq | ||
| ``` | ||
| - Example (batch): | ||
| ```bash | ||
| curl -s -X POST "https://api.databuddy.cc/v1/query?website_id=WEBSITE_ID" \ | ||
| -H "content-type: application/json" \ | ||
| -H "cookie: ...session..." \ | ||
| -d '[ | ||
| { "parameters": ["summary_overview"], "granularity": "daily" }, | ||
| { "parameters": [{ "name": "pages_top", "start_date": "2025-01-01", "end_date": "2025-01-31" }] } | ||
| ]' | jq | ||
| ``` | ||
|
|
||
| ### Assistant API (streaming) | ||
| - **Prefix**: `/v1/assistant` | ||
| - **POST** `/v1/assistant/stream` | ||
| - Streams assistant responses for a given website and message. | ||
| - Body: `{ message: string, website_id: string, model?: 'chat'|'agent'|'agent-max', context?: { previousMessages?: { role?: string, content: string }[] } }` | ||
| - Example (fetch streaming): | ||
| ```ts | ||
| async function streamAssistant() { | ||
| const res = await fetch('https://api.databuddy.cc/v1/assistant/stream?website_id=WEBSITE_ID', { | ||
| method: 'POST', | ||
| headers: { 'content-type': 'application/json', 'cookie': '...session...' }, | ||
| body: JSON.stringify({ message: 'Show sessions trend', website_id: 'WEBSITE_ID' }) | ||
| }); | ||
| const reader = res.body!.getReader(); | ||
| const decoder = new TextDecoder(); | ||
| while (true) { | ||
| const { value, done } = await reader.read(); | ||
| if (done) break; | ||
| console.log(decoder.decode(value)); // streaming updates | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Authentication Notes |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Address remaining markdownlint spacing issues throughout
Multiple MD022/MD032/MD031 hits: ensure a blank line before/after headings, lists, and fenced code blocks across the file.
I can push a follow-up commit auto-formatting this page with markdownlint rules if you want.
🧰 Tools
🪛 LanguageTool
[grammar] ~1-~1: Use correct spacing
Context: ## HTTP API Base URL examples: - Production: `https:...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~3-~3: There might be a mistake here.
Context: ## HTTP API Base URL examples: - Production: https://api.databuddy.cc -...
(QB_NEW_EN)
[grammar] ~4-~4: There might be a mistake here.
Context: ...P API Base URL examples: - Production: https://api.databuddy.cc - Local dev: your apps/api server (defau...
(QB_NEW_EN)
[grammar] ~5-~5: Use correct spacing
Context: ...ur apps/api server (default port 3001) Authentication: - Most routes require ei...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~7-~7: There might be a mistake here.
Context: ...ver (default port 3001) Authentication: - Most routes require either a logged-in s...
(QB_NEW_EN)
[grammar] ~8-~8: Use correct spacing
Context: ...x-api-keyheader scoped to the website. ### Health - **GET**/health` - Returns ser...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~13-~13: Use correct spacing
Context: ...ckHouse, Database, and Redis. - Example: bash curl -s https://api.databuddy.cc/health | jq ### Query API (analytics) - Prefix: `/v1...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~20-~20: Use correct spacing
Context: ... authenticated (session or x-api-key). - GET `/v1/query/types?include_meta=true...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~24-~24: Use correct spacing
Context: ..., defaults, optional meta). - Example: bash curl -s "https://api.databuddy.cc/v1/query/types?include_meta=true" \ -H "cookie: ...session..." | jq - POST /v1/query/compile - Validates...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~32-~32: Use correct spacing
Context: ...t without executing it. - Body fields: - projectId (string), type (string), from (ISO d...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~33-~33: There might be a mistake here.
Context: ...ing), from (ISO date), to (ISO date) - Optional: timeUnit, filters[], `grou...
(QB_NEW_EN)
[grammar] ~34-~34: Use commas correctly
Context: ...ters[], groupBy[], orderBy, limit, offset` - Example: ```bash curl -s -X POST https:/...
(QB_NEW_EN_OTHER_ERROR_IDS_33)
[grammar] ~35-~35: Use correct spacing
Context: ...orderBy, limit, offset - Example: ```bash curl -s -X POST https://api.databuddy.cc/v1/query/compile?website_id=WEBSITE_ID \ -H "content-type: application/json" \ -H "cookie: ...session..." \ -d '{ "projectId": "WEBSITE_ID", "type": "summary_overview", "from": "2025-01-01", "to": "2025-01-31", "timeUnit": "day", "limit": 100 }' | jq ``` - **POST**/v1/query` - Executes one or m...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~52-~52: Use colons correctly
Context: ...nput (array). - Body (single request): - parameters: Array of strings or objects `{ name, st...
(QB_NEW_EN_OTHER_ERROR_IDS_30)
[grammar] ~53-~53: There might be a mistake here.
Context: ...parameters: Array of strings or objects { name, start_date?, end_date?, granularity?, id? } - Optional:limit, page, filters[]`, ...
(QB_NEW_EN_OTHER)
[grammar] ~54-~54: There might be a mistake here.
Context: ...rity, groupBy, startDate, endDate, timeZone` - Example (single): ```bash curl -s -X POS...
(QB_NEW_EN_OTHER)
[grammar] ~55-~55: Use correct spacing
Context: ...dDate, timeZone` - Example (single): bash curl -s -X POST "https://api.databuddy.cc/v1/query?website_id=WEBSITE_ID" \ -H "content-type: application/json" \ -H "x-api-key: YOUR_WEBSITE_API_KEY" \ -d '{ "parameters": ["summary_overview"], "limit": 50, "granularity": "daily" }' | jq - Example (batch): ```bash curl -s -X POST...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~66-~66: Use correct spacing
Context: ...aily" }' | jq - Example (batch):bash curl -s -X POST "https://api.databuddy.cc/v1/query?website_id=WEBSITE_ID" \ -H "content-type: application/json" \ -H "cookie: ...session..." \ -d '[ { "parameters": ["summary_overview"], "granularity": "daily" }, { "parameters": [{ "name": "pages_top", "start_date": "2025-01-01", "end_date": "2025-01-31" }] } ]' | jq ``` ### Assistant API (streaming) - Prefix: ...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~81-~81: There might be a mistake here.
Context: ... a given website and message. - Body: { message: string, website_id: string, model?: 'chat'|'agent'|'agent-max', context?: { previousMessages?: { role?: string, content: string }[] } } - Example (fetch streaming): ```ts async f...
(QB_NEW_EN)
[grammar] ~82-~82: Use correct spacing
Context: ... }[] } }` - Example (fetch streaming): ts async function streamAssistant() { const res = await fetch('https://api.databuddy.cc/v1/assistant/stream?website_id=WEBSITE_ID', { method: 'POST', headers: { 'content-type': 'application/json', 'cookie': '...session...' }, body: JSON.stringify({ message: 'Show sessions trend', website_id: 'WEBSITE_ID' }) }); const reader = res.body!.getReader(); const decoder = new TextDecoder(); while (true) { const { value, done } = await reader.read(); if (done) break; console.log(decoder.decode(value)); // streaming updates } } ### Authentication Notes - Routes enforce we...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
🪛 markdownlint-cli2 (0.17.2)
1-1: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
3-3: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
4-4: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
7-7: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
8-8: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
15-15: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
16-16: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
45-45: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
62-62: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
63-63: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
71-71: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
75-75: Files should end with a single newline character
(MD047, single-trailing-newline)
🤖 Prompt for AI Agents
In docs/reference/api.md lines 1–100, fix markdownlint errors MD022/MD032/MD031
by ensuring there is exactly one blank line before and after each heading, list
block, and fenced code block throughout the file; add or remove blank lines so
headings (##, ###), list items, and triple-backtick code fences are separated by
a blank line from surrounding text, then run markdownlint (or prettier --write)
to auto-validate and commit the formatting changes.
| ## HTTP API | ||
|
|
||
| Base URL examples: | ||
| - Production: `https://api.databuddy.cc` | ||
| - Local dev: your `apps/api` server (default port 3001) | ||
|
|
||
| Authentication: | ||
| - Most routes require either a logged-in session cookie or an `x-api-key` header scoped to the website. | ||
|
|
||
| ### Health |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Promote to H1 and fix basic Markdown spacing
Adopt a top-level heading and surround lists/headings/fences with blank lines to satisfy markdownlint (MD041/MD022/MD032/MD031) and improve readability.
-## HTTP API
+# HTTP API Reference
+
+## HTTP API
+
Base URL examples:
- Production: `https://api.databuddy.cc`
- Local dev: your `apps/api` server (default port 3001)
Authentication:
- Most routes require either a logged-in session cookie or an `x-api-key` header scoped to the website.Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 LanguageTool
[grammar] ~1-~1: Use correct spacing
Context: ## HTTP API Base URL examples: - Production: `https:...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~3-~3: There might be a mistake here.
Context: ## HTTP API Base URL examples: - Production: https://api.databuddy.cc -...
(QB_NEW_EN)
[grammar] ~4-~4: There might be a mistake here.
Context: ...P API Base URL examples: - Production: https://api.databuddy.cc - Local dev: your apps/api server (defau...
(QB_NEW_EN)
[grammar] ~5-~5: Use correct spacing
Context: ...ur apps/api server (default port 3001) Authentication: - Most routes require ei...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~7-~7: There might be a mistake here.
Context: ...ver (default port 3001) Authentication: - Most routes require either a logged-in s...
(QB_NEW_EN)
[grammar] ~8-~8: Use correct spacing
Context: ...x-api-keyheader scoped to the website. ### Health - **GET**/health` - Returns ser...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
🪛 markdownlint-cli2 (0.17.2)
1-1: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
3-3: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
4-4: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
7-7: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
8-8: Lists should be surrounded by blank lines
(MD032, blanks-around-lists)
🤖 Prompt for AI Agents
In docs/reference/api.md around lines 1 to 10, the top-level document heading
and surrounding blank lines are missing which triggers markdownlint rules
(MD041/MD022/MD032/MD031); change "## HTTP API" to a top-level H1 ("# HTTP API")
and ensure there is a blank line before and after the H1, and add blank lines
between the H1 and the following paragraphs and between the lists/headings/code
fences so lists and headings are separated by single blank lines for proper
markdown spacing.
| - `projectId` (string), `type` (string), `from` (ISO date), `to` (ISO date) | ||
| - Optional: `timeUnit`, `filters[]`, `groupBy[]`, `orderBy`, `limit`, `offset` | ||
| - Example: |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Parameter naming is inconsistent (camelCase vs snake_case, projectId vs website_id)
The docs mix projectId with website_id, and start_date/end_date with startDate/endDate. This is likely to cause integration errors.
Proposed normalization (assuming camelCase API; adjust if schema says otherwise):
- - `projectId` (string), `type` (string), `from` (ISO date), `to` (ISO date)
- - Optional: `timeUnit`, `filters[]`, `groupBy[]`, `orderBy`, `limit`, `offset`
+ - `websiteId` (string), `type` (string), `from` (ISO date), `to` (ISO date)
+ - Optional: `timeUnit`, `filters[]`, `groupBy[]`, `orderBy`, `limit`, `offset`- - `parameters`: Array of strings or objects `{ name, start_date?, end_date?, granularity?, id? }`
- - Optional: `limit`, `page`, `filters[]`, `granularity`, `groupBy`, `startDate`, `endDate`, `timeZone`
+ - `parameters`: Array of strings or objects `{ name, startDate?, endDate?, granularity?, id? }`
+ - Optional: `limit`, `page`, `filters[]`, `granularity`, `groupBy`, `startDate`, `endDate`, `timeZone`Run this script to verify the actual accepted field names in the codebase:
Also applies to: 52-55
🏁 Script executed:
#!/bin/bash
# Verify schemas and handlers for /v1/query to confirm parameter names.
set -euo pipefail
echo "Search endpoints:"
rg -n -A3 -B3 $'/v1/query' || true
echo
echo "Search schema keys likely used by compile/execute:"
rg -n -A3 -B3 $'projectId|websiteId|start_date|end_date|startDate|endDate|timeUnit|granularity' || true
echo
echo "Search zod schemas for query endpoints:"
rg -n -A4 -B4 $'z\\.object\\(\\{' || trueLength of output: 267299
Docs: normalize API parameter names — use website_id & snake_case dates to match code
The docs mix projectId / website_id and startDate / start_date (and endDate / end_date). I checked the codebase: public query URLs use ?website_id, shared API types use start_date/end_date, and several backend/frontend handlers use websiteId internally — the public API surface in docs should match the query param and payload shape.
Files to fix
- docs/reference/api.md — /v1/query/compile (lines ~33–47): body + example currently use
projectId,from/to. - docs/reference/api.md — /v1/query (lines ~52–75): parameter object vs optional list (mixes
start_dateandstartDate). - packages/shared/src/types/api.ts — ParameterWithDates uses start_date/end_date (keep docs aligned).
- apps/docs/app/(home)/api/query-type-dialog.tsx — curl snippets already use ?website_id (use as canonical example).
- Grep for remaining occurrences of
projectId,startDate,endDatein docs and examples and align to the chosen convention.
Suggested doc changes (use snake_case for the public API):
Replace compile section:
- - `projectId` (string), `type` (string), `from` (ISO date), `to` (ISO date)
- - Optional: `timeUnit`, `filters[]`, `groupBy[]`, `orderBy`, `limit`, `offset`
+ - Query param: `website_id` (string) — required (used for website auth)
+ - Body fields: `type` (string), `start_date` (ISO date), `end_date` (ISO date)
+ - Optional: `timeUnit`, `filters[]`, `groupBy[]`, `orderBy`, `limit`, `offset`Update example JSON in that section:
- "projectId": "WEBSITE_ID",
- "type": "summary_overview",
- "from": "2025-01-01",
- "to": "2025-01-31",
+ "type": "summary_overview",
+ "start_date": "2025-01-01",
+ "end_date": "2025-01-31",Replace parameter/optional list for POST /v1/query:
- - `parameters`: Array of strings or objects `{ name, start_date?, end_date?, granularity?, id? }`
- - Optional: `limit`, `page`, `filters[]`, `granularity`, `groupBy`, `startDate`, `endDate`, `timeZone`
+ - `parameters`: Array of strings or objects `{ name, start_date?, end_date?, granularity?, id? }`
+ - Optional: `limit`, `page`, `filters[]`, `granularity`, `groupBy`, `start_date`, `end_date`, `timeZone`Reasoning: public endpoints/examples use the query param website_id (snake_case) and shared API types use snake_case date fields — keeping docs consistent with these avoids integration bugs. If you want the public API to be camelCase instead, we should change the code (and shared types + example builders) — otherwise update docs to snake_case as above.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - `projectId` (string), `type` (string), `from` (ISO date), `to` (ISO date) | |
| - Optional: `timeUnit`, `filters[]`, `groupBy[]`, `orderBy`, `limit`, `offset` | |
| - Example: | |
| - Query param: `website_id` (string) — required (used for website auth) | |
| - Body fields: `type` (string), `start_date` (ISO date), `end_date` (ISO date) | |
| - Optional: `timeUnit`, `filters[]`, `groupBy[]`, `orderBy`, `limit`, `offset` | |
| - Example: |
🧰 Tools
🪛 LanguageTool
[grammar] ~33-~33: There might be a mistake here.
Context: ...ing), from (ISO date), to (ISO date) - Optional: timeUnit, filters[], `grou...
(QB_NEW_EN)
[grammar] ~34-~34: Use commas correctly
Context: ...ters[], groupBy[], orderBy, limit, offset` - Example: ```bash curl -s -X POST https:/...
(QB_NEW_EN_OTHER_ERROR_IDS_33)
[grammar] ~35-~35: Use correct spacing
Context: ...orderBy, limit, offset - Example: ```bash curl -s -X POST https://api.databuddy.cc/v1/query/compile?website_id=WEBSITE_ID \ -H "content-type: application/json" \ -H "cookie: ...session..." \ -d '{ "projectId": "WEBSITE_ID", "type": "summary_overview", "from": "2025-01-01", "to": "2025-01-31", "timeUnit": "day", "limit": 100 }' | jq ``` - **POST**/v1/query` - Executes one or m...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
🤖 Prompt for AI Agents
In docs/reference/api.md around lines 33 to 35 (and the surrounding
/v1/query/compile and /v1/query sections up through ~75), the docs use mixed
parameter names (projectId, from/to, startDate/endDate) that do not match the
public API and shared types; update the compile and query sections and their
example JSON and parameter lists to use snake_case public names: website_id for
the query param and start_date / end_date for date fields (and replace any
projectId, from, to, startDate, endDate occurrences in these blocks), and search
the docs/examples for remaining instances of projectId, startDate, endDate to
normalize them to website_id, start_date, end_date so examples align with
packages/shared/src/types/api.ts and the curl snippets in
apps/docs/app/(home)/api/query-type-dialog.tsx.
| curl -s -X POST https://api.databuddy.cc/v1/query/compile?website_id=WEBSITE_ID \ | ||
| -H "content-type: application/json" \ | ||
| -H "cookie: ...session..." \ | ||
| -d '{ | ||
| "projectId": "WEBSITE_ID", | ||
| "type": "summary_overview", | ||
| "from": "2025-01-01", | ||
| "to": "2025-01-31", | ||
| "timeUnit": "day", | ||
| "limit": 100 | ||
| }' | jq |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Body example for compile mixes website_id query and projectId body
Passing website_id in the query string and projectId in the body for the same resource is confusing. Prefer a single identifier consistently (either websiteId in body or website_id in query), as per your server’s contract.
-curl -s -X POST https://api.databuddy.cc/v1/query/compile?website_id=WEBSITE_ID \
+curl -s -X POST https://api.databuddy.cc/v1/query/compile \
-H "content-type: application/json" \
-H "cookie: ...session..." \
-d '{
- "projectId": "WEBSITE_ID",
+ "websiteId": "WEBSITE_ID",
"type": "summary_overview",
"from": "2025-01-01",
"to": "2025-01-31",
"timeUnit": "day",
"limit": 100
}' | jqIf the server requires website_id in the query string, reflect that consistently and rename body fields accordingly.
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== docs/reference/api.md (first 200 lines) ==="
if [ -f docs/reference/api.md ]; then
sed -n '1,200p' docs/reference/api.md || true
else
echo "docs/reference/api.md not found"
fi
echo
echo "=== Searching repository for 'query/compile' ==="
rg --hidden -n "query/compile" || true
echo
echo "=== Searching repository for 'compile' (context lines) ==="
rg --hidden -n -S "compile" -g '!node_modules' -g '!.git' -n -N --context 2 || true
echo
echo "=== Searching repository for 'projectId' ==="
rg --hidden -n "projectId" -S || true
echo
echo "=== Searching repository for 'website_id' ==="
rg --hidden -n "website_id" -S || true
echo
echo "=== Searching repository for 'websiteId' ==="
rg --hidden -n "websiteId" -S || true
echo
echo "=== Search for OpenAPI / swagger files mentioning compile or website_id/projectId ==="
rg --hidden -n "openapi|swagger|paths|projectId|website_id|websiteId|/query/compile" || trueLength of output: 176049
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== apps/api/src/routes/query.ts ==="
sed -n '1,240p' apps/api/src/routes/query.ts || true
echo
echo "=== apps/api/src/schemas/query-schemas.ts ==="
sed -n '1,220p' apps/api/src/schemas/query-schemas.ts || true
echo
echo "=== apps/api/src/query/index.ts ==="
sed -n '1,240p' apps/api/src/query/index.ts || true
echo
echo "=== apps/api/src/query/simple-builder.ts (first 220 lines) ==="
sed -n '1,220p' apps/api/src/query/simple-builder.ts || true
echo
echo "=== apps/api/src/middleware/website-auth.ts ==="
sed -n '1,220p' apps/api/src/middleware/website-auth.ts || trueLength of output: 19927
Docs: clarify compile endpoint expects website_id (query) for auth and projectId (body) for the compiled query
Verified: the server's compile handler reads website_id from the query (website-auth / domain lookup) while the compile request schema uses projectId in the body (and SimpleQueryBuilder uses request.projectId as the SQL websiteId). Update the docs to explain this to avoid confusion.
Files to update
- docs/reference/api.md — clarify the compile endpoint behavior and example (current snippet mixes query website_id and body projectId).
- (reference) apps/api/src/routes/query.ts — compile handler reads query param website_id.
- (reference) apps/api/src/schemas/query-schemas.ts — CompileRequestSchema uses projectId.
- (reference) apps/api/src/query/simple-builder.ts — uses request.projectId as websiteId in SQL.
Suggested docs patch (replace the compile section with a short clarification and keep the example):
@@ docs/reference/api.md
- **POST** `/v1/query/compile`
- Validates and compiles a query request without executing it.
- Body fields:
- - `projectId` (string), `type` (string), `from` (ISO date), `to` (ISO date)
+ - `projectId` (string), `type` (string), `from` (ISO date), `to` (ISO date)
+ Note: this endpoint also expects the website identifier in the query string as `website_id`. The query param is used for authentication/domain lookup; the `projectId` in the body is used by the query builder as the website identifier — they should match.
- Optional: `timeUnit`, `filters[]`, `groupBy[]`, `orderBy`, `limit`, `offset`
- Example:
-```bash
-curl -s -X POST https://api.databuddy.cc/v1/query/compile?website_id=WEBSITE_ID \
- -H "content-type: application/json" \
- -H "cookie: ...session..." \
- -d '{
- "projectId": "WEBSITE_ID",
- "type": "summary_overview",
- "from": "2025-01-01",
- "to": "2025-01-31",
- "timeUnit": "day",
- "limit": 100
- }' | jq
-```
+```bash
+curl -s -X POST "https://api.databuddy.cc/v1/query/compile?website_id=WEBSITE_ID" \
+ -H "content-type: application/json" \
+ -H "cookie: ...session..." \
+ -d '{
+ "projectId": "WEBSITE_ID",
+ "type": "summary_overview",
+ "from": "2025-01-01",
+ "to": "2025-01-31",
+ "timeUnit": "day",
+ "limit": 100
+ }' | jq
+```If you prefer consistent naming across the API (recommended for long-term clarity), rename the CompileRequestSchema.field projectId -> websiteId and update usages (apps/api/src/schemas/query-schemas.ts, apps/api/src/query/*, apps/api/src/query/simple-builder.ts, and any callers). That is a larger, backwards-breaking change and should be coordinated across clients.
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
45-45: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
🤖 Prompt for AI Agents
In docs/reference/api.md around lines 37-47, clarify that the /v1/query/compile
endpoint expects website_id as a query parameter (used for authentication/domain
lookup) while the compile request body uses projectId for building the compiled
query; update the prose to state this explicitly and adjust the example curl to
put WEBSITE_ID in the URL query
(https://api.databuddy.cc/v1/query/compile?website_id=WEBSITE_ID) while keeping
projectId in the JSON body, and retain or add a short note suggesting that
renaming projectId→websiteId across the API is a larger, breaking change that
should be coordinated if desired.
| - Body: `{ message: string, website_id: string, model?: 'chat'|'agent'|'agent-max', context?: { previousMessages?: { role?: string, content: string }[] } }` | ||
| - Example (fetch streaming): | ||
| ```ts | ||
| async function streamAssistant() { | ||
| const res = await fetch('https://api.databuddy.cc/v1/assistant/stream?website_id=WEBSITE_ID', { | ||
| method: 'POST', | ||
| headers: { 'content-type': 'application/json', 'cookie': '...session...' }, | ||
| body: JSON.stringify({ message: 'Show sessions trend', website_id: 'WEBSITE_ID' }) | ||
| }); | ||
| const reader = res.body!.getReader(); | ||
| const decoder = new TextDecoder(); | ||
| while (true) { | ||
| const { value, done } = await reader.read(); | ||
| if (done) break; | ||
| console.log(decoder.decode(value)); // streaming updates | ||
| } | ||
| } | ||
| ``` |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Harden the streaming example with status/error handling
Add response status checks and proper stream decoding so users don’t hang on non-2xx or partial chunks.
async function streamAssistant() {
const res = await fetch('https://api.databuddy.cc/v1/assistant/stream?website_id=WEBSITE_ID', {
method: 'POST',
headers: { 'content-type': 'application/json', 'cookie': '...session...' },
body: JSON.stringify({ message: 'Show sessions trend', website_id: 'WEBSITE_ID' })
});
- const reader = res.body!.getReader();
+ if (!res.ok || !res.body) {
+ const text = await res.text().catch(() => '');
+ throw new Error(`Request failed: ${res.status} ${res.statusText} ${text}`);
+ }
+ const reader = res.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { value, done } = await reader.read();
if (done) break;
- console.log(decoder.decode(value)); // streaming updates
+ const chunk = decoder.decode(value, { stream: true });
+ console.log(chunk); // streaming updates
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - Body: `{ message: string, website_id: string, model?: 'chat'|'agent'|'agent-max', context?: { previousMessages?: { role?: string, content: string }[] } }` | |
| - Example (fetch streaming): | |
| ```ts | |
| async function streamAssistant() { | |
| const res = await fetch('https://api.databuddy.cc/v1/assistant/stream?website_id=WEBSITE_ID', { | |
| method: 'POST', | |
| headers: { 'content-type': 'application/json', 'cookie': '...session...' }, | |
| body: JSON.stringify({ message: 'Show sessions trend', website_id: 'WEBSITE_ID' }) | |
| }); | |
| const reader = res.body!.getReader(); | |
| const decoder = new TextDecoder(); | |
| while (true) { | |
| const { value, done } = await reader.read(); | |
| if (done) break; | |
| console.log(decoder.decode(value)); // streaming updates | |
| } | |
| } | |
| ``` | |
| async function streamAssistant() { | |
| const res = await fetch('https://api.databuddy.cc/v1/assistant/stream?website_id=WEBSITE_ID', { | |
| method: 'POST', | |
| headers: { 'content-type': 'application/json', 'cookie': '...session...' }, | |
| body: JSON.stringify({ message: 'Show sessions trend', website_id: 'WEBSITE_ID' }) | |
| }); | |
| if (!res.ok || !res.body) { | |
| const text = await res.text().catch(() => ''); | |
| throw new Error(`Request failed: ${res.status} ${res.statusText} ${text}`); | |
| } | |
| const reader = res.body.getReader(); | |
| const decoder = new TextDecoder(); | |
| while (true) { | |
| const { value, done } = await reader.read(); | |
| if (done) break; | |
| const chunk = decoder.decode(value, { stream: true }); | |
| console.log(chunk); // streaming updates | |
| } | |
| } |
🧰 Tools
🪛 LanguageTool
[grammar] ~81-~81: There might be a mistake here.
Context: ... a given website and message. - Body: { message: string, website_id: string, model?: 'chat'|'agent'|'agent-max', context?: { previousMessages?: { role?: string, content: string }[] } } - Example (fetch streaming): ```ts async f...
(QB_NEW_EN)
[grammar] ~82-~82: Use correct spacing
Context: ... }[] } }` - Example (fetch streaming): ts async function streamAssistant() { const res = await fetch('https://api.databuddy.cc/v1/assistant/stream?website_id=WEBSITE_ID', { method: 'POST', headers: { 'content-type': 'application/json', 'cookie': '...session...' }, body: JSON.stringify({ message: 'Show sessions trend', website_id: 'WEBSITE_ID' }) }); const reader = res.body!.getReader(); const decoder = new TextDecoder(); while (true) { const { value, done } = await reader.read(); if (done) break; console.log(decoder.decode(value)); // streaming updates } } ### Authentication Notes - Routes enforce we...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
🤖 Prompt for AI Agents
In docs/reference/api.md around lines 81 to 98, the streaming example lacks
response status checks and robust stream decoding which can cause callers to
hang on non-2xx responses or mis-decode partial UTF-8 chunks; update the example
to (1) verify res.ok (or check res.status) and throw/log a useful error when not
2xx, (2) ensure res.body is non-null before calling getReader(), (3) use a
TextDecoder with stream: true and decode each Uint8Array chunk incrementally
(decoder.decode(chunk, { stream: true })) and call decoder.decode() with no args
when done to flush, and (4) wrap the read loop in try/catch and properly
close/release the reader in finally to handle network errors cleanly.
| #### Discord Webhook Utilities | ||
| - `initializeDiscordWebhook(url, options?) => DiscordWebhook` | ||
| - `initializeErrorWebhook(url) => DiscordWebhook` | ||
| - `initializeActivityWebhook(url) => DiscordWebhook` | ||
| - `getDefaultWebhook() | getErrorWebhook() | getActivityWebhook()` | ||
| - `discord` convenience object | ||
| - `logger` pre-configured instance | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Surround lists with blank lines and add a security note for webhooks.
- Add blank lines before/after the list.
- Strongly recommend noting that webhook URLs are secrets and should not be exposed in client code or logs.
#### Discord Webhook Utilities
-- `initializeDiscordWebhook(url, options?) => DiscordWebhook`
-- `initializeErrorWebhook(url) => DiscordWebhook`
-- `initializeActivityWebhook(url) => DiscordWebhook`
-- `getDefaultWebhook() | getErrorWebhook() | getActivityWebhook()`
-- `discord` convenience object
-- `logger` pre-configured instance
+
+- `initializeDiscordWebhook(url, options?) => DiscordWebhook`
+- `initializeErrorWebhook(url) => DiscordWebhook`
+- `initializeActivityWebhook(url) => DiscordWebhook`
+- `getDefaultWebhook() | getErrorWebhook() | getActivityWebhook()`
+- `discord` convenience object
+- `logger` pre-configured instance
+
+Note: Treat webhook URLs as secrets. Do not expose them to the browser. Rotate if leaked.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #### Discord Webhook Utilities | |
| - `initializeDiscordWebhook(url, options?) => DiscordWebhook` | |
| - `initializeErrorWebhook(url) => DiscordWebhook` | |
| - `initializeActivityWebhook(url) => DiscordWebhook` | |
| - `getDefaultWebhook() | getErrorWebhook() | getActivityWebhook()` | |
| - `discord` convenience object | |
| - `logger` pre-configured instance | |
| #### Discord Webhook Utilities | |
| - `initializeDiscordWebhook(url, options?) => DiscordWebhook` | |
| - `initializeErrorWebhook(url) => DiscordWebhook` | |
| - `initializeActivityWebhook(url) => DiscordWebhook` | |
| - `getDefaultWebhook() | getErrorWebhook() | getActivityWebhook()` | |
| - `discord` convenience object | |
| - `logger` pre-configured instance | |
| Note: Treat webhook URLs as secrets. Do not expose them to the browser. Rotate if leaked. |
🧰 Tools
🪛 LanguageTool
[grammar] ~29-~29: Use correct spacing
Context: ...noid ``` #### Discord Webhook Utilities - initializeDiscordWebhook(url, options?) => DiscordWebhook - `initializeErrorWebhook(url) => DiscordWebhook` - `initializeActivityWebhook(url) => DiscordWebhook` - `getDefaultWebhook() | getErrorWebhook() | getActivityWebhook()` - `discord` convenience object - `logger` pre-confi...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~34-~34: Use correct spacing
Context: ...ebhook()-discordconvenience object -logger` pre-configured instance Example: ```ts ...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~35-~35: Use correct spacing
Context: ...bject - logger pre-configured instance Example: ```ts import { initializeDiscor...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
🤖 Prompt for AI Agents
In docs/reference/shared.md around lines 29 to 36, the markdown list of Discord
Webhook Utilities needs blank lines before and after the list and a security
note added: add an empty line above the "#### Discord Webhook Utilities" block
and another empty line after the list, and append a short bolded security note
below the list stating that webhook URLs are secrets and must not be exposed in
client-side code or logs (recommend storing them server-side and treating them
like credentials).
| Example: | ||
| ```ts | ||
| import { initializeDiscordWebhook, discord, logger } from '@databuddy/shared'; | ||
|
|
||
| initializeDiscordWebhook(process.env.DISCORD_WEBHOOK_URL!); | ||
| await discord.log.success('Deployment', 'New version deployed', { version: '1.2.3' }); | ||
|
|
||
| try { | ||
| throw new Error('Boom'); | ||
| } catch (e) { | ||
| logger.exception(e as Error, { service: 'api' }); | ||
| } | ||
| ``` |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Add blank lines around the example fenced block.
Addresses MD031.
-Example:
-```ts
+Example:
+
+```ts
import { initializeDiscordWebhook, discord, logger } from '@databuddy/shared';
@@
}
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 LanguageTool</summary>
[grammar] ~37-~37: There might be a problem here.
Context: ...ogger` pre-configured instance Example: ```ts import { initializeDiscordWebhook, discord, logger } from '@databuddy/shared'; initializeDiscordWebhook(process.env.DISCORD_WEBHOOK_URL!); await discord.log.success('Deployment', 'New version deployed', { version: '1.2.3' }); try { throw new Error('Boom'); } catch (e) { logger.exception(e as Error, { service: 'api' }); } ``` ### Lists - `filterOptions`: array of allowed filter fields for quer...
(QB_NEW_EN_MERGED_MATCH)
</details>
</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
In docs/reference/shared.md around lines 37 to 49, the fenced TypeScript example
needs blank lines added to satisfy MD031: insert one blank line between the
"Example:" line and the opening ts fence, and ensure there is a blank line after the closing fence (so the code block is surrounded by empty lines).
</details>
<!-- fingerprinting:phantom:triton:chinchilla -->
<!-- This is an auto-generated comment by CodeRabbit -->
| ### Lists | ||
| - `filterOptions`: array of allowed filter fields for query UI and API. | ||
| - `TIMEZONES`, `bots`, `referrers`: curated datasets for enrichment. | ||
|
|
||
| ### Types | ||
| - Various types for metrics, pages, journeys, errors, website models, realtime payloads, etc. Import from `@databuddy/shared` as needed to type responses and UI models. No newline at end of file |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Spacing around lists and clarify dataset sources.
- Add a blank line after “### Lists”.
- If possible, cite or describe the provenance/update cadence of
TIMEZONES,bots, andreferrersdatasets.
-### Lists
-- `filterOptions`: array of allowed filter fields for query UI and API.
-- `TIMEZONES`, `bots`, `referrers`: curated datasets for enrichment.
+### Lists
+
+- `filterOptions`: array of allowed filter fields for query UI and API.
+- `TIMEZONES`, `bots`, `referrers`: curated datasets for enrichment.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ### Lists | |
| - `filterOptions`: array of allowed filter fields for query UI and API. | |
| - `TIMEZONES`, `bots`, `referrers`: curated datasets for enrichment. | |
| ### Types | |
| - Various types for metrics, pages, journeys, errors, website models, realtime payloads, etc. Import from `@databuddy/shared` as needed to type responses and UI models. | |
| ### Lists | |
| - `filterOptions`: array of allowed filter fields for query UI and API. | |
| - `TIMEZONES`, `bots`, `referrers`: curated datasets for enrichment. | |
| ### Types | |
| - Various types for metrics, pages, journeys, errors, website models, realtime payloads, etc. Import from `@databuddy/shared` as needed to type responses and UI models. |
🧰 Tools
🪛 LanguageTool
[grammar] ~52-~52: There might be a mistake here.
Context: ...owed filter fields for query UI and API. - TIMEZONES, bots, referrers: curated datasets ...
(QB_NEW_EN)
[grammar] ~53-~53: Use correct spacing
Context: ...rrers`: curated datasets for enrichment. ### Types - Various types for metrics, pages...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~55-~55: There might be a mistake here.
Context: ...ated datasets for enrichment. ### Types - Various types for metrics, pages, journe...
(QB_NEW_EN)
[grammar] ~56-~56: There might be a mistake here.
Context: ...ages, journeys, errors, website models, realtime payloads, etc. Import from `@databuddy/...
(QB_NEW_EN_OTHER)
🤖 Prompt for AI Agents
In docs/reference/shared.md around lines 51 to 56, add a blank line immediately
after the "### Lists" heading, and update the three dataset bullets
(`TIMEZONES`, `bots`, `referrers`) to include a short provenance and update
cadence note for each (e.g., source system or upstream dataset and how often
it's refreshed). If the exact source or cadence is unknown, add a placeholder
like "curated internally — confirm source/cadence with the data owner" so
reviewers know to fill it in.
| ### Types | ||
| - Various types for metrics, pages, journeys, errors, website models, realtime payloads, etc. Import from `@databuddy/shared` as needed to type responses and UI models. No newline at end of file |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Consider linking to specific type entry points.
“Various types…” is vague. Point to a path or named export to help users discover types quickly (e.g., “import { Website, MetricsSummary } from '@databuddy/shared/types'” if applicable).
🧰 Tools
🪛 LanguageTool
[grammar] ~55-~55: There might be a mistake here.
Context: ...ated datasets for enrichment. ### Types - Various types for metrics, pages, journe...
(QB_NEW_EN)
[grammar] ~56-~56: There might be a mistake here.
Context: ...ages, journeys, errors, website models, realtime payloads, etc. Import from `@databuddy/...
(QB_NEW_EN_OTHER)
🤖 Prompt for AI Agents
In docs/reference/shared.md around lines 55-56, the phrase "Various types for
metrics, pages, journeys, errors, website models, realtime payloads, etc." is
too vague; update the sentence to point to the specific type entry point and
give a few representative named exports so users can discover types quickly —
e.g., reference the types entry path (such as the package's types barrel) and
list common exports like Website, MetricsSummary, Journey, ErrorPayload and
RealtimePayload, and suggest importing from that path; ensure the text uses the
actual package path used in the codebase and remove ambiguity by replacing
"Various types..." with a concise example import target and several named type
examples.
| ### Constants | ||
| - `MAX_FUTURE_MS`, `MIN_TIMESTAMP` | ||
| - `VALIDATION_LIMITS`: field length and range limits used across validation. | ||
|
|
||
| ### Regexes | ||
| - `RESOLUTION_REGEX`, `RESOLUTION_SIMPLE_REGEX` | ||
| - `LANGUAGE_REGEX`, `TIMEZONE_REGEX`, `SESSION_ID_REGEX` | ||
| - `LOCALHOST_URL_REGEX`, `DURATION_REGEX` | ||
| - `WEBSITE_NAME_REGEX`, `DOMAIN_REGEX`, `SUBDOMAIN_REGEX` | ||
|
|
||
| ### Utilities | ||
|
|
||
| - `parseDurationToSeconds(duration: string): number` | ||
| ```ts | ||
| parseDurationToSeconds('15s'); // 15 | ||
| parseDurationToSeconds('2m'); // 120 | ||
| parseDurationToSeconds('1h'); // 3600 | ||
| parseDurationToSeconds('1d'); // 86400 | ||
| ``` | ||
|
|
||
| - `sanitizeString(input: unknown, maxLength?: number): string` | ||
| - Trims, removes control chars and HTML specials, collapses whitespace. | ||
|
|
||
| - `validateTimezone(value: unknown): string` | ||
| - `validateTimezoneOffset(value: unknown): number | null` | ||
| - `validateLanguage(value: unknown): string` | ||
| - `validateSessionId(value: unknown): string` | ||
| - `validateUtmParameter(value: unknown): string` | ||
| - `validateNumeric(value: unknown, min?: number, max?: number): number | null` | ||
| - `validateUrl(value: unknown): string` | ||
| - `filterSafeHeaders(headers: Record<string, string|string[]|undefined>): Record<string, string>` | ||
| - `validateProperties(properties: unknown): Record<string, unknown>` | ||
| - `validatePayloadSize(data: unknown, maxSizeBytes = 1_048_576): boolean` | ||
| - `validatePerformanceMetric(value: unknown): number | undefined` | ||
| - `validateScreenResolution(value: unknown): string` | ||
| - `validateViewportSize(value: unknown): string` | ||
| - `validateScrollDepth(value: unknown): number | null` | ||
| - `validatePageCount(value: unknown): number | null` | ||
| - `validateInteractionCount(value: unknown): number | null` | ||
| - `validateExitIntent(value: unknown): number` | ||
|
|
||
| Example: | ||
| ```ts | ||
| import { | ||
| validateUrl, | ||
| validateLanguage, | ||
| validateProperties, | ||
| filterSafeHeaders, | ||
| } from '@databuddy/validation'; | ||
|
|
||
| const url = validateUrl('https://example.com/path?x=1'); | ||
| const lang = validateLanguage('en-US'); | ||
| const props = validateProperties({ name: ' Alice ', score: '42', active: true, unset: undefined }); | ||
| // props -> { name: 'Alice', score: 42, active: true, unset: null } | ||
|
|
||
| const safe = filterSafeHeaders({ 'User-Agent': 'X', 'X-Secret': 'hidden' }); | ||
| // safe -> { 'user-agent': 'X' } | ||
| ``` | ||
|
|
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Fix remaining markdownlint spacing (headings/lists/fences)
There are MD022/MD031/MD032 hits. Add blank lines before/after headings, lists, and code fences in these ranges.
I can autofix this file with markdownlint if helpful.
Also applies to: 70-75
🧰 Tools
🪛 LanguageTool
[grammar] ~5-~5: Use correct spacing
Context: ...and range limits used across validation. ### Regexes - RESOLUTION_REGEX, `RESOLUTIO...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~7-~7: There might be a mistake here.
Context: ...its used across validation. ### Regexes - RESOLUTION_REGEX, RESOLUTION_SIMPLE_REGEX - `LANGUAGE_...
(QB_NEW_EN_OTHER)
[grammar] ~8-~8: There might be a mistake here.
Context: ...ion. ### Regexes - RESOLUTION_REGEX, RESOLUTION_SIMPLE_REGEX - LANGUAGE_REGEX, TIMEZONE_REGEX, SESSION_ID_REGEX - ...
(QB_NEW_EN)
[grammar] ~9-~9: There might be a mistake here.
Context: ...-LANGUAGE_REGEX, TIMEZONE_REGEX, SESSION_ID_REGEX-LOCALHOST_URL_REGEX, DURATION_REGEX-WEBSITE_NAME_REGEX, DOMAIN_REGEX, SUBDOMAIN_REGEX` ### ...
(QB_NEW_EN_OTHER)
[grammar] ~11-~11: Use commas correctly
Context: ...-WEBSITE_NAME_REGEX, DOMAIN_REGEX, SUBDOMAIN_REGEX ### Utilities -parseDurationToSeconds(dur...
(QB_NEW_EN_OTHER_ERROR_IDS_33)
[grammar] ~13-~13: Use correct spacing
Context: ...REGEX, SUBDOMAIN_REGEX ### Utilities -parseDurationToSeconds(duration: string): number```ts parseDurationToSeconds('15s'); // 15 parseDurationToSeconds('2m'); // 120 parseDurationToSeconds('1h'); // 3600 parseDurationToSeconds('1d'); // 86400 ``` -sanitizeString(input: unknown, maxLength?: number): string` - Trims, removes control chars and HTML sp...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~24-~24: Insert the missing word
Context: ... removes control chars and HTML specials, collapses whitespace. - `validateTimez...
(QB_NEW_EN_OTHER_ERROR_IDS_32)
[grammar] ~24-~24: Use correct spacing
Context: ...and HTML specials, collapses whitespace. - validateTimezone(value: unknown): string - validateTimezoneOffset(value: unknown): number | null - validateLanguage(value: unknown): string - validateSessionId(value: unknown): string - validateUtmParameter(value: unknown): string - validateNumeric(value: unknown, min?: number, max?: number): number | null - validateUrl(value: unknown): string - filterSafeHeaders(headers: Record<string, string|string[]|undefined>): Record<string, string> - validateProperties(properties: unknown): Record<string, unknown> - validatePayloadSize(data: unknown, maxSizeBytes = 1_048_576): boolean - validatePerformanceMetric(value: unknown): number | undefined - validateScreenResolution(value: unknown): string - validateViewportSize(value: unknown): string - validateScrollDepth(value: unknown): number | null - validatePageCount(value: unknown): number | null - validateInteractionCount(value: unknown): number | null - validateExitIntent(value: unknown): number Example: ```ts import { validateUrl, ...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~44-~44: Use correct spacing
Context: ...ntent(value: unknown): number Example: ```ts import { validateUrl, validateLanguage, validateProperties, filterSafeHeaders, } from '@databuddy/validation'; const url = validateUrl('https://example.com/path?x=1'); const lang = validateLanguage('en-US'); const props = validateProperties({ name: ' Alice ', score: '42', active: true, unset: undefined }); // props -> { name: 'Alice', score: 42, active: true, unset: null } const safe = filterSafeHeaders({ 'User-Agent': 'X', 'X-Secret': 'hidden' }); // safe -> { 'user-agent': 'X' } ``` ### Schemas (zod) -analyticsEventSchema` -...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
🤖 Prompt for AI Agents
In docs/reference/validation.md around lines 3–61 (and also lines 70–75), there
are markdownlint spacing violations (MD022/MD031/MD032): add a single blank line
before and after each heading, ensure list blocks have a blank line separating
them from surrounding content, and add blank lines before and after fenced code
blocks; update the file to insert those blank lines consistently in the
specified ranges so headings, lists, and ``` fenced blocks conform to
markdownlint rules.
| ## @databuddy/validation | ||
|
|
||
| ### Constants |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Use a top-level heading and spacing
Promote to H1 and add a blank line for markdownlint compliance.
-## @databuddy/validation
+# @databuddy/validation
+
+## @databuddy/validation📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ## @databuddy/validation | |
| ### Constants | |
| # @databuddy/validation | |
| ## @databuddy/validation | |
| ### Constants |
🧰 Tools
🪛 LanguageTool
[grammar] ~1-~1: There might be a problem here.
Context: ## @databuddy/validation ### Constants - MAX_FUTURE_MS, MIN_TIMESTAMP - VALIDATION_LIMITS: field length and range limits used acro...
(QB_NEW_EN_MERGED_MATCH)
🤖 Prompt for AI Agents
In docs/reference/validation.md around lines 1 to 3, the top section uses an H2
header and lacks a blank line; change the header to a top-level H1 ("#
@databuddy/validation") and add a single blank line after it so the file starts
with an H1 followed by an empty line, then keep the "### Constants" section
as-is below.
| Example: | ||
| ```ts | ||
| import { | ||
| validateUrl, | ||
| validateLanguage, | ||
| validateProperties, | ||
| filterSafeHeaders, | ||
| } from '@databuddy/validation'; | ||
|
|
||
| const url = validateUrl('https://example.com/path?x=1'); | ||
| const lang = validateLanguage('en-US'); | ||
| const props = validateProperties({ name: ' Alice ', score: '42', active: true, unset: undefined }); | ||
| // props -> { name: 'Alice', score: 42, active: true, unset: null } | ||
|
|
||
| const safe = filterSafeHeaders({ 'User-Agent': 'X', 'X-Secret': 'hidden' }); | ||
| // safe -> { 'user-agent': 'X' } | ||
| ``` | ||
|
|
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Clarify filterSafeHeaders behavior
Document that keys are lowercased and sensitive headers (list examples) are removed. Helps set expectations.
-const safe = filterSafeHeaders({ 'User-Agent': 'X', 'X-Secret': 'hidden' });
-// safe -> { 'user-agent': 'X' }
+const safe = filterSafeHeaders({ 'User-Agent': 'X', 'X-Secret': 'hidden' });
+// safe -> { 'user-agent': 'X' }
+// Note: Keys are lowercased; sensitive headers like authorization, cookie, set-cookie, x-secret are stripped.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Example: | |
| ```ts | |
| import { | |
| validateUrl, | |
| validateLanguage, | |
| validateProperties, | |
| filterSafeHeaders, | |
| } from '@databuddy/validation'; | |
| const url = validateUrl('https://example.com/path?x=1'); | |
| const lang = validateLanguage('en-US'); | |
| const props = validateProperties({ name: ' Alice ', score: '42', active: true, unset: undefined }); | |
| // props -> { name: 'Alice', score: 42, active: true, unset: null } | |
| const safe = filterSafeHeaders({ 'User-Agent': 'X', 'X-Secret': 'hidden' }); | |
| // safe -> { 'user-agent': 'X' } | |
| ``` | |
| Example: |
🧰 Tools
🪛 LanguageTool
[grammar] ~44-~44: Use correct spacing
Context: ...ntent(value: unknown): number Example: ```ts import { validateUrl, validateLanguage, validateProperties, filterSafeHeaders, } from '@databuddy/validation'; const url = validateUrl('https://example.com/path?x=1'); const lang = validateLanguage('en-US'); const props = validateProperties({ name: ' Alice ', score: '42', active: true, unset: undefined }); // props -> { name: 'Alice', score: 42, active: true, unset: null } const safe = filterSafeHeaders({ 'User-Agent': 'X', 'X-Secret': 'hidden' }); // safe -> { 'user-agent': 'X' } ``` ### Schemas (zod) -analyticsEventSchema` -...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
🤖 Prompt for AI Agents
In docs/reference/validation.md around lines 44 to 61, the filterSafeHeaders
example does not describe its normalization/removal behavior; update the text to
explicitly state that filterSafeHeaders lowercases all header keys and strips
out sensitive headers, and enumerate common sensitive headers that are removed
(e.g., Authorization, Proxy-Authorization, Cookie, Set-Cookie, X-Api-Key,
X-Secret, and any custom-secret headers). Add a short sentence clarifying the
rationale (safety/normalization) and update or add the example output comment to
show the lowercased key and that sensitive headers are omitted.
| ### Schemas (zod) | ||
| - `analyticsEventSchema` | ||
| - `batchAnalyticsEventSchema`, `batchAnalyticsEventsSchema` | ||
| - `emailEventSchema`, `batchEmailEventSchema` | ||
| - `errorEventSchema` | ||
| - `webVitalsEventSchema` | ||
| - `websiteNameSchema`, `domainSchema`, `subdomainSchema`, `createWebsiteSchema`, `updateWebsiteSchema`, `transferWebsiteSchema` | ||
|
|
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Potential schema name duplication (batchAnalyticsEventSchema vs batchAnalyticsEventsSchema)
Two similarly named exports can be confusing; verify both exist and are intentionally distinct. If one is obsolete/alias, document that or remove to avoid confusion.
🏁 Script executed:
#!/bin/bash
# Confirm both schemas are exported and distinct
rg -n $'batchAnalyticsEventSchema' -A2 -B2
rg -n $'batchAnalyticsEventsSchema' -A2 -B2Length of output: 1998
Action: Resolve inconsistent schema naming — batchAnalyticsEventSchema vs. batchAnalyticsEventsSchema
Verified results:
- packages/validation/src/schemas/batch.ts —
export const batchAnalyticsEventSchema = z.object(...)(≈line 3). - packages/validation/src/schemas/batch.ts —
export const batchAnalyticsEventsSchema = z.array(batchAnalyticsEventSchema).max(100)(≈lines 14–16). - apps/basket/src/utils/validation.ts —
export const batchAnalyticsEventSchema = z.array(analyticsEventSchema).max(VALIDATION_LIMITS.BATCH_MAX_SIZE)(≈line 288) — this is an array but uses the singular name. - docs/reference/validation.md — lists both names (line 64).
Recommendation:
- Align naming to avoid confusion. Either rename the array export in apps/basket to
batchAnalyticsEventsSchemaor import/use the canonicalbatchAnalyticsEventsSchemafrom packages/validation. If the duplication is intentional, add a clear comment or documentation stating it’s an alias and why.
🧰 Tools
🪛 LanguageTool
[grammar] ~62-~62: Use correct spacing
Context: ...ser-agent': 'X' } ``` ### Schemas (zod) - analyticsEventSchema - `batchAnalyticsEventSchema`, `batchAnalyticsEventsSchema` - `emailE...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~64-~64: There might be a mistake here.
Context: ...tSchema-batchAnalyticsEventSchema, batchAnalyticsEventsSchema-emailEventSchema, batchEmailEventSchema-errorEventS...
(QB_NEW_EN)
[grammar] ~65-~65: There might be a problem here.
Context: ...ticsEventsSchema-emailEventSchema, batchEmailEventSchema-errorEventSchema-webVitalsEventSchema-websiteNameSchema, domainSchema, subdomainSchema, cre...
(QB_NEW_EN_MERGED_MATCH)
[grammar] ~68-~68: Use correct spacing
Context: ...eWebsiteSchema, updateWebsiteSchema, transferWebsiteSchema` Usage: ```ts import { analyticsEventSche...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
🤖 Prompt for AI Agents
In docs/reference/validation.md around lines 62 to 69 and in
packages/validation/src/schemas/batch.ts (≈lines 3 and 14–16) and
apps/basket/src/utils/validation.ts (≈line 288), there is an inconsistent naming
for the batch analytics schema where the package exports
batchAnalyticsEventSchema (singular) and batchAnalyticsEventsSchema (array)
while the app defines an array under the singular name; fix this by making the
app use the canonical exported array name: import batchAnalyticsEventsSchema
from packages/validation and replace the local array export, or alternatively
rename the app’s export to batchAnalyticsEventsSchema and update all usages and
the docs to reference the single canonical name; if intentional aliasing is
required, add a clear comment in the app file explaining it is an alias and
update docs to state the alias.
Pull Request
Description
This PR introduces comprehensive reference documentation for all public APIs, functions, and components across the monorepo.
The primary motivation is to provide clear, centralized, and accessible documentation to help developers understand and effectively utilize the various modules and endpoints. This addresses the need for detailed usage instructions and examples for key packages like
@databuddy/sdk,@databuddy/auth,@databuddy/rpc, and the HTTP API.A new
docs/referencedirectory has been created, containing dedicated markdown files for:cacheablefunction, and Drizzle cache integration.Each documentation file includes function signatures, usage examples, and relevant context to guide developers.
Checklist
Summary by CodeRabbit