Release: identity segmentation, SDK reliability, ingest gates, OG rebrand#540
Conversation
…so value step opens
…er-scoped invalidation
…butes from tracking
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
The latest updates on your projects. Learn more about Unkey Deploy
|
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
📄 Knowledge review🆕 New pages1 new page was drafted from this PR.
|
There was a problem hiding this comment.
2 issues found across 14 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/tracker/src/core/utils.ts">
<violation number="1" location="packages/tracker/src/core/utils.ts:76">
P2: Root-path masking can be rewritten to a wildcard path when using `/**`, which changes `/` into `/*` and can mis-group homepage traffic. This happens because the `**` check counts the trailing empty split segment as remaining path content; checking for non-empty remaining segments avoids masking `/`.</violation>
</file>
<file name="apps/dashboard/components/providers/session-guard.tsx">
<violation number="1" location="apps/dashboard/components/providers/session-guard.tsx:15">
P2: If `clearPersistedQueryCache()` throws (e.g., localStorage access denied), the subsequent `authClient.signOut()` and redirect never run, leaving the user stuck on a broken page with no session. Wrap in try-catch so a cache-clearing failure doesn't block the mandatory redirect.</violation>
</file>
<file name="apps/dashboard/app/(dby)/dby/og/route.tsx">
<violation number="1" location="apps/dashboard/app/(dby)/dby/og/route.tsx:144">
P2: OG image requests now re-read all three font files on every hit, which adds avoidable IO latency and load for a hot endpoint. Caching the font promise at module scope (and reusing it in `fonts`) would keep the branding change while avoiding per-request filesystem work.</violation>
</file>
<file name="apps/docs/lib/og.tsx">
<violation number="1" location="apps/docs/lib/og.tsx:6">
P2: Two newly added brand files (`apps/docs/lib/og.tsx` and `apps/dashboard/app/(dby)/dby/og/brand.tsx`) are exact duplicates — the same SVG components, color palette, and font-loading logic. Since this is a monorepo with a `packages/` directory for shared code, the duplicate will drift over time as the brand evolves. Consider extracting the shared OG brand primitives (colors, font loading, logo SVGs) into a shared package or library so both apps consume a single source of truth. This keeps future brand updates atomic and prevents subtle visual inconsistencies between the docs and dashboard OG images.</violation>
<violation number="2" location="apps/docs/lib/og.tsx:24">
P1: The memoized `loadOgFonts()` caches a rejected promise permanently. If `readOgFonts()` fails once (e.g., transient filesystem error), `ogFontsPromise` holds a rejected Promise object, which is not `null`/`undefined`, so `ogFontsPromise ??= readOgFonts()` is skipped on every subsequent call. All OG-image requests then fail until the process restarts. Consider resetting `ogFontsPromise` to `undefined` in a `.catch()` handler so the next call retries the read.</violation>
</file>
<file name="apps/dashboard/app/(dby)/dby/og/brand.tsx">
<violation number="1" location="apps/dashboard/app/(dby)/dby/og/brand.tsx:24">
P2: Memoizing the font-read promise with `??=` improves performance, but it also permanently caches a rejected promise if the first `readFile` fails (e.g., transient I/O error during a cold-start container). Once `ogFontsPromise` is set to a rejected promise, every subsequent call to `loadOgFonts()` will immediately throw without retrying, breaking OG image generation for the lifetime of the process. Consider resetting the cache on rejection so the next request can retry.</violation>
</file>
Shadow auto-approve: would not auto-approve because issues were found.
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| let ogFontsPromise: ReturnType<typeof readOgFonts> | undefined; | ||
|
|
||
| export function loadOgFonts() { | ||
| ogFontsPromise ??= readOgFonts(); |
There was a problem hiding this comment.
P1: The memoized loadOgFonts() caches a rejected promise permanently. If readOgFonts() fails once (e.g., transient filesystem error), ogFontsPromise holds a rejected Promise object, which is not null/undefined, so ogFontsPromise ??= readOgFonts() is skipped on every subsequent call. All OG-image requests then fail until the process restarts. Consider resetting ogFontsPromise to undefined in a .catch() handler so the next call retries the read.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/docs/lib/og.tsx, line 24:
<comment>The memoized `loadOgFonts()` caches a rejected promise permanently. If `readOgFonts()` fails once (e.g., transient filesystem error), `ogFontsPromise` holds a rejected Promise object, which is not `null`/`undefined`, so `ogFontsPromise ??= readOgFonts()` is skipped on every subsequent call. All OG-image requests then fail until the process restarts. Consider resetting `ogFontsPromise` to `undefined` in a `.catch()` handler so the next call retries the read.</comment>
<file context>
@@ -18,7 +18,14 @@ export const OG_COLORS = {
+let ogFontsPromise: ReturnType<typeof readOgFonts> | undefined;
+
+export function loadOgFonts() {
+ ogFontsPromise ??= readOgFonts();
+ return ogFontsPromise;
+}
</file context>
| ogFontsPromise ??= readOgFonts(); | |
| ogFontsPromise ??= readOgFonts().catch((err) => { | |
| ogFontsPromise = undefined; | |
| throw err; | |
| }); |
| let ogFontsPromise: ReturnType<typeof readOgFonts> | undefined; | ||
|
|
||
| export function loadOgFonts() { | ||
| ogFontsPromise ??= readOgFonts(); |
There was a problem hiding this comment.
P2: Memoizing the font-read promise with ??= improves performance, but it also permanently caches a rejected promise if the first readFile fails (e.g., transient I/O error during a cold-start container). Once ogFontsPromise is set to a rejected promise, every subsequent call to loadOgFonts() will immediately throw without retrying, breaking OG image generation for the lifetime of the process. Consider resetting the cache on rejection so the next request can retry.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/dashboard/app/(dby)/dby/og/brand.tsx, line 24:
<comment>Memoizing the font-read promise with `??=` improves performance, but it also permanently caches a rejected promise if the first `readFile` fails (e.g., transient I/O error during a cold-start container). Once `ogFontsPromise` is set to a rejected promise, every subsequent call to `loadOgFonts()` will immediately throw without retrying, breaking OG image generation for the lifetime of the process. Consider resetting the cache on rejection so the next request can retry.</comment>
<file context>
@@ -18,7 +18,14 @@ export const OG_COLORS = {
+let ogFontsPromise: ReturnType<typeof readOgFonts> | undefined;
+
+export function loadOgFonts() {
+ ogFontsPromise ??= readOgFonts();
+ return ogFontsPromise;
+}
</file context>
| ogFontsPromise ??= readOgFonts(); | |
| ogFontsPromise ??= readOgFonts().catch((err) => { | |
| ogFontsPromise = undefined; | |
| throw err; | |
| }); |
… query website_id
There was a problem hiding this comment.
0 issues found across 1 file (changes from recent commits).
Shadow auto-approve: would not auto-approve. Auto-approval blocked by 6 unresolved issues from previous reviews.
Re-trigger cubic
What's in this release
Identity & segmentation
trait:<key>filters resolve to identified-user segments server-side and apply across query builders (users page UI with key/value picker, agentget_data, all custom-events builders). Builders that can't segment return an explicit error instead of silently unsegmented data.profile_revenuebuilder attributes transactions via profile id, device set, and session stitching; revenue section on the user detail page.profiles.traitKeys/profiles.traitValuesendpoints for filter autocomplete.SDK reliability
Tracker
maskPathname), with unit + e2e coverage; dashboard now masks its own high-cardinality paths and drops website id/name tracking attributes.Ingest hardening
/trackand/identifypaths now enforce website existence, org match, and ACTIVE status (paused sites stop ingesting).Perf & fixes
Docs & brand
Summary by cubic
Release adds trait-based identity segmentation across queries, improves SDK/tracker reliability, hardens API‑key ingest (now requires org‑scoped keys) with org/status checks, and refreshes OG branding. It also surfaces user revenue, caches billing reads, and persists key dashboard queries with owner‑scoped, session‑gated hydration for a faster UX. Ships
@databuddy/sdk2.6.0.New Features
trait:<key>resolve to identified-user segments across query builders; unsupported builders return clear errors.profile_revenuebuilder with transactions; revenue section on the user detail page.profiles.traitKeysandprofiles.traitValues.maskPathname; dashboard masks high‑cardinality paths and drops website id/name tracking attributes.Bug Fixes
@databuddy/sdk2.6.0./trackand/identifyenforce website existence, org match, ACTIVE status; querywebsite_idis honored.maskPathnameenforces middle fragments in multi‑wildcard patterns; tests added.Written for commit 3eb00a3. Summary will update on new commits.