Skip to content

Skip analytics init on apps without persistent token store#1336

Merged
BilalG1 merged 4 commits into
devfrom
analytics-access-token-issue-fix
Apr 14, 2026
Merged

Skip analytics init on apps without persistent token store#1336
BilalG1 merged 4 commits into
devfrom
analytics-access-token-issue-fix

Conversation

@BilalG1
Copy link
Copy Markdown
Collaborator

@BilalG1 BilalG1 commented Apr 14, 2026

Owned admin apps are constructed with tokenStore: null, which caused EventTracker/SessionRecorder flushes to throw from _ensurePersistentTokenStore() after #1331 removed the silencing.

Summary by CodeRabbit

  • Bug Fixes
    • Improved analytics stability and privacy by restricting session recording and event tracking to environments with required persistent storage.
  • Tests
    • Adjusted a few end-to-end tests to skip when running against a local emulator to reduce spurious failures.

Owned admin apps are constructed with `tokenStore: null`, which caused
EventTracker/SessionRecorder flushes to throw from
_ensurePersistentTokenStore() after #1331 removed the silencing.
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 14, 2026

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

Project Deployment Actions Updated (UTC)
3 Building Building Preview, Comment Apr 14, 2026 5:41pm
3-1776188452445-5Jus Canceled Canceled Apr 14, 2026 5:41pm
stack-auth-hosted-components Ready Ready Preview, Comment Apr 14, 2026 5:41pm
stack-backend Ready Ready Preview, Comment Apr 14, 2026 5:41pm
stack-dashboard Ready Ready Preview, Comment Apr 14, 2026 5:41pm
stack-demo Ready Ready Preview, Comment Apr 14, 2026 5:41pm
stack-docs Ready Ready Preview, Comment Apr 14, 2026 5:41pm
stack-preview-backend Ready Ready Preview, Comment Apr 14, 2026 5:41pm
stack-preview-dashboard Ready Ready Preview, Comment Apr 14, 2026 5:41pm

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 14, 2026

📝 Walkthrough

Walkthrough

Analytics startup in the client app was made conditional on the presence of a persistent token store; several tests were updated to skip specific cases when running against a local emulator.

Changes

Cohort / File(s) Summary
Analytics gating
packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts
Added _hasPersistentTokenStore() checks to SessionRecorder and EventTracker initialization so they only start when a persistent token store is present (in addition to existing browser/replay flags).
E2E feedback tests
apps/e2e/tests/backend/endpoints/api/v1/internal/feedback.test.ts
Introduced isLocalEmulator from env and wrapped three it cases with it.runIf(!isLocalEmulator, ...) to skip those tests when the local emulator flag is true.

Sequence Diagram(s)

(omitted — changes are minor/control gating and test-condition updates, not a multi-component new flow)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • N2D4

Poem

🐰 I nibble tokens, check the store,

Only then do replays soar.
Tests skip hops when emulators play,
Quiet fields until real tokens stay.
🎋 Hop, click, and log away.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly reflects the main change: gating analytics initialization on the presence of a persistent token store.
Description check ✅ Passed The description clearly explains the context (owned admin apps with null tokenStore), the problem (post-#1331 errors), and the solution (skip analytics init). Template requirements are minimal.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch analytics-access-token-issue-fix

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.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 14, 2026

Greptile Summary

This PR fixes a crash in owned admin apps (constructed with tokenStore: null) by guarding SessionRecorder and EventTracker initialization behind _hasPersistentTokenStore() checks, preventing the _ensurePersistentTokenStore() throw that #1331 re-exposed. The fix is minimal, correct, and well-targeted.

Confidence Score: 5/5

  • Safe to merge — the fix is narrowly scoped and all remaining findings are P2 style suggestions.
  • The two added _hasPersistentTokenStore() guards are exactly the right fix: EventTracker and SessionRecorder are not created when tokenStore === null, so the async sendBatch callbacks (which call _ensurePersistentTokenStore()) are never registered or invoked. The optional-chaining usage in _signOut already handles null trackers safely. The only remaining note is a P2 style suggestion about moving the getAnalyticsSession closure inside the guarded scope.
  • No files require special attention.

Important Files Changed

Filename Overview
packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts Adds _hasPersistentTokenStore() guards before initializing SessionRecorder and EventTracker, preventing throws on owned admin apps constructed with tokenStore: null.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[StackClientApp Constructor] --> B{isBrowserLike?}
    B -- No --> Z[No analytics initialized]
    B -- Yes --> C{_hasPersistentTokenStore?}
    C -- tokenStore is null --> Z
    C -- tokenStore is set --> D{replays.enabled?}
    D -- Yes --> E[Create and start SessionRecorder]
    D -- No --> F[Skip SessionRecorder]
    E --> G[Create and start EventTracker]
    F --> G
    G --> H[Analytics fully initialized]
Loading

Comments Outside Diff (1)

  1. packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts, line 556-564 (link)

    P2 getAnalyticsSession defined unconditionally

    getAnalyticsSession is defined regardless of _hasPersistentTokenStore(), even though it is only ever invoked inside the two guarded if blocks below. When tokenStore === null the closure is created and immediately discarded. Moving it inside the first _hasPersistentTokenStore() guard makes the dependency explicit and keeps the _ensurePersistentTokenStore() call safely unreachable on null-store apps.

    (Or keep it in one place and hoist only the outer guard — the main point is it should live inside the _hasPersistentTokenStore() scope.)

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts
    Line: 556-564
    
    Comment:
    **`getAnalyticsSession` defined unconditionally**
    
    `getAnalyticsSession` is defined regardless of `_hasPersistentTokenStore()`, even though it is only ever invoked inside the two guarded `if` blocks below. When `tokenStore === null` the closure is created and immediately discarded. Moving it inside the first `_hasPersistentTokenStore()` guard makes the dependency explicit and keeps the `_ensurePersistentTokenStore()` call safely unreachable on null-store apps.
    
    
    
    (Or keep it in one place and hoist only the outer guard — the main point is it should live inside the `_hasPersistentTokenStore()` scope.)
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts
Line: 556-564

Comment:
**`getAnalyticsSession` defined unconditionally**

`getAnalyticsSession` is defined regardless of `_hasPersistentTokenStore()`, even though it is only ever invoked inside the two guarded `if` blocks below. When `tokenStore === null` the closure is created and immediately discarded. Moving it inside the first `_hasPersistentTokenStore()` guard makes the dependency explicit and keeps the `_ensurePersistentTokenStore()` call safely unreachable on null-store apps.

```suggestion
    if (isBrowserLike() && this._hasPersistentTokenStore() && this._analyticsOptions?.replays?.enabled === true) {
      const getAnalyticsSession = async (): Promise<InternalSession> => {
        this._ensurePersistentTokenStore();
        const partialUser = await this.getPartialUser({ from: 'token', or: 'anonymous-if-exists' });
        if (partialUser) {
          return await this._getSession();
        }
        const anonUser = await this.getUser({ or: "anonymous" });
        return anonUser._internalSession;
      };
      this._sessionRecorder = new SessionRecorder({
```

(Or keep it in one place and hoist only the outer guard — the main point is it should live inside the `_hasPersistentTokenStore()` scope.)

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Skip analytics init on apps without pers..." | Re-trigger Greptile

@github-actions github-actions Bot assigned BilalG1 and unassigned N2D4 Apr 14, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/e2e/tests/backend/endpoints/api/v1/internal/feedback.test.ts`:
- Line 6: The skip predicate is too broad: change the boolean logic around
isLocalEmulator so tests only skip when running a local emulator AND the
feedback mode is NOT forwarding; check process.env.STACK_FEEDBACK_MODE !==
"FORWARD_TO_PRODUCTION" in the same condition (update or create a helper like
shouldSkipLocalEmailAssertions that returns isLocalEmulator &&
process.env.STACK_FEEDBACK_MODE !== "FORWARD_TO_PRODUCTION"). Also add an
it.runIf(shouldSkipLocalEmailAssertions) test case that runs when the emulator
is present but STACK_FEEDBACK_MODE === "FORWARD_TO_PRODUCTION" asserting a
simple 200 { success: true } response to cover the forwarding-mode path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 96a99466-4d76-4883-9639-56f5ad408978

📥 Commits

Reviewing files that changed from the base of the PR and between db4d275 and bb858d1.

📒 Files selected for processing (1)
  • apps/e2e/tests/backend/endpoints/api/v1/internal/feedback.test.ts

Comment thread apps/e2e/tests/backend/endpoints/api/v1/internal/feedback.test.ts
@BilalG1 BilalG1 merged commit 2af2a59 into dev Apr 14, 2026
32 of 36 checks passed
@BilalG1 BilalG1 deleted the analytics-access-token-issue-fix branch April 14, 2026 16:43
@coderabbitai coderabbitai Bot mentioned this pull request Apr 14, 2026
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