Skip to content

Conversation

@panteliselef
Copy link
Contributor

@panteliselef panteliselef commented Nov 21, 2025

Description

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

  • Bug Fixes

    • Disabled automatic query retries and tightened refetch behavior to improve stability.
  • Chores

    • Switched query dependency resolution to a catalog-based setup.
    • Made query client lazy-initialize and emit a clear readiness status.
  • Tests

    • Updated test defaults to match the new query client retry/refetch settings.

✏️ Tip: You can customize this high-level summary in your review settings.

@panteliselef panteliselef self-assigned this Nov 21, 2025
@changeset-bot
Copy link

changeset-bot bot commented Nov 21, 2025

🦋 Changeset detected

Latest commit: bb5028c

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/shared 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/nextjs Patch
@clerk/nuxt Patch
@clerk/react-router Patch
@clerk/clerk-react Patch
@clerk/remix Patch
@clerk/tanstack-react-start Patch
@clerk/testing Patch
@clerk/themes Patch
@clerk/types Patch
@clerk/vue Patch
@clerk/localizations 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

@vercel
Copy link

vercel bot commented Nov 21, 2025

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

Project Deployment Preview Comments Updated (UTC)
clerk-js-sandbox Ready Ready Preview Comment Nov 28, 2025 2:55pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 21, 2025

Walkthrough

Adds a pnpm catalog for @tanstack/query-core, updates package references to use it, introduces a lazy initializer for a tagged QueryClient with explicit default options and an event emission, adjusts test QueryClient defaults, and aligns internal typing in a shared React hook.

Changes

Cohort / File(s) Summary
Dependency catalog and package refs
pnpm-workspace.yaml, packages/clerk-js/package.json, packages/shared/package.json
Added pnpm catalog entry tanstack mapping '@tanstack/query-core'5.87.4; updated package references to use "catalog:tanstack".
Changeset
.changeset/thirty-pears-reply.md
Added changeset patch for @clerk/clerk-js and @clerk/shared, noting QueryClient retry disabled.
QueryClient initialization and config
packages/clerk-js/src/core/clerk.ts
Added RQ_CLIENT_TAG constant, ClerkRQClient type, clerkQueryClientConfig (defaultOptions: retry: false, refetchOnWindowFocus: false, refetchOnReconnect: false, refetchOnMount: true), and private #initQueryClient that lazy-loads @tanstack/query-core, creates a QueryClient, wraps it with the tag, and emits queryClientStatus; __internal_queryClient now calls #initQueryClient.
Test QueryClient defaults
packages/clerk-js/src/test/mock-helpers.ts
Added defaultOptions flags to test QueryClient: refetchOnWindowFocus: false, refetchOnReconnect: false, refetchOnMount: false (keeps retry and staleTime settings).
Shared hook typing adjustment
packages/shared/src/react/clerk-rq/use-clerk-query-client.ts
Introduced internal ClerkRQClient type alias and replaced inline cast with that alias when deriving the client from clerk.__internal_queryClient (no public API changes).

Sequence Diagram

sequenceDiagram
    participant Component as React Component
    participant Hook as useClerkQueryClient
    participant Clerk as Clerk Instance
    participant QueryClient as `@tanstack/query-core`

    Component->>Hook: mount / call useClerkQueryClient()
    Hook->>Clerk: read __internal_queryClient / subscribe (if implemented)
    Note over Clerk: Query client may be uninitialized
    Clerk->>Clerk: __internal_queryClient -> `#initQueryClient`()
    Clerk->>QueryClient: dynamic import & create QueryClient (clerkQueryClientConfig)
    QueryClient-->>Clerk: QueryClient instance
    Clerk->>Clerk: wrap with RQ_CLIENT_TAG and emit "queryClientStatus"
    Clerk-->>Hook: queryClientStatus event / updated __internal_queryClient
    Hook-->>Component: set state { client, isLoaded: true } / re-render
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Review packages/clerk-js/src/core/clerk.ts for lazy-load correctness, race conditions, and the exact payload/name of the queryClientStatus event.
  • Verify typing correctness and runtime guard around the tagged ClerkRQClient.
  • Confirm test adjustments in packages/clerk-js/src/test/mock-helpers.ts are consistent with intended production defaults.
  • Ensure pnpm catalog entry in pnpm-workspace.yaml resolves correctly in CI.

Poem

🐰
I tucked the client in a cozy hole,
No retries rumbling through the knoll,
A catalog points the secret way,
An event will shout when it's at play,
Now queries hop out bright and whole! 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: setting default options for the queryClient across the shared and clerk-js packages, which is reflected in the configuration updates and dependency consolidation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch elef/consolidate-query-client-settings

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Nov 21, 2025

Open in StackBlitz

@clerk/agent-toolkit

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

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/dev-cli

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

@clerk/elements

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

@clerk/clerk-expo

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

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/clerk-react

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

@clerk/react-router

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

@clerk/remix

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

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/themes

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

@clerk/types

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

@clerk/upgrade

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

@clerk/vue

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

commit: bb5028c

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 (2)
packages/shared/src/react/clerk-rq/use-clerk-query-client.ts (1)

62-69: Consider strengthening the type guard to validate the client property.

The isTaggedRQClient type guard checks for the __tag property but doesn't verify that the client property exists or is a QueryClient. While this is likely safe given internal usage, adding a validation for the client property would make the guard more robust.

Apply this diff to strengthen the type guard:

 const isTaggedRQClient = (value: unknown): value is ClerkRQClient => {
   return (
     typeof value === 'object' &&
     value !== null &&
     '__tag' in (value as Record<string, unknown>) &&
-    (value as Record<string, unknown>).__tag === 'clerk-rq-client'
+    (value as Record<string, unknown>).__tag === 'clerk-rq-client' &&
+    'client' in (value as Record<string, unknown>)
   );
 };
packages/clerk-js/src/core/clerk.ts (1)

299-316: Consider adding error handling for query client initialization.

The #initQueryClient method uses a fire-and-forget pattern with dynamic import but doesn't handle initialization failures. If the import fails or the QueryClient constructor throws, the #queryClient remains undefined and the queryClientStatus event is never emitted, leaving consumers in a perpetual loading state.

Apply this diff to add error handling:

 #initQueryClient = (): void => {
   if (this.#queryClient) {
     return;
   }
 
   void import('./query-core')
     .then(module => module.QueryClient)
     .then(QueryClientCtor => {
       if (this.#queryClient) {
         return;
       }
 
       this.#queryClient = new QueryClientCtor(clerkQueryClientConfig);
 
       // @ts-expect-error - queryClientStatus is not typed
       this.#publicEventBus.emit('queryClientStatus', 'ready');
+    })
+    .catch(error => {
+      // Log initialization failure but don't throw
+      console.error('Failed to initialize query client:', error);
+      // Optionally emit error event
+      // @ts-expect-error - queryClientStatus is not typed
+      this.#publicEventBus.emit('queryClientStatus', 'error');
     });
 };
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 69833fe and fab9ef2.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (7)
  • .changeset/thirty-pears-reply.md (1 hunks)
  • packages/clerk-js/package.json (1 hunks)
  • packages/clerk-js/src/core/clerk.ts (4 hunks)
  • packages/clerk-js/src/test/mock-helpers.ts (1 hunks)
  • packages/shared/package.json (1 hunks)
  • packages/shared/src/react/clerk-rq/use-clerk-query-client.ts (1 hunks)
  • pnpm-workspace.yaml (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/clerk-js/src/core/clerk.ts (1)
packages/clerk-js/src/core/query-core.ts (1)
  • QueryClient (3-3)
⏰ 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: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (9)
packages/shared/src/react/clerk-rq/use-clerk-query-client.ts (2)

71-79: LGTM!

The getQueryClientState function correctly handles both the initialized and uninitialized query client states, providing a mock client when the real one isn't ready yet.


81-101: LGTM!

The event-driven approach for tracking query client initialization is well-implemented:

  • Initial state is correctly derived
  • Event subscription properly updates state
  • Cleanup prevents memory leaks
  • Falls back to mock client when not loaded
packages/shared/package.json (1)

166-166: LGTM!

The migration to catalog-based resolution for @tanstack/query-core aligns with the new catalog entry in pnpm-workspace.yaml and maintains version consistency.

pnpm-workspace.yaml (1)

21-23: LGTM!

The new catalog entry for TanStack Query provides centralized version management across the workspace, which is a best practice for monorepos.

packages/clerk-js/src/test/mock-helpers.ts (1)

58-60: LGTM!

Disabling refetch behaviors in test configuration improves test determinism and prevents flaky tests caused by automatic query refetches. This aligns with the production query client configuration.

packages/clerk-js/package.json (1)

74-74: LGTM!

The migration to catalog-based resolution maintains version consistency across the workspace and aligns with the catalog entry in pnpm-workspace.yaml.

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

97-97: LGTM!

The type-only imports and discriminated union pattern using RQ_CLIENT_TAG are well-designed and enable proper tree-shaking while maintaining type safety.

Also applies to: 201-203


205-217: LGTM!

The query client configuration is well-thought-out:

  • Disables retry to use fapiClient's existing retry logic
  • Disables automatic refetch on window focus/reconnect to reduce unnecessary requests
  • Enables refetch on mount for stale data
  • Clear comments explain the design decisions

264-273: LGTM!

The getter pattern ensures lazy initialization while protecting against re-initialization via the guard in #initQueryClient. Returns undefined safely when the client isn't ready yet.

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

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

201-217: Centralized query client config is clear and aligned with intent

Extracting RQ_CLIENT_TAG, ClerkRQClient, and clerkQueryClientConfig makes the internal query client shape and its defaults explicit and easy to audit. The chosen defaults (no internal retries, no focus/reconnect refetch, refetch-on-mount enabled) fit well with the comment about delegating retry behavior to fapiClient.

If you anticipate needing per-environment tuning later, you could consider threading an optional override into #initQueryClient (or into ClerkOptions) and shallow-merging it into clerkQueryClientConfig, but that’s not necessary for this PR.


264-316: Lazy query client init flow looks correct; consider logging import failures

The interaction between __internal_queryClient and #initQueryClient is sound: the getter kicks off async initialization, returns a tagged wrapper only once the client exists, and guards against duplicate construction if multiple calls race.

One small improvement for observability would be to surface failures of the dynamic import or constructor, so consumers have something concrete to debug instead of a silently missing client. You can, for example, log via the existing debugLogger:

   #initQueryClient = (): void => {
     if (this.#queryClient) {
       return;
     }
 
     void import('./query-core')
       .then(module => module.QueryClient)
       .then(QueryClientCtor => {
         if (this.#queryClient) {
           return;
         }
 
         this.#queryClient = new QueryClientCtor(clerkQueryClientConfig);
 
         // @ts-expect-error - queryClientStatus is not typed
         this.#publicEventBus.emit('queryClientStatus', 'ready');
-      });
+      })
+      .catch(error => {
+        debugLogger.error('Failed to initialize QueryClient', { error }, 'clerk');
+      });
   };

This keeps behavior the same on success while giving a clear signal in dev/production logs when something goes wrong during initialization.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between fab9ef2 and 3bb19da.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (7)
  • .changeset/thirty-pears-reply.md (1 hunks)
  • packages/clerk-js/package.json (1 hunks)
  • packages/clerk-js/src/core/clerk.ts (4 hunks)
  • packages/clerk-js/src/test/mock-helpers.ts (1 hunks)
  • packages/shared/package.json (1 hunks)
  • packages/shared/src/react/clerk-rq/use-clerk-query-client.ts (1 hunks)
  • pnpm-workspace.yaml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/shared/src/react/clerk-rq/use-clerk-query-client.ts
  • packages/clerk-js/package.json
  • packages/clerk-js/src/test/mock-helpers.ts
  • pnpm-workspace.yaml
  • .changeset/thirty-pears-reply.md
🧰 Additional context used
🧬 Code graph analysis (1)
packages/clerk-js/src/core/clerk.ts (1)
packages/clerk-js/src/core/query-core.ts (1)
  • QueryClient (3-3)
⏰ 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: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (1)
packages/clerk-js/src/core/clerk.ts (1)

97-97: Type-only import for QueryClient/QueryClientConfig is appropriate

Using a type import here keeps runtime bundling tied to the local ./query-core dynamic import while still giving the class strong typing for #queryClient and ClerkRQClient. This looks correct and consistent with the lazy-initialization approach.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/clerk-js/src/core/clerk.ts (1)

267-276: Document the lazy initialization behavior and event-driven pattern.

The getter triggers asynchronous initialization but returns synchronously, which may return undefined until the dynamic import completes. Consumers should listen to the 'queryClientStatus' event to know when the client is ready.

Add JSDoc to document this behavior:

+  /**
+   * Internal query client accessor with lazy initialization.
+   * 
+   * @remarks
+   * - First access triggers asynchronous initialization via dynamic import
+   * - Returns undefined until initialization completes
+   * - Listen to the 'queryClientStatus' event (payload: 'ready') to know when available
+   * - Safe to call multiple times; initialization happens only once
+   * 
+   * @returns ClerkRQClient wrapper with tag discriminator, or undefined if not yet initialized
+   * 
+   * @internal
+   */
   get __internal_queryClient(): ClerkRQClient | undefined {

Based on coding guidelines: Document functions with JSDoc comments including @param, @returns, @throws, and @example tags.

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

316-317: Type the queryClientStatus event properly instead of using @ts-expect-error.

The event emission uses @ts-expect-error because the event isn't typed in the event bus. This should be properly typed to maintain type safety and enable IntelliSense for event listeners.

Consider adding the event type to the event bus interface definition. The event should have a payload type of 'ready' | 'error' (with error support if you add error handling per the previous comment).

Based on coding guidelines: Avoid any types without justification, and use proper TypeScript error types.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3bb19da and 9bd928b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (7)
  • .changeset/thirty-pears-reply.md (1 hunks)
  • packages/clerk-js/package.json (1 hunks)
  • packages/clerk-js/src/core/clerk.ts (4 hunks)
  • packages/clerk-js/src/test/mock-helpers.ts (1 hunks)
  • packages/shared/package.json (1 hunks)
  • packages/shared/src/react/clerk-rq/use-clerk-query-client.ts (1 hunks)
  • pnpm-workspace.yaml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • pnpm-workspace.yaml
  • packages/shared/package.json
  • packages/clerk-js/src/test/mock-helpers.ts
  • packages/shared/src/react/clerk-rq/use-clerk-query-client.ts
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{js,jsx,ts,tsx,json,md,yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/clerk-js/package.json
  • packages/clerk-js/src/core/clerk.ts
packages/*/package.json

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

packages/*/package.json: Packages should export TypeScript types alongside runtime code
Follow semantic versioning for all packages

All packages must be published under @clerk namespace

Files:

  • packages/clerk-js/package.json
**/package.json

📄 CodeRabbit inference engine (.cursor/rules/global.mdc)

Use pnpm as the package manager for this monorepo

Files:

  • packages/clerk-js/package.json
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

All code must pass ESLint checks with the project's configuration

Files:

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

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

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

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Follow established naming conventions (PascalCase for components, camelCase for variables)

Prefer importing types from @clerk/shared/types instead of the deprecated @clerk/types alias

Files:

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

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

packages/**/src/**/*.{ts,tsx,js,jsx}: Maintain comprehensive JSDoc comments for public APIs
Use tree-shaking friendly exports
Validate all inputs and sanitize outputs
All public APIs must be documented with JSDoc
Use dynamic imports for optional features
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
Implement proper logging with different levels

Files:

  • packages/clerk-js/src/core/clerk.ts
**/*.ts?(x)

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

Files:

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

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/*.{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
Implement type guards for unknown types using the pattern function isType(value: unknown): value is Type
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 in classes
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Use mixins for shared behavior across unrelated classes in TypeScript
Use generic constraints with bounded type parameters like <T extends { id: string }>
Use utility types like Omit, Partial, and Pick for data transformation instead of manual type construction
Use discriminated unions instead of boolean flags for state management and API responses
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation at the type level
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Document functions with JSDoc comments including @param, @returns, @throws, and @example tags
Create custom error classes that extend Error for specific error types
Use the Result pattern for error handling instead of throwing exceptions
Use optional chaining (?.) and nullish coalescing (??) operators for safe property access
Let TypeScript infer obvious types to reduce verbosity
Use const assertions with as const for literal types
Use satisfies operator for type checking without widening types
Declare readonly arrays and objects for immutable data structures
Use spread operator and array spread for immutable updates instead of mutations
Use lazy loading for large types...

Files:

  • packages/clerk-js/src/core/clerk.ts
🧬 Code graph analysis (1)
packages/clerk-js/src/core/clerk.ts (1)
packages/clerk-js/src/core/query-core.ts (1)
  • QueryClient (3-3)
⏰ 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: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (3)
.changeset/thirty-pears-reply.md (1)

1-6: LGTM! Changeset properly documents the change.

The changeset correctly marks both affected packages with patch-level changes and provides a clear description.

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

100-100: LGTM! Import addition for QueryClientConfig.

The QueryClientConfig type import is properly added and used for typing the clerkQueryClientConfig constant.

packages/clerk-js/package.json (1)

73-73: Catalog entry verified and correctly configured.

The @tanstack/query-core dependency correctly references catalog:tanstack, which is defined in pnpm-workspace.yaml with version 5.87.4. Both packages/clerk-js and packages/shared use the same catalog reference, ensuring consistent versioning across the monorepo.

Comment on lines +208 to +220
const clerkQueryClientConfig: QueryClientConfig = {
defaultOptions: {
queries: {
// use the retry logic that fapiClient uses
retry: false,
// Note: to refetch onWindowFocus, you need to call `queryClient.mount()`
refetchOnWindowFocus: false,
refetchOnReconnect: false,
// the query will refetch on mount if the data is stale
refetchOnMount: true,
},
},
};
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 | 🟠 Major

Add JSDoc documentation for the exported configuration.

The clerkQueryClientConfig constant is exported but lacks JSDoc documentation. Per coding guidelines, all public APIs must be documented with JSDoc including description, usage notes, and any important behavioral details.

Apply this diff to add documentation:

+/**
+ * Default configuration for the Clerk QueryClient instance.
+ * 
+ * @remarks
+ * - Retries are disabled to use the retry logic from fapiClient
+ * - Window focus and reconnect refetching are disabled by default
+ * - Mount refetching is enabled to fetch stale data on component mount
+ * 
+ * @internal
+ */
 const clerkQueryClientConfig: QueryClientConfig = {
   defaultOptions: {
     queries: {
       // use the retry logic that fapiClient uses
       retry: false,
       // Note: to refetch onWindowFocus, you need to call `queryClient.mount()`
       refetchOnWindowFocus: false,
       refetchOnReconnect: false,
       // the query will refetch on mount if the data is stale
       refetchOnMount: true,
     },
   },
 };

Based on coding guidelines: All public APIs must be documented with JSDoc.

📝 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
const clerkQueryClientConfig: QueryClientConfig = {
defaultOptions: {
queries: {
// use the retry logic that fapiClient uses
retry: false,
// Note: to refetch onWindowFocus, you need to call `queryClient.mount()`
refetchOnWindowFocus: false,
refetchOnReconnect: false,
// the query will refetch on mount if the data is stale
refetchOnMount: true,
},
},
};
/**
* Default configuration for the Clerk QueryClient instance.
*
* @remarks
* - Retries are disabled to use the retry logic from fapiClient
* - Window focus and reconnect refetching are disabled by default
* - Mount refetching is enabled to fetch stale data on component mount
*
* @internal
*/
const clerkQueryClientConfig: QueryClientConfig = {
defaultOptions: {
queries: {
// use the retry logic that fapiClient uses
retry: false,
// Note: to refetch onWindowFocus, you need to call `queryClient.mount()`
refetchOnWindowFocus: false,
refetchOnReconnect: false,
// the query will refetch on mount if the data is stale
refetchOnMount: true,
},
},
};

Comment on lines +302 to +319
#initQueryClient = (): void => {
if (this.#queryClient) {
return;
}

void import('./query-core')
.then(module => module.QueryClient)
.then(QueryClientCtor => {
if (this.#queryClient) {
return;
}

this.#queryClient = new QueryClientCtor(clerkQueryClientConfig);

// @ts-expect-error - queryClientStatus is not typed
this.#publicEventBus.emit('queryClientStatus', 'ready');
});
};
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 | 🟠 Major

Add error handling for dynamic import failures.

The #initQueryClient method lacks error handling if the dynamic import fails. This could occur due to network issues, build problems, or missing modules, leading to silent failures where features depending on the query client won't work without any diagnostic information.

Apply this diff to add error handling:

   #initQueryClient = (): void => {
     if (this.#queryClient) {
       return;
     }
 
     void import('./query-core')
       .then(module => module.QueryClient)
       .then(QueryClientCtor => {
         if (this.#queryClient) {
           return;
         }
 
         this.#queryClient = new QueryClientCtor(clerkQueryClientConfig);
 
         // @ts-expect-error - queryClientStatus is not typed
         this.#publicEventBus.emit('queryClientStatus', 'ready');
-      });
+      })
+      .catch(err => {
+        console.error('Clerk: Failed to initialize QueryClient', err);
+        // @ts-expect-error - queryClientStatus is not typed
+        this.#publicEventBus.emit('queryClientStatus', 'error');
+      });
   };
📝 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
#initQueryClient = (): void => {
if (this.#queryClient) {
return;
}
void import('./query-core')
.then(module => module.QueryClient)
.then(QueryClientCtor => {
if (this.#queryClient) {
return;
}
this.#queryClient = new QueryClientCtor(clerkQueryClientConfig);
// @ts-expect-error - queryClientStatus is not typed
this.#publicEventBus.emit('queryClientStatus', 'ready');
});
};
#initQueryClient = (): void => {
if (this.#queryClient) {
return;
}
void import('./query-core')
.then(module => module.QueryClient)
.then(QueryClientCtor => {
if (this.#queryClient) {
return;
}
this.#queryClient = new QueryClientCtor(clerkQueryClientConfig);
// @ts-expect-error - queryClientStatus is not typed
this.#publicEventBus.emit('queryClientStatus', 'ready');
})
.catch(err => {
console.error('Clerk: Failed to initialize QueryClient', err);
// @ts-expect-error - queryClientStatus is not typed
this.#publicEventBus.emit('queryClientStatus', 'error');
});
};
🤖 Prompt for AI Agents
In packages/clerk-js/src/core/clerk.ts around lines 302 to 319, the dynamic
import promise in #initQueryClient has no error handling so import failures are
silent; add a .catch handler to the import chain that logs the error (e.g.,
console.error or an existing logger) and emits a failure status on the public
event bus (e.g., this.#publicEventBus.emit('queryClientStatus', 'error', error)
or similar) so consumers can react, and ensure the handler prevents further
initialization when an error occurs.

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

🧹 Nitpick comments (2)
packages/shared/src/react/clerk-rq/use-clerk-query-client.ts (2)

66-84: Extract type checking logic into a type guard function.

The type checking logic typeof queryClient === 'object' && '__tag' in queryClient && queryClient.__tag === 'clerk-rq-client' is duplicated on lines 68 and 81.

Apply this refactor to improve maintainability and follow the type guard pattern:

+function isClerkRQClient(value: unknown): value is ClerkRQClient {
+  return (
+    value !== null &&
+    typeof value === 'object' &&
+    '__tag' in value &&
+    value.__tag === 'clerk-rq-client'
+  );
+}
+
 const useClerkQueryClient = (): [QueryClient, boolean] => {
   const clerk = useClerkInstanceContext();

   // @ts-expect-error - __internal_queryClient is not typed
   const queryClient = clerk.__internal_queryClient as ClerkRQClient | undefined;
-  const [, setQueryClientLoaded] = useState(
-    typeof queryClient === 'object' && '__tag' in queryClient && queryClient.__tag === 'clerk-rq-client',
-  );
+  const [, setQueryClientLoaded] = useState(isClerkRQClient(queryClient));

   useEffect(() => {
     const _setQueryClientLoaded = () => setQueryClientLoaded(true);
     // @ts-expect-error - queryClientStatus is not typed
     clerk.on('queryClientStatus', _setQueryClientLoaded);
     return () => {
       // @ts-expect-error - queryClientStatus is not typed
       clerk.off('queryClientStatus', _setQueryClientLoaded);
     };
   }, [clerk, setQueryClientLoaded]);

-  const isLoaded = typeof queryClient === 'object' && '__tag' in queryClient && queryClient.__tag === 'clerk-rq-client';
+  const isLoaded = isClerkRQClient(queryClient);

   return [queryClient?.client || mockQueryClient, isLoaded];
 };

Note: Added value !== null check for defensive programming, as typeof null === 'object' in JavaScript.

As per coding guidelines, implement type guards for type checking patterns.


62-62: Add JSDoc documentation for the exported function.

The useClerkQueryClient function is exported but lacks JSDoc documentation. The return tuple's meaning (QueryClient and loading state) should be documented for developers using this API.

Apply this diff to add documentation:

+/**
+ * Returns the Clerk-managed QueryClient instance and its loading state.
+ *
+ * @returns A tuple containing:
+ *   - [0]: The QueryClient instance (or a mock if not loaded)
+ *   - [1]: A boolean indicating whether the real QueryClient is loaded
+ *
+ * @example
+ * ```tsx
+ * const [queryClient, isLoaded] = useClerkQueryClient();
+ * if (isLoaded) {
+ *   // Use the real QueryClient
+ * }
+ * ```
+ */
 const useClerkQueryClient = (): [QueryClient, boolean] => {

As per coding guidelines, all public APIs must be documented with JSDoc including @returns and @example tags.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9bd928b and bb5028c.

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

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

All code must pass ESLint checks with the project's configuration

Files:

  • packages/shared/src/react/clerk-rq/use-clerk-query-client.ts
**/*.{js,jsx,ts,tsx,json,md,yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/shared/src/react/clerk-rq/use-clerk-query-client.ts
packages/**/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/shared/src/react/clerk-rq/use-clerk-query-client.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Follow established naming conventions (PascalCase for components, camelCase for variables)

Prefer importing types from @clerk/shared/types instead of the deprecated @clerk/types alias

Files:

  • packages/shared/src/react/clerk-rq/use-clerk-query-client.ts
packages/**/src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

packages/**/src/**/*.{ts,tsx,js,jsx}: Maintain comprehensive JSDoc comments for public APIs
Use tree-shaking friendly exports
Validate all inputs and sanitize outputs
All public APIs must be documented with JSDoc
Use dynamic imports for optional features
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
Implement proper logging with different levels

Files:

  • packages/shared/src/react/clerk-rq/use-clerk-query-client.ts
**/*.ts?(x)

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

Files:

  • packages/shared/src/react/clerk-rq/use-clerk-query-client.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/*.{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
Implement type guards for unknown types using the pattern function isType(value: unknown): value is Type
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 in classes
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Use mixins for shared behavior across unrelated classes in TypeScript
Use generic constraints with bounded type parameters like <T extends { id: string }>
Use utility types like Omit, Partial, and Pick for data transformation instead of manual type construction
Use discriminated unions instead of boolean flags for state management and API responses
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation at the type level
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Document functions with JSDoc comments including @param, @returns, @throws, and @example tags
Create custom error classes that extend Error for specific error types
Use the Result pattern for error handling instead of throwing exceptions
Use optional chaining (?.) and nullish coalescing (??) operators for safe property access
Let TypeScript infer obvious types to reduce verbosity
Use const assertions with as const for literal types
Use satisfies operator for type checking without widening types
Declare readonly arrays and objects for immutable data structures
Use spread operator and array spread for immutable updates instead of mutations
Use lazy loading for large types...

Files:

  • packages/shared/src/react/clerk-rq/use-clerk-query-client.ts
🧬 Code graph analysis (1)
packages/shared/src/react/clerk-rq/use-clerk-query-client.ts (2)
packages/clerk-js/src/core/query-core.ts (1)
  • QueryClient (3-3)
packages/shared/src/react/contexts.tsx (1)
  • useClerkInstanceContext (128-128)
⏰ 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: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants