Skip to content

feat(clerk-js): Introduce debugLogger #6452

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

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open

Conversation

jacekradko
Copy link
Member

@jacekradko jacekradko commented Jul 31, 2025

Description

Create a debugLogger module that will be lazy instantiated when environment shows we are in a client debug mode.

Fixes: USER-2540

Related: https://github.com/clerk/cloudflare-workers/pull/672

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features
    • Advanced debug logging with configurable levels, filters, and multiple outputs (console + telemetry).
    • Client-side debug mode toggle in environment settings and new telemetry log entry type.
  • Improvements
    • Navigation actions now emit debug logs when debug mode is enabled.
    • Concurrent-safe debug logger initialization and an internal reset API.
    • Telemetry collector now records debug logs with buffered, batched flush behavior.
  • Bug Fixes
    • Improved error handling during logger initialization and transport delivery.
  • Tests
    • Added tests covering logger behavior, filtering, and telemetry transport.

Copy link

changeset-bot bot commented Jul 31, 2025

🦋 Changeset detected

Latest commit: b25d4d4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 22 packages
Name Type
@clerk/clerk-js Patch
@clerk/types Patch
@clerk/chrome-extension Patch
@clerk/clerk-expo Patch
@clerk/agent-toolkit Patch
@clerk/astro Patch
@clerk/backend Patch
@clerk/elements Patch
@clerk/expo-passkeys Patch
@clerk/express Patch
@clerk/fastify Patch
@clerk/localizations Patch
@clerk/nextjs Patch
@clerk/nuxt Patch
@clerk/react-router Patch
@clerk/clerk-react Patch
@clerk/remix Patch
@clerk/shared Patch
@clerk/tanstack-react-start Patch
@clerk/testing Patch
@clerk/themes Patch
@clerk/vue Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@jacekradko jacekradko marked this pull request as ready for review July 31, 2025 20:22
Copy link

vercel bot commented Jul 31, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Project Deployment Preview Comments Updated (UTC)
clerk-js-sandbox Ready Preview Comment Aug 12, 2025 3:50pm

Copy link
Contributor

coderabbitai bot commented Jul 31, 2025

📝 Walkthrough

Walkthrough

Adds a debug logging subsystem to clerk-js and integrates it with Clerk. New modules add types, a DebugLogger, transports (console, telemetry, composite), a DebugLoggerManager singleton with dynamic initialization, and an internal reset API. Clerk gains an optional debugLogger property, initializes the debug module when environment.clientDebugMode is true, and logs navigation via the debug logger. TelemetryCollector and telemetry types are extended to accept and flush debug log entries. Tests for the logger and telemetry transport were added. Bundlewatch and changeset metadata were updated.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective (issue) Addressed Explanation
Implement debugLogger with logging methods and types (USER-2540)
Initialize debug logger based on environment flag clientDebugMode (USER-2540)
Integrate debug logging into Clerk runtime (navigation logging, __internal_resetDebugLogger) (USER-2540)
Add telemetry support for debug logs and TelemetryCollector.recordLog (USER-2540)

Assessment against linked issues: Out-of-scope changes

Code Change (file_path) Explanation
bundlewatch size and file list updates (packages/clerk-js/bundlewatch.config.json) Packaging/CI thresholds and added bundle patterns are unrelated to the debugLogger implementation objectives.
changeset metadata (.changeset/all-cougars-hide.md) Release/changeset metadata is administrative and not required by the debugLogger feature.

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
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: 9

🧹 Nitpick comments (10)
packages/types/src/json.ts (1)

74-82: Consider the necessity of property reordering.

The addition of client_debug_mode: boolean is correct and follows proper naming conventions. However, the reordering of existing properties (auth_config, user_settings, organization_settings) appears unnecessary and could potentially cause confusion without providing functional benefits.

While TypeScript interfaces don't enforce property order, maintaining consistent ordering can help with code readability and reduce unnecessary diffs in version control.

packages/clerk-js/src/core/modules/debug/transports/console.ts (1)

3-32: Solid console transport implementation.

The ConsoleTransport class provides a clean implementation of the DebugTransport interface with proper message formatting and appropriate console method routing based on log levels.

Consider adding error handling for JSON.stringify to prevent issues with circular references:

-    const context = entry.context ? ` ${JSON.stringify(entry.context)}` : '';
+    const context = entry.context ? ` ${JSON.stringify(entry.context, null, 2)}` : '';

Or use a safer stringify approach:

-    const context = entry.context ? ` ${JSON.stringify(entry.context)}` : '';
+    let context = '';
+    if (entry.context) {
+      try {
+        context = ` ${JSON.stringify(entry.context)}`;
+      } catch (err) {
+        context = ` [Circular/Non-serializable context]`;
+      }
+    }
packages/clerk-js/src/core/modules/debug/transports/composite.ts (2)

3-10: Interface includes unused properties.

The CompositeLoggerOptions interface defines logLevel and filters properties that aren't used by the CompositeTransport class. Consider either implementing these features or removing them from the interface to avoid confusion.

The options property in the transport configuration is also unused.


12-27: Well-designed composite transport with minor logging concern.

The CompositeTransport implementation properly handles multiple transports with good error isolation using Promise.allSettled. However, the error logging on line 22 uses console.error, which could create noise or conflicts if one of the transports is a ConsoleTransport.

Consider using a different error handling approach or making the error logging configurable:

-        console.error('Failed to send to transport:', err);
+        // Only log if not in browser environment or if no console transport is present
+        if (typeof window === 'undefined' || !this.transports.some(t => t.constructor.name === 'ConsoleTransport')) {
+          console.error('Failed to send to transport:', err);
+        }
packages/clerk-js/src/core/modules/debug/transports/telemetry.ts (2)

16-22: Consider lazy timer initialization to avoid unnecessary resource usage.

Starting the flush timer immediately in the constructor creates a timer even if the transport is never used for logging. Consider starting the timer on the first send() call instead.

Apply this diff for lazy timer initialization:

 constructor(endpoint = 'https://telemetry.clerk.com/v1/debug', batchSize = 50, flushInterval = 10000) {
   this.batchSize = batchSize;
   this.endpoint = endpoint;
   this.flushInterval = flushInterval;
-  this.startFlushTimer();
 }

Then modify the send method to start the timer if not already running:

 async send(entry: DebugLogEntry): Promise<void> {
+  if (!this.flushTimer) {
+    this.startFlushTimer();
+  }
   this.batchBuffer.push(entry);

32-66: Add response validation and consider retry logic for production robustness.

The flush implementation correctly batches and sends data, but could be more robust for production use.

Consider adding response validation:

 await fetch(this.endpoint, {
   method: 'POST',
   headers: {
     'Content-Type': 'application/json',
   },
   body: JSON.stringify(debugDataArray),
-});
+}).then(response => {
+  if (!response.ok) {
+    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
+  }
+});

Also consider making the eventType configurable rather than hardcoded as 'custom_event'.

packages/clerk-js/src/core/clerk.ts (2)

209-216: Improve error handling and type safety.

The implementation is good but could be enhanced:

  1. Type safety: The imported module should be type-checked
  2. Error logging: Consider using the existing logger from '@clerk/shared/logger' for consistency
  3. Error details: The error message could be more specific

Apply this diff to improve the implementation:

  async #initializeDebugModule(): Promise<void> {
    try {
-      const { getDebugLogger } = await import('./modules/debug');
-      this.debugLogger = await getDebugLogger({});
+      const debugModule = await import('./modules/debug');
+      if ('getDebugLogger' in debugModule && typeof debugModule.getDebugLogger === 'function') {
+        this.debugLogger = await debugModule.getDebugLogger({});
+      }
    } catch (error) {
-      console.error('Failed to initialize debug module:', error);
+      logger.warn('Failed to initialize debug module:', error);
    }
  }

858-865: Add error handling and consider access modifier.

The method implementation is correct but could be improved:

  1. Error handling: Add try-catch around the dynamic import
  2. Access modifier: Consider making this method private if it's truly internal

Apply this diff to improve robustness:

  /**
   * @internal
   */
- public static async __internal_resetDebugLogger(): Promise<void> {
+ private static async __internal_resetDebugLogger(): Promise<void> {
-   // This method is now handled by the debug module itself
-   const { __internal_resetDebugLogger } = await import('./modules/debug');
-   __internal_resetDebugLogger();
+   try {
+     const { __internal_resetDebugLogger } = await import('./modules/debug');
+     __internal_resetDebugLogger();
+   } catch (error) {
+     logger.warn('Failed to reset debug logger:', error);
+   }
  }

If this method needs to be public for external testing, keep it public but add the error handling.

packages/clerk-js/src/core/modules/debug/index.ts (1)

1-171: Add comprehensive test coverage for the debug module.

The coding guidelines specify that tests should be added to cover changes. This debug module needs extensive testing for:

  • Singleton behavior
  • Logger initialization with various options
  • Error handling during initialization
  • Factory function behaviors
  • Reset functionality

Would you like me to generate comprehensive unit tests for this debug module to ensure proper functionality and prevent regressions?

packages/clerk-js/src/core/modules/debug/types.ts (1)

1-140: Add comprehensive test coverage for type definitions.

The type guards and utility functions need test coverage to ensure they work correctly with various input scenarios.

Would you like me to generate unit tests for the type guard functions and utility types to ensure they properly validate objects and handle edge cases?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3355af and f9a6a97.

📒 Files selected for processing (10)
  • packages/clerk-js/src/core/clerk.ts (5 hunks)
  • packages/clerk-js/src/core/modules/debug/index.ts (1 hunks)
  • packages/clerk-js/src/core/modules/debug/logger.ts (1 hunks)
  • packages/clerk-js/src/core/modules/debug/transports/composite.ts (1 hunks)
  • packages/clerk-js/src/core/modules/debug/transports/console.ts (1 hunks)
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts (1 hunks)
  • packages/clerk-js/src/core/modules/debug/types.ts (1 hunks)
  • packages/clerk-js/src/core/resources/Environment.ts (3 hunks)
  • packages/types/src/environment.ts (1 hunks)
  • packages/types/src/json.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/types/src/environment.ts
  • packages/clerk-js/src/core/resources/Environment.ts
  • packages/types/src/json.ts
  • packages/clerk-js/src/core/modules/debug/transports/console.ts
  • packages/clerk-js/src/core/modules/debug/transports/composite.ts
  • packages/clerk-js/src/core/modules/debug/logger.ts
  • packages/clerk-js/src/core/modules/debug/index.ts
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts
  • packages/clerk-js/src/core/clerk.ts
  • packages/clerk-js/src/core/modules/debug/types.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/types/src/environment.ts
  • packages/clerk-js/src/core/resources/Environment.ts
  • packages/types/src/json.ts
  • packages/clerk-js/src/core/modules/debug/transports/console.ts
  • packages/clerk-js/src/core/modules/debug/transports/composite.ts
  • packages/clerk-js/src/core/modules/debug/logger.ts
  • packages/clerk-js/src/core/modules/debug/index.ts
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts
  • packages/clerk-js/src/core/clerk.ts
  • packages/clerk-js/src/core/modules/debug/types.ts
packages/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/types/src/environment.ts
  • packages/clerk-js/src/core/resources/Environment.ts
  • packages/types/src/json.ts
  • packages/clerk-js/src/core/modules/debug/transports/console.ts
  • packages/clerk-js/src/core/modules/debug/transports/composite.ts
  • packages/clerk-js/src/core/modules/debug/logger.ts
  • packages/clerk-js/src/core/modules/debug/index.ts
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts
  • packages/clerk-js/src/core/clerk.ts
  • packages/clerk-js/src/core/modules/debug/types.ts
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/types/src/environment.ts
  • packages/clerk-js/src/core/resources/Environment.ts
  • packages/types/src/json.ts
  • packages/clerk-js/src/core/modules/debug/transports/console.ts
  • packages/clerk-js/src/core/modules/debug/transports/composite.ts
  • packages/clerk-js/src/core/modules/debug/logger.ts
  • packages/clerk-js/src/core/modules/debug/index.ts
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts
  • packages/clerk-js/src/core/clerk.ts
  • packages/clerk-js/src/core/modules/debug/types.ts
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/types/src/environment.ts
  • packages/clerk-js/src/core/resources/Environment.ts
  • packages/types/src/json.ts
  • packages/clerk-js/src/core/modules/debug/transports/console.ts
  • packages/clerk-js/src/core/modules/debug/transports/composite.ts
  • packages/clerk-js/src/core/modules/debug/logger.ts
  • packages/clerk-js/src/core/modules/debug/index.ts
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts
  • packages/clerk-js/src/core/clerk.ts
  • packages/clerk-js/src/core/modules/debug/types.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/types/src/environment.ts
  • packages/clerk-js/src/core/resources/Environment.ts
  • packages/types/src/json.ts
  • packages/clerk-js/src/core/modules/debug/transports/console.ts
  • packages/clerk-js/src/core/modules/debug/transports/composite.ts
  • packages/clerk-js/src/core/modules/debug/logger.ts
  • packages/clerk-js/src/core/modules/debug/index.ts
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts
  • packages/clerk-js/src/core/clerk.ts
  • packages/clerk-js/src/core/modules/debug/types.ts
**/*

⚙️ CodeRabbit Configuration File

**/*: If there are no tests added or modified as part of the PR, please suggest that tests be added to cover the changes.

Whenever reviewing a pull request, if there are any changes that could impact security, always tag @clerk/security in the PR.

Security-impacting changes include, but are not limited to:

  • Changes to authentication logic or mechanisms (e.g. login, session handling, token issuance)
  • Any modification to access control, authorization checks, or role-based permissions
  • Introduction or modification of hashing algorithms, signature verification, or cryptographic primitives
  • Handling of sensitive data (e.g. passwords, tokens, secrets, PII)
  • Integration with external identity providers (e.g. SSO, OAuth, OpenID Connect)
  • Modifications to security headers, cookie flags, CORS policies, or CSRF protections
  • Bypass mechanisms (e.g. feature flags, testing overrides) that could weaken protections
  • Changes to rate limiting, abuse prevention, or input validation

If you're unsure whether a change is security-relevant, err on the side of caution and tag @clerk/security.

Any time that you tag @clerk/security, please do so explicitly in a code comment, rather than within a collapsed section in a coderabbit comment, such as the "recent review details" section. If you do use the team name in any thinking or non-direct-code-comment content, it can be referred to as "clerk security team" to avoid accidentally printing the tag which sends a notification to the team.

Files:

  • packages/types/src/environment.ts
  • packages/clerk-js/src/core/resources/Environment.ts
  • packages/types/src/json.ts
  • packages/clerk-js/src/core/modules/debug/transports/console.ts
  • packages/clerk-js/src/core/modules/debug/transports/composite.ts
  • packages/clerk-js/src/core/modules/debug/logger.ts
  • packages/clerk-js/src/core/modules/debug/index.ts
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts
  • packages/clerk-js/src/core/clerk.ts
  • packages/clerk-js/src/core/modules/debug/types.ts
packages/**/index.{js,ts}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use tree-shaking friendly exports

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
**/index.ts

📄 CodeRabbit Inference Engine (.cursor/rules/react.mdc)

Use index.ts files for clean imports but avoid deep barrel exports

Avoid barrel files (index.ts re-exports) as they can cause circular dependencies

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
🧬 Code Graph Analysis (5)
packages/types/src/json.ts (4)
packages/types/src/commerceSettings.ts (1)
  • CommerceSettingsJSON (6-21)
packages/types/src/displayConfig.ts (1)
  • DisplayConfigJSON (10-48)
packages/types/src/organizationSettings.ts (1)
  • OrganizationSettingsJSON (6-20)
packages/types/src/userSettings.ts (1)
  • UserSettingsJSON (112-130)
packages/clerk-js/src/core/modules/debug/transports/console.ts (2)
packages/clerk-js/src/core/modules/debug/index.ts (1)
  • ConsoleTransport (9-9)
packages/clerk-js/src/core/modules/debug/types.ts (2)
  • DebugTransport (43-48)
  • DebugLogEntry (14-24)
packages/clerk-js/src/core/modules/debug/logger.ts (1)
packages/clerk-js/src/core/modules/debug/types.ts (4)
  • DebugTransport (43-48)
  • DebugLogLevel (4-4)
  • DebugLogFilter (79-86)
  • DebugLogEntry (14-24)
packages/clerk-js/src/core/modules/debug/index.ts (6)
packages/clerk-js/src/core/modules/debug/types.ts (2)
  • DebugLogFilter (79-86)
  • DebugLogLevel (4-4)
packages/clerk-js/src/core/modules/debug/transports/console.ts (1)
  • ConsoleTransport (3-32)
packages/clerk-js/src/core/modules/debug/transports/telemetry.ts (2)
  • TelemetryTransport (9-83)
  • TelemetryLoggerOptions (3-7)
packages/clerk-js/src/core/modules/debug/transports/composite.ts (2)
  • CompositeTransport (12-27)
  • CompositeLoggerOptions (3-10)
packages/clerk-js/src/core/modules/debug/logger.ts (2)
  • DebugLogger (6-116)
  • error (17-19)
packages/clerk-js/src/core/clerk.ts (1)
  • __internal_resetDebugLogger (2861-2865)
packages/clerk-js/src/core/modules/debug/transports/telemetry.ts (1)
packages/clerk-js/src/core/modules/debug/types.ts (4)
  • DebugLogFilter (79-86)
  • DebugTransport (43-48)
  • DebugLogEntry (14-24)
  • DebugData (29-38)
⏰ 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). (3)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (17)
packages/types/src/environment.ts (1)

22-22: LGTM! Clean addition of debug mode flag.

The new clientDebugMode boolean property is appropriately named and fits well within the existing EnvironmentResource interface structure.

packages/clerk-js/src/core/resources/Environment.ts (3)

23-23: Property declaration looks good.

The clientDebugMode property is properly initialized with a sensible default value of false.


52-52: Proper initialization pattern.

The use of withDefault helper ensures safe initialization from JSON data, following the established pattern used by other properties in this class.


93-93: Consistent serialization.

The property is correctly included in the snapshot serialization with proper snake_case naming convention for the JSON field.

packages/clerk-js/src/core/modules/debug/transports/telemetry.ts (4)

24-30: LGTM! Clean batching implementation.

The batching logic is straightforward and correctly triggers a flush when the batch size is reached. The async/await usage ensures proper error propagation.


68-73: LGTM! Proper cleanup implementation.

The destroy method correctly clears the timer and flushes any remaining buffered entries, preventing data loss during cleanup.


75-82: Verify browser environment compatibility.

The method uses window.setTimeout which is browser-specific. Ensure this transport is only used in browser environments or consider using a more universal timer approach.

The timer implementation is otherwise correct with proper error handling and recursive restart pattern.


1-83: Security review required for telemetry data transmission.

This transport sends debug log entries to external endpoints, which may contain sensitive information including user IDs, session IDs, organization IDs, and arbitrary context data. The debug entries are transmitted without apparent sanitization.

@clerk/security Please review this telemetry transport implementation for:

  • Potential PII leakage in debug context data
  • Data sanitization requirements before external transmission
  • Endpoint security and authentication requirements
  • Whether debug data should be filtered before sending to telemetry
packages/clerk-js/src/core/modules/debug/logger.ts (4)

3-15: LGTM! Well-designed class with proper dependency injection.

The class follows good practices with dependency injection for the transport mechanism, appropriate default values, and proper TypeScript typing.


17-35: LGTM! Consistent and clean logging method interface.

All logging methods follow the same pattern with consistent signatures and proper delegation to the private log method. The API design is intuitive for developers.


37-58: Verify crypto.randomUUID() browser compatibility.

The implementation is solid with proper early returns and error handling. However, crypto.randomUUID() requires modern browser support (Chrome 92+, Firefox 95+, Safari 15.4+).

Consider a fallback for older browsers or verify minimum browser requirements:

id: crypto.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,

Otherwise, the logging logic and error handling are well implemented.


60-65: LGTM! Correct log level hierarchy implementation.

The level checking logic correctly implements the standard logging hierarchy where error is the highest priority and trace is the lowest. The array-based approach is clean and efficient.

packages/clerk-js/src/core/clerk.ts (2)

202-207: Consider the implications of fire-and-forget async call.

The debug module initialization is called without awaiting, which creates a fire-and-forget pattern. This might be intentional for lazy loading, but consider:

  1. Potential race conditions if debugLogger is accessed immediately after updateEnvironment
  2. Error handling is delegated to the private method

If this behavior is intentional, consider adding a comment explaining the design decision.


1484-1484: LGTM! Good use of optional chaining for debug logging.

The debug logging implementation is well done:

  • Safe optional chaining prevents runtime errors
  • Consistent with existing router debug pattern
  • Provides valuable debugging information
packages/clerk-js/src/core/modules/debug/types.ts (3)

4-4: LGTM! Well-defined debug log levels.

The debug log levels follow standard logging conventions and provide appropriate granularity for debugging purposes.


130-132: Consider if mutable utility types are necessary.

The MutableDebugLogEntry and MutableDebugData types remove readonly constraints, which goes against the immutable design principle established by the readonly properties in the base interfaces.

Could you clarify the use case for these mutable utility types? If they're needed for specific scenarios, consider adding JSDoc comments explaining when they should be used, as removing readonly constraints could lead to unintended mutations.

Also applies to: 137-139


14-24: LGTM! Well-structured interfaces with proper readonly properties.

The interfaces are well-designed with:

  • Proper use of readonly properties for immutability
  • Comprehensive field coverage for debug logging needs
  • Optional properties marked appropriately
  • Good separation between log entries and debug data structures

Also applies to: 29-38

Copy link

pkg-pr-new bot commented Jul 31, 2025

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@6452

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@6452

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@6452

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@6452

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@6452

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@6452

@clerk/elements

npm i https://pkg.pr.new/@clerk/elements@6452

@clerk/clerk-expo

npm i https://pkg.pr.new/@clerk/clerk-expo@6452

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@6452

@clerk/express

npm i https://pkg.pr.new/@clerk/express@6452

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@6452

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@6452

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@6452

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@6452

@clerk/clerk-react

npm i https://pkg.pr.new/@clerk/clerk-react@6452

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@6452

@clerk/remix

npm i https://pkg.pr.new/@clerk/remix@6452

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@6452

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@6452

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@6452

@clerk/themes

npm i https://pkg.pr.new/@clerk/themes@6452

@clerk/types

npm i https://pkg.pr.new/@clerk/types@6452

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@6452

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@6452

commit: b25d4d4

Copy link
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

♻️ Duplicate comments (3)
packages/clerk-js/src/core/modules/debug/index.ts (3)

58-144: Well-implemented singleton with race condition protection.

The promise caching mechanism effectively prevents concurrent initialization issues, and the error handling properly clears state for retries. The implementation follows TypeScript best practices.

However, the telemetry endpoint security validation mentioned in past reviews appears to still be missing.


252-254: Add environment guard for internal reset function.

As mentioned in previous reviews, this internal function should be protected with environment checks to prevent misuse in production environments.

 export function __internal_resetDebugLogger(): void {
+  if (process.env.NODE_ENV === 'production') {
+    throw new Error('[Clerk] __internal_resetDebugLogger is disabled in production');
+  }
   DebugLoggerManager.getInstance().reset();
 }

106-106: Security concern: Telemetry endpoints lack validation.

As mentioned in previous reviews, the telemetry endpoints are used without validation, which could enable data exfiltration to malicious endpoints. This affects multiple locations where TelemetryTransport is instantiated.

@clerk/security - Please review the telemetry endpoint configuration as it poses a data exfiltration risk.

Consider implementing endpoint validation as suggested in previous reviews:

+function isValidTelemetryEndpoint(endpoint?: string): boolean {
+  if (!endpoint) return true; // Use default
+  try {
+    const url = new URL(endpoint);
+    return url.hostname.endsWith('.clerk.com') || url.hostname === 'clerk.com';
+  } catch {
+    return false;
+  }
+}

And validate before creating TelemetryTransport instances.

Also applies to: 172-172, 215-215

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b6f886a and eaeacb8.

📒 Files selected for processing (5)
  • packages/clerk-js/src/core/modules/debug/index.ts (1 hunks)
  • packages/clerk-js/src/core/modules/debug/logger.ts (1 hunks)
  • packages/clerk-js/src/core/modules/debug/transports/console.ts (1 hunks)
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts (1 hunks)
  • packages/clerk-js/src/core/modules/debug/types.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts
  • packages/clerk-js/src/core/modules/debug/transports/console.ts
  • packages/clerk-js/src/core/modules/debug/logger.ts
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
  • packages/clerk-js/src/core/modules/debug/types.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
  • packages/clerk-js/src/core/modules/debug/types.ts
packages/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
  • packages/clerk-js/src/core/modules/debug/types.ts
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
  • packages/clerk-js/src/core/modules/debug/types.ts
packages/**/index.{js,ts}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use tree-shaking friendly exports

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
  • packages/clerk-js/src/core/modules/debug/types.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
  • packages/clerk-js/src/core/modules/debug/types.ts
**/index.ts

📄 CodeRabbit Inference Engine (.cursor/rules/react.mdc)

Use index.ts files for clean imports but avoid deep barrel exports

Avoid barrel files (index.ts re-exports) as they can cause circular dependencies

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
**/*

⚙️ CodeRabbit Configuration File

**/*: If there are no tests added or modified as part of the PR, please suggest that tests be added to cover the changes.

Whenever reviewing a pull request, if there are any changes that could impact security, always tag @clerk/security in the PR.

Security-impacting changes include, but are not limited to:

  • Changes to authentication logic or mechanisms (e.g. login, session handling, token issuance)
  • Any modification to access control, authorization checks, or role-based permissions
  • Introduction or modification of hashing algorithms, signature verification, or cryptographic primitives
  • Handling of sensitive data (e.g. passwords, tokens, secrets, PII)
  • Integration with external identity providers (e.g. SSO, OAuth, OpenID Connect)
  • Modifications to security headers, cookie flags, CORS policies, or CSRF protections
  • Bypass mechanisms (e.g. feature flags, testing overrides) that could weaken protections
  • Changes to rate limiting, abuse prevention, or input validation

If you're unsure whether a change is security-relevant, err on the side of caution and tag @clerk/security.

Any time that you tag @clerk/security, please do so explicitly in a code comment, rather than within a collapsed section in a coderabbit comment, such as the "recent review details" section. If you do use the team name in any thinking or non-direct-code-comment content, it can be referred to as "clerk security team" to avoid accidentally printing the tag which sends a notification to the team.

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
  • packages/clerk-js/src/core/modules/debug/types.ts
🧬 Code Graph Analysis (1)
packages/clerk-js/src/core/modules/debug/index.ts (1)
packages/clerk-js/src/core/modules/debug/types.ts (4)
  • DebugLogLevel (4-4)
  • isValidLogLevel (96-98)
  • VALID_LOG_LEVELS (9-9)
  • DebugLogFilter (84-91)
⏰ 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). (22)
  • GitHub Check: Integration Tests (nextjs, chrome, 14)
  • GitHub Check: Integration Tests (nuxt, chrome)
  • GitHub Check: Integration Tests (tanstack-react-start, chrome)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (tanstack-react-router, chrome)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (expo-web, chrome)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (vue, chrome)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (quickstart, chrome)
  • GitHub Check: Integration Tests (elements, chrome)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Integration Tests (express, chrome)
  • GitHub Check: Publish with pkg-pr-new
  • GitHub Check: Unit Tests (22, **)
  • GitHub Check: Unit Tests (18, --filter=@clerk/astro --filter=@clerk/backend --filter=@clerk/express --filter=@c...
  • GitHub Check: Static analysis
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (7)
packages/clerk-js/src/core/modules/debug/index.ts (3)

1-11: LGTM!

Clean imports and appropriate default log level configuration.


18-25: Well-implemented validation with helpful error messaging.

The generic constraint and comprehensive error message make this validation function both flexible and developer-friendly.


27-47: Excellent use of type-only exports and well-documented interfaces.

Follows coding guidelines for clean imports and comprehensive JSDoc documentation.

packages/clerk-js/src/core/modules/debug/types.ts (4)

1-15: Well-defined type system with proper const assertions.

The union types and readonly constant array follow TypeScript best practices for type safety.


19-91: Comprehensive interface definitions with excellent documentation.

The interfaces properly use readonly properties for immutable data structures and include thorough JSDoc documentation, following the coding guidelines.


96-136: Type guards properly enhanced based on previous feedback.

The type guards now correctly validate enum values against their union types, addressing the security and type safety concerns from previous reviews.


141-155: Well-implemented utility types using advanced TypeScript features.

The mapped types properly handle readonly constraint removal while maintaining type safety.

Copy link
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: 0

♻️ Duplicate comments (4)
packages/clerk-js/src/core/modules/debug/index.ts (4)

171-172: Security concern: Same telemetry endpoint validation needed here.

This function also creates a TelemetryTransport without endpoint validation, which has the same security implications as flagged in the performInitialization method.


215-215: Security concern: Same telemetry endpoint validation needed here.

This function also creates a TelemetryTransport without endpoint validation, which has the same security implications as flagged in the performInitialization method.


254-256: Security concern: Internal reset function lacks environment protection.

This internal function can still be called in production environments, potentially clearing important debug state. The environment guard suggested in previous reviews has not been implemented.

Add environment protection:

 export function __internal_resetDebugLogger(): void {
+  if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production') {
+    throw new Error('[Clerk] __internal_resetDebugLogger is disabled in production');
+  }
   DebugLoggerManager.getInstance().reset();
 }

106-106: Security concern: Telemetry endpoint validation still missing.

The telemetry endpoint is used without validation, which poses a security risk for data exfiltration. This was flagged in previous reviews but remains unaddressed.

@clerk/security - Please review the telemetry endpoint configuration as debug data could be sent to arbitrary endpoints.

Consider implementing endpoint validation:

+// Add endpoint validation helper
+function isValidTelemetryEndpoint(endpoint?: string): boolean {
+  if (!endpoint) return true; // Use default
+  try {
+    const url = new URL(endpoint);
+    // Only allow clerk.com domains for security
+    return url.hostname.endsWith('.clerk.com') || url.hostname === 'clerk.com';
+  } catch {
+    return false;
+  }
+}

-      const transports = [{ transport: new ConsoleTransport() }, { transport: new TelemetryTransport(endpoint) }];
+      if (endpoint && !isValidTelemetryEndpoint(endpoint)) {
+        console.warn('Invalid telemetry endpoint provided, using default');
+        endpoint = undefined;
+      }
+      const transports = [{ transport: new ConsoleTransport() }, { transport: new TelemetryTransport(endpoint) }];
🧹 Nitpick comments (1)
packages/clerk-js/src/core/modules/debug/index.ts (1)

237-239: Simplify explicit type annotation.

The explicit type annotation is unnecessary since TypeScript can infer the type from the CompositeLoggerOptions interface.

-    const transportInstances = transports.map(
-      (t: { transport: DebugTransport; options?: Record<string, unknown> }) => t.transport,
-    );
+    const transportInstances = transports.map(t => t.transport);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c3e6e52 and bd86e19.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (1)
  • packages/clerk-js/src/core/modules/debug/index.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
packages/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
packages/**/index.{js,ts}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use tree-shaking friendly exports

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
**/index.ts

📄 CodeRabbit Inference Engine (.cursor/rules/react.mdc)

Use index.ts files for clean imports but avoid deep barrel exports

Avoid barrel files (index.ts re-exports) as they can cause circular dependencies

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
**/*

⚙️ CodeRabbit Configuration File

**/*: If there are no tests added or modified as part of the PR, please suggest that tests be added to cover the changes.

Whenever reviewing a pull request, if there are any changes that could impact security, always tag @clerk/security in the PR.

Security-impacting changes include, but are not limited to:

  • Changes to authentication logic or mechanisms (e.g. login, session handling, token issuance)
  • Any modification to access control, authorization checks, or role-based permissions
  • Introduction or modification of hashing algorithms, signature verification, or cryptographic primitives
  • Handling of sensitive data (e.g. passwords, tokens, secrets, PII)
  • Integration with external identity providers (e.g. SSO, OAuth, OpenID Connect)
  • Modifications to security headers, cookie flags, CORS policies, or CSRF protections
  • Bypass mechanisms (e.g. feature flags, testing overrides) that could weaken protections
  • Changes to rate limiting, abuse prevention, or input validation

If you're unsure whether a change is security-relevant, err on the side of caution and tag @clerk/security.

Any time that you tag @clerk/security, please do so explicitly in a code comment, rather than within a collapsed section in a coderabbit comment, such as the "recent review details" section. If you do use the team name in any thinking or non-direct-code-comment content, it can be referred to as "clerk security team" to avoid accidentally printing the tag which sends a notification to the team.

Files:

  • packages/clerk-js/src/core/modules/debug/index.ts
🧬 Code Graph Analysis (1)
packages/clerk-js/src/core/modules/debug/index.ts (6)
packages/clerk-js/src/core/modules/debug/types.ts (5)
  • DebugLogLevel (4-4)
  • isValidLogLevel (96-98)
  • VALID_LOG_LEVELS (9-9)
  • DebugLogFilter (84-91)
  • DebugTransport (48-53)
packages/clerk-js/src/core/modules/debug/logger.ts (2)
  • DebugLogger (11-121)
  • error (22-24)
packages/clerk-js/src/core/modules/debug/transports/console.ts (1)
  • ConsoleTransport (31-69)
packages/clerk-js/src/core/modules/debug/transports/telemetry.ts (2)
  • TelemetryTransport (9-83)
  • TelemetryLoggerOptions (3-7)
packages/clerk-js/src/core/modules/debug/transports/composite.ts (2)
  • CompositeTransport (12-27)
  • CompositeLoggerOptions (3-10)
packages/clerk-js/src/core/clerk.ts (1)
  • __internal_resetDebugLogger (2892-2896)
⏰ 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). (4)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
packages/clerk-js/src/core/modules/debug/index.ts (4)

1-31: LGTM! Clean imports and exports structure.

The imports are well-organized with proper type-only imports where appropriate. The exports follow tree-shaking friendly patterns and properly separate runtime code from type definitions.


8-25: LGTM! Well-implemented validation with helpful error messages.

The validation function uses proper generic constraints and provides clear, actionable error messages that include the invalid value and list of valid options.


32-47: LGTM! Clean interface definitions with proper documentation.

The interfaces are well-structured and provide clear contracts for logger configuration options.


58-144: LGTM! Singleton pattern with proper race condition handling.

The implementation correctly addresses the race condition concerns from previous reviews by using a promise cache pattern. The type safety issues have also been resolved with proper TypeScript types throughout.

Copy link
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: 0

🧹 Nitpick comments (1)
packages/shared/src/telemetry/collector.ts (1)

190-358: Consider adding unit tests for the new logging functionality

The new logging capabilities represent a significant feature addition. Based on the coding guidelines, tests should be added to cover the new functionality.

Key areas that should be tested include:

  • recordLog method behavior with various log entries
  • Log filtering logic in #shouldRecordLog
  • Log flush scheduling and execution
  • Error handling in log flush operations
  • Integration with existing telemetry functionality

Would you like me to help generate unit tests for the new logging functionality?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 441061e and 2170de0.

📒 Files selected for processing (1)
  • packages/shared/src/telemetry/collector.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/shared/src/telemetry/collector.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/shared/src/telemetry/collector.ts
packages/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/shared/src/telemetry/collector.ts
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/shared/src/telemetry/collector.ts
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/shared/src/telemetry/collector.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/shared/src/telemetry/collector.ts
**/*

⚙️ CodeRabbit Configuration File

If there are no tests added or modified as part of the PR, please suggest that tests be added to cover the changes.

Files:

  • packages/shared/src/telemetry/collector.ts
🧬 Code Graph Analysis (1)
packages/shared/src/telemetry/collector.ts (3)
packages/types/src/telemetry.ts (1)
  • TelemetryLogEntry (49-59)
packages/clerk-js/src/core/clerk.ts (2)
  • sdkMetadata (297-299)
  • sdkMetadata (301-303)
packages/react/src/isomorphicClerk.ts (1)
  • sdkMetadata (265-267)
⏰ 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). (5)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (9)
packages/shared/src/telemetry/collector.ts (9)

19-19: LGTM - Import addition is correct

The TelemetryLogEntry import is properly added to support the new logging functionality.


64-87: Well-structured type definition with clear documentation

The TelemetryLogData type is properly defined with comprehensive JSDoc comments explaining each field. This addresses the previous concern about using any[] by providing a specific type for log buffer entries.


102-106: Log buffer fields properly typed and protected

The log buffer and flush promise fields are correctly typed using the new TelemetryLogData[] type, and the pending flush protection has been added as suggested in previous reviews.


190-217: Robust log recording implementation with proper error boundaries

The recordLog method is well-implemented with:

  • Clear JSDoc documentation
  • Proper filtering via #shouldRecordLog
  • Correct data transformation using SDK metadata
  • Safe null handling for optional fields

The implementation correctly follows the existing pattern established by the record method.


223-225: Consider more granular log filtering logic

The current #shouldRecordLog implementation only checks if telemetry is enabled, but unlike events, it doesn't respect the debug mode check. This means logs will be recorded even in debug mode, which may or may not be intended.

Should logs be filtered out in debug mode like events are? The current logic differs from #shouldRecord which excludes debug mode:

// Events are filtered out in debug mode
#shouldRecord(preparedPayload: TelemetryEvent, eventSamplingRate?: number) {
  return this.isEnabled && !this.isDebug && this.#shouldBeSampled(preparedPayload, eventSamplingRate);
}

// But logs are not
#shouldRecordLog(_entry: TelemetryLogEntry): boolean {
  return this.isEnabled;
}

If logs should also be filtered in debug mode, apply this diff:

 #shouldRecordLog(_entry: TelemetryLogEntry): boolean {
-  return this.isEnabled;
+  return this.isEnabled && !this.isDebug;
 }

268-277: Consistent flush cleanup implementation

The addition of this.#pendingFlush = null; properly cleans up the pending flush state after completion, maintaining consistency with the new log flush implementation.


279-310: Well-implemented log flush scheduling with proper concurrency protection

The #scheduleLogFlush method correctly implements:

  • Server-side immediate flushing
  • Buffer size-based immediate flushing with pending flush cancellation
  • Duplicate flush prevention
  • Proper cleanup of pending flush state

This addresses the previous concern about missing pending flush protection for logs.


312-333: Improved event flush logic with better concurrency handling

The modifications to #flush add proper:

  • Duplicate flush prevention via #flushPromise check
  • Empty buffer early return
  • Promise cleanup in finally block

These improvements enhance the robustness of the existing event flushing mechanism.


335-358: Comprehensive log flush implementation with proper error handling

The #flushLogs method is well-implemented with:

  • Duplicate flush prevention
  • Empty buffer early return
  • Correct endpoint (/v1/logs)
  • Proper JSON serialization of log entries array
  • Exception handling with console error logging
  • Promise cleanup in both catch and finally blocks

The error handling is more comprehensive than the event flush, which is appropriate given that log flushing is a new feature.

Copy link
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

🔭 Outside diff range comments (1)
packages/clerk-js/bundlewatch.config.json (1)

3-33: Use lowercase “kB” for maxSize units in bundlewatch config
BundleWatch expects size units in “kB” (lowercase k, uppercase B). Update all occurrences in the config to match the official docs.

• packages/clerk-js/bundlewatch.config.json (lines 3–33): replace every "KB" with "kB" in the maxSize values.

Example diff:

--- a/packages/clerk-js/bundlewatch.config.json
+++ b/packages/clerk-js/bundlewatch.config.json
@@ -3,7 +3,7 @@
     { "path": "./dist/clerk.js", "maxSize": "623KB" },
-    { "path": "./dist/clerk.browser.js", "maxSize": "76KB" },
+    { "path": "./dist/clerk.browser.js", "maxSize": "76kB" },
     { "path": "./dist/clerk.legacy.browser.js", "maxSize": "118KB" },
-    { "path": "./dist/waitlist*.js", "maxSize": "1.5KB" },
+    { "path": "./dist/waitlist*.js", "maxSize": "1.5kB" },

Apply the same change to all other entries in this block to ensure consistency with BundleWatch’s documented format.

🧹 Nitpick comments (7)
packages/clerk-js/bundlewatch.config.json (4)

5-5: Legacy build budget increased; double-check legacy-only impact.

dist/clerk.legacy.browser.js to 118KB. Confirm the legacy build also keeps debug-only code out of the critical path and doesn’t pull the logger into shared chunks.


7-7: ui-common is widely shared; avoid pulling debug code into it.

ui-common*.js to 114KB. Since ui-common is broadly consumed, ensure the debug logger resides in a separate, lazily loaded chunk rather than inflating a shared common chunk.

If the logger currently lives under a path included in ui-common, consider moving it to a leaf module and lazily importing it only under clientDebugMode.


9-9: Vendors budget increased; verify debug deps didn’t leak into vendors.

vendors*.js to 41KB. The logger and its transports should not introduce third-party deps into the vendors chunk. Please confirm no new vendor dependencies were added by this feature.


3-3: Confirm debug logger dynamic‐import splitting
We see in packages/clerk-js/src/core/clerk.ts that you’re using:

  • Line 2273: const { getDebugLogger } = await import('./modules/debug');
  • Line 2947: const { __internal_resetDebugLogger } = await import('./modules/debug');

These dynamic imports should produce a separate “debug” chunk at build time. Since the dist output isn’t present here, please manually verify that your bundler:

  • Preserves await import('./modules/debug') rather than inlining it
  • Emits a standalone debug module (e.g. modules/debug.<hash>.js)
  • Leaves dist/clerk.js free of debug code when debug mode is disabled

This will ensure bumping the 623 KB budget is justified and that debug logging won’t bloat the main bundle.

packages/clerk-js/src/core/clerk.ts (1)

265-269: Consider awaiting debug module initialization or document the async behavior.

The debug module initialization is called without await, making it fire-and-forget. While this may be intentional for non-blocking initialization, it could lead to race conditions if debugLogger is accessed immediately after updateEnvironment.

Consider either awaiting the initialization or documenting this async behavior:

  // Initialize debug module if client_debug_mode is enabled
  if (environment.clientDebugMode) {
-   this.#initializeDebugModule();
+   void this.#initializeDebugModule();
  }

Or make it awaited if synchronous initialization is needed.

packages/shared/src/telemetry/collector.ts (2)

222-224: Consider removing unused parameter or document future use.

The _entry parameter is not used in the method. If it's not needed for future use, consider removing it. If it's reserved for future functionality, add a comment explaining this.

If not needed:

-  #shouldRecordLog(_entry: TelemetryLogEntry): boolean {
+  #shouldRecordLog(): boolean {

And update the call site at line 195:

-    if (!this.#shouldRecordLog(entry)) {
+    if (!this.#shouldRecordLog()) {

337-356: Consider adding debug logging for flush errors.

While silently catching errors prevents crashes, it might hide issues in development. Consider logging errors when in debug mode to aid troubleshooting.

-    }).catch(() => void 0);
+    }).catch((error) => {
+      if (this.isDebug) {
+        console.error('[clerk/telemetry] Failed to flush logs:', error);
+      }
+    });

The same improvement could be applied to the event flush at line 334.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5ff7b86 and f532cf0.

⛔ Files ignored due to path filters (2)
  • .typedoc/__tests__/__snapshots__/file-structure.test.ts.snap is excluded by !**/*.snap
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • packages/clerk-js/bundlewatch.config.json (1 hunks)
  • packages/clerk-js/src/core/clerk.ts (6 hunks)
  • packages/shared/src/telemetry/collector.ts (6 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/shared/src/telemetry/collector.ts
  • packages/clerk-js/src/core/clerk.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/shared/src/telemetry/collector.ts
  • packages/clerk-js/src/core/clerk.ts
  • packages/clerk-js/bundlewatch.config.json
packages/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/shared/src/telemetry/collector.ts
  • packages/clerk-js/src/core/clerk.ts
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/shared/src/telemetry/collector.ts
  • packages/clerk-js/src/core/clerk.ts
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/shared/src/telemetry/collector.ts
  • packages/clerk-js/src/core/clerk.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/shared/src/telemetry/collector.ts
  • packages/clerk-js/src/core/clerk.ts
**/*

⚙️ CodeRabbit Configuration File

If there are no tests added or modified as part of the PR, please suggest that tests be added to cover the changes.

Files:

  • packages/shared/src/telemetry/collector.ts
  • packages/clerk-js/src/core/clerk.ts
  • packages/clerk-js/bundlewatch.config.json
⏰ 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). (24)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (nuxt, chrome)
  • GitHub Check: Integration Tests (tanstack-react-router, chrome)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 14)
  • GitHub Check: Integration Tests (expo-web, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (vue, chrome)
  • GitHub Check: Integration Tests (elements, chrome)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Integration Tests (tanstack-react-start, chrome)
  • GitHub Check: Integration Tests (quickstart, chrome)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Integration Tests (express, chrome)
  • GitHub Check: Publish with pkg-pr-new
  • GitHub Check: Unit Tests (22, **)
  • GitHub Check: Unit Tests (18, --filter=@clerk/astro --filter=@clerk/backend --filter=@clerk/express --filter=@c...
  • GitHub Check: Static analysis
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (11)
packages/clerk-js/bundlewatch.config.json (2)

4-4: Justify budget change for browser build.

dist/clerk.browser.js maxSize raised to 76KB. Please add a brief rationale in the PR description linking the delta to debugLogger and confirm it won’t load in production/non-debug scenarios.


12-33: AI summary vs annotations discrepancy on “new” file patterns.

The AI summary claims ~21 new bundle entries were added, but this diff doesn’t mark them as changed lines. If these are indeed new, please confirm their budgets are derived from current gzip/brotli sizes with minimal headroom (ideally <=1–2%) and not overly permissive.

packages/clerk-js/src/core/clerk.ts (6)

164-173: LGTM! Well-structured interface.

The DebugLoggerInterface is properly defined with consistent method signatures and appropriate optional parameters for contextual logging.


175-188: LGTM! Comprehensive type guard implementation.

The type guard properly validates all required methods of the DebugLoggerInterface. The implementation correctly uses type assertions and checks for the presence of all required methods.


241-241: LGTM! Proper type definition implemented.

The debugLogger property now uses the proper DebugLoggerInterface type instead of any, addressing the previous review feedback about type safety.


271-281: LGTM! Well-implemented dynamic module loading.

The method properly handles dynamic import, validates the returned logger with the type guard, and includes appropriate error handling. The lazy loading pattern is correctly implemented.


1539-1539: LGTM! Clean integration of debug logging.

The debug logging for navigation is well-implemented with safe optional chaining and provides valuable debugging information.


942-949: LGTM! Proper internal API implementation.

The static reset method correctly delegates to the debug module and follows established patterns for internal APIs. The dynamic import ensures the debug module is available for the reset operation.

packages/shared/src/telemetry/collector.ts (3)

64-86: Well-structured type definition with proper documentation.

The TelemetryLogData type is well-defined with clear documentation for each field and follows TypeScript best practices by avoiding any types.


280-311: Well-implemented log flush scheduling with proper concurrency protection.

The #scheduleLogFlush method correctly implements pending flush protection and properly manages the flush state, addressing previous review concerns.


194-216: Add explicit return type to public API method.

The recordLog method is a public API method but lacks an explicit return type, which violates the coding guideline "Always define explicit return types for functions, especially public APIs".

Apply this diff:

-  recordLog(entry: TelemetryLogEntry): void {
+  recordLog(entry: TelemetryLogEntry): void {

Wait, the method already has : void return type. Let me re-examine...

Actually, the return type is already defined. The implementation looks good!

Copy link
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

♻️ Duplicate comments (2)
packages/shared/src/telemetry/collector.ts (2)

102-104: LGTM! Proper type definitions for pending flush handles.

The type definitions for #logBuffer and #pendingLogFlush correctly use union types with specific return types instead of any, addressing the issues from previous reviews.


283-317: LGTM! Well-implemented log flush scheduling with proper concurrency control.

The #scheduleLogFlush method correctly implements the same flush scheduling pattern as events, with proper pending flush protection and buffer management.

🧹 Nitpick comments (4)
packages/shared/src/telemetry/collector.ts (4)

222-224: Consider implementing sampling for logs similar to events.

The #shouldRecordLog method currently doesn't implement sampling logic. For consistency with event handling and to control log volume, consider adding sampling support.

Apply this diff to add sampling support for logs:

-#shouldRecordLog(_entry: TelemetryLogEntry): boolean {
-  return this.isEnabled && !this.isDebug;
+#shouldRecordLog(entry: TelemetryLogEntry): boolean {
+  if (!this.isEnabled || this.isDebug) {
+    return false;
+  }
+  
+  // Apply sampling rate to logs if configured
+  if (this.#config.samplingRate < 1 && Math.random() > this.#config.samplingRate) {
+    return false;
+  }
+  
+  return true;
 }

254-258: Simplify cancelIdleCallback type casting.

The Number() casting for cancelIdleCallback is unnecessary since TypeScript already knows the type from the union definition.

Apply this diff to simplify the code:

 if (typeof cancelIdleCallback !== 'undefined') {
-  cancelIdleCallback(Number(this.#pendingFlush));
+  cancelIdleCallback(this.#pendingFlush as number);
 } else {
-  clearTimeout(Number(this.#pendingFlush));
+  clearTimeout(this.#pendingFlush as ReturnType<typeof setTimeout>);
 }

343-362: Consider adding error handling and retry logic for log flushing.

While silently catching errors is acceptable for telemetry, consider implementing retry logic for transient network failures to improve reliability.

Consider implementing a retry mechanism with exponential backoff for failed log submissions. This could be shared between both event and log flushing to ensure telemetry data is not lost due to temporary network issues.

Example implementation approach:

private async #flushWithRetry(url: URL, data: unknown, maxRetries = 3): Promise<void> {
  let lastError: Error | undefined;
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, {
        method: 'POST',
        body: JSON.stringify(data),
        keepalive: true,
        headers: { 'Content-Type': 'application/json' },
      });
      if (response.ok) return;
      lastError = new Error(`HTTP ${response.status}`);
    } catch (error) {
      lastError = error as Error;
    }
    // Exponential backoff
    if (attempt < maxRetries - 1) {
      await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
    }
  }
  if (this.isDebug && lastError) {
    console.error('[clerk/telemetry] Failed to flush after retries:', lastError);
  }
}

291-296: Apply same type casting simplification as in event flushing.

For consistency with the event flushing code, simplify the type casting in log flush cancellation.

Apply this diff:

 if (typeof cancelIdleCallback !== 'undefined') {
-  cancelIdleCallback(Number(this.#pendingLogFlush));
+  cancelIdleCallback(this.#pendingLogFlush as number);
 } else {
-  clearTimeout(Number(this.#pendingLogFlush));
+  clearTimeout(this.#pendingLogFlush as ReturnType<typeof setTimeout>);
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 55bda4e and 243f598.

📒 Files selected for processing (1)
  • packages/shared/src/telemetry/collector.ts (7 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/shared/src/telemetry/collector.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/shared/src/telemetry/collector.ts
packages/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/shared/src/telemetry/collector.ts
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/shared/src/telemetry/collector.ts
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/shared/src/telemetry/collector.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/shared/src/telemetry/collector.ts
**/*

⚙️ CodeRabbit Configuration File

If there are no tests added or modified as part of the PR, please suggest that tests be added to cover the changes.

Files:

  • packages/shared/src/telemetry/collector.ts
🧬 Code Graph Analysis (1)
packages/shared/src/telemetry/collector.ts (3)
packages/types/src/telemetry.ts (2)
  • TelemetryLogEntry (49-59)
  • TelemetryEvent (8-35)
packages/clerk-js/src/core/clerk.ts (2)
  • sdkMetadata (298-300)
  • sdkMetadata (302-304)
packages/react/src/isomorphicClerk.ts (1)
  • sdkMetadata (266-268)
⏰ 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). (5)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (1)
packages/shared/src/telemetry/collector.ts (1)

64-86: LGTM! Well-structured type definition for log data.

The TelemetryLogData type is properly documented and follows TypeScript best practices with clear field names and appropriate types.

Copy link
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: 2

♻️ Duplicate comments (1)
packages/shared/src/telemetry/collector.ts (1)

311-345: LGTM! Proper concurrent flush protection implemented.

The log flush scheduling correctly implements pending flush protection and handles both browser and server environments appropriately. The implementation mirrors the event flush logic with proper timer cancellation.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 243f598 and b25d4d4.

📒 Files selected for processing (1)
  • packages/shared/src/telemetry/collector.ts (8 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/shared/src/telemetry/collector.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/shared/src/telemetry/collector.ts
packages/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/shared/src/telemetry/collector.ts
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/shared/src/telemetry/collector.ts
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/shared/src/telemetry/collector.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/shared/src/telemetry/collector.ts
**/*

⚙️ CodeRabbit Configuration File

If there are no tests added or modified as part of the PR, please suggest that tests be added to cover the changes.

Files:

  • packages/shared/src/telemetry/collector.ts
🧬 Code Graph Analysis (1)
packages/shared/src/telemetry/collector.ts (4)
packages/clerk-js/src/core/modules/debug/types.ts (1)
  • VALID_LOG_LEVELS (9-9)
packages/types/src/telemetry.ts (2)
  • TelemetryLogEntry (49-59)
  • TelemetryEvent (8-35)
packages/clerk-js/src/core/clerk.ts (2)
  • sdkMetadata (298-300)
  • sdkMetadata (302-304)
packages/react/src/isomorphicClerk.ts (1)
  • sdkMetadata (266-268)
⏰ 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). (4)
  • GitHub Check: Build Packages
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (2)
packages/shared/src/telemetry/collector.ts (2)

464-480: LGTM! Robust context sanitization.

The #sanitizeContext method properly handles all edge cases and ensures JSON-serializable output. The implementation correctly rejects arrays and handles errors gracefully.


197-244: Verify and standardize error context in telemetry

We ran searches for all recordLog invocations but didn’t find any call sites in the repo. If you intend to use recordLog for error reporting, please manually confirm where it’s called and ensure the context payload enforces a uniform error schema. For example:

• Validate that context.error is an object with at least
 – message: string
 – stack: string
 – name: string
 (and optional fields like code?: string)
• Normalize or strip non-portable data from stacks (paths, timestamps)
• Apply these checks in #sanitizeContext or at the start of recordLog

This will help prevent inconsistent telemetry entries when errors are logged from different upstream/downstream modules.

Comment on lines +250 to +252
#shouldRecordLog(_entry: TelemetryLogEntry): boolean {
return this.isEnabled && !this.isDebug;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding rate limiting for log recording.

While event recording has throttling via TelemetryEventThrottler, the log recording doesn't have any rate limiting mechanism. This could lead to excessive log volume during error conditions or debug scenarios.

Consider implementing rate limiting similar to the event throttler:

+import { TelemetryLogThrottler } from './log-throttler';
+
 export class TelemetryCollector implements TelemetryCollectorInterface {
   #config: Required<TelemetryCollectorConfig>;
   #eventThrottler: TelemetryEventThrottler;
+  #logThrottler: TelemetryLogThrottler;
   
   constructor(options: TelemetryCollectorOptions) {
     // ... existing code ...
     this.#eventThrottler = new TelemetryEventThrottler();
+    this.#logThrottler = new TelemetryLogThrottler();
   }
   
   #shouldRecordLog(entry: TelemetryLogEntry): boolean {
-    return this.isEnabled && !this.isDebug;
+    return this.isEnabled && !this.isDebug && !this.#logThrottler.isLogThrottled(entry);
   }

You would need to implement a TelemetryLogThrottler class similar to the existing event throttler.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/shared/src/telemetry/collector.ts around lines 250-252, log
recording currently only checks isEnabled and isDebug and lacks rate limiting;
implement a TelemetryLogThrottler (mirroring the existing
TelemetryEventThrottler) and update shouldRecordLog to consult that throttler
before allowing a log to be recorded. Create a TelemetryLogThrottler class that
exposes the same interface as the event throttler (e.g., shouldAllow(key) or
tryRecord(key)) with configurable limits and time windows, wire it into the
collector (inject or instantiate respecting existing configuration flags and
toggles), ensure it short-circuits when telemetry is disabled or in debug mode,
and add unit tests and configuration entries matching the event throttler so log
volume is controlled during error storms.

Comment on lines +371 to +390
#flushLogs(): void {
// Capture the current buffer and clear it immediately to avoid closure references
const entriesToSend = [...this.#logBuffer];
this.#logBuffer = [];

this.#pendingLogFlush = null;

if (entriesToSend.length === 0) {
return;
}

fetch(new URL('/v1/logs', this.#config.endpoint), {
method: 'POST',
body: JSON.stringify(entriesToSend),
keepalive: true,
headers: {
'Content-Type': 'application/json',
},
}).catch(() => void 0);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling and retry logic for log flushing.

The #flushLogs method silently swallows errors without any retry mechanism or error telemetry. This could lead to silent data loss during network issues.

Consider adding retry logic and error reporting:

-  #flushLogs(): void {
+  async #flushLogs(retryCount = 0): Promise<void> {
     // Capture the current buffer and clear it immediately to avoid closure references
     const entriesToSend = [...this.#logBuffer];
     this.#logBuffer = [];
 
     this.#pendingLogFlush = null;
 
     if (entriesToSend.length === 0) {
       return;
     }
 
-    fetch(new URL('/v1/logs', this.#config.endpoint), {
-      method: 'POST',
-      body: JSON.stringify(entriesToSend),
-      keepalive: true,
-      headers: {
-        'Content-Type': 'application/json',
-      },
-    }).catch(() => void 0);
+    try {
+      const response = await fetch(new URL('/v1/logs', this.#config.endpoint), {
+        method: 'POST',
+        body: JSON.stringify(entriesToSend),
+        keepalive: true,
+        headers: {
+          'Content-Type': 'application/json',
+        },
+      });
+      
+      if (!response.ok && retryCount < 2) {
+        // Retry with exponential backoff
+        setTimeout(() => {
+          this.#logBuffer.unshift(...entriesToSend);
+          this.#flushLogs(retryCount + 1);
+        }, Math.pow(2, retryCount) * 1000);
+      }
+    } catch (error) {
+      if (this.isDebug) {
+        console.error('[clerk/telemetry] Failed to flush logs:', error);
+      }
+      // Consider re-queuing on recoverable errors
+      if (retryCount < 2) {
+        this.#logBuffer.unshift(...entriesToSend);
+      }
+    }
   }
📝 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.

Suggested change
#flushLogs(): void {
// Capture the current buffer and clear it immediately to avoid closure references
const entriesToSend = [...this.#logBuffer];
this.#logBuffer = [];
this.#pendingLogFlush = null;
if (entriesToSend.length === 0) {
return;
}
fetch(new URL('/v1/logs', this.#config.endpoint), {
method: 'POST',
body: JSON.stringify(entriesToSend),
keepalive: true,
headers: {
'Content-Type': 'application/json',
},
}).catch(() => void 0);
}
async #flushLogs(retryCount = 0): Promise<void> {
// Capture the current buffer and clear it immediately to avoid closure references
const entriesToSend = [...this.#logBuffer];
this.#logBuffer = [];
this.#pendingLogFlush = null;
if (entriesToSend.length === 0) {
return;
}
try {
const response = await fetch(
new URL('/v1/logs', this.#config.endpoint),
{
method: 'POST',
body: JSON.stringify(entriesToSend),
keepalive: true,
headers: {
'Content-Type': 'application/json',
},
}
);
if (!response.ok && retryCount < 2) {
// Retry with exponential backoff
setTimeout(() => {
this.#logBuffer.unshift(...entriesToSend);
this.#flushLogs(retryCount + 1);
}, Math.pow(2, retryCount) * 1000);
}
} catch (error) {
if (this.isDebug) {
console.error('[clerk/telemetry] Failed to flush logs:', error);
}
// Re-queue entries for up to 2 retries
if (retryCount < 2) {
this.#logBuffer.unshift(...entriesToSend);
}
}
}
🤖 Prompt for AI Agents
In packages/shared/src/telemetry/collector.ts around lines 371 to 390, the
#flushLogs implementation currently swallows fetch errors and can lose logs; add
retry and error reporting by: wrap the fetch in a retry loop with a capped
number of attempts (e.g., 3) and exponential backoff delays, on failure re-queue
the entries (append them back to this.#logBuffer or a separate retry buffer) so
they aren’t lost, and emit/record an error telemetry event or call a logger with
the error and attempt count; ensure retries are non-blocking (use setTimeout)
and don’t duplicate entries when multiple flushes run concurrently by locking or
checking a pending flag.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants