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

Merged
merged 7 commits into from
Aug 14, 2025
Merged

feat(clerk-js): Introduce debugLogger #6452

merged 7 commits into from
Aug 14, 2025

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

    • Opt-in client debug mode and a public debug logger surface with buffered pre-init logging.
    • Expanded debug events across load, navigation, session activation, sign-out, and network requests.
    • Enhanced console formatting and optional forwarding of structured debug logs to telemetry; telemetry now accepts log entries and batches/sends them.
  • Tests

    • Added comprehensive tests for logger behavior, transports, telemetry transport, and telemetry log delivery.
  • Chores

    • Updated bundle size thresholds and expanded artifact monitoring.

Copy link

changeset-bot bot commented Jul 31, 2025

🦋 Changeset detected

Latest commit: ceb629e

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 14, 2025 0:42am

Copy link
Contributor

coderabbitai bot commented Jul 31, 2025

📝 Walkthrough

Walkthrough

This PR adds a debug logging subsystem to clerk-js: new types, transports (console, telemetry, composite), a DebugLogger class, and a DebugLoggerManager singleton with lazy initialization. A public debug surface (debugLogger, initDebugLogger) buffers pre-init logs. Clerk surfaces a public debugLogger member and emits debug calls in load, navigation, setActive, signOut, and fapiClient flows. Environment gains clientDebugMode to control client activation. TelemetryCollector gains recordLog and batching/flush logic to POST /v1/logs. Tests for logger and telemetry transport are included and types across packages were extended.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Assessment against linked issues

Objective Addressed Explanation
Create debugLogger for clerk-js (USER-2540)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Removal of environment from Clerk.sdkMetadata initialization (packages/clerk-js/src/core/clerk.ts) This metadata field change is unrelated to implementing the debug logger; it is not referenced by USER-2540.
Added generateUuid utility and export (packages/shared/src/utils/uuid.ts; packages/shared/src/utils/index.ts) New UUID generator is not used by the debug logger implementation or its types; outside the stated debug-logger objective.
Reordered/moved fields in EnvironmentJSON (packages/types/src/json.ts) Property reordering and movement do not affect the debug logger objective (client_debug_mode addition only required).

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 98133bb and ceb629e.

📒 Files selected for processing (1)
  • packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.spec.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/clerk-js/src/core/modules/debug/transports/tests/telemetry.spec.ts
⏰ 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: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan

🪧 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: ceb629e

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/clerk-js/src/core/modules/debug/__tests__/logger.test.ts (1)

5-10: Consider using proper TypeScript types for better type safety.

The MockTransport uses any type for log entries, which reduces type safety in tests. Consider using the actual DebugLogEntry type to ensure the mock accurately reflects the real transport interface.

+import type { DebugLogEntry } from '../types';
+
 class MockTransport {
-  public sentEntries: any[] = [];
+  public sentEntries: DebugLogEntry[] = [];

-  async send(entry: any): Promise<void> {
+  async send(entry: DebugLogEntry): Promise<void> {
     this.sentEntries.push(entry);
   }
📜 Review details

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

📥 Commits

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

📒 Files selected for processing (2)
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.test.ts (1 hunks)
  • packages/clerk-js/src/core/modules/debug/logger.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/clerk-js/src/core/modules/debug/logger.ts
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{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/__tests__/logger.test.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/__tests__/logger.test.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/__tests__/logger.test.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/__tests__/logger.test.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/__tests__/logger.test.ts
packages/**/*.{test,spec}.{js,jsx,ts,tsx}

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

Unit tests should use Jest or Vitest as the test runner.

Files:

  • packages/clerk-js/src/core/modules/debug/__tests__/logger.test.ts
packages/{clerk-js,elements,themes}/**/*.{test,spec}.{js,jsx,ts,tsx}

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

Visual regression testing should be performed for UI components.

Files:

  • packages/clerk-js/src/core/modules/debug/__tests__/logger.test.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/__tests__/logger.test.ts
**/__tests__/**/*.{ts,tsx}

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

**/__tests__/**/*.{ts,tsx}: Create type-safe test builders/factories
Use branded types for test isolation
Implement proper mock types that match interfaces

Files:

  • packages/clerk-js/src/core/modules/debug/__tests__/logger.test.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/__tests__/logger.test.ts
⏰ 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: semgrep-cloud-platform/scan
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (5)
packages/clerk-js/src/core/modules/debug/__tests__/logger.test.ts (5)

30-69: Excellent test coverage for basic logging functionality.

The tests comprehensively cover all logging levels, context/source inclusion, and log level filtering. The test structure is clear and descriptive, making it easy to understand what each test validates.


71-327: Outstanding comprehensive filter testing.

This section provides exceptional coverage of the filtering system, including:

  • All filter types (level, source, include/exclude patterns)
  • Both string and RegExp pattern matching
  • Complex filter combinations with AND logic
  • Proper edge case handling (empty patterns, special characters, case sensitivity)
  • Boundary conditions (undefined/empty filter arrays)

The nested describe structure makes the tests well-organized and maintainable.


329-372: Thorough validation of log entry structure.

These tests effectively validate the complete log entry structure, ensuring:

  • All required properties are present
  • Correct data types for each field
  • Unique ID generation for traceability
  • Accurate timestamp generation

This provides confidence that the logger produces well-structured, consistent output.


17-28: Proper test setup with good isolation.

The test setup correctly:

  • Creates fresh instances for each test to prevent test interdependence
  • Uses 'trace' level for maximum log coverage during testing
  • Properly cleans up mock state between tests

This ensures reliable and isolated test execution.


1-3: Clean and appropriate imports.

The imports are minimal and correctly structured, importing only the necessary components for testing.

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: 4

🔭 Outside diff range comments (1)
packages/clerk-js/src/core/modules/debug/index.ts (1)

1-260: Consider adding comprehensive tests for this core module.

This is a critical module that manages the entire debug logging system, but no tests are included in this PR. The complexity and importance of this module warrant comprehensive test coverage.

Would you like me to help create a comprehensive test suite for the DebugLoggerManager and factory functions?

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

256-259: Add environment protection for internal reset function.

Based on the past review comments, this internal function should be protected from production use to prevent accidental state clearing.

🧹 Nitpick comments (3)
packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.test.ts (1)

20-46: Consider adding more comprehensive test coverage.

While the basic functionality is tested, consider adding tests for:

  • Handling of all DebugLogEntry properties
  • Error scenarios in the collector's recordLog method
  • Validation of the exact data transformation between DebugLogEntry and TelemetryLogEntry
packages/clerk-js/src/core/modules/debug/transports/telemetry.ts (1)

5-9: Consider removing unused TelemetryLoggerOptions interface.

The TelemetryLoggerOptions interface is defined but doesn't appear to be used in this file. It might belong in the main debug module or could be removed if unused.

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

51-55: Consider making CompositeLoggerOptions more flexible.

The transport array is constrained to only ConsoleTransport | TelemetryTransport, but the CompositeTransport class accepts any DebugTransport. This limits extensibility.

Apply this diff to make it more flexible:

export interface CompositeLoggerOptions {
-  transports: Array<{ transport: ConsoleTransport | TelemetryTransport }>;
+  transports: Array<{ transport: DebugTransport }>;
   logLevel?: DebugLogLevel;
   filters?: DebugLogFilter[];
 }

You'll need to import DebugTransport from './types'.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 9c234a4 and 496cd4c.

📒 Files selected for processing (6)
  • packages/clerk-js/bundlewatch.config.json (1 hunks)
  • packages/clerk-js/src/core/modules/debug/index.ts (1 hunks)
  • packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.test.ts (1 hunks)
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts (1 hunks)
  • packages/shared/src/telemetry/collector.ts (5 hunks)
  • packages/types/src/telemetry.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/clerk-js/bundlewatch.config.json
🧰 Additional context used
📓 Path-based instructions (12)
**/*.{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/transports/__tests__/telemetry.test.ts
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts
  • packages/types/src/telemetry.ts
  • packages/shared/src/telemetry/collector.ts
  • 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/transports/__tests__/telemetry.test.ts
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts
  • packages/types/src/telemetry.ts
  • packages/shared/src/telemetry/collector.ts
  • 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/transports/__tests__/telemetry.test.ts
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts
  • packages/types/src/telemetry.ts
  • packages/shared/src/telemetry/collector.ts
  • 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/transports/__tests__/telemetry.test.ts
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts
  • packages/types/src/telemetry.ts
  • packages/shared/src/telemetry/collector.ts
  • 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/transports/__tests__/telemetry.test.ts
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts
  • packages/types/src/telemetry.ts
  • packages/shared/src/telemetry/collector.ts
  • packages/clerk-js/src/core/modules/debug/index.ts
packages/**/*.{test,spec}.{js,jsx,ts,tsx}

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

Unit tests should use Jest or Vitest as the test runner.

Files:

  • packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.test.ts
packages/{clerk-js,elements,themes}/**/*.{test,spec}.{js,jsx,ts,tsx}

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

Visual regression testing should be performed for UI components.

Files:

  • packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.test.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/transports/__tests__/telemetry.test.ts
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts
  • packages/types/src/telemetry.ts
  • packages/shared/src/telemetry/collector.ts
  • packages/clerk-js/src/core/modules/debug/index.ts
**/__tests__/**/*.{ts,tsx}

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

**/__tests__/**/*.{ts,tsx}: Create type-safe test builders/factories
Use branded types for test isolation
Implement proper mock types that match interfaces

Files:

  • packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.test.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/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.test.ts
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts
  • packages/types/src/telemetry.ts
  • packages/shared/src/telemetry/collector.ts
  • 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
**/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 (3)
packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.test.ts (4)
packages/types/src/telemetry.ts (1)
  • TelemetryCollector (61-66)
packages/shared/src/telemetry/collector.ts (1)
  • TelemetryCollector (73-383)
packages/clerk-js/src/core/modules/debug/transports/telemetry.ts (1)
  • TelemetryTransport (11-35)
packages/clerk-js/src/core/modules/debug/types.ts (1)
  • DebugLogEntry (19-29)
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 (297-299)
  • sdkMetadata (301-303)
packages/react/src/isomorphicClerk.ts (1)
  • sdkMetadata (265-267)
packages/clerk-js/src/core/modules/debug/index.ts (8)
packages/clerk-js/src/core/modules/debug/types.ts (2)
  • DebugLogLevel (4-4)
  • DebugLogFilter (84-91)
packages/types/src/telemetry.ts (1)
  • TelemetryCollector (61-66)
packages/shared/src/telemetry/collector.ts (1)
  • TelemetryCollector (73-383)
packages/clerk-js/src/core/modules/debug/transports/telemetry.ts (2)
  • TelemetryLoggerOptions (5-9)
  • TelemetryTransport (11-35)
packages/clerk-js/src/core/modules/debug/transports/composite.ts (2)
  • CompositeLoggerOptions (3-10)
  • CompositeTransport (12-27)
packages/clerk-js/src/core/modules/debug/transports/console.ts (1)
  • ConsoleTransport (31-69)
packages/clerk-js/src/core/modules/debug/logger.ts (2)
  • DebugLogger (11-139)
  • error (22-24)
packages/clerk-js/src/core/clerk.ts (1)
  • __internal_resetDebugLogger (2899-2903)
🪛 ESLint
packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.test.ts

[error] 1-3: Run autofix to sort these imports!

(simple-import-sort/imports)


[error] 2-2: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)

⏰ 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: semgrep-cloud-platform/scan
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (7)
packages/types/src/telemetry.ts (2)

46-59: LGTM - Well-structured debug log entry interface.

The TelemetryLogEntry interface is well-designed with:

  • Readonly properties for immutability
  • Proper typing with constrained log levels
  • Appropriate optional fields for metadata
  • Good alignment with the debug logging system requirements

65-65: LGTM - Clean extension of TelemetryCollector interface.

The addition of the recordLog method to the TelemetryCollector interface is clean and follows the existing pattern established by the record method.

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

11-35: LGTM - Clean and robust transport implementation.

The TelemetryTransport class is well-implemented with:

  • Proper null-checking for optional collector
  • Clean property mapping between log entry types
  • Graceful handling of missing dependencies
  • Appropriate async/await usage
packages/shared/src/telemetry/collector.ts (2)

163-190: LGTM - Well-structured log recording implementation.

The recordLog method follows good patterns:

  • Proper filtering with #shouldRecordLog
  • Consistent metadata enrichment using #getSDKMetadata
  • Appropriate data transformation and buffering
  • Integration with scheduling logic

294-313: LGTM - Robust log flushing implementation.

The #flushLogs method is well-implemented with:

  • Proper empty buffer check
  • Safe buffer copying and clearing
  • Appropriate error handling with console.error
  • Correct endpoint usage
packages/clerk-js/src/core/modules/debug/index.ts (2)

14-18: LGTM - Proper input validation.

The validateLoggerOptions function provides essential runtime validation to prevent configuration errors.


60-148: LGTM - Well-implemented singleton pattern with race condition protection.

The DebugLoggerManager class properly implements:

  • Thread-safe singleton pattern
  • Race condition protection with promise caching
  • Proper error handling and cleanup
  • Clear separation of concerns

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: 3

♻️ Duplicate comments (1)
packages/clerk-js/src/utils/debug.ts (1)

24-27: Fix races and duplicate initialization: add in-flight guard, snapshot options, and re-check isEnabled.

Without an in-flight guard and post-await checks, concurrent calls can:

  • Initialize twice in parallel.
  • Overwrite a newly reconfigured logger with an older instance.
  • Attach a logger after isEnabled has been flipped to false.

Add initializingPromise, snapshot lastOptions, re-check isEnabled after awaits, and await any in-flight init before reconfiguring.

Apply these diffs:

 let isEnabled = false;
 let realLogger: DebugLoggerInterface | null = null;
 let lastOptions: Omit<InitOptions, 'enabled'> | null = null;
+let initializingPromise: Promise<void> | null = null;
-async function ensureInitialized(): Promise<void> {
-  try {
-    if (!isEnabled || realLogger) {
-      return;
-    }
-
-    const { getDebugLogger } = await import('@/core/modules/debug');
-    const logger = await getDebugLogger({
-      filters: lastOptions?.filters,
-      logLevel: lastOptions?.logLevel ?? 'trace',
-      telemetryCollector: lastOptions?.telemetryCollector,
-    });
-
-    if (logger) {
-      realLogger = logger;
-      flushBuffered();
-    }
-  } catch (error) {
-    const message = 'Debug logger initialization failed';
-    if (isEnabled && realLogger) {
-      try {
-        realLogger.trace(message, { error });
-      } catch {
-        // ignore secondary logging errors
-      }
-    } else {
-      try {
-        // Use a safe, minimal fallback to avoid noisy errors
-        console.debug?.(message, error);
-      } catch {
-        // ignore secondary logging errors
-      }
-    }
-    // Silently return to avoid unhandled rejections and preserve behavior
-    return;
-  }
-}
+async function ensureInitialized(): Promise<void> {
+  // Bail if disabled, already initialized, or an init is in-flight
+  if (!isEnabled || realLogger || initializingPromise) {
+    return;
+  }
+  // Snapshot to avoid races during awaits
+  const options = lastOptions;
+  const enabledAtStart = isEnabled;
+
+  initializingPromise = (async () => {
+    try {
+      const { getDebugLogger } = await import('@/core/modules/debug');
+      const logger = await getDebugLogger({
+        filters: options?.filters,
+        logLevel: options?.logLevel ?? 'trace',
+        telemetryCollector: options?.telemetryCollector,
+      });
+      // If disabled or already set while awaiting, do nothing
+      if (!enabledAtStart || !isEnabled || realLogger) {
+        return;
+      }
+      if (logger) {
+        realLogger = logger;
+        flushBuffered();
+      }
+    } catch (error) {
+      const message = 'Debug logger initialization failed';
+      try {
+        if (isEnabled && realLogger) {
+          realLogger.trace(message, { error });
+        } else {
+          console.debug?.(message, error);
+        }
+      } catch {
+        // ignore secondary logging errors
+      }
+    } finally {
+      initializingPromise = null;
+    }
+  })();
+
+  await initializingPromise;
+}
   if (realLogger) {
     void (async () => {
       try {
+        // Avoid racing with an in-flight initialization
+        if (initializingPromise) {
+          try {
+            await initializingPromise;
+          } catch {
+            // ignore
+          }
+        }
         const { __internal_resetDebugLogger, getDebugLogger } = await import('@/core/modules/debug');
         __internal_resetDebugLogger();
         const logger = await getDebugLogger({

Also applies to: 79-115, 156-178

🧹 Nitpick comments (3)
packages/clerk-js/src/utils/debug.ts (3)

17-22: Export the options type to complete the public API.

Consumers may want to import the options type used by initDebugLogger. Exporting it aligns with package guidelines to export types alongside runtime code.

-type InitOptions = {
+export type InitOptions = {
   enabled?: boolean;
   filters?: DebugLogFilter[];
   logLevel?: DebugLogLevel;
   telemetryCollector?: TelemetryCollector;
 };

5-15: Mark public surfaces with @public and document buffering semantics explicitly.

Both the interface and the exported singleton are public. Also clarify that calls are buffered until initialization when enabled (not strictly “no-op”).

Apply these doc tweaks:

-/**
- * Lightweight logger surface that callers can import as a singleton.
- * Methods are no-ops until initialized via `initDebugLogger`.
- */
+/**
+ * Lightweight logger surface that callers can import as a singleton.
+ * When enabled, calls are buffered until initialized via `initDebugLogger`; when disabled, methods no-op.
+ * @public
+ */
 export interface DebugLoggerInterface {
 /**
- * Singleton debug logger surface.
+ * Singleton debug logger surface.
  *
- * - No-op until `initDebugLogger` initializes the real logger
+ * - When enabled, calls are buffered until the real logger is initialized via `initDebugLogger`
+ * - When disabled, methods are no-ops
  * - Safe to import anywhere; all methods are guarded
  *
+ * @public
  * @example

Also applies to: 184-197


198-236: Consider a small helper to reduce repetition in the wrapper methods.

Not required, but a local logOrBuffer(level, ...) would DRY the five nearly identical methods without sacrificing readability.

Example:

function logOrBuffer(level: DebugLogLevel, message: string, context?: Record<string, unknown>, source?: string) {
  if (!isEnabled) return;
  if (!realLogger) return pushBuffered(level, message, context, source);
  (realLogger as any)[level](message, context, source);
}

Then forward each method to logOrBuffer('info', ...), etc.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f856c2f and 113807b.

⛔ Files ignored due to path filters (1)
  • .typedoc/__tests__/__snapshots__/file-structure.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (2)
  • packages/clerk-js/src/core/fapiClient.ts (2 hunks)
  • packages/clerk-js/src/utils/debug.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/clerk-js/src/core/fapiClient.ts
🧰 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/clerk-js/src/utils/debug.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/utils/debug.ts
packages/**/*.{ts,tsx}

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

TypeScript is required for all packages

Files:

  • packages/clerk-js/src/utils/debug.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/utils/debug.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/utils/debug.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/utils/debug.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/clerk-js/src/utils/debug.ts
🧬 Code Graph Analysis (1)
packages/clerk-js/src/utils/debug.ts (3)
packages/clerk-js/src/core/modules/debug/types.ts (2)
  • DebugLogFilter (84-91)
  • DebugLogLevel (4-4)
packages/clerk-js/src/core/modules/debug/index.ts (2)
  • getDebugLogger (174-177)
  • __internal_resetDebugLogger (280-283)
packages/clerk-js/src/core/modules/debug/logger.ts (1)
  • error (51-53)
⏰ 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 (4)
packages/clerk-js/src/utils/debug.ts (4)

39-77: Optional: Bound buffered replay cost and preserve order; current approach is fine.

The ring-buffer with MAX_BUFFERED_LOGS = 200 and replay via a for-of loop preserves FIFO order and caps memory. Looks good.


117-145: JSDoc: solid coverage – thanks.

Public API is documented with options, defaults, and example, and the function has an explicit return type. This aligns with project guidelines.


1-4: Type-only imports and named exports look consistent.

Imports are type-only and you’re using named exports for tree-shaking. Good.


146-150: initDebugLogger default usage verified

All existing call sites explicitly pass enabled: true, so the default value is never used at runtime. No change to the default is necessary.

Comment on lines +79 to +115
async function ensureInitialized(): Promise<void> {
try {
if (!isEnabled || realLogger) {
return;
}

const { getDebugLogger } = await import('@/core/modules/debug');
const logger = await getDebugLogger({
filters: lastOptions?.filters,
logLevel: lastOptions?.logLevel ?? 'trace',
telemetryCollector: lastOptions?.telemetryCollector,
});

if (logger) {
realLogger = logger;
flushBuffered();
}
} catch (error) {
const message = 'Debug logger initialization failed';
if (isEnabled && realLogger) {
try {
realLogger.trace(message, { error });
} catch {
// ignore secondary logging errors
}
} else {
try {
// Use a safe, minimal fallback to avoid noisy errors
console.debug?.(message, error);
} catch {
// ignore secondary logging errors
}
}
// Silently return to avoid unhandled rejections and preserve behavior
return;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

❓ Verification inconclusive

Tests: please ensure wrapper-specific semantics are covered.

Given buffering and (re)initialization logic live here, add or verify unit tests for:

  • No buffering when disabled; buffer flush only when enabled.
  • Single initialization under rapid repeated initDebugLogger calls.
  • Reconfiguration replaces the logger and does not replay stale inits.

Run to look for tests:

I can help scaffold these tests if missing.


🏁 Script executed:

#!/bin/bash
# Search tests referencing this wrapper or its API
fd -t f -e ts -e tsx -e js -e jsx test | xargs -r rg -n "initDebugLogger|debugLogger\\."

Length of output: 89


Add unit tests for debug logger wrapper

It looks like there are currently no tests covering the initDebugLogger / debugLogger wrapper in packages/clerk-js/src/utils/debug.ts. Please add unit tests to cover the following scenarios:

  • No buffering when debugging is disabled, and buffer flush only occurs once enabled
  • Only a single initialization happens under rapid, repeated initDebugLogger calls
  • Reconfiguration replaces the existing logger and does not replay any stale initialization calls

These tests will ensure the buffering and (re)initialization logic behaves as expected.

🤖 Prompt for AI Agents
In packages/clerk-js/src/utils/debug.ts around lines 79 to 115, add unit tests
for the initDebugLogger/debugLogger wrapper that (1) verify no buffering occurs
when debugging is disabled and that buffered messages flush exactly once after
enabling (mock getDebugLogger to return a logger and assert buffered calls are
replayed only on first successful initialization), (2) verify only a single
initialization happens under rapid/repeated initDebugLogger calls (call init
concurrently or in a tight loop, mock getDebugLogger to track invocation count
and ensure it is called once), and (3) verify reconfiguration replaces the
existing logger and does not replay stale buffered calls (simulate an initial
logger, then call init with new options returning a different logger and assert
old buffered messages are not replayed). For each test, mock/import
'@/core/modules/debug' to control getDebugLogger behavior, use promises or jest
fake timers to simulate async timing, assert on calls to the mocked logger
methods, and reset module state between tests (clear
realLogger/buffer/lastOptions) to avoid cross-test contamination.

Comment on lines +151 to +154
if (!isEnabled) {
realLogger = null;
return;
}
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

⚠️ Potential issue

Do not buffer when disabled; clear the buffer on disable to match documented semantics.

Currently, calls are buffered even when enabled is false and those logs are flushed later, contradicting “logger is a no-op when disabled.” Guard logging with isEnabled and drop buffered entries on disable.

Apply these diffs:

   if (!isEnabled) {
     realLogger = null;
+    // Drop any pre-init logs collected while disabled
+    preInitBuffer.length = 0;
     return;
   }
   debug(message: string, context?: Record<string, unknown>, source?: string): void {
-    if (!realLogger) {
+    if (!isEnabled) {
+      return;
+    }
+    if (!realLogger) {
       pushBuffered('debug', message, context, source);
       return;
     }
     realLogger.debug(message, context, source);
   },
   error(message: string, context?: Record<string, unknown>, source?: string): void {
-    if (!realLogger) {
+    if (!isEnabled) {
+      return;
+    }
+    if (!realLogger) {
       pushBuffered('error', message, context, source);
       return;
     }
     realLogger.error(message, context, source);
   },
   info(message: string, context?: Record<string, unknown>, source?: string): void {
-    if (!realLogger) {
+    if (!isEnabled) {
+      return;
+    }
+    if (!realLogger) {
       pushBuffered('info', message, context, source);
       return;
     }
     realLogger.info(message, context, source);
   },
   trace(message: string, context?: Record<string, unknown>, source?: string): void {
-    if (!realLogger) {
+    if (!isEnabled) {
+      return;
+    }
+    if (!realLogger) {
       pushBuffered('trace', message, context, source);
       return;
     }
     realLogger.trace(message, context, source);
   },
   warn(message: string, context?: Record<string, unknown>, source?: string): void {
-    if (!realLogger) {
+    if (!isEnabled) {
+      return;
+    }
+    if (!realLogger) {
       pushBuffered('warn', message, context, source);
       return;
     }
     realLogger.warn(message, context, source);
   },

Also applies to: 199-234

🤖 Prompt for AI Agents
In packages/clerk-js/src/utils/debug.ts around lines 151-154 (and also apply the
same change to lines 199-234), the logger currently continues to buffer log
calls when disabled and later flushes them; update the disable path so that when
isEnabled is false you 1) set realLogger = null, 2) clear/drop any existing
buffer (e.g., empty the in-memory queue/array), and 3) ensure all logging entry
points check isEnabled before pushing to the buffer so no new entries are added
while disabled; apply this exact behavior to both locations mentioned.

Comment on lines +156 to +178
if (realLogger) {
void (async () => {
try {
const { __internal_resetDebugLogger, getDebugLogger } = await import('@/core/modules/debug');
__internal_resetDebugLogger();
const logger = await getDebugLogger({
filters: lastOptions?.filters,
logLevel: lastOptions?.logLevel ?? 'trace',
telemetryCollector: lastOptions?.telemetryCollector,
});
if (logger) {
realLogger = logger;
flushBuffered();
}
} catch (error) {
try {
console.debug?.('Debug logger reconfiguration failed', error);
} catch {
// ignore secondary logging errors
}
}
})();
return;
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

Reconfigure path: handle init race and avoid stale overwrite (await in-flight init).

Even with the guard above, reconfiguration should await any in-flight init to avoid resetting the manager mid-init.

If not applying the broader initializingPromise change, at minimum add:

       try {
+        if (typeof initializingPromise?.then === 'function') {
+          try {
+            await initializingPromise;
+          } catch {
+            // ignore
+          }
+        }
         const { __internal_resetDebugLogger, getDebugLogger } = await import('@/core/modules/debug');
📝 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
if (realLogger) {
void (async () => {
try {
const { __internal_resetDebugLogger, getDebugLogger } = await import('@/core/modules/debug');
__internal_resetDebugLogger();
const logger = await getDebugLogger({
filters: lastOptions?.filters,
logLevel: lastOptions?.logLevel ?? 'trace',
telemetryCollector: lastOptions?.telemetryCollector,
});
if (logger) {
realLogger = logger;
flushBuffered();
}
} catch (error) {
try {
console.debug?.('Debug logger reconfiguration failed', error);
} catch {
// ignore secondary logging errors
}
}
})();
return;
if (realLogger) {
void (async () => {
try {
if (typeof initializingPromise?.then === 'function') {
try {
await initializingPromise;
} catch {
// ignore
}
}
const { __internal_resetDebugLogger, getDebugLogger } = await import('@/core/modules/debug');
__internal_resetDebugLogger();
const logger = await getDebugLogger({
filters: lastOptions?.filters,
logLevel: lastOptions?.logLevel ?? 'trace',
telemetryCollector: lastOptions?.telemetryCollector,
});
if (logger) {
realLogger = logger;
flushBuffered();
}
} catch (error) {
try {
console.debug?.('Debug logger reconfiguration failed', error);
} catch {
// ignore secondary logging errors
}
}
})();
return;
🤖 Prompt for AI Agents
packages/clerk-js/src/utils/debug.ts lines 156-178: the reconfiguration block
starts an async IIFE without awaiting any in-flight initialization which can
cause a race where __internal_resetDebugLogger() or assigning realLogger
overwrites a manager that is currently initializing; fix by checking for and
awaiting a shared initializingPromise (or create one before starting the IIFE)
so the reconfiguration waits for any ongoing init to finish, only calls
__internal_resetDebugLogger() and assigns realLogger if the awaited init still
indicates reconfiguration is needed, and ensure the promise is cleared on
completion or error to avoid stale state.

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 (7)
packages/clerk-js/src/core/clerk.ts (5)

1460-1463: Do not log full URLs; redact sensitive query params and use structured logging

The URL can include secrets (e.g., tokens, handshake). Redact before logging and prefer structured logs.

-    debugLogger.info(`Clerk is navigating to: ${toURL}`);
+    // Redact potentially sensitive params before logging
+    const redacted = new URL(toURL.toString());
+    ['__session','__client_uat','token','dev_browser_token','__clerk_handshake','__clerk_handshake_nonce','auth','authorization']
+      .forEach(k => redacted.searchParams.has(k) && redacted.searchParams.set(k, '[REDACTED]'));
+    debugLogger.info('navigate', { to: redacted.toString(), replace: !!options?.replace }, 'clerk.navigate');

Optional: mirror the same redaction for routerDebug console.log to keep behavior consistent.


221-223: Avoid shadowing the imported singleton; deprecate or remove the instance property

You import a global debugLogger singleton and also declare public debugLogger?: DebugLoggerInterface;. This name collision is confusing and invites bugs (instance property vs module singleton). If you intend consumers to use the singleton, drop the instance field (or rename it), and add an explicit JSDoc @deprecated on the property if you keep it for back-compat.

Apply one of the following diffs:

  • Prefer removing the property entirely:
-  // Deprecated: use global singleton from `@/utils/debug`
-  public debugLogger?: DebugLoggerInterface;
  • Or keep it but deprecate and rename to avoid shadowing:
-  // Deprecated: use global singleton from `@/utils/debug`
-  public debugLogger?: DebugLoggerInterface;
+  /**
+   * @deprecated Use the module singleton from `@/utils/debug` instead.
+   */
+  public deprecatedDebugLogger?: DebugLoggerInterface;

471-474: Sanitize error payloads before logging to avoid PII/non-serializable data

Passing raw errors can leak sensitive info and break telemetry serialization. Log a safe summary.

-      debugLogger.error('load() failed', { error }, 'clerk');
+      {
+        const err =
+          error instanceof Error
+            ? { name: error.name, message: error.message, stack: error.stack }
+            : { value: String(error) };
+        debugLogger.error('load() failed', { error: err }, 'clerk.load');
+      }

1236-1246: Redact redirectUrl in setActive() logs; use a stable source name

Same privacy risk applies here. Redact and standardize the source.

-    debugLogger.debug(
-      'setActive() start',
-      {
-        hasClient: Boolean(this.client),
-        sessionTarget: typeof session === 'string' ? session : (session?.id ?? session ?? null),
-        organizationTarget:
-          typeof organization === 'string' ? organization : (organization?.id ?? organization ?? null),
-        redirectUrl: redirectUrl ?? null,
-      },
-      'clerk',
-    );
+    const redactedRedirectUrl = (() => {
+      if (!redirectUrl) return null;
+      try {
+        const u = new URL(redirectUrl, window.location.href);
+        ['__session','__client_uat','token','dev_browser_token','__clerk_handshake','__clerk_handshake_nonce','auth','authorization']
+          .forEach(k => u.searchParams.has(k) && u.searchParams.set(k, '[REDACTED]'));
+        return u.toString();
+      } catch {
+        return redirectUrl;
+      }
+    })();
+    debugLogger.debug(
+      'setActive() start',
+      {
+        hasClient: Boolean(this.client),
+        sessionTarget: typeof session === 'string' ? session : (session?.id ?? session ?? null),
+        organizationTarget:
+          typeof organization === 'string' ? organization : (organization?.id ?? organization ?? null),
+        redirectUrl: redactedRedirectUrl,
+      },
+      'clerk.setActive',
+    );

498-509: Redact sensitive params before logging redirectUrl; prefer structured logging

redirectUrl may include tokens (e.g., __session, token, dev_browser_token, handshake). Log a redacted version and use structured logging with a precise source.

-    const redirectUrl = opts?.redirectUrl || this.buildAfterSignOutUrl();
-    debugLogger.debug(
-      'signOut() start',
-      {
-        hasClient: Boolean(this.client),
-        multiSessionCount: this.client?.signedInSessions.length ?? 0,
-        redirectUrl,
-        sessionTarget: opts?.sessionId ?? null,
-      },
-      'clerk',
-    );
+    const redirectUrl = opts?.redirectUrl || this.buildAfterSignOutUrl();
+    const redactedRedirectUrl = (() => {
+      try {
+        const u = new URL(redirectUrl, window.location.href);
+        ['__session','__client_uat','token','dev_browser_token','__clerk_handshake','__clerk_handshake_nonce','auth','authorization']
+          .forEach(k => u.searchParams.has(k) && u.searchParams.set(k, '[REDACTED]'));
+        return u.toString();
+      } catch {
+        return redirectUrl;
+      }
+    })();
+    debugLogger.debug(
+      'signOut() start',
+      {
+        hasClient: Boolean(this.client),
+        multiSessionCount: this.client?.signedInSessions.length ?? 0,
+        redirectUrl: redactedRedirectUrl,
+        sessionTarget: opts?.sessionId ?? null,
+      },
+      'clerk.signOut',
+    );
packages/clerk-js/src/core/modules/debug/logger.ts (2)

88-109: Populate identity fields and avoid recursive logging on transport failure

  • Include userId, sessionId, organizationId extracted from context to honor identity-aware filters and enrich entries.
  • Logging transport failures via console is fine, but use console.debug to avoid noisy error reports and recursion risk if transports also hook into console.
-  private log(level: DebugLogLevel, message: string, context?: Record<string, unknown>, source?: string): void {
+  private log(level: DebugLogLevel, message: string, context?: Record<string, unknown>, source?: string): void {
     if (!this.shouldLogLevel(level)) {
       return;
     }

-    if (!this.shouldLogFilters(level, message, source)) {
+    const identity = this.extractIdentity(context);
+    if (!this.shouldLogFilters(level, message, source, identity)) {
       return;
     }

     const entry: DebugLogEntry = {
       id: generateUuid(),
       timestamp: Date.now(),
       level,
       message,
       context,
       source,
+      userId: identity.userId,
+      sessionId: identity.sessionId,
+      organizationId: identity.organizationId,
     };

-    this.transport.send(entry).catch(err => {
-      console.error('Failed to send log entry:', err);
-    });
+    this.transport.send(entry).catch(() => {
+      // Avoid recursive logging or noisy errors when transport fails
+      if (typeof console !== 'undefined' && typeof console.debug === 'function') {
+        console.debug('[clerk/debug] Failed to send log entry');
+      }
+    });
   }

Add these helpers outside or near filter logic:

+  private extractIdentity(
+    context?: Record<string, unknown>,
+  ): { userId?: string; sessionId?: string; organizationId?: string } {
+    const ctx = (context ?? {}) as Record<string, unknown>;
+    const userId = typeof ctx.userId === 'string' ? ctx.userId : undefined;
+    const sessionId = typeof ctx.sessionId === 'string' ? ctx.sessionId : undefined;
+    const organizationId = typeof ctx.organizationId === 'string' ? ctx.organizationId : undefined;
+    return { userId, sessionId, organizationId };
+  }

118-150: Honor identity-based filters (userId/sessionId/organizationId)

DebugLogFilter supports identity fields but they are not evaluated. Incorporate them so filters are effective.

-  private shouldLogFilters(level: DebugLogLevel, message: string, source?: string): boolean {
+  private shouldLogFilters(
+    level: DebugLogLevel,
+    message: string,
+    source?: string,
+    identity?: { userId?: string; sessionId?: string; organizationId?: string },
+  ): boolean {
     if (!this.filters || this.filters.length === 0) {
       return true;
     }

     return this.filters.every(filter => {
       if (filter.level && filter.level !== level) {
         return false;
       }

       if (filter.source && !this.matchesSource(filter.source, source)) {
         return false;
       }
+
+      if (filter.userId && filter.userId !== identity?.userId) {
+        return false;
+      }
+      if (filter.sessionId && filter.sessionId !== identity?.sessionId) {
+        return false;
+      }
+      // Optional future-proofing if you add it to the type
+      // @ts-expect-error organizationId may be added to DebugLogFilter later
+      if (filter.organizationId && filter.organizationId !== identity?.organizationId) {
+        return false;
+      }

       if (
         filter.includePatterns &&
         filter.includePatterns.length > 0 &&
         !this.shouldInclude(message, filter.includePatterns)
       ) {
         return false;
       }

       if (
         filter.excludePatterns &&
         filter.excludePatterns.length > 0 &&
         this.shouldExclude(message, filter.excludePatterns)
       ) {
         return false;
       }

       return true;
     });
   }
🧹 Nitpick comments (10)
packages/clerk-js/bundlewatch.config.json (5)

3-3: Validate the 1KB budget increase for core bundle (clerk.js).

Ensure the size increase is strictly attributable to the new debugLogger surface and that the code is tree-shakeable/lazy for non-debug scenarios. Keep budgets as tight as possible to avoid masking regressions; if 626KB reflects the new steady-state with minimal headroom, consider documenting the rationale in the PR description.

Would you like me to propose a follow-up script/guide to capture and compare gzip sizes per chunk to keep a tighter budget?


5-5: Confirm necessity of raising legacy bundle budget (clerk.legacy.browser.js).

Legacy targets are more sensitive to bloat. Verify that debugLogger code is not eagerly bundled for legacy users unless debug mode is explicitly enabled. If the bump is defensive, consider profiling and shaving non-critical code paths for legacy builds.


9-9: Vendors size increase—ensure no unnecessary dependencies were introduced.

If debugLogger introduced new third-party deps, consider vendor-neutral implementations for client bundles, or mark them as optional in debug-only chunks. Keep vendor budgets strict to avoid long-term creep.


25-33: Nit: Normalize KB formatting for consistency.

The file mixes integer KB (e.g., "5KB") with decimals like "1.0KB" and "3.0KB". Consider normalizing to avoid churn from cosmetic edits.

Suggested diff:

-    { "path": "./dist/pricingTable*.js", "maxSize": "4.02KB" },
+    { "path": "./dist/pricingTable*.js", "maxSize": "4.02KB" },
-    { "path": "./dist/up-billing-page*.js", "maxSize": "3.0KB" },
-    { "path": "./dist/op-billing-page*.js", "maxSize": "3.0KB" },
-    { "path": "./dist/up-plans-page*.js", "maxSize": "1.0KB" },
-    { "path": "./dist/op-plans-page*.js", "maxSize": "1.0KB" },
-    { "path": "./dist/statement-page*.js", "maxSize": "1.0KB" },
-    { "path": "./dist/payment-attempt-page*.js", "maxSize": "3.0KB" },
+    { "path": "./dist/up-billing-page*.js", "maxSize": "3KB" },
+    { "path": "./dist/op-billing-page*.js", "maxSize": "3KB" },
+    { "path": "./dist/up-plans-page*.js", "maxSize": "1KB" },
+    { "path": "./dist/op-plans-page*.js", "maxSize": "1KB" },
+    { "path": "./dist/statement-page*.js", "maxSize": "1KB" },
+    { "path": "./dist/payment-attempt-page*.js", "maxSize": "3KB" },

3-9: Add a brief note in PR description justifying each budget bump.

Even small increases should be explained (e.g., debugLogger scaffolding) to maintain the team’s historical context. This helps prevent incremental drift over time.

If useful, I can draft a short “bundle budgets rationale” section for this PR.

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

1249-1249: Standardize log source identifiers

Use consistent, namespaced sources (e.g., 'clerk.setActive') to improve filtering and analysis.

-        debugLogger.warn('Clerk setActive called before client is loaded', {}, 'clerk');
+        debugLogger.warn('Clerk setActive called before client is loaded', {}, 'clerk.setActive');
@@
-        debugLogger.warn('Clerk setActive precondition not met: no target session and no active session', {}, 'clerk');
+        debugLogger.warn('Clerk setActive precondition not met: no target session and no active session', {}, 'clerk.setActive');

Also applies to: 1254-1255

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

106-108: Tighten the pending flush handle typing

Prefer precise return types for clarity and to avoid unnecessary casts when cancelling.

-  #buffer: TelemetryBufferItem[] = [];
-  #pendingFlush: number | ReturnType<typeof setTimeout> | null = null;
+  #buffer: TelemetryBufferItem[] = [];
+  #pendingFlush: ReturnType<typeof requestIdleCallback> | ReturnType<typeof setTimeout> | null = null;

271-310: Cancel the correct pending handle without coercion; clear handle before flush

Minor ergonomics: avoid Number(...) coercion and ensure the handle is cleared just before flush to prevent overlap.

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

312-355: Consider minimal retry on network failure to reduce log loss

Fetch errors are swallowed, which can drop logs under transient failures. A capped retry with backoff would materially reduce loss without much complexity.

I can propose a small, self-contained retry wrapper with 1–2 backoff attempts if you want to pursue this.

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

5-15: Document public API with JSDoc for package consumers

The class is public; ensure the exported API is fully documented (parameters and behavior of filters, level semantics, and source usage), and add @public tags per guidelines if your docs tooling relies on them.

I can draft the full JSDoc block for constructor and methods if helpful.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 113807b and b69a7be.

⛔ 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 (21)
  • .changeset/all-cougars-hide.md (1 hunks)
  • packages/clerk-js/bundlewatch.config.json (1 hunks)
  • packages/clerk-js/src/core/clerk.ts (11 hunks)
  • packages/clerk-js/src/core/fapiClient.ts (2 hunks)
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.test.ts (1 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/__tests__/telemetry.test.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/clerk-js/src/utils/debug.ts (1 hunks)
  • packages/shared/src/__tests__/telemetry.logs.test.ts (1 hunks)
  • packages/shared/src/telemetry/collector.ts (8 hunks)
  • packages/shared/src/utils/index.ts (1 hunks)
  • packages/shared/src/utils/uuid.ts (1 hunks)
  • packages/types/src/environment.ts (1 hunks)
  • packages/types/src/json.ts (1 hunks)
  • packages/types/src/telemetry.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/shared/src/utils/index.ts
🚧 Files skipped from review as they are similar to previous changes (16)
  • packages/shared/src/tests/telemetry.logs.test.ts
  • packages/clerk-js/src/core/modules/debug/transports/console.ts
  • packages/types/src/environment.ts
  • .changeset/all-cougars-hide.md
  • packages/clerk-js/src/core/modules/debug/types.ts
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts
  • packages/clerk-js/src/core/modules/debug/transports/composite.ts
  • packages/clerk-js/src/utils/debug.ts
  • packages/clerk-js/src/core/modules/debug/tests/logger.test.ts
  • packages/clerk-js/src/core/resources/Environment.ts
  • packages/clerk-js/src/core/modules/debug/index.ts
  • packages/types/src/telemetry.ts
  • packages/shared/src/utils/uuid.ts
  • packages/clerk-js/src/core/modules/debug/transports/tests/telemetry.test.ts
  • packages/clerk-js/src/core/fapiClient.ts
  • packages/types/src/json.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{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/bundlewatch.config.json
  • packages/shared/src/telemetry/collector.ts
  • packages/clerk-js/src/core/modules/debug/logger.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/clerk-js/bundlewatch.config.json
  • packages/shared/src/telemetry/collector.ts
  • packages/clerk-js/src/core/modules/debug/logger.ts
  • packages/clerk-js/src/core/clerk.ts
**/*.{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/modules/debug/logger.ts
  • packages/clerk-js/src/core/clerk.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/clerk-js/src/core/modules/debug/logger.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/modules/debug/logger.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/modules/debug/logger.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/modules/debug/logger.ts
  • packages/clerk-js/src/core/clerk.ts
🧬 Code Graph Analysis (3)
packages/shared/src/telemetry/collector.ts (4)
packages/types/src/telemetry.ts (2)
  • TelemetryEvent (8-35)
  • TelemetryLogEntry (49-59)
packages/clerk-js/src/core/modules/debug/types.ts (1)
  • VALID_LOG_LEVELS (9-9)
packages/clerk-js/src/core/clerk.ts (2)
  • sdkMetadata (278-280)
  • sdkMetadata (282-284)
packages/react/src/isomorphicClerk.ts (1)
  • sdkMetadata (264-266)
packages/clerk-js/src/core/modules/debug/logger.ts (2)
packages/clerk-js/src/core/modules/debug/types.ts (4)
  • DebugLogLevel (4-4)
  • DebugLogFilter (84-91)
  • DebugTransport (48-53)
  • DebugLogEntry (19-29)
packages/shared/src/utils/uuid.ts (1)
  • generateUuid (9-60)
packages/clerk-js/src/core/clerk.ts (4)
packages/clerk-js/src/utils/debug.ts (4)
  • DebugLoggerInterface (9-15)
  • debugLogger (236-236)
  • initDebugLogger (146-182)
  • error (206-212)
packages/clerk-js/src/core/modules/debug/logger.ts (1)
  • error (51-53)
packages/shared/src/clerkEventBus.ts (1)
  • clerkEvents (5-7)
packages/clerk-js/src/utils/url.ts (1)
  • toURL (160-162)
⏰ 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: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (8)
packages/clerk-js/bundlewatch.config.json (2)

12-12: Bundlewatch config entry createorganization*.js is still valid

The CreateOrganization lazy-loaded component in packages/clerk-js/src/ui/lazyModules/components.ts uses

/* webpackChunkName: "createorganization" */

so the build continues to emit dist/createorganization*.js. No changes needed.


7-7: Verify UI-common bundle path and debug leakage
I couldn’t locate any files matching ./dist/ui-common*.js in packages/clerk-js/dist. Please confirm and update the path in bundlewatch.config.json, then ensure no debug-only utilities are leaking into the shared UI-common bundle by searching for console.log or debug() calls and gating them behind production-only checks.

  • Update the "path" in packages/clerk-js/bundlewatch.config.json (line 7) to match the actual dist filename
  • List files under packages/clerk-js/dist/ and verify the UI-common bundle name
  • Grep built bundle(s) for debug calls (console.log, debug() and wrap any in if (process.env.NODE_ENV !== 'production')
packages/clerk-js/src/core/clerk.ts (2)

416-420: LGTM: early load() instrumentation

Using the debug logger before initialization is safe with the buffering singleton. Good placement and source tagging.


462-469: LGTM: lazy initialization gated by environment

Initializing via initDebugLogger only when environment?.clientDebugMode is set matches the objective and keeps the feature lazy.

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

64-87: LGTM: explicit log payload shape for telemetry logs

Clear, explicit schema for the logs payload improves type-safety and server compatibility.


88-92: LGTM: runtime validation of log levels

Local VALID_LOG_LEVELS avoids cross-package coupling and prevents type drift.


425-445: LGTM: best-effort context sanitization

Good approach to ensure JSON-serializable context; returning null for arrays keeps payload shape predictable.

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

111-116: LGTM: level threshold logic

The level ordering and comparison produce the expected threshold behavior.

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/clerk-js/src/core/modules/debug/logger.ts (1)

91-103: Identity-based filtering not applied and identity fields not populated on entries.

Filters expose userId/sessionId (and likely organizationId), but shouldLogFilters doesn’t evaluate them and entries omit identity fields, so such filters are ineffective.

Apply this diff to extract identity from context, evaluate identity filters, and populate the entry:

@@
-    if (!this.shouldLogFilters(level, message, source)) {
+    const identity = this.extractIdentity(context);
+    if (!this.shouldLogFilters(level, message, source, identity)) {
       return;
     }
 
     const entry: DebugLogEntry = {
       timestamp: Date.now(),
       level,
       message,
       context,
       source,
+      userId: identity?.userId,
+      sessionId: identity?.sessionId,
+      organizationId: identity?.organizationId,
     };
@@
-  private shouldLogFilters(level: DebugLogLevel, message: string, source?: string): boolean {
+  private shouldLogFilters(
+    level: DebugLogLevel,
+    message: string,
+    source?: string,
+    identity?: { userId?: string; sessionId?: string; organizationId?: string },
+  ): boolean {
     if (!this.filters || this.filters.length === 0) {
       return true;
     }
 
     return this.filters.every(filter => {
       if (filter.level && filter.level !== level) {
         return false;
       }
 
       if (filter.source && !this.matchesSource(filter.source, source)) {
         return false;
       }
 
+      if (filter.userId && filter.userId !== identity?.userId) {
+        return false;
+      }
+
+      if (filter.sessionId && filter.sessionId !== identity?.sessionId) {
+        return false;
+      }
+
+      // If you add organizationId to DebugLogFilter (recommended), include this:
+      if ((filter as any).organizationId && (filter as any).organizationId !== identity?.organizationId) {
+        return false;
+      }
+
       if (
         filter.includePatterns &&
         filter.includePatterns.length > 0 &&
         !this.shouldInclude(message, filter.includePatterns)
       ) {
         return false;
       }
@@
   private matchesPattern(message: string, pattern: string | RegExp): boolean {
     if (typeof pattern === 'string') {
       return message.includes(pattern);
     }
-    return pattern.test(message);
+    // Avoid RegExp.lastIndex side-effects when /g is used
+    if ((pattern as RegExp).global) {
+      (pattern as RegExp).lastIndex = 0;
+    }
+    return (pattern as RegExp).test(message);
   }
+
+  private extractIdentity(
+    context?: Record<string, unknown>,
+  ): { userId?: string; sessionId?: string; organizationId?: string } {
+    const ctx = (context ?? {}) as Record<string, unknown>;
+    const userId = typeof ctx['userId'] === 'string' ? (ctx['userId'] as string) : undefined;
+    const sessionId = typeof ctx['sessionId'] === 'string' ? (ctx['sessionId'] as string) : undefined;
+    const organizationId =
+      typeof ctx['organizationId'] === 'string' ? (ctx['organizationId'] as string) : undefined;
+    return { userId, sessionId, organizationId };
+  }

Follow-up:

  • Please add unit tests for identity-based filtering (userId/sessionId/organizationId match/mismatch, and absence of identity). I can draft them if you’d like.

Also applies to: 115-147, 176-181

🧹 Nitpick comments (4)
packages/clerk-js/src/core/modules/debug/types.ts (2)

109-113: Stronger validation: ensure timestamp is finite.

Guard against NaN and Infinity values for timestamp.

-    typeof (obj as DebugLogEntry).timestamp === 'number' &&
+    Number.isFinite((obj as DebugLogEntry).timestamp) &&

83-90: Support organization-scoped filtering to match entry identity fields.

DebugLogEntry exposes organizationId but DebugLogFilter can’t target it. Add organizationId?: string for completeness and future-proof filtering.

 export interface DebugLogFilter {
   readonly excludePatterns?: (string | RegExp)[];
   readonly includePatterns?: (string | RegExp)[];
   readonly level?: DebugLogLevel;
   readonly sessionId?: string;
   readonly source?: string | RegExp;
   readonly userId?: string;
+  readonly organizationId?: string;
 }
packages/clerk-js/src/core/modules/debug/logger.ts (2)

38-84: Mark public methods explicitly for clarity.

Per repo guidelines, add public to the class’s public API methods.

-  debug(message: string, context?: Record<string, unknown>, source?: string): void {
+  public debug(message: string, context?: Record<string, unknown>, source?: string): void {
@@
-  error(message: string, context?: Record<string, unknown>, source?: string): void {
+  public error(message: string, context?: Record<string, unknown>, source?: string): void {
@@
-  info(message: string, context?: Record<string, unknown>, source?: string): void {
+  public info(message: string, context?: Record<string, unknown>, source?: string): void {
@@
-  trace(message: string, context?: Record<string, unknown>, source?: string): void {
+  public trace(message: string, context?: Record<string, unknown>, source?: string): void {
@@
-  warn(message: string, context?: Record<string, unknown>, source?: string): void {
+  public warn(message: string, context?: Record<string, unknown>, source?: string): void {

103-105: Include minimal context when transport send fails.

Adding structured fields helps debugging transport failures without exposing full context.

-    this.transport.send(entry).catch(err => {
-      console.error('Failed to send log entry:', err);
-    });
+    this.transport.send(entry).catch((err: unknown) => {
+      console.error('Failed to send log entry', { error: err, level, message, source });
+    });
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b69a7be and 1b1f96f.

📒 Files selected for processing (3)
  • packages/clerk-js/src/core/clerk.ts (11 hunks)
  • packages/clerk-js/src/core/modules/debug/logger.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 (1)
  • packages/clerk-js/src/core/clerk.ts
🧰 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/clerk-js/src/core/modules/debug/types.ts
  • packages/clerk-js/src/core/modules/debug/logger.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/types.ts
  • packages/clerk-js/src/core/modules/debug/logger.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/types.ts
  • packages/clerk-js/src/core/modules/debug/logger.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/types.ts
  • packages/clerk-js/src/core/modules/debug/logger.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/types.ts
  • packages/clerk-js/src/core/modules/debug/logger.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/types.ts
  • packages/clerk-js/src/core/modules/debug/logger.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/clerk-js/src/core/modules/debug/types.ts
  • packages/clerk-js/src/core/modules/debug/logger.ts
🧬 Code Graph Analysis (1)
packages/clerk-js/src/core/modules/debug/logger.ts (1)
packages/clerk-js/src/core/modules/debug/types.ts (4)
  • DebugLogLevel (4-4)
  • DebugLogFilter (83-90)
  • DebugTransport (47-52)
  • DebugLogEntry (19-28)
⏰ 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/ci
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (2)
packages/clerk-js/src/core/modules/debug/types.ts (1)

95-97: LGTM: single source-of-truth for levels.

VALID_LOG_LEVELS + isValidLogLevel is clean and type-safe. Good use of as const and a narrow predicate.

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

150-171: Pattern helpers look good and readable.

Nice extraction of pattern matching helpers; improves testability and keeps shouldLogFilters focused on control flow.

@@ -0,0 +1,182 @@
import type { DebugLogEntry, DebugLogFilter, DebugLogLevel, DebugTransport } from './types';
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

Use a single source of truth for level order.

Avoid duplicating the levels array. Import and use VALID_LOG_LEVELS from types to keep behavior consistent with the runtime guards.

-import type { DebugLogEntry, DebugLogFilter, DebugLogLevel, DebugTransport } from './types';
+import type { DebugLogEntry, DebugLogFilter, DebugLogLevel, DebugTransport } from './types';
+import { VALID_LOG_LEVELS } from './types';
@@
-  private shouldLogLevel(level: DebugLogLevel): boolean {
-    const levels: DebugLogLevel[] = ['error', 'warn', 'info', 'debug', 'trace'];
-    const currentLevelIndex = levels.indexOf(this.logLevel);
-    const messageLevelIndex = levels.indexOf(level);
+  private shouldLogLevel(level: DebugLogLevel): boolean {
+    const currentLevelIndex = VALID_LOG_LEVELS.indexOf(this.logLevel);
+    const messageLevelIndex = VALID_LOG_LEVELS.indexOf(level);
     return messageLevelIndex <= currentLevelIndex;
   }

Also applies to: 108-113

🤖 Prompt for AI Agents
In packages/clerk-js/src/core/modules/debug/logger.ts around lines 1 and
108-113, the file defines a local levels array duplicated from the runtime guard
constants; replace those local duplicates by importing VALID_LOG_LEVELS from
'./types' and use that single source of truth wherever level ordering or
membership is needed (e.g., computing level indices, filtering, and comparisons)
so the module relies on VALID_LOG_LEVELS for order and validation instead of a
hard-coded array.

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 (2)
packages/shared/src/telemetry/collector.ts (2)

192-201: Logs gating is inconsistent with JSDoc; tighten to isEnabled && !isDebug.

JSDoc says “Records a telemetry log entry if logging is enabled and not in debug mode,” but #shouldRecordLog returns true unconditionally. This risks uploading logs in production/misconfigured environments (including server paths where #scheduleFlush flushes immediately).

Apply this diff:

-  #shouldRecordLog(_entry: TelemetryLogEntry): boolean {
-    // Always allow logs from debug logger to be sent. Debug logger itself is already gated elsewhere.
-    return true;
-  }
+  #shouldRecordLog(_entry: TelemetryLogEntry): boolean {
+    // Mirror event gating; the debug logger is gated elsewhere,
+    // but this protects against misconfiguration.
+    return this.isEnabled && !this.isDebug;
+  }

If logs are intentionally meant to bypass isEnabled, update the JSDoc and inline comments to state that explicitly and explain the safety considerations.

Also applies to: 247-250


328-339: Don’t swallow fetch errors silently; at least log in debug (and consider retry/backoff).

Currently, failures are dropped with no signal and entries are lost. As a minimal step, log failures in debug builds. Longer-term, add bounded retries with backoff and re-queue on recoverable errors.

Apply this minimal diff:

       fetch(eventsUrl, {
         headers: {
           'Content-Type': 'application/json',
         },
         keepalive: true,
         method: 'POST',
         // TODO: We send an array here with that idea that we can eventually send multiple events.
         body: JSON.stringify({ events: eventsToSend }),
-      }).catch(() => void 0);
+      }).catch(err => {
+        if (this.isDebug && typeof console !== 'undefined') {
+          console.error('[clerk/telemetry] Failed to flush events', err);
+        }
+      });
       fetch(logsUrl, {
         headers: {
           'Content-Type': 'application/json',
         },
         keepalive: true,
         method: 'POST',
         body: JSON.stringify({ logs: logsToSend }),
-      }).catch(() => void 0);
+      }).catch(err => {
+        if (this.isDebug && typeof console !== 'undefined') {
+          console.error('[clerk/telemetry] Failed to flush logs', err);
+        }
+      });

If you want, I can draft a follow-up with async flush + capped retry/backoff that keeps the current API unchanged.

Also applies to: 341-351

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

88-92: Avoid duplication and type VALID_LOG_LEVELS precisely.

You already have the level union on TelemetryLogEntry (and a similar constant in the debug module). At minimum, strongly type this Set to avoid drift.

Apply this diff:

-// Accepted log levels for runtime validation
-const VALID_LOG_LEVELS = new Set<string>(['error', 'warn', 'info', 'debug', 'trace']);
+// Accepted log levels for runtime validation
+const VALID_LOG_LEVELS: ReadonlySet<TelemetryLogEntry['level']> = new Set([
+  'error',
+  'warn',
+  'info',
+  'debug',
+  'trace',
+]);

Longer-term, consider centralizing the level list in @clerk/types to ensure single source of truth across packages.


202-213: Consider accepting Date instances for timestamp.

Small DX tweak: if a Date is passed directly, treat it as valid without re-parsing.

Apply this diff:

-    if (typeof timestampInput === 'number' || typeof timestampInput === 'string') {
+    if (timestampInput instanceof Date) {
+      if (!Number.isNaN(timestampInput.getTime())) {
+        normalizedTimestamp = timestampInput;
+      }
+    } else if (typeof timestampInput === 'number' || typeof timestampInput === 'string') {
       const candidate = new Date(timestampInput);
       if (!Number.isNaN(candidate.getTime())) {
         normalizedTimestamp = candidate;
       }
     }

320-327: Minor: split items into events/logs in a single pass.

You can avoid two filter+map passes. Not critical given small buffers, but trivial to streamline.

Apply this diff:

-    const eventsToSend = itemsToSend
-      .filter(item => item.kind === 'event')
-      .map(item => (item as { kind: 'event'; value: TelemetryEvent }).value);
-
-    const logsToSend = itemsToSend
-      .filter(item => item.kind === 'log')
-      .map(item => (item as { kind: 'log'; value: TelemetryLogData }).value);
+    const eventsToSend: TelemetryEvent[] = [];
+    const logsToSend: TelemetryLogData[] = [];
+    for (const item of itemsToSend) {
+      if (item.kind === 'event') {
+        eventsToSend.push(item.value);
+      } else {
+        logsToSend.push(item.value);
+      }
+    }

422-442: Sanitize context: consider payload size limits.

Deep-cloning via JSON roundtrip is fine, but a runaway context can still exceed reasonable payload sizes, impacting keepalive uploads. Consider truncating large string values and enforcing a max serialized size before enqueue.

I can propose a small helper (e.g., clamp to ~32KB total, with per-field truncation) if you'd like.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1b1f96f and 1c07e4c.

📒 Files selected for processing (3)
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts (1 hunks)
  • packages/shared/src/telemetry/collector.ts (8 hunks)
  • packages/types/src/telemetry.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/types/src/telemetry.ts
  • packages/clerk-js/src/core/modules/debug/transports/telemetry.ts
🧰 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/types/src/telemetry.ts (2)
  • TelemetryEvent (8-35)
  • TelemetryLogEntry (49-58)
packages/clerk-js/src/core/modules/debug/types.ts (1)
  • VALID_LOG_LEVELS (9-9)
packages/clerk-js/src/core/clerk.ts (2)
  • sdkMetadata (278-280)
  • sdkMetadata (282-284)
packages/react/src/isomorphicClerk.ts (1)
  • sdkMetadata (264-266)
⏰ 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 (2)
packages/shared/src/telemetry/collector.ts (2)

19-20: Import of TelemetryLogEntry looks correct.

Type-only import is aligned with guidelines and used appropriately below.


187-190: Buffering events and unified flush scheduling: LGTM.

The unified buffer and single flush scheduler improve consistency and reduce races.

Comment on lines +106 to 108
#buffer: TelemetryBufferItem[] = [];
#pendingFlush: number | ReturnType<typeof setTimeout> | null = null;

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix pending flush handle typing and cancellation (avoid Number() coercion).

Number(this.#pendingFlush) risks becoming NaN in some environments and is unnecessary in the browser. Since scheduling here only happens when window is defined, you can consistently use the window timers/idle APIs and keep the handle as a number. This also simplifies typing and avoids subtle bugs.

Apply this diff:

-  #buffer: TelemetryBufferItem[] = [];
-  #pendingFlush: number | ReturnType<typeof setTimeout> | null = null;
+  #buffer: TelemetryBufferItem[] = [];
+  #pendingFlush: number | null = null;
-      if (this.#pendingFlush) {
-        if (typeof cancelIdleCallback !== 'undefined') {
-          cancelIdleCallback(Number(this.#pendingFlush));
-        } else {
-          clearTimeout(Number(this.#pendingFlush));
-        }
-      }
+      if (this.#pendingFlush !== null) {
+        if (typeof window.cancelIdleCallback !== 'undefined') {
+          window.cancelIdleCallback(this.#pendingFlush);
+        } else {
+          window.clearTimeout(this.#pendingFlush);
+        }
+      }
-    if ('requestIdleCallback' in window) {
-      this.#pendingFlush = requestIdleCallback(() => {
+    if (typeof window.requestIdleCallback !== 'undefined') {
+      this.#pendingFlush = window.requestIdleCallback(() => {
         this.#flush();
         this.#pendingFlush = null;
       });
     } else {
       // This is not an ideal solution, but it at least waits until the next tick
-      this.#pendingFlush = setTimeout(() => {
+      this.#pendingFlush = window.setTimeout(() => {
         this.#flush();
         this.#pendingFlush = null;
       }, 0);
     }

Also applies to: 280-284, 295-299, 302-305

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: 3

♻️ Duplicate comments (1)
packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.test.ts (1)

1-4: Imports are correctly organized and type-only usage is spot on.

The previous lint issues around import order and type-only imports look resolved. This should satisfy simple-import-sort and consistent-type-imports.

🧹 Nitpick comments (6)
packages/clerk-js/src/core/modules/debug/__tests__/logger.test.ts (3)

26-29: Unnecessary afterEach reset

beforeEach creates a fresh MockTransport, so an explicit reset in afterEach is redundant. Remove for clarity.

-  afterEach(() => {
-    mockTransport.reset();
-  });
+  // afterEach not needed; fresh transport is created in beforeEach

124-131: Missing test: RegExp source filter with missing source

You covered the case where a string source filter is provided but the log has undefined source. Consider adding the same for RegExp sources to lock semantics.

Proposed test addition:

       it('should not log when source is undefined and filter expects a source', () => {
         const filters: DebugLogFilter[] = [{ source: 'auth-module' }];
         const filteredLogger = new DebugLogger(mockTransport, 'debug', filters);

         filteredLogger.info('message without source');

         expect(mockTransport.sentEntries).toHaveLength(0);
       });
+
+      it('should not log when source is undefined and filter expects a RegExp source', () => {
+        const filters: DebugLogFilter[] = [{ source: /auth-.*/ }];
+        const filteredLogger = new DebugLogger(mockTransport, 'debug', filters);
+
+        filteredLogger.info('message without source');
+
+        expect(mockTransport.sentEntries).toHaveLength(0);
+      });

352-361: Timestamp test may become flaky if transport/emit becomes async

This test assumes synchronous emission; if DebugLogger or transports become async (e.g., batching), timestamp could be recorded after after = Date.now(), causing failures. Make the test resilient by yielding the microtask queue before taking the “after” snapshot.

-    it('should use current timestamp for log entries', () => {
-      const before = Date.now();
-      logger.info('test message');
-      const after = Date.now();
+    it('should use current timestamp for log entries', async () => {
+      const before = Date.now();
+      logger.info('test message');
+      // Yield once to allow any microtasks in transports to run
+      await Promise.resolve();
+      const after = Date.now();
packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.test.ts (3)

21-45: Make the expectation resilient to future shape changes by using objectContaining.

If TelemetryTransport ever adds fields to the forwarded log entry, this assertion may become brittle. Use expect.objectContaining to assert on the important keys without over-constraining the payload. Also assert the call count.

Apply this diff:

-    expect(mockCollector.recordLog).toHaveBeenCalledWith({
-      level: 'info',
-      message: 'Test message',
-      timestamp: logEntry.timestamp,
-      context: { test: 'value' },
-      source: 'test',
-      userId: 'user-123',
-      sessionId: 'session-456',
-      organizationId: 'org-789',
-    });
+    expect(mockCollector.recordLog).toHaveBeenCalledWith(
+      expect.objectContaining({
+        level: 'info',
+        message: 'Test message',
+        timestamp: logEntry.timestamp,
+        context: { test: 'value' },
+        source: 'test',
+        userId: 'user-123',
+        sessionId: 'session-456',
+        organizationId: 'org-789',
+      }),
+    );
+    expect(mockCollector.recordLog).toHaveBeenCalledTimes(1);

10-18: Prefer a typed factory helper over inline type assertion for the mock.

This improves reuse and avoids repeated casting. It also keeps the beforeEach concise.

Apply this diff within beforeEach:

   beforeEach(() => {
-    mockCollector = {
-      recordLog: jest.fn(),
-      record: jest.fn(),
-      isEnabled: true,
-      isDebug: false,
-    } as jest.Mocked<TelemetryCollector>;
+    mockCollector = createMockCollector();
 
     transport = new TelemetryTransport(mockCollector);
   });

And add this helper near the top (e.g., after imports):

const createMockCollector = (): jest.Mocked<TelemetryCollector> => ({
  recordLog: jest.fn(),
  record: jest.fn(),
  isEnabled: true,
  isDebug: false,
});

47-57: Add a test to ensure send tolerates collector errors.

To keep debug logging from breaking flows, send should be defensive if the collector throws. Add a test that asserts we don’t throw on collector errors.

Apply this diff to append a new test before the closing describe brace:

   it('should handle missing telemetry collector gracefully', async () => {
     const transportWithoutCollector = new TelemetryTransport();
     const logEntry: DebugLogEntry = {
       level: 'info',
       message: 'Test message',
       timestamp: Date.now(),
     };
 
     // Should not throw when no collector is provided
     await expect(transportWithoutCollector.send(logEntry)).resolves.toBeUndefined();
   });
+
+  it('should swallow collector errors during send', async () => {
+    mockCollector.recordLog.mockImplementation(() => {
+      throw new Error('boom');
+    });
+    await expect(
+      transport.send({
+        level: 'info',
+        message: 'Test message',
+        timestamp: Date.now(),
+      }),
+    ).resolves.toBeUndefined();
+  });

If the current design intentionally rethrows, ignore this suggestion.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1c07e4c and 1c99348.

📒 Files selected for processing (3)
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.test.ts (1 hunks)
  • packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.test.ts (1 hunks)
  • packages/shared/src/__tests__/telemetry.logs.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/shared/src/tests/telemetry.logs.test.ts
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{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/transports/__tests__/telemetry.test.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.test.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/transports/__tests__/telemetry.test.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.test.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/transports/__tests__/telemetry.test.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.test.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/transports/__tests__/telemetry.test.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.test.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/transports/__tests__/telemetry.test.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.test.ts
packages/**/*.{test,spec}.{js,jsx,ts,tsx}

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

Unit tests should use Jest or Vitest as the test runner.

Files:

  • packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.test.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.test.ts
packages/{clerk-js,elements,themes}/**/*.{test,spec}.{js,jsx,ts,tsx}

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

Visual regression testing should be performed for UI components.

Files:

  • packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.test.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.test.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/transports/__tests__/telemetry.test.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.test.ts
**/__tests__/**/*.{ts,tsx}

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

**/__tests__/**/*.{ts,tsx}: Create type-safe test builders/factories
Use branded types for test isolation
Implement proper mock types that match interfaces

Files:

  • packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.test.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.test.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/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.test.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.test.ts
🧬 Code Graph Analysis (1)
packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.test.ts (3)
packages/types/src/telemetry.ts (1)
  • TelemetryCollector (60-65)
packages/shared/src/telemetry/collector.ts (1)
  • TelemetryCollector (102-443)
packages/clerk-js/src/core/modules/debug/types.ts (1)
  • DebugLogEntry (19-28)
⏰ 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 (3)
packages/clerk-js/src/core/modules/debug/__tests__/logger.test.ts (3)

239-253: Confirm AND vs OR semantics across filter array

This test enforces AND semantics across multiple filter objects in the filters array. Many filtering APIs use OR across array entries (AND within each object). Please confirm this is the intended contract for DebugLogger. If intent is OR, both tests and/or implementation should be updated accordingly.

Would you like me to add a complementary test that locks in the chosen semantics and updates the JSDoc for DebugLogFilter[] to document it?


275-283: Empty string include pattern matches everything — intended?

includePatterns: [''] will match all messages (as asserted). If that’s not desired, the implementation should ignore empty strings in include/exclude arrays to avoid surprising “match-all” behavior.

If you want to ignore empty strings, I can adjust the tests and propose a small guard in the filter predicate (e.g., skip falsy or zero-length patterns).


30-45: Solid baseline coverage for all levels

Good verification of level ordering and end-to-end capture through the transport.

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: 3

🧹 Nitpick comments (3)
packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.spec.ts (2)

42-52: Strengthen assertion with call count

Adding an explicit call count ensures no duplicate sends slip in unnoticed.

Apply this diff:

     expect(mockCollector.recordLog).toHaveBeenCalledWith({
       level: 'info',
       message: 'Test message',
       timestamp: logEntry.timestamp,
       context: { test: 'value' },
       source: 'test',
       userId: 'user-123',
       sessionId: 'session-456',
       organizationId: 'org-789',
     });
+    expect(mockCollector.recordLog).toHaveBeenCalledTimes(1);

54-64: Also assert that no telemetry call is made when collector is absent

This complements the “no-throw” assertion and tightens the contract for the “no collector” path.

Apply this diff:

   it('should handle missing telemetry collector gracefully', async () => {
     const transportWithoutCollector = new TelemetryTransport();
     const logEntry: DebugLogEntry = {
       level: 'info',
       message: 'Test message',
       timestamp: Date.now(),
     };

     // Should not throw when no collector is provided
     await expect(transportWithoutCollector.send(logEntry)).resolves.toBeUndefined();
+    expect(mockCollector.recordLog).not.toHaveBeenCalled();
   });
packages/clerk-js/src/core/modules/debug/__tests__/logger.spec.ts (1)

305-323: Prefer typing the counting transport and avoid setTimeout for determinism

Two small improvements:

  • Type the transport as DebugTransport to keep it aligned with the interface.
  • Avoid setTimeout(0) in unit tests when possible; consider awaiting a microtask or returning a promise from send and awaiting it via a small helper.

Apply this diff to strengthen typing:

-        let sendCallCount = 0;
-        const countingTransport = {
-          async send(_entry: DebugLogEntry): Promise<void> {
-            sendCallCount++;
-          },
-        };
+        let sendCallCount = 0;
+        const countingTransport: DebugTransport = {
+          async send(_entry: DebugLogEntry): Promise<void> {
+            sendCallCount++;
+          },
+        };

Optionally, replace the timeout with a microtask flush:

// Replace setTimeout with a microtask flush for determinism
await Promise.resolve();
📜 Review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1e1241f and 98133bb.

📒 Files selected for processing (2)
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.spec.ts (1 hunks)
  • packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.spec.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{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/transports/__tests__/telemetry.spec.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.spec.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/transports/__tests__/telemetry.spec.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.spec.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/transports/__tests__/telemetry.spec.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.spec.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/transports/__tests__/telemetry.spec.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.spec.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/transports/__tests__/telemetry.spec.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.spec.ts
packages/**/*.{test,spec}.{js,jsx,ts,tsx}

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

Unit tests should use Jest or Vitest as the test runner.

Files:

  • packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.spec.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.spec.ts
packages/{clerk-js,elements,themes}/**/*.{test,spec}.{js,jsx,ts,tsx}

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

Visual regression testing should be performed for UI components.

Files:

  • packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.spec.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.spec.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/transports/__tests__/telemetry.spec.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.spec.ts
**/__tests__/**/*.{ts,tsx}

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

**/__tests__/**/*.{ts,tsx}: Create type-safe test builders/factories
Use branded types for test isolation
Implement proper mock types that match interfaces

Files:

  • packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.spec.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.spec.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/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.spec.ts
  • packages/clerk-js/src/core/modules/debug/__tests__/logger.spec.ts
🧬 Code Graph Analysis (2)
packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.spec.ts (2)
packages/clerk-js/src/core/modules/debug/transports/telemetry.ts (1)
  • TelemetryTransport (24-60)
packages/clerk-js/src/core/modules/debug/types.ts (1)
  • DebugLogEntry (24-33)
packages/clerk-js/src/core/modules/debug/__tests__/logger.spec.ts (2)
packages/clerk-js/src/core/modules/debug/types.ts (2)
  • DebugLogEntry (24-33)
  • DebugLogFilter (88-95)
packages/clerk-js/src/core/modules/debug/logger.ts (1)
  • DebugLogger (13-182)
🪛 ESLint
packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.spec.ts

[error] 1-6: Run autofix to sort these imports!

(simple-import-sort/imports)

⏰ 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 (vue, chrome)
  • GitHub Check: Integration Tests (machine, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (express, chrome)
  • GitHub Check: Integration Tests (nuxt, chrome)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 14)
  • GitHub Check: Integration Tests (expo-web, chrome)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (tanstack-react-router, chrome)
  • GitHub Check: Integration Tests (quickstart, chrome)
  • GitHub Check: Integration Tests (tanstack-react-start, chrome)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Integration Tests (elements, chrome)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Static analysis
  • GitHub Check: Publish with pkg-pr-new
  • GitHub Check: Unit Tests (22, **)
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (3)
packages/clerk-js/src/core/modules/debug/transports/__tests__/telemetry.spec.ts (1)

28-52: LGTM: Correct mapping from DebugLogEntry to TelemetryLogEntry

The test verifies 1:1 field mapping and awaits the async send. This provides solid coverage for the transport’s primary responsibility.

packages/clerk-js/src/core/modules/debug/__tests__/logger.spec.ts (2)

32-46: LGTM: Level ordering and emission verified

Great, this validates ordering across all levels and ensures messages flow through as expected at the highest verbosity.


73-188: LGTM: Comprehensive filter coverage

The suite thoroughly exercises level, source (string/RegExp), include/exclude, AND-composition, and edge cases. This is strong behavioral coverage for the filter engine.

Comment on lines +6 to +17
// Mock transport for testing
class MockTransport {
public sentEntries: DebugLogEntry[] = [];

async send(entry: DebugLogEntry): Promise<void> {
this.sentEntries.push(entry);
}

reset(): void {
this.sentEntries.length = 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

Type-safety: Make MockTransport implement DebugTransport

Binding the mock to the DebugTransport interface hardens tests against interface changes and improves IDE/type support.

Apply this diff:

-import { DebugLogger } from '../logger';
-import type { DebugLogEntry, DebugLogFilter } from '../types';
+import { DebugLogger } from '../logger';
+import type { DebugLogEntry, DebugLogFilter, DebugTransport } from '../types';

 // Mock transport for testing
-class MockTransport {
+class MockTransport implements DebugTransport {
   public sentEntries: DebugLogEntry[] = [];

   async send(entry: DebugLogEntry): Promise<void> {
     this.sentEntries.push(entry);
   }
📝 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
// Mock transport for testing
class MockTransport {
public sentEntries: DebugLogEntry[] = [];
async send(entry: DebugLogEntry): Promise<void> {
this.sentEntries.push(entry);
}
reset(): void {
this.sentEntries.length = 0;
}
}
import { DebugLogger } from '../logger';
import type { DebugLogEntry, DebugLogFilter, DebugTransport } from '../types';
// Mock transport for testing
class MockTransport implements DebugTransport {
public sentEntries: DebugLogEntry[] = [];
async send(entry: DebugLogEntry): Promise<void> {
this.sentEntries.push(entry);
}
reset(): void {
this.sentEntries.length = 0;
}
}
🤖 Prompt for AI Agents
In packages/clerk-js/src/core/modules/debug/__tests__/logger.spec.ts around
lines 6 to 17, the MockTransport class is not declared to implement the
DebugTransport interface — update the class declaration to implement
DebugTransport, import or reference DebugTransport if not already imported, and
ensure the class method signatures (send and reset) exactly match the interface
(including async/Promise<void> return for send and correct parameter types) so
TypeScript will enforce compatibility and provide IDE/type support.

Comment on lines +304 to +334
describe('transport integration', () => {
it('should call transport.send for each log entry', async () => {
let sendCallCount = 0;
const countingTransport = {
async send(_entry: DebugLogEntry): Promise<void> {
sendCallCount++;
},
};

const testLogger = new DebugLogger(countingTransport, 'info');

testLogger.info('message 1');
testLogger.warn('message 2');
testLogger.error('message 3');

// Allow async operations to complete
await new Promise(resolve => setTimeout(resolve, 0));

expect(sendCallCount).toBe(3);
});

it('should include timestamp in log entries', () => {
const beforeTime = Date.now();
logger.info('test message');
const afterTime = Date.now();

expect(mockTransport.sentEntries).toHaveLength(1);
expect(mockTransport.sentEntries[0].timestamp).toBeGreaterThanOrEqual(beforeTime);
expect(mockTransport.sentEntries[0].timestamp).toBeLessThanOrEqual(afterTime);
});
});
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 a test to assert transport errors are handled (no throw, logged to console)

DebugLogger catches transport errors. Add a test to ensure rejections don’t crash and are surfaced to console.error.

Apply this diff:

     describe('transport integration', () => {
+      it('should not throw if transport.send rejects and should log to console.error', async () => {
+        const failingTransport: DebugTransport = {
+          async send(): Promise<void> {
+            throw new Error('send failed');
+          },
+        };
+        const failingLogger = new DebugLogger(failingTransport, 'info');
+        const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
+
+        // Trigger a log; the transport will reject
+        failingLogger.info('message that triggers rejection');
+
+        // Allow the Promise rejection handler in logger to run
+        await new Promise(resolve => setTimeout(resolve, 0));
+
+        expect(consoleSpy).toHaveBeenCalled();
+        consoleSpy.mockRestore();
+      });
📝 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
describe('transport integration', () => {
it('should call transport.send for each log entry', async () => {
let sendCallCount = 0;
const countingTransport = {
async send(_entry: DebugLogEntry): Promise<void> {
sendCallCount++;
},
};
const testLogger = new DebugLogger(countingTransport, 'info');
testLogger.info('message 1');
testLogger.warn('message 2');
testLogger.error('message 3');
// Allow async operations to complete
await new Promise(resolve => setTimeout(resolve, 0));
expect(sendCallCount).toBe(3);
});
it('should include timestamp in log entries', () => {
const beforeTime = Date.now();
logger.info('test message');
const afterTime = Date.now();
expect(mockTransport.sentEntries).toHaveLength(1);
expect(mockTransport.sentEntries[0].timestamp).toBeGreaterThanOrEqual(beforeTime);
expect(mockTransport.sentEntries[0].timestamp).toBeLessThanOrEqual(afterTime);
});
});
// File: packages/clerk-js/src/core/modules/debug/__tests__/logger.spec.ts
describe('transport integration', () => {
it('should not throw if transport.send rejects and should log to console.error', async () => {
const failingTransport: DebugTransport = {
async send(): Promise<void> {
throw new Error('send failed');
},
};
const failingLogger = new DebugLogger(failingTransport, 'info');
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
// Trigger a log; the transport will reject
failingLogger.info('message that triggers rejection');
// Allow the Promise rejection handler in logger to run
await new Promise(resolve => setTimeout(resolve, 0));
expect(consoleSpy).toHaveBeenCalled();
consoleSpy.mockRestore();
});
it('should call transport.send for each log entry', async () => {
let sendCallCount = 0;
const countingTransport = {
async send(_entry: DebugLogEntry): Promise<void> {
sendCallCount++;
},
};
const testLogger = new DebugLogger(countingTransport, 'info');
testLogger.info('message 1');
testLogger.warn('message 2');
testLogger.error('message 3');
// Allow async operations to complete
await new Promise(resolve => setTimeout(resolve, 0));
expect(sendCallCount).toBe(3);
});
it('should include timestamp in log entries', () => {
const beforeTime = Date.now();
logger.info('test message');
const afterTime = Date.now();
expect(mockTransport.sentEntries).toHaveLength(1);
expect(mockTransport.sentEntries[0].timestamp).toBeGreaterThanOrEqual(beforeTime);
expect(mockTransport.sentEntries[0].timestamp).toBeLessThanOrEqual(afterTime);
});
});

@jacekradko jacekradko merged commit 4db1e58 into main Aug 14, 2025
39 checks passed
@jacekradko jacekradko deleted the feat/debug-module branch August 14, 2025 12:45
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.

3 participants