-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add Brave browser detection #125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Greptile Overview
Greptile Summary
This PR adds Brave browser detection capability to the analytics SDK by introducing an asynchronous check for the Brave browser's native API (navigator.brave.isBrave()). The core implementation resides in EventFactory's new isBraveBrowser() method, which checks for the Brave-specific navigator property and calls its async detection method. This detection is performed during context generation for every event, adding Brave identification to the analytics context object. Since Brave's detection API is inherently asynchronous, this required converting the entire event creation pipeline from synchronous to asynchronous - propagating through EventFactory.create() → EventManager.addEvent() → FormoAnalytics tracking methods. TypeScript type definitions were added to the global Navigator interface to support the Brave API. The change includes code formatting standardization (double quotes) and proper error handling for the detection logic. This fits into the SDK's broader goal of enriching analytics events with browser context information, which is particularly valuable given Brave's unique privacy features and tracking prevention mechanisms.
Changed Files
| Filename | Score | Overview |
|---|---|---|
| src/global.d.ts | 5/5 | Added TypeScript type definitions for Brave browser detection by extending Navigator interface with optional brave property |
| src/lib/event/type.ts | 4/5 | Changed IEventManager and IEventFactory interface signatures from synchronous to asynchronous (breaking change) |
| src/lib/event/EventFactory.ts | 4/5 | Added async isBraveBrowser() method and converted entire class from sync to async to support detection on every event |
| src/lib/event/EventManager.ts | 4/5 | Converted addEvent method to async to support awaiting EventFactory's now-async create() method |
| src/FormoAnalytics.ts | 4/5 | Updated to await eventManager.addEvent() calls and applied formatting standardization throughout the file |
Confidence score: 4/5
- This PR requires careful review but appears safe to merge with moderate risk due to breaking API changes
- Score reflects the breaking change to public interfaces (sync to async), potential performance impact from detection on every event, and the need to verify all call sites properly handle the new async nature; no critical bugs detected but the architectural impact is significant
- Pay close attention to src/lib/event/type.ts (interface breaking changes), src/lib/event/EventFactory.ts (detection implementation called on every event), and verify all consumers of these APIs throughout the codebase properly await the now-async methods
Sequence Diagram
sequenceDiagram
participant User
participant FormoAnalytics
participant EventFactory
participant Navigator
participant EventQueue
User->>FormoAnalytics: "Initialize SDK or Trigger Event"
FormoAnalytics->>EventFactory: "generateContext()"
EventFactory->>Navigator: "navigator.brave?.isBrave()"
alt Brave Browser
Navigator-->>EventFactory: "true"
else Not Brave
Navigator-->>EventFactory: "false"
end
EventFactory->>EventFactory: "Set is_brave_browser in context"
EventFactory-->>FormoAnalytics: "Return enriched context with is_brave_browser"
FormoAnalytics->>EventFactory: "create(event, address, userId)"
EventFactory->>EventFactory: "Generate event with context including is_brave_browser"
EventFactory-->>FormoAnalytics: "Return IFormoEvent"
FormoAnalytics->>EventQueue: "enqueue(formoEvent)"
EventQueue-->>User: "Event tracked with Brave detection"
5 files reviewed, 1 comment
55837d3 to
e1619d5
Compare
|
bugbot run |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Greptile Overview
Greptile Summary
This PR adds Brave browser detection capability to the analytics SDK by introducing asynchronous browser identification. The changes convert the entire event generation pipeline from synchronous to asynchronous to accommodate Brave's promise-based navigator.brave.isBrave() API. TypeScript type definitions are added in global.d.ts to properly type the Brave API, while EventFactory implements the detection logic with a caching mechanism to avoid repeated API calls. The asynchronous nature propagates through IEventFactory and IEventManager interfaces, requiring EventManager.addEvent() and all factory methods to return Promises. Finally, FormoAnalytics.trackEvent() now properly awaits event addition. The implementation adds an is_brave_browser boolean field to all event contexts, enabling the analytics platform to track Brave browser usage alongside other browser metrics.
Changed Files
| Filename | Score | Overview |
|---|---|---|
| src/global.d.ts | 5/5 | Adds TypeScript type definitions for Brave's browser detection API to the Navigator interface |
| src/lib/event/type.ts | 4/5 | Updates interfaces to make event creation and management methods asynchronous |
| src/lib/event/EventFactory.ts | 4/5 | Implements Brave browser detection with caching and converts all event generation methods to async |
| src/lib/event/EventManager.ts | 4/5 | Converts addEvent method to async and awaits eventFactory.create() |
| src/FormoAnalytics.ts | 4/5 | Adds await to eventManager.addEvent() call plus extensive formatting improvements |
Confidence score: 4/5
- This PR requires careful review as it introduces a breaking API change by converting synchronous methods to asynchronous throughout the event pipeline.
- Score reflects that while the implementation is sound with proper error handling and caching, the architectural shift from sync to async affects the entire event generation flow. Points deducted for: (1) Breaking change in public interfaces requiring all consumers to update their code to await these methods, (2) Potential issues if existing code calling
addEvent()doesn't properly handle the returned Promise, (3) The async nature adds overhead to every event generation call even with caching. - Pay close attention to
src/lib/event/type.ts(interface changes),src/lib/event/EventFactory.ts(core detection logic), andsrc/lib/event/EventManager.ts(async propagation). Verify that all callers of these methods throughout the codebase have been updated to handle Promises correctly.
Sequence Diagram
sequenceDiagram
participant User
participant FormoAnalytics
participant EventFactory
participant Navigator
participant EventManager
participant EventQueue
User->>FormoAnalytics: trackEvent(type, payload)
FormoAnalytics->>EventManager: addEvent(event, address, userId)
EventManager->>EventFactory: create(event, address, userId)
EventFactory->>EventFactory: generateContext(context)
EventFactory->>Navigator: navigator.brave?.isBrave()
alt Brave browser detected
Navigator-->>EventFactory: true
else Not Brave or unavailable
Navigator-->>EventFactory: false/undefined
end
EventFactory->>EventFactory: Cache result in cachedIsBrave
EventFactory->>EventFactory: Merge context with is_brave_browser flag
EventFactory-->>EventManager: return IFormoEvent
EventManager->>EventQueue: enqueue(formoEvent, callback)
EventQueue-->>User: callback(err, _, data)
5 files reviewed, 1 comment
|
bugbot run |
|
Skipping Bugbot: Bugbot is disabled for this repository |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Greptile Overview
Greptile Summary
This PR adds Brave browser detection to the analytics SDK and refactors the event generation pipeline to be async. The implementation introduces a new browsers.ts module with cached browser detection using multiple heuristics (navigator.brave.isBrave(), userAgentData.brands, and user-agent string matching). All EventFactory methods were converted from synchronous to async to support the browser detection call in generateContext().
Key changes:
- New
detectBrowser()function with module-level caching and in-flight request deduplication - Browser name added to event context for all tracked events
- Type interfaces updated to return
Promisetypes acrossIEventFactoryandIEventManager - Bundle size limit increased from 32KB to 36KB (12.5% increase)
Implementation strengths:
- Robust caching strategy prevents redundant API calls (browser type doesn't change during session)
- Multiple detection heuristics with proper fallbacks
- Comprehensive error handling with try-catch blocks
- In-flight promise tracking prevents race conditions on concurrent calls
Confidence Score: 4/5
- This PR is safe to merge with minimal risk; well-structured refactor with good error handling
- Score reflects solid implementation with caching, error handling, and comprehensive async refactor. The 12.5% bundle size increase is notable but acceptable for the feature value. No critical bugs identified, though the async conversion is a significant API surface change that should be monitored in production.
- No files require special attention - all changes follow consistent patterns with proper error handling
Important Files Changed
File Analysis
| Filename | Score | Overview |
|---|---|---|
| src/lib/browser/browsers.ts | 4/5 | New browser detection module with caching and multi-heuristic Brave detection; handles edge cases well with proper error handling |
| src/lib/event/EventFactory.ts | 4/5 | Converted all event generation methods to async to support browser detection; properly awaits detectBrowser() in context generation |
| package.json | 5/5 | Bundle size limit increased from 32KB to 36KB to accommodate new browser detection feature |
Sequence Diagram
sequenceDiagram
participant App as Application
participant FA as FormoAnalytics
participant EM as EventManager
participant EF as EventFactory
participant BD as detectBrowser()
participant Nav as Navigator API
participant EQ as EventQueue
App->>FA: trackEvent()
FA->>EM: addEvent(event, address, userId)
EM->>EF: create(event, address, userId)
EF->>EF: generateContext()
EF->>BD: detectBrowser()
alt First call (not cached)
BD->>Nav: navigator.brave?.isBrave()
Nav-->>BD: Promise<boolean>
BD->>BD: Cache result
BD-->>EF: browserName
else Subsequent calls (cached)
BD-->>EF: browserName (from cache)
end
EF->>EF: Enrich context with browser
EF-->>EM: IFormoEvent
EM->>EQ: enqueue(formoEvent)
EQ-->>EM: queued
EM-->>FA: void
FA-->>App: Promise<void>
3 files reviewed, no comments
|
bugbot run |
|
🎉 This PR is included in version 1.21.0 🎉 |
| params, | ||
| undefined, | ||
| capturedChainId | ||
| ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Unhandled Promises in Fire-and-Forget Calls
Async method this.signature() is called without await inside a fire-and-forget async IIFE. Since signature() now returns Promise<void> (because it calls async trackEvent()), the returned promise is not being awaited. This breaks error handling - errors in the async chain won't be caught by the try-catch block, potentially leading to unhandled promise rejections. The same issue occurs for this.transaction() calls at lines 1364, 1382, and similar locations.
Note
Adds browser detection (with Brave heuristic) to event context and refactors event creation/queueing to async, updating types and call sites; bumps UMD size limit.
src/lib/browser/browsers.tsand includesbrowserin generated event context.navigator.brave.isBrave()insrc/global.d.tsfor Brave detection.EventFactorycontext/enrichment and allgenerate*/createmethods async; imports and usesdetectBrowser().EventManager.addEventto async and awaits factorycreate.FormoAnalyticsto awaiteventManager.addEventand align with async tracking flows.dist/index.umd.min.jsto36 KB.Written by Cursor Bugbot for commit 4514bdd. This will update automatically on new commits. Configure here.