Skip to content

clean up#354

Open
izadoesdev wants to merge 33 commits intomainfrom
staging
Open

clean up#354
izadoesdev wants to merge 33 commits intomainfrom
staging

Conversation

@izadoesdev
Copy link
Member

Description

Please include a summary of the change and which issue is fixed. Also include relevant motivation and context.

Checklist
  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Wire evlog/elysia into API, basket, links, and uptime with initLogger.
Replace the old @databuddy/shared pino logger with evlog (including an
RPC-compatible shim). Basket uses wide-event context via useLogger,
moves producer/geo/schema enrichment off OTel span attributes, and drops
setAttributes from basket tracing. Update lockfile and dependencies.
…xiom

Remove OTLP trace SDK; wire createAxiomDrain in initLogger and simplify
tracing helpers to evlog-only captureError/record.
Remove OTLP Node SDK, HTTP/pg/ORPC instrumentations, and request span
plumbing. Wire createAxiomDrain on initLogger; map setAttributes/captureError
to evlog; simplify agent query execution without active spans.
- Add structured-errors with basketErrors factories, ingest helpers, and
  buildBasketErrorPayload for consistent success/error/message responses.
- Throw EvlogErrors from track, llm, request-validation (non-billing), and
  basket ingest routes; keep billing Response and pixel/bot ignore behavior.
- Centralize onError JSON via buildBasketErrorPayload; fix invalid Biome
  nursery key useMaxParams so biome check runs.
@cursor
Copy link

cursor bot commented Mar 21, 2026

You have used all of your free Bugbot PR reviews.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 21, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 558e106c-88fb-4e17-9775-3e5f11426123

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch staging

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@vercel
Copy link

vercel bot commented Mar 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dashboard (staging) Ready Ready Preview, Comment Mar 24, 2026 9:39am
databuddy-links Ready Ready Preview, Comment Mar 24, 2026 9:39am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
documentation (staging) Skipped Skipped Mar 24, 2026 9:39am

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 21, 2026

Greptile Summary

This PR is a large-scale observability infrastructure swap: OpenTelemetry (SDK, exporters, span processors) is removed from api and basket, and replaced throughout with evlog — a structured wide-event logger that integrates with the Elysia request lifecycle. links and uptime keep their existing OTel tracing but also gain evlog for log draining. Alongside the logging migration, basket introduces a typed EvlogError hierarchy (structured-errors.ts) that replaces ad-hoc new Response(JSON.stringify(...)) returns with throw basketErrors.*(), and the RPC package moves from pino/@axiomhq/pino to a log-based shim.

Key changes:

  • All setAttributes() / span lifecycle calls replaced with useLogger().set({})/log.info()/log.error() request-scoped calls
  • validateRequest() in basket now throws EvlogError on validation failures instead of returning { error: Response } (billing-exceeded still returns the response object for differentiation)
  • packages/shared/src/utils/logger.ts (Pino) and @axiomhq/pino dependency removed; pino/pino-pretty also dropped from shared
  • biome.jsonc re-enables the useMaxParams lint rule

Issues found:

  • The new Pino-compat shim in packages/rpc/src/lib/logger.ts silently drops logger.method({ fields }) calls that don't include a message string (missing else-branch in emit).
  • apps/api/src/routes/public/flags.ts parseProperties swallows JSON parse errors with no log output, removing a useful observability signal.
  • apps/links/src/index.ts and apps/uptime/src/index.ts initialise evlog without an Axiom drain, unlike api and basket, so structured logs from those services won't be shipped.

Confidence Score: 4/5

  • Safe to merge after fixing the silent log-drop in the RPC logger shim; other findings are observability gaps that don't affect correctness.
  • The core migration is well-executed: OTel removed cleanly, EvlogError hierarchy is solid, error handling improved. The P1 finding (silent drop in emit) is a real correctness gap in the logger shim but doesn't affect runtime request behaviour since all current call-sites pass a message string. The P2 findings are observability regressions (missing drain in links/uptime, silent parseProperties failure) but do not break functionality.
  • packages/rpc/src/lib/logger.ts needs the missing else-branch; apps/links/src/index.ts and apps/uptime/src/index.ts need createAxiomDrain() added to their initLogger calls.

Important Files Changed

Filename Overview
apps/basket/src/lib/structured-errors.ts New file introducing a typed error hierarchy via evlog's createError/EvlogError. Well-structured with clear why/fix messages and a buildBasketErrorPayload helper that centralises error serialisation. No issues found.
packages/rpc/src/lib/logger.ts New Pino-compatible shim over evlog. The emit helper has a missing else-branch: calls of the form logger.info({ fields }) (object, no message string) silently emit nothing. All current call sites happen to pass a message, but the gap is a latent trap.
apps/api/src/routes/public/flags.ts Migrated from logger to useLogger(). The parseProperties error handler no longer logs the parse error, silently swallowing invalid JSON with no observability signal.
apps/basket/src/lib/request-validation.ts Significant refactor replacing error-return pattern with EvlogError throws. Body/query typed from any to unknown with explicit narrowing. Billing-block still returns { error: Response } for differentiation. Clean and correct.
apps/api/src/index.ts Removes OpenTelemetry span-lifecycle hooks; swaps in evlog middleware. Error handler extended with structured why/fix/link fields via parseError. SIGINT/SIGTERM handlers simplified (shutdown no longer awaited).
apps/basket/src/lib/tracing.ts OTel SDK fully removed. record() is a thin pass-through, captureError delegates to useLogger() with a global log fallback. setAttributes and span lifecycle functions deleted.
apps/basket/src/index.ts OTel middleware and span-state removed; replaced with evlog() plugin. Global error handler now calls buildBasketErrorPayload. unhandledRejection/uncaughtException handlers log via evlog global log.
apps/links/src/index.ts Adds evlog middleware alongside retained OpenTelemetry. initLogger is called without an Axiom drain (unlike api and basket), so structured logs will not be shipped to the backend.
apps/uptime/src/index.ts Adds evlog middleware alongside retained OpenTelemetry. initLogger is also missing an Axiom drain, matching the links service inconsistency.
apps/basket/src/utils/parsing-helpers.ts createSchemaErrorResponse/createBotDetectedResponse refactored to return plain objects (batch-safe). validateEventSchema logs via global log.info instead of the request-scoped useLogger(), so the context won't be merged into the wide request event.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Elysia as Elysia Middleware
    participant evlog as evlog Plugin<br/>(Wide Event)
    participant Handler as Route Handler
    participant ValidateReq as validateRequest()
    participant ErrorHandler as Global onError

    Client->>Elysia: HTTP Request
    Elysia->>evlog: Initialise wide event per request
    evlog->>Handler: request context available

    Handler->>Handler: useLogger().set({ route })
    Handler->>ValidateReq: validateRequest(body, query, request)

    alt Validation error (payload, clientId, origin, IP)
        ValidateReq-->>Handler: throw EvlogError (status 4xx)
        Handler-->>ErrorHandler: EvlogError re-thrown
        ErrorHandler->>ErrorHandler: buildBasketErrorPayload()
        ErrorHandler-->>Client: { status, error, why, fix }
    else Billing exceeded
        ValidateReq-->>Handler: return { error: Response }
        Handler-->>Client: billing.response (429)
    else Success
        ValidateReq-->>Handler: return ValidatedRequest
        Handler->>Handler: useLogger().set({ clientId, eventType, … })
        Handler-->>Client: 200 OK
    end

    evlog->>evlog: Flush wide event to Axiom drain
Loading

Comments Outside Diff (2)

  1. apps/api/src/routes/public/flags.ts, line 831-836 (link)

    P2 Silent JSON parse failure — no observability signal

    The previous code logged a warn with the raw propertiesJson string, which made debugging malformed payloads possible. The PR removes the log entirely, leaving a silent {} fallback that gives no indication of the failure in production.

  2. apps/basket/src/utils/parsing-helpers.ts, line 47 (link)

    P2 Validation context logged to global log, not the request-scoped wide event

    validateEventSchema is always called from within an Elysia request handler, so useLogger() is available. Using the global log.info here means the validation fields won't be merged into the per-request wide event that evlog's middleware accumulates.

Last reviewed commit: "feat(basket): unify ..."

Comment on lines +13 to +27
log[level]({ ...base, message: fieldsOrMessage });
} else if (message !== undefined) {
log[level]({ ...base, ...fieldsOrMessage, message });
}
}

/**
* Pino-compatible (obj, msg) or (msg) logging via evlog global `log`.
*/
export const logger = {
error: (fieldsOrMessage: Fields | string, message?: string) =>
emit("error", fieldsOrMessage, message),
info: (fieldsOrMessage: Fields | string, message?: string) =>
emit("info", fieldsOrMessage, message),
warn: (fieldsOrMessage: Fields | string, message?: string) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Silent log drop when called with only an object

The emit helper has no else branch. When it is called as logger.info({ someField }) — an object with no message string — neither condition matches and the call is silently discarded. Pino (which this shim is replacing) would emit the entry with an empty msg field.

All current call-sites happen to pass a message, but the contract mismatch is a latent trap for any future caller.

Suggested change
log[level]({ ...base, message: fieldsOrMessage });
} else if (message !== undefined) {
log[level]({ ...base, ...fieldsOrMessage, message });
}
}
/**
* Pino-compatible (obj, msg) or (msg) logging via evlog global `log`.
*/
export const logger = {
error: (fieldsOrMessage: Fields | string, message?: string) =>
emit("error", fieldsOrMessage, message),
info: (fieldsOrMessage: Fields | string, message?: string) =>
emit("info", fieldsOrMessage, message),
warn: (fieldsOrMessage: Fields | string, message?: string) =>
function emit(
level: "error" | "info" | "warn",
fieldsOrMessage: Fields | string,
message?: string
): void {
if (typeof fieldsOrMessage === "string") {
log[level]({ ...base, message: fieldsOrMessage });
} else if (message !== undefined) {
log[level]({ ...base, ...fieldsOrMessage, message });
} else {
// Object-only call (no message string) – emit as-is
log[level]({ ...base, ...fieldsOrMessage });
}
}

Comment on lines 25 to +28
});

initLogger({
env: { service: "links" },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Missing Axiom drain — logs stay local

api and basket both configure drain: createAxiomDrain() in their initLogger calls. links (and uptime — same pattern at apps/uptime/src/index.ts:9-11) omit it, so structured logs from these services will never reach Axiom.

Suggested change
});
initLogger({
env: { service: "links" },
initLogger({
env: { service: "links" },
drain: createAxiomDrain(),
});

Wire api and basket through createDrainPipeline, initLogger tail sampling,
middleware enrich (UA, request size, trace context), and optional NDJSON to
apps/*/.evlog/logs in development. Basket: structured errors in auth, geo,
producer, and request validation wide events. Ignore **/.evlog/ at repo root.
Biome: disable useHookAtTopLevel for evlog useLogger in api and basket.
Replace z.record output schemas with explicit Zod models for getAnalytics
and getAnalyticsByReferrer so handlers match processFunnelAnalytics return types.
@railway-app railway-app bot temporarily deployed to Databuddy / production March 21, 2026 19:56 Inactive
@vercel vercel bot temporarily deployed to Preview – databuddy-links March 21, 2026 19:56 Inactive
@vercel vercel bot temporarily deployed to staging – documentation March 21, 2026 19:56 Inactive
- Replace OpenTelemetry span helpers in @databuddy/rpc with evlog wide-event helpers (rpc-log-context.ts); remove @opentelemetry/api and @orpc/otel.

- API: mergeWideEvent/captureError patterns, drop no-op record() wrapper, basket-style uncaught handlers, logging on MCP/health/insights/public routes.

- Touch RPC routers and lockfile for consistency with the RPC logging changes.
…vent enricher

Replace fragmented API key enricher with applyAuthWideEvent that resolves
both session and API key in parallel. Strip duplicated auth fields from
RPC enricher, remove redundant route fields from health/mcp/insights.
@railway-app railway-app bot temporarily deployed to Databuddy / production March 21, 2026 20:24 Inactive
@vercel vercel bot temporarily deployed to staging – documentation March 21, 2026 20:24 Inactive
@vercel vercel bot temporarily deployed to Preview – databuddy-links March 21, 2026 20:24 Inactive
…ext output

- Pre-fetch summary, top pages, errors, referrers for WoW comparison
- Replace ToolLoopAgent with generateText + Output.object (non-deprecated)
- Tighten prompts and expand insight type taxonomy
Right-clicking the nav logo opens a context menu with visual previews
of all brand assets (logo, wordmark, primary, stacked) in light/dark
variants. Supports copy as SVG, copy as PNG, and download. Unified
docs and main site to share the same Navbar component.

Also adds supermemory integration and agent memory tools for the API.
… contrast

- Add /branding page with brand assets, color swatches, and download cards
- Replace Geist/Manrope fonts with LT Superior and LT Superior Mono
- Add brand color tokens (amber, coral, purple)
- Fix dark mode --accent matching --popover (#2A2A31 → #323239) so hover
  highlights are visible globally across all menu/select/dropdown components
- Update context menu with data-highlighted support and cursor-pointer
- Simplify brand context menu with copy SVG/PNG actions
…t colors

- Replace Geist/Geist Mono with LT Superior and LT Superior Mono local fonts
- Convert all oklch color variables to hex, matching docs brand palette
- Add brand color tokens (amber, coral, purple)
- Swap chart rendering from --color-primary (now near-black/white) to
  --color-chart-1 (purple) across all chart components: stat cards,
  mini charts, website cards, metrics, pie, retention, revenue, events,
  errors, LLM, consumption, link stats, and chart preview
@railway-app railway-app bot temporarily deployed to Databuddy / production March 23, 2026 10:42 Inactive
@vercel vercel bot temporarily deployed to staging – documentation March 23, 2026 10:42 Inactive
@vercel vercel bot temporarily deployed to Preview – databuddy-links March 23, 2026 10:42 Inactive
Replace bg-primary with brand-purple for interactive controls (switch,
checkbox, slider, progress, radio, segmented control, calendar, tabs)
and chart-1 for data visualization elements (tooltip dots, cohort grid,
funnel bars). Aligns all UI primitives with the new brand palette.
…fests

Add favicon.ico, icon0.svg, icon1.png, apple-icon.png, and app/manifest.json
to both apps; serve PWA icons from public/. Set appleWebApp title metadata.
Remove legacy favicon.svg and redundant docs assets.
…olbar/header scroll

- Separate --border / --sidebar-border tokens from accent fills so
  dividers no longer read as active/selected surfaces (light: #d1d3dc,
  dark: #3b3b45).
- Move border-b onto h-10 elements in category sidebar and mobile
  category selector so every row is exactly 40px (border-box).
- Remove sticky positioning from the analytics toolbar wrapper — the
  flex column with overflow-hidden already pins it. Replace
  overscroll-contain with overscroll-none on content scroll areas to
  prevent elastic bounce from moving fixed chrome.
- When the toolbar is hidden (agent, flags, settings, users, pulse),
  use overflow-hidden on the website layout content wrapper so child
  page headers never participate in parent scroll.
- Add overflow-y-auto to goals, funnels, and settings pages that
  previously relied on the parent scroll container.
…oss app

- Fix outline button variant losing border on hover
- Swap ghost→outline for cancel buttons in all sheet/dialog footers
- Fix checkbox contrast (text-primary-foreground instead of hardcoded white)
- Simplify API key create/detail dialogs: flatten metadata, consolidate danger zone
- Remove Getting Started filler from create org dialog
- Remove redundant step count badge from funnel dialog header
- Remove Coming Soon scheduling placeholder from flag sheet
- Simplify monitor sheet JSON parsing description
…ighter layout

- Replace generic link icon with FaviconImage from target URL domain
- Add inline copy-to-clipboard button on short URL (visible on hover)
- Compact row spacing (remove fixed h-20, use py-3 padding)
- Simplify expiry badges with colored backgrounds and tooltips
- Redesign search bar: ghost input, smaller controls, cleaner integration
- Fix header height to 88px, make refresh button icon-only
- Improved empty search state with icon and quoted query
- Extract shared utils, form schema, collapsible section, and chart components
- Split link-sheet from ~988 to ~388 lines, link-stats-content from ~659 to ~288 lines
izadoesdev and others added 6 commits March 23, 2026 19:18
…E fixes

- Use Navigation API + fallback instead of monkey-patching history (Next.js 16 safe)
- Apply filter/sampling in _trackInternal; custom track() bypasses them
- Merge global properties in track(); remove client eventId on /track payloads
- Add test-utils for batched Playwright assertions; use databuddy-debug in tests
- docs: update script size copy to under 30 KB
- chore(dashboard): api key row display and dialog formatting
…D, open AI crawlers

- Root layout: title template (%s | Databuddy), tighter default description, twitter/OG defaults inherited by children
- Homepage: dedicated metadata from home-seo.ts, FAQPage JSON-LD wired to shared FAQ data
- Blog posts: BlogPosting JSON-LD with dates/images, canonical URL, simplified metadata
- Docs pages: TechArticle JSON-LD on every doc, shared getDocsPageSeo helper with section labels
- API playground: dedicated api-playground-seo.ts with focused copy
- Compare/pricing/blog listing: cleaner metadata, no duplicate local vars
- Robots: GPTBot and ChatGPT-User now allowed on all marketing pages, shared disallow list, removed stale public/robots.txt
* feat(api): add tcc instrumentation

* feat(api): init tcc tracining and add deps

* fix(api): remove sessionId from analyzeWebsite

* style(api): properly cast types of app context

* fix(api): trycatch NodeSDK init

* Apply suggestion from @greptile-apps[bot]

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: iza <59828082+izadoesdev@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
fix(dashboard): validate trusted image hostnames in getProxiedImageUrl (CodeQL).

Replace substring checks with URL hostname matching for cdn.databuddy.cc and api.dicebear.com.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants