-
Notifications
You must be signed in to change notification settings - Fork 391
feat(shared): React Query variant for useSubscription #6913
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
base: main
Are you sure you want to change the base?
Conversation
🦋 Changeset detectedLatest commit: c07fe17 The changes in this PR will be included in the next version bump. This PR includes changesets to release 19 packages
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 |
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughAdds TanStack Query Core dependency, lazy-initialized QueryClient in clerk-js with event propagation, bundler chunking, React-isomorphic exposure, new React Query hooks/types and virtualized data-hook selection (.rq vs .swr) via build-time plugin, plus related TS and build config updates. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor App
participant Component as React Component
participant Isomorphic as IsomorphicClerk
participant Clerk as Clerk (clerk-js)
participant QCore as @tanstack/query-core
Component->>Isomorphic: access __internal_queryClient getter
Isomorphic->>Clerk: forward __internal_queryClient access
alt first access
Clerk->>Clerk: dynamic import('./query-core')
Clerk->>QCore: instantiate QueryClient
Clerk->>Isomorphic: emit queryClientStatus / ready
Clerk-->>Component: return { tag, queryClient }
else already initialized
Clerk-->>Component: return existing { tag, queryClient }
end
Component->>QCore: create QueryObserver / subscribe
QCore-->>Component: observer updates -> re-render
sequenceDiagram
autonumber
participant Build as tsup/esbuild
participant Plugin as HookAliasPlugin
participant FS as fs
participant Importer as "import 'virtual:data-hooks/useSubscription'"
Importer->>Build: request module resolution
Build->>Plugin: onResolve('virtual:data-hooks/useSubscription')
Plugin->>FS: check for .rq.tsx and .swr.tsx files
Plugin-->>Build: return resolved real file path (based on env / existence)
Build-->>Importer: bundle chosen implementation
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Disabled knowledge base sources:
📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ 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)
Comment |
@clerk/agent-toolkit
@clerk/astro
@clerk/backend
@clerk/chrome-extension
@clerk/clerk-js
@clerk/dev-cli
@clerk/elements
@clerk/clerk-expo
@clerk/expo-passkeys
@clerk/express
@clerk/fastify
@clerk/localizations
@clerk/nextjs
@clerk/nuxt
@clerk/clerk-react
@clerk/react-router
@clerk/remix
@clerk/shared
@clerk/tanstack-react-start
@clerk/testing
@clerk/themes
@clerk/types
@clerk/upgrade
@clerk/vue
commit: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (7)
packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx (1)
55-56
: Clarify the intent of commented-out__internal_queryClient
prop.The commented-out lines reference
clerk.__internal_queryClient
, which is part of the new internal QueryClient integration introduced in this PR. Thets-expect-error
annotation indicates it is not yet typed on the clerk instance. Is this a placeholder for future work, or should it be uncommented once typing is resolved? If it's deferred, consider adding a TODO or issue reference to track completion.Do you want me to open a tracking issue for this incomplete integration?
packages/react/src/contexts/ClerkContextProvider.tsx (1)
96-100
: Clarify commented-outkey
andqueryClient
props.The commented-out
key={clerkStatus + queryStatus}
andqueryClient={queryClient}
props suggest an incomplete migration or placeholder for future work. If these are intended for a follow-up PR, add a TODO or issue reference to track the work. Otherwise, if they are not needed, remove the comments to avoid confusion.Do you want me to open a tracking issue for this incomplete integration, or should these comments be removed?
packages/clerk-js/package.json (1)
74-74
: Align @tanstack/query-core versions across packages
- packages/shared/package.json (line 158): bump devDependency from
5.87.4
to^5.90.2
to match the caret range in packages/clerk-js.- No known security advisories for @tanstack/query-core (latest 5.90.2).
packages/shared/src/react/hooks/useSubscription.types.ts (1)
3-10
: Add brief JSDoc for thefor
param (public API polish).Document acceptable values ('user' | 'organization') and default behavior to match the rest of the API docs.
As per coding guidelines
packages/clerk-js/src/core/clerk.ts (1)
245-265
: Harden lazy client init: add error handling and emit failure status.Dynamic import lacks a catch; a failed import will surface as an unhandled rejection. Also consider emitting an intermediate/loading status.
Apply this diff:
if (!this.#queryClient) { - void import('./query-core') - .then(module => module.QueryClient) - .then(QueryClient => { + void import('./query-core') + .then(module => module.QueryClient) + .then(QueryClient => { if (this.#queryClient) { return; } this.#queryClient = new QueryClient(); // @ts-expect-error - queryClientStatus is not typed this.#publicEventBus.emit('queryClientStatus', 'ready'); - }); + }) + .catch(err => { + // @ts-expect-error - queryClientStatus is not typed + this.#publicEventBus.emit('queryClientStatus', 'error'); + // Optional: surface debug info + // console.error('Failed to initialize QueryClient', err); + }); }Optional: replace the string tag with a Symbol to avoid collisions.
packages/react/src/isomorphicClerk.ts (1)
149-150
: Remove unused flag and stale prefetch comment.
prefetchQueryClientStatus
is unused and the commented call references a non-existent method. Remove both to avoid confusion and possible lint failures.Apply this diff:
- private prefetchQueryClientStatus = false; + // Intentionally left out; enable if/when prefetching the internal query client is supported. @@ - // if (this.prefetchQueryClientStatus) { - // // @ts-expect-error - queryClientStatus is not typed - // this.clerkjs.getInternalQueryClient?.(); - // } + // Prefetching the internal query client could be enabled in the future. + // Accessing `this.clerkjs?.__internal_queryClient` triggers lazy init in ClerkJS. + // Keep disabled until we decide on prefetch semantics.Also applies to: 628-632
packages/shared/src/react/hooks/useSubscription.swr.tsx (1)
38-56
: Gate the SWR key onuser?.id
for parity with RQenabled
.Avoid creating cache entries when no user is present and skip running the fetcher entirely.
Apply this diff:
- const swr = useSWR( - billingEnabled - ? { - type: 'commerce-subscription', - userId: user?.id, - args: { orgId: isOrganization ? organization?.id : undefined }, - } - : null, - ({ args, userId }) => { - if (userId) { - return clerk.billing.getSubscription(args); - } - return null; - }, - { + const swr = useSWR( + billingEnabled && user?.id + ? { + type: 'commerce-subscription', + userId: user.id, + args: { orgId: isOrganization ? organization?.id : undefined }, + } + : null, + ({ args }) => clerk.billing.getSubscription(args), + { dedupingInterval: 1_000 * 60, keepPreviousData: params?.keepPreviousData, }, );
📜 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.
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (25)
packages/clerk-js/package.json
(1 hunks)packages/clerk-js/rspack.config.js
(1 hunks)packages/clerk-js/src/core/clerk.ts
(3 hunks)packages/clerk-js/src/core/query-core.ts
(1 hunks)packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx
(1 hunks)packages/react/src/contexts/ClerkContextProvider.tsx
(1 hunks)packages/react/src/isomorphicClerk.ts
(4 hunks)packages/shared/global.d.ts
(1 hunks)packages/shared/package.json
(1 hunks)packages/shared/src/react/clerk-rq/queryOptions.ts
(1 hunks)packages/shared/src/react/clerk-rq/types.ts
(1 hunks)packages/shared/src/react/clerk-rq/use-clerk-query-client.ts
(1 hunks)packages/shared/src/react/clerk-rq/useBaseQuery.ts
(1 hunks)packages/shared/src/react/clerk-rq/useQuery.ts
(1 hunks)packages/shared/src/react/contexts.tsx
(2 hunks)packages/shared/src/react/hooks/useSubscription.rq.tsx
(1 hunks)packages/shared/src/react/hooks/useSubscription.swr.tsx
(1 hunks)packages/shared/src/react/hooks/useSubscription.tsx
(1 hunks)packages/shared/src/react/hooks/useSubscription.types.ts
(1 hunks)packages/shared/src/react/providers/SWRConfigCompat.rq.tsx
(1 hunks)packages/shared/src/react/providers/SWRConfigCompat.swr.tsx
(1 hunks)packages/shared/src/react/providers/SWRConfigCompat.tsx
(1 hunks)packages/shared/src/types/virtual-data-hooks.d.ts
(1 hunks)packages/shared/tsconfig.json
(1 hunks)packages/shared/tsup.config.ts
(3 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
**/*.{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/tsconfig.json
packages/clerk-js/src/core/clerk.ts
packages/shared/src/react/hooks/useSubscription.tsx
packages/shared/src/react/hooks/useSubscription.swr.tsx
packages/react/src/contexts/ClerkContextProvider.tsx
packages/shared/src/types/virtual-data-hooks.d.ts
packages/shared/src/react/providers/SWRConfigCompat.rq.tsx
packages/clerk-js/rspack.config.js
packages/shared/src/react/contexts.tsx
packages/shared/src/react/clerk-rq/use-clerk-query-client.ts
packages/shared/global.d.ts
packages/clerk-js/package.json
packages/shared/tsup.config.ts
packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx
packages/shared/package.json
packages/react/src/isomorphicClerk.ts
packages/shared/src/react/hooks/useSubscription.types.ts
packages/shared/src/react/providers/SWRConfigCompat.swr.tsx
packages/shared/src/react/clerk-rq/types.ts
packages/shared/src/react/providers/SWRConfigCompat.tsx
packages/clerk-js/src/core/query-core.ts
packages/shared/src/react/clerk-rq/queryOptions.ts
packages/shared/src/react/clerk-rq/useQuery.ts
packages/shared/src/react/clerk-rq/useBaseQuery.ts
packages/shared/src/react/hooks/useSubscription.rq.tsx
packages/*/tsconfig.json
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
Type checking must be performed with TypeScript and publint.
Files:
packages/shared/tsconfig.json
**/*.{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/clerk.ts
packages/shared/src/react/hooks/useSubscription.tsx
packages/shared/src/react/hooks/useSubscription.swr.tsx
packages/react/src/contexts/ClerkContextProvider.tsx
packages/shared/src/types/virtual-data-hooks.d.ts
packages/shared/src/react/providers/SWRConfigCompat.rq.tsx
packages/clerk-js/rspack.config.js
packages/shared/src/react/contexts.tsx
packages/shared/src/react/clerk-rq/use-clerk-query-client.ts
packages/shared/global.d.ts
packages/shared/tsup.config.ts
packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx
packages/react/src/isomorphicClerk.ts
packages/shared/src/react/hooks/useSubscription.types.ts
packages/shared/src/react/providers/SWRConfigCompat.swr.tsx
packages/shared/src/react/clerk-rq/types.ts
packages/shared/src/react/providers/SWRConfigCompat.tsx
packages/clerk-js/src/core/query-core.ts
packages/shared/src/react/clerk-rq/queryOptions.ts
packages/shared/src/react/clerk-rq/useQuery.ts
packages/shared/src/react/clerk-rq/useBaseQuery.ts
packages/shared/src/react/hooks/useSubscription.rq.tsx
packages/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
TypeScript is required for all packages
Files:
packages/clerk-js/src/core/clerk.ts
packages/shared/src/react/hooks/useSubscription.tsx
packages/shared/src/react/hooks/useSubscription.swr.tsx
packages/react/src/contexts/ClerkContextProvider.tsx
packages/shared/src/types/virtual-data-hooks.d.ts
packages/shared/src/react/providers/SWRConfigCompat.rq.tsx
packages/shared/src/react/contexts.tsx
packages/shared/src/react/clerk-rq/use-clerk-query-client.ts
packages/shared/global.d.ts
packages/shared/tsup.config.ts
packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx
packages/react/src/isomorphicClerk.ts
packages/shared/src/react/hooks/useSubscription.types.ts
packages/shared/src/react/providers/SWRConfigCompat.swr.tsx
packages/shared/src/react/clerk-rq/types.ts
packages/shared/src/react/providers/SWRConfigCompat.tsx
packages/clerk-js/src/core/query-core.ts
packages/shared/src/react/clerk-rq/queryOptions.ts
packages/shared/src/react/clerk-rq/useQuery.ts
packages/shared/src/react/clerk-rq/useBaseQuery.ts
packages/shared/src/react/hooks/useSubscription.rq.tsx
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/clerk.ts
packages/shared/src/react/hooks/useSubscription.tsx
packages/shared/src/react/hooks/useSubscription.swr.tsx
packages/react/src/contexts/ClerkContextProvider.tsx
packages/shared/src/types/virtual-data-hooks.d.ts
packages/shared/src/react/providers/SWRConfigCompat.rq.tsx
packages/shared/src/react/contexts.tsx
packages/shared/src/react/clerk-rq/use-clerk-query-client.ts
packages/shared/global.d.ts
packages/shared/tsup.config.ts
packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx
packages/react/src/isomorphicClerk.ts
packages/shared/src/react/hooks/useSubscription.types.ts
packages/shared/src/react/providers/SWRConfigCompat.swr.tsx
packages/shared/src/react/clerk-rq/types.ts
packages/shared/src/react/providers/SWRConfigCompat.tsx
packages/clerk-js/src/core/query-core.ts
packages/shared/src/react/clerk-rq/queryOptions.ts
packages/shared/src/react/clerk-rq/useQuery.ts
packages/shared/src/react/clerk-rq/useBaseQuery.ts
packages/shared/src/react/hooks/useSubscription.rq.tsx
**/*.{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
Avoidany
type - preferunknown
when type is uncertain, then narrow with type guards
Useinterface
for object shapes that might be extended
Usetype
for unions, primitives, and computed types
Preferreadonly
properties for immutable data structures
Useprivate
for internal implementation details
Useprotected
for inheritance hierarchies
Usepublic
explicitly for clarity in public APIs
Preferreadonly
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
Useconst assertions
for literal types:as const
Usesatisfies
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 ...
Noany
types without justification
Proper error handling with typed errors
Consistent use ofreadonly
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/clerk.ts
packages/shared/src/react/hooks/useSubscription.tsx
packages/shared/src/react/hooks/useSubscription.swr.tsx
packages/react/src/contexts/ClerkContextProvider.tsx
packages/shared/src/types/virtual-data-hooks.d.ts
packages/shared/src/react/providers/SWRConfigCompat.rq.tsx
packages/shared/src/react/contexts.tsx
packages/shared/src/react/clerk-rq/use-clerk-query-client.ts
packages/shared/global.d.ts
packages/shared/tsup.config.ts
packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx
packages/react/src/isomorphicClerk.ts
packages/shared/src/react/hooks/useSubscription.types.ts
packages/shared/src/react/providers/SWRConfigCompat.swr.tsx
packages/shared/src/react/clerk-rq/types.ts
packages/shared/src/react/providers/SWRConfigCompat.tsx
packages/clerk-js/src/core/query-core.ts
packages/shared/src/react/clerk-rq/queryOptions.ts
packages/shared/src/react/clerk-rq/useQuery.ts
packages/shared/src/react/clerk-rq/useBaseQuery.ts
packages/shared/src/react/hooks/useSubscription.rq.tsx
**/*.{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/clerk.ts
packages/shared/src/react/hooks/useSubscription.tsx
packages/shared/src/react/hooks/useSubscription.swr.tsx
packages/react/src/contexts/ClerkContextProvider.tsx
packages/shared/src/types/virtual-data-hooks.d.ts
packages/shared/src/react/providers/SWRConfigCompat.rq.tsx
packages/clerk-js/rspack.config.js
packages/shared/src/react/contexts.tsx
packages/shared/src/react/clerk-rq/use-clerk-query-client.ts
packages/shared/global.d.ts
packages/shared/tsup.config.ts
packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx
packages/react/src/isomorphicClerk.ts
packages/shared/src/react/hooks/useSubscription.types.ts
packages/shared/src/react/providers/SWRConfigCompat.swr.tsx
packages/shared/src/react/clerk-rq/types.ts
packages/shared/src/react/providers/SWRConfigCompat.tsx
packages/clerk-js/src/core/query-core.ts
packages/shared/src/react/clerk-rq/queryOptions.ts
packages/shared/src/react/clerk-rq/useQuery.ts
packages/shared/src/react/clerk-rq/useBaseQuery.ts
packages/shared/src/react/hooks/useSubscription.rq.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
**/*.{jsx,tsx}
: Use error boundaries in React components
Minimize re-renders in React components
**/*.{jsx,tsx}
: Always use functional components with hooks instead of class components
Follow PascalCase naming for components:UserProfile
,NavigationMenu
Keep components focused on a single responsibility - split large components
Limit component size to 150-200 lines; extract logic into custom hooks
Use composition over inheritance - prefer smaller, composable components
Export components as named exports for better tree-shaking
One component per file with matching filename and component name
Use useState for simple state management
Use useReducer for complex state logic
Implement proper state initialization
Use proper state updates with callbacks
Implement proper state cleanup
Use Context API for theme/authentication
Implement proper state selectors
Use proper state normalization
Implement proper state persistence
Use React.memo for expensive components
Implement proper useCallback for handlers
Use proper useMemo for expensive computations
Implement proper virtualization for lists
Use proper code splitting with React.lazy
Implement proper cleanup in useEffect
Use proper refs for DOM access
Implement proper event listener cleanup
Use proper abort controllers for fetch
Implement proper subscription cleanup
Use proper HTML elements
Implement proper ARIA attributes
Use proper heading hierarchy
Implement proper form labels
Use proper button types
Implement proper focus management
Use proper keyboard shortcuts
Implement proper tab order
Use proper skip links
Implement proper focus traps
Implement proper error boundaries
Use proper error logging
Implement proper error recovery
Use proper error messages
Implement proper error fallbacks
Use proper form validation
Implement proper error states
Use proper error messages
Implement proper form submission
Use proper form reset
Use proper component naming
Implement proper file naming
Use proper prop naming
Implement proper...
Files:
packages/shared/src/react/hooks/useSubscription.tsx
packages/shared/src/react/hooks/useSubscription.swr.tsx
packages/react/src/contexts/ClerkContextProvider.tsx
packages/shared/src/react/providers/SWRConfigCompat.rq.tsx
packages/shared/src/react/contexts.tsx
packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx
packages/shared/src/react/providers/SWRConfigCompat.swr.tsx
packages/shared/src/react/providers/SWRConfigCompat.tsx
packages/shared/src/react/hooks/useSubscription.rq.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/react.mdc)
**/*.tsx
: Use proper type definitions for props and state
Leverage TypeScript's type inference where possible
Use proper event types for handlers
Implement proper generic types for reusable components
Use proper type guards for conditional rendering
Files:
packages/shared/src/react/hooks/useSubscription.tsx
packages/shared/src/react/hooks/useSubscription.swr.tsx
packages/react/src/contexts/ClerkContextProvider.tsx
packages/shared/src/react/providers/SWRConfigCompat.rq.tsx
packages/shared/src/react/contexts.tsx
packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx
packages/shared/src/react/providers/SWRConfigCompat.swr.tsx
packages/shared/src/react/providers/SWRConfigCompat.tsx
packages/shared/src/react/hooks/useSubscription.rq.tsx
packages/*/package.json
📄 CodeRabbit inference engine (.cursor/rules/global.mdc)
All publishable packages should be placed under the packages/ directory
packages/*/package.json
: All publishable packages must be located in the 'packages/' directory.
All packages must be published under the @clerk namespace on npm.
Semantic versioning must be used across all packages.
Files:
packages/clerk-js/package.json
packages/shared/package.json
packages/*/tsup.config.{js,ts}
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
TypeScript compilation and bundling must use tsup.
Files:
packages/shared/tsup.config.ts
packages/clerk-js/src/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/clerk-js-ui.mdc)
packages/clerk-js/src/ui/**/*.{ts,tsx}
: Element descriptors should always be camelCase
Use element descriptors in UI components to enable consistent theming and styling via appearance.elements
Element descriptors should generate unique, stable CSS classes for theming
Element descriptors should handle state classes (e.g., cl-loading, cl-active, cl-error, cl-open) automatically based on component state
Do not render hard-coded values; all user-facing strings must be localized using provided localization methods
Use the useLocalizations hook and localizationKeys utility for all text and error messages
Use the styled system (sx prop, theme tokens, responsive values) for custom component styling
Use useCardState for card-level state, useFormState for form-level state, and useLoadingStatus for loading states
Always use handleError utility for API errors and use translateError for localized error messages
Use useFormControl for form field state, implement proper validation, and handle loading and error states in forms
Use localization keys for all form labels and placeholders
Use element descriptors for consistent styling and follow the theme token system
Use the Card and FormContainer patterns for consistent UI structure
Files:
packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx
🧬 Code graph analysis (15)
packages/clerk-js/src/core/clerk.ts (1)
packages/clerk-js/src/core/query-core.ts (1)
QueryClient
(3-3)
packages/shared/src/react/hooks/useSubscription.swr.tsx (4)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)
useSubscription
(22-70)packages/shared/src/react/hooks/useSubscription.types.ts (2)
UseSubscriptionParams
(3-10)SubscriptionResult
(12-21)packages/types/src/environment.ts (1)
EnvironmentResource
(10-24)packages/shared/src/telemetry/events/method-called.ts (1)
eventMethodCalled
(13-25)
packages/react/src/contexts/ClerkContextProvider.tsx (2)
packages/shared/src/react/contexts.tsx (1)
OrganizationProvider
(108-108)packages/shared/src/react/index.ts (1)
OrganizationProvider
(7-7)
packages/shared/src/types/virtual-data-hooks.d.ts (5)
packages/shared/src/react/providers/SWRConfigCompat.rq.tsx (1)
SWRConfigCompat
(6-8)packages/shared/src/react/providers/SWRConfigCompat.swr.tsx (1)
SWRConfigCompat
(7-9)packages/shared/src/react/hooks/useSubscription.rq.tsx (1)
useSubscription
(22-70)packages/shared/src/react/hooks/useSubscription.swr.tsx (1)
useSubscription
(21-69)packages/shared/global.d.ts (1)
useSubscription
(17-17)
packages/shared/src/react/providers/SWRConfigCompat.rq.tsx (2)
packages/shared/src/react/providers/SWRConfigCompat.swr.tsx (1)
SWRConfigCompat
(7-9)packages/shared/src/types/virtual-data-hooks.d.ts (1)
SWRConfigCompat
(3-3)
packages/shared/src/react/contexts.tsx (3)
packages/shared/src/react/providers/SWRConfigCompat.rq.tsx (1)
SWRConfigCompat
(6-8)packages/shared/src/react/providers/SWRConfigCompat.swr.tsx (1)
SWRConfigCompat
(7-9)packages/shared/src/types/virtual-data-hooks.d.ts (1)
SWRConfigCompat
(3-3)
packages/shared/src/react/clerk-rq/use-clerk-query-client.ts (1)
packages/shared/src/react/contexts.tsx (1)
useClerkInstanceContext
(117-117)
packages/shared/global.d.ts (3)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)
useSubscription
(22-70)packages/shared/src/react/hooks/useSubscription.swr.tsx (1)
useSubscription
(21-69)packages/shared/src/types/virtual-data-hooks.d.ts (1)
useSubscription
(4-4)
packages/shared/tsup.config.ts (1)
packages/shared/jest.config.js (1)
clerkJsVersion
(2-2)
packages/shared/src/react/hooks/useSubscription.types.ts (1)
packages/types/src/billing.ts (1)
ForPayerType
(69-69)
packages/shared/src/react/providers/SWRConfigCompat.swr.tsx (3)
packages/shared/src/react/providers/SWRConfigCompat.rq.tsx (1)
SWRConfigCompat
(6-8)packages/shared/src/react/providers/SWRConfigCompat.tsx (1)
SWRConfigCompat
(1-1)packages/shared/src/types/virtual-data-hooks.d.ts (1)
SWRConfigCompat
(3-3)
packages/shared/src/react/clerk-rq/queryOptions.ts (1)
packages/shared/src/react/clerk-rq/types.ts (1)
UseQueryOptions
(27-32)
packages/shared/src/react/clerk-rq/useQuery.ts (3)
packages/shared/src/react/clerk-rq/queryOptions.ts (2)
DefinedInitialDataOptions
(32-40)UndefinedInitialDataOptions
(14-21)packages/shared/src/react/clerk-rq/types.ts (3)
DefinedUseQueryResult
(53-53)UseQueryResult
(51-51)UseQueryOptions
(27-32)packages/shared/src/react/clerk-rq/useBaseQuery.ts (1)
useBaseQuery
(17-55)
packages/shared/src/react/clerk-rq/useBaseQuery.ts (2)
packages/shared/src/react/clerk-rq/types.ts (1)
UseBaseQueryOptions
(12-24)packages/shared/src/react/clerk-rq/use-clerk-query-client.ts (1)
useClerkQueryClient
(82-82)
packages/shared/src/react/hooks/useSubscription.rq.tsx (8)
packages/shared/src/react/hooks/useSubscription.swr.tsx (1)
useSubscription
(21-69)packages/shared/src/react/hooks/useSubscription.types.ts (2)
UseSubscriptionParams
(3-10)SubscriptionResult
(12-21)packages/types/src/billing.ts (1)
BillingSubscriptionResource
(562-612)packages/shared/src/react/contexts.tsx (4)
useAssertWrappedByClerkProvider
(120-120)useClerkInstanceContext
(117-117)useUserContext
(113-113)useOrganizationContext
(109-109)packages/types/src/environment.ts (1)
EnvironmentResource
(10-24)packages/shared/src/telemetry/events/method-called.ts (1)
eventMethodCalled
(13-25)packages/shared/src/react/clerk-rq/use-clerk-query-client.ts (1)
useClerkQueryClient
(82-82)packages/shared/src/react/clerk-rq/useQuery.ts (1)
useClerkQuery
(35-37)
⏰ 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). (6)
- GitHub Check: Formatting | Dedupe | Changeset
- GitHub Check: Build Packages
- GitHub Check: semgrep/ci
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: semgrep-cloud-platform/scan
- GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (11)
packages/clerk-js/rspack.config.js (1)
117-122
: LGTM!The
queryCoreVendor
cache group correctly isolates@tanstack/query-core
into its own chunk, consistent with the existing pattern forstripeVendor
and other third-party libraries. The configuration appropriately usesenforce: true
to ensure the chunk is always created.packages/shared/src/react/contexts.tsx (2)
17-17
: LGTM! Clean migration to SWRConfigCompat wrapper.Replacing the direct import of
SWRConfig
with the newSWRConfigCompat
wrapper is a clean refactor that supports both SWR and React Query implementations via the virtual module system. The public API is preserved (swrConfig
prop is still passed through), and the change aligns with the overall pattern established in this PR.
69-77
: LGTM! OrganizationProvider correctly uses SWRConfigCompat.The component now renders
SWRConfigCompat
instead ofSWRConfig
, which will delegate to the appropriate implementation (SWR or React Query) based on the build-time virtual module resolution. TheswrConfig
prop is correctly passed through, maintaining backward compatibility.packages/shared/src/react/providers/SWRConfigCompat.tsx (1)
1-1
: Verified SWRConfigCompat.rq.tsx renders children only and SWRConfigCompat.swr.tsx wraps SWRConfig with the swrConfig prop as expected.packages/clerk-js/src/core/query-core.ts (1)
1-3
: QueryClient re-export looks good.This keeps consumers synced with the new core integration.
packages/shared/src/react/hooks/useSubscription.types.ts (1)
12-21
: Types look good.Shape aligns with both SWR and React Query variants; using
unknown
for error is appropriate.packages/shared/src/react/clerk-rq/useBaseQuery.ts (1)
28-55
: Hook logic mirrors TanStack’s pattern. LGTM.Optimistic result, useSyncExternalStore subscription, and result tracking are correct.
packages/react/src/isomorphicClerk.ts (2)
288-292
: Proxy getter for internal query client is fine.Simple passthrough is adequate for React-side access.
577-583
: Good: propagatequeryClientStatus
listeners on hydrate.This keeps pre-hydration listeners wired to the live ClerkJS event bus.
packages/shared/src/react/hooks/useSubscription.swr.tsx (1)
62-69
: Overall SWR mapping looks good.Return shape matches the shared SubscriptionResult. Telemetry and env gating are correct.
packages/clerk-js/src/core/clerk.ts (1)
245-265
: useClerkQueryClient correctly handles undefined readiness
It subscribes to ‘queryClientStatus’, triggers a re-render via state, and falls back to a mock client until the real QueryClient is available, avoiding runtime errors.
"devDependencies": { | ||
"@stripe/react-stripe-js": "3.1.1", | ||
"@stripe/stripe-js": "5.6.0", | ||
"@tanstack/query-core": "5.87.4", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Version mismatch with clerk-js package.
@tanstack/query-core
is added here as exact version 5.87.4
(devDependency), but packages/clerk-js/package.json
line 74 declares it as ^5.87.4
(runtime dependency). The caret range in clerk-js allows minor/patch drift, which can cause inconsistencies if shared's dev tooling expects the exact version. For workspace consistency, align both to the same specifier—either exact 5.87.4
or workspace:^
.
Apply this diff to use the workspace protocol for consistency:
- "@tanstack/query-core": "5.87.4",
+ "@tanstack/query-core": "workspace:^",
Alternatively, ensure both packages use the same exact version or caret range.
📝 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.
"@tanstack/query-core": "5.87.4", | |
"@tanstack/query-core": "workspace:^", |
🤖 Prompt for AI Agents
In packages/shared/package.json around line 158, the devDependency for
@tanstack/query-core is pinned to an exact version ("5.87.4") but
packages/clerk-js/package.json declares it as a caret range (^5.87.4), causing a
version specifier mismatch; update packages/shared/package.json to use the
workspace protocol (e.g., "workspace:^5.87.4") or change it to the same
specifier used in clerk-js (e.g., "^5.87.4") so both packages use an identical
dependency specifier to ensure workspace consistency.
const observer = React.useMemo(() => { | ||
return new Observer<TQueryFnData, TError, TData, TQueryData, TQueryKey>(client, defaultedOptions); | ||
}, [client]); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure ESLint passes for hook deps (react-hooks/exhaustive-deps).
useMemo
uses defaultedOptions
but intentionally excludes it from deps. Add a suppression to avoid lint failures.
Apply this diff:
- const observer = React.useMemo(() => {
+ // Intentionally exclude `defaultedOptions` to avoid re-instantiation; updates are applied via `setOptions`.
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ const observer = React.useMemo(() => {
return new Observer<TQueryFnData, TError, TData, TQueryData, TQueryKey>(client, defaultedOptions);
- }, [client]);
+ }, [client]);
Optionally include Observer
in deps if your linter requires it.
📝 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.
const observer = React.useMemo(() => { | |
return new Observer<TQueryFnData, TError, TData, TQueryData, TQueryKey>(client, defaultedOptions); | |
}, [client]); | |
// Intentionally exclude `defaultedOptions` to avoid re-instantiation; updates are applied via `setOptions`. | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
const observer = React.useMemo(() => { | |
return new Observer<TQueryFnData, TError, TData, TQueryData, TQueryKey>(client, defaultedOptions); | |
}, [client]); |
🤖 Prompt for AI Agents
In packages/shared/src/react/clerk-rq/useBaseQuery.ts around lines 24 to 27, the
useMemo callback references defaultedOptions (and optionally Observer) but only
lists client in the deps which triggers react-hooks/exhaustive-deps; update the
line to either add a suppression comment to ignore the exhaustive-deps rule
(e.g. // eslint-disable-next-line react-hooks/exhaustive-deps) directly above
the useMemo call, or include the missing dependencies (defaultedOptions and
optionally Observer) in the dependency array so ESLint is satisfied; ensure the
suppression is scoped only to that line if used.
const query = useClerkQuery({ | ||
queryKey, | ||
queryFn: ({ queryKey }) => { | ||
const obj = queryKey[1] as { args: { orgId?: string } }; | ||
return clerk.billing.getSubscription(obj.args); | ||
}, | ||
staleTime: 1_000 * 60, | ||
enabled: Boolean(user?.id && billingEnabled), | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Restore keepPreviousData
behavior
Line 58: the SWR version forwarded params?.keepPreviousData
to useSWR
, but the React Query port drops it. That regresses the public API—callers that relied on it now lose cached data and see loading flicker on refetch. Please pass the flag to the query options just like before.
const query = useClerkQuery({
queryKey,
queryFn: ({ queryKey }) => {
const obj = queryKey[1] as { args: { orgId?: string } };
return clerk.billing.getSubscription(obj.args);
},
staleTime: 1_000 * 60,
enabled: Boolean(user?.id && billingEnabled),
+ keepPreviousData: params?.keepPreviousData,
});
📝 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.
const query = useClerkQuery({ | |
queryKey, | |
queryFn: ({ queryKey }) => { | |
const obj = queryKey[1] as { args: { orgId?: string } }; | |
return clerk.billing.getSubscription(obj.args); | |
}, | |
staleTime: 1_000 * 60, | |
enabled: Boolean(user?.id && billingEnabled), | |
}); | |
const query = useClerkQuery({ | |
queryKey, | |
queryFn: ({ queryKey }) => { | |
const obj = queryKey[1] as { args: { orgId?: string } }; | |
return clerk.billing.getSubscription(obj.args); | |
}, | |
staleTime: 1_000 * 60, | |
enabled: Boolean(user?.id && billingEnabled), | |
keepPreviousData: params?.keepPreviousData, | |
}); |
🤖 Prompt for AI Agents
In packages/shared/src/react/hooks/useSubscription.rq.tsx around lines 51 to 59,
the React Query port dropped support for params?.keepPreviousData (previously
forwarded to useSWR), causing callers to lose cached data and see loading
flicker; restore behavior by passing the keepPreviousData flag into the
useClerkQuery options (e.g., add keepPreviousData: params?.keepPreviousData
alongside queryKey, queryFn, staleTime, enabled) so callers that set that param
retain previous data during refetch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (2)
packages/clerk-js/bundlewatch.config.json (1)
3-3
: Add bundlewatch coverage for the new TanStack Query chunk.We just split out a
query-core
vendor chunk, but bundlewatch still has no entry for it. Without a limit here, any future growth in that chunk will go unnoticed. Please add a{ "path": "./dist/query-core-vendors*.js", ... }
(or whatever the final filename is) entry with an appropriate ceiling when bumping this maxSize.packages/shared/src/react/providers/SWRConfigCompat.rq.tsx (1)
4-6
: Add documentation explaining the compatibility shim's purpose.The
@internal
marker is appropriate, but the JSDoc should explain that this is a no-op compatibility shim for the React Query variant, allowing seamless switching between SWR and React Query implementations via the virtual module system.Apply this diff to improve the documentation:
/** + * No-op compatibility shim for React Query variant. When using React Query, + * QueryClientProvider is used elsewhere, so this simply passes children through. + * The SWR variant wraps children with SWRConfig for configuration. * @internal */
📜 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.
📒 Files selected for processing (5)
.changeset/tricky-badgers-post.md
(1 hunks)packages/clerk-js/bundlewatch.config.json
(1 hunks)packages/react/src/contexts/ClerkContextProvider.tsx
(1 hunks)packages/react/src/isomorphicClerk.ts
(3 hunks)packages/shared/src/react/providers/SWRConfigCompat.rq.tsx
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- .changeset/tricky-badgers-post.md
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/react/src/contexts/ClerkContextProvider.tsx
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{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/react/providers/SWRConfigCompat.rq.tsx
packages/react/src/isomorphicClerk.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/react/providers/SWRConfigCompat.rq.tsx
packages/react/src/isomorphicClerk.ts
packages/clerk-js/bundlewatch.config.json
packages/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
TypeScript is required for all packages
Files:
packages/shared/src/react/providers/SWRConfigCompat.rq.tsx
packages/react/src/isomorphicClerk.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/react/providers/SWRConfigCompat.rq.tsx
packages/react/src/isomorphicClerk.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
Avoidany
type - preferunknown
when type is uncertain, then narrow with type guards
Useinterface
for object shapes that might be extended
Usetype
for unions, primitives, and computed types
Preferreadonly
properties for immutable data structures
Useprivate
for internal implementation details
Useprotected
for inheritance hierarchies
Usepublic
explicitly for clarity in public APIs
Preferreadonly
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
Useconst assertions
for literal types:as const
Usesatisfies
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 ...
Noany
types without justification
Proper error handling with typed errors
Consistent use ofreadonly
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/react/providers/SWRConfigCompat.rq.tsx
packages/react/src/isomorphicClerk.ts
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
**/*.{jsx,tsx}
: Use error boundaries in React components
Minimize re-renders in React components
**/*.{jsx,tsx}
: Always use functional components with hooks instead of class components
Follow PascalCase naming for components:UserProfile
,NavigationMenu
Keep components focused on a single responsibility - split large components
Limit component size to 150-200 lines; extract logic into custom hooks
Use composition over inheritance - prefer smaller, composable components
Export components as named exports for better tree-shaking
One component per file with matching filename and component name
Use useState for simple state management
Use useReducer for complex state logic
Implement proper state initialization
Use proper state updates with callbacks
Implement proper state cleanup
Use Context API for theme/authentication
Implement proper state selectors
Use proper state normalization
Implement proper state persistence
Use React.memo for expensive components
Implement proper useCallback for handlers
Use proper useMemo for expensive computations
Implement proper virtualization for lists
Use proper code splitting with React.lazy
Implement proper cleanup in useEffect
Use proper refs for DOM access
Implement proper event listener cleanup
Use proper abort controllers for fetch
Implement proper subscription cleanup
Use proper HTML elements
Implement proper ARIA attributes
Use proper heading hierarchy
Implement proper form labels
Use proper button types
Implement proper focus management
Use proper keyboard shortcuts
Implement proper tab order
Use proper skip links
Implement proper focus traps
Implement proper error boundaries
Use proper error logging
Implement proper error recovery
Use proper error messages
Implement proper error fallbacks
Use proper form validation
Implement proper error states
Use proper error messages
Implement proper form submission
Use proper form reset
Use proper component naming
Implement proper file naming
Use proper prop naming
Implement proper...
Files:
packages/shared/src/react/providers/SWRConfigCompat.rq.tsx
**/*.{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/react/providers/SWRConfigCompat.rq.tsx
packages/react/src/isomorphicClerk.ts
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/react.mdc)
**/*.tsx
: Use proper type definitions for props and state
Leverage TypeScript's type inference where possible
Use proper event types for handlers
Implement proper generic types for reusable components
Use proper type guards for conditional rendering
Files:
packages/shared/src/react/providers/SWRConfigCompat.rq.tsx
🧬 Code graph analysis (1)
packages/shared/src/react/providers/SWRConfigCompat.rq.tsx (2)
packages/shared/src/react/providers/SWRConfigCompat.swr.tsx (1)
SWRConfigCompat
(7-9)packages/shared/src/types/virtual-data-hooks.d.ts (1)
SWRConfigCompat
(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). (6)
- GitHub Check: Build Packages
- GitHub Check: Formatting | Dedupe | Changeset
- GitHub Check: semgrep/ci
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: semgrep-cloud-platform/scan
- GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (1)
packages/shared/src/react/providers/SWRConfigCompat.rq.tsx (1)
1-2
: LGTM with a minor note.The type-only import for
PropsWithChildren
follows TypeScript best practices. TheReact
import is needed for JSX, though with React 17+ and the new JSX transform configured, explicit React imports may be unnecessary.
// @ts-expect-error - queryClientStatus is not typed | ||
this.#eventBus.internal.retrieveListeners('queryClientStatus')?.forEach(listener => { | ||
// Since clerkjs exists it will call `this.clerkjs.on('queryClientStatus', listener)` | ||
// @ts-expect-error - queryClientStatus is not typed | ||
this.on('queryClientStatus', listener, { notify: true }); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Ensure queryClientStatus
event is properly typed in a follow-up.
The queryClientStatus
event propagation uses @ts-expect-error
suppressions, indicating the event is not yet part of the type system. While this mirrors the pattern used for status
event listeners (lines 571-574), the event name and callback signature should be properly typed to maintain type safety.
Verify that:
- The
queryClientStatus
event is added to the Clerk event type definitions - The listener callback signature is properly typed
- A follow-up task exists to remove these
@ts-expect-error
suppressions
You can run this script to check if the event is documented elsewhere:
🏁 Script executed:
#!/bin/bash
# Search for queryClientStatus event definitions and usages
rg -nC3 "queryClientStatus" --type=ts -g '!*.test.ts'
Length of output: 148
🏁 Script executed:
#!/bin/bash
rg -nC3 "queryClientStatus"
Length of output: 2581
Define and type the queryClientStatus
event
Add queryClientStatus
to Clerk’s event type definitions and remove the @ts-expect-error
suppressions in:
- packages/clerk-js/src/core/clerk.ts (emit)
- packages/react/src/isomorphicClerk.ts (propagation)
- packages/shared/src/react/clerk-rq/use-clerk-query-client.ts (hook)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
packages/shared/src/react/clerk-rq/types.ts (1)
26-33
: Consider adding a brief explanation for the ESLint disable.The ESLint disable for
no-empty-object-type
is necessary here sinceUseQueryOptions
intentionally creates a specialized type by omitting properties. However, adding a brief inline comment would improve maintainability.Apply this diff to add explanatory context:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type +// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- Empty interface intentionally refines UseBaseQueryOptions by omitting 'suspense' export interface UseQueryOptions<
📜 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.
📒 Files selected for processing (1)
packages/shared/src/react/clerk-rq/types.ts
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{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/react/clerk-rq/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/shared/src/react/clerk-rq/types.ts
packages/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
TypeScript is required for all packages
Files:
packages/shared/src/react/clerk-rq/types.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/react/clerk-rq/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
Avoidany
type - preferunknown
when type is uncertain, then narrow with type guards
Useinterface
for object shapes that might be extended
Usetype
for unions, primitives, and computed types
Preferreadonly
properties for immutable data structures
Useprivate
for internal implementation details
Useprotected
for inheritance hierarchies
Usepublic
explicitly for clarity in public APIs
Preferreadonly
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
Useconst assertions
for literal types:as const
Usesatisfies
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 ...
Noany
types without justification
Proper error handling with typed errors
Consistent use ofreadonly
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/react/clerk-rq/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/shared/src/react/clerk-rq/types.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). (6)
- GitHub Check: Build Packages
- GitHub Check: Formatting | Dedupe | Changeset
- GitHub Check: semgrep/ci
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: semgrep-cloud-platform/scan
- GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (4)
packages/shared/src/react/clerk-rq/types.ts (4)
1-9
: LGTM!The type-only imports follow best practices and align with the coding guideline for using
import type
syntax.
11-24
: LGTM!The
UseBaseQueryOptions
interface properly extendsQueryObserverOptions
and adds a well-documentedsubscribed
property. The type alias and generics follow TanStack Query conventions.
35-48
: LGTM!The
UseInfiniteQueryOptions
interface correctly extendsInfiniteQueryObserverOptions
and consistently applies thesubscribed
property pattern fromUseBaseQueryOptions
. The infinite query-specificTPageParam
generic is properly included.
50-54
: LGTM!The result type aliases provide consistent naming and allow for future extensibility through the indirection layer (
UseQueryResult
→UseBaseQueryResult
→QueryObserverResult
).
c8781b7
to
c07fe17
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work on this, these are just a few random smaller comments I saw when skimming through it.
<SessionContext.Provider value={sessionCtx}> | ||
<OrganizationProvider {...organizationCtx.value}> | ||
<OrganizationProvider | ||
// key={clerkStatus + queryStatus} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: ✂️
if (this.#queryClient) { | ||
return; | ||
} | ||
this.#queryClient = new QueryClient(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there are options we might want to consider here, like retry logic. Do we want to always retry all errors, or ignore retrying 4xx kind of errors for example? How many retries should we do by default? Is the default retry delay good? Do we want to match these closely to what we have in SWR today, or change them as part of this?
To be clear, the default RQ ones does the job so I don't think we need to, especially at this early stage, just wanted to mention it.
if (this.#queryClient) { | ||
return; | ||
} | ||
this.#queryClient = new QueryClient(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want revalidation on focus and the network status things to work, you will also need to call queryClient.mount()
. This is normally done in QueryClientProvider
but since we are skipping that here we'd need to do it manually if we need it.
This is safe but a noop for native environments.
Description
Since the introduction of the paginated hooks and useSWR our SDKs have been suffering from a cache synchnonization issue, resulting in bad DX and stale UIs.
To help you visualize the issue, imagine a checkout flow, where the developer is using the prebuilt AIO Checkout component and then uses the useSubscription() hook to display the plan name in their custom implemented User button.
If a C2 were to checkout a paid plan and looked at their User button, the plan would still mention “Free” instead of the checkout they just paid for.
Our Plan
Per our recent discussions, we decided to move away from SWR and use React Query instead, since it allows us to correctly cache, invalidate and subscribe to changes across the host application and AIOs.
Migration path
In order to slowly migrate every hook, we are using build-time feature flag in the
@clerk/shared
package that controls which hook implementation is used based on the file extension. For example for theuseSubscription()
hooks we now have 2 files,useSubscription.rq.ts
anduseSubscription.swr.ts
.Once all hooks are implemented with React Query, we will start building the
@clerk/shared
withCLERK_USE_RQ=true
in order surface the React Query implementation in the SDKs.clerk-js
It now lazy loads
QueryClient
from@tanstack/query-core
. That means it will only be loaded if requested by the new hooks.Checklist
pnpm test
runs as expected.pnpm build
runs as expected.Type of change
Summary by CodeRabbit