UNPKG

@clerk/shared

Version:

Internal package utils used by the Clerk SDKs

1 lines 256 kB
{"version":3,"file":"index.mjs","names":["React","HOOK_NAME","undefinedPaginatedResource","HOOK_NAME","hookName","hookName","deepEqual","HOOK_NAME","HOOK_NAME","CheckoutProvider","PaymentElement","StripePaymentElement"],"sources":["../../src/react/hooks/createContextAndHook.ts","../../src/react/contexts.tsx","../../src/react/stable-keys.ts","../../src/react/hooks/createCacheKeys.ts","../../src/react/query/keep-previous-data.ts","../../src/react/query/clerk-query-client.ts","../../src/react/query/use-clerk-query-client.ts","../../src/react/query/useBaseQuery.ts","../../src/react/query/useInfiniteQuery.ts","../../src/react/query/useQuery.ts","../../src/react/hooks/usePreviousValue.ts","../../src/react/hooks/useClearQueriesOnSignOut.ts","../../src/react/hooks/usePagesOrInfinite.shared.ts","../../src/react/hooks/usePagesOrInfinite.tsx","../../src/react/hooks/useAPIKeys.tsx","../../src/react/hooks/base/useUserBase.ts","../../src/react/hooks/useOAuthConsent.shared.ts","../../src/react/hooks/useOAuthConsent.tsx","../../src/react/hooks/base/useOrganizationBase.ts","../../src/react/hooks/base/useSessionBase.ts","../../src/react/hooks/useClerk.ts","../../src/react/hooks/useAttemptToEnableOrganizations.ts","../../src/react/hooks/useOrganization.tsx","../../src/react/hooks/useOrganizationCreationDefaults.shared.ts","../../src/react/hooks/useOrganizationCreationDefaults.tsx","../../src/react/hooks/useOrganizationList.tsx","../../src/react/hooks/useSafeLayoutEffect.tsx","../../src/react/hooks/useSession.ts","../../src/react/hooks/base/useClientBase.ts","../../src/react/hooks/useSessionList.ts","../../src/react/hooks/useUser.ts","../../src/react/hooks/useDeepEqualMemo.ts","../../src/react/hooks/useReverification.ts","../../src/react/hooks/useBillingIsEnabled.ts","../../src/react/hooks/createBillingPaginatedHook.tsx","../../src/react/hooks/useStatements.tsx","../../src/react/hooks/usePaymentAttempts.tsx","../../src/react/hooks/usePaymentMethods.tsx","../../src/react/hooks/usePlans.tsx","../../src/react/hooks/useSubscription.shared.ts","../../src/react/hooks/useSubscription.tsx","../../src/react/hooks/useCheckout.ts","../../src/react/hooks/useCreditBalance.tsx","../../src/react/hooks/useCreditHistory.tsx","../../src/react/hooks/useStatementQuery.shared.ts","../../src/react/hooks/useStatementQuery.tsx","../../src/react/hooks/usePlanDetailsQuery.shared.ts","../../src/react/hooks/usePlanDetailsQuery.tsx","../../src/react/hooks/usePaymentAttemptQuery.shared.ts","../../src/react/hooks/usePaymentAttemptQuery.tsx","../../src/react/hooks/useUserEnterpriseConnections.shared.ts","../../src/react/hooks/useUserEnterpriseConnections.tsx","../../src/react/hooks/useOrganizationEnterpriseConnections.shared.ts","../../src/react/hooks/useOrganizationEnterpriseConnections.tsx","../../src/react/hooks/useOrganizationDomains.shared.ts","../../src/react/hooks/useOrganizationDomains.tsx","../../src/react/hooks/useOrganizationEnterpriseConnectionTestRuns.shared.ts","../../src/react/hooks/useOrganizationEnterpriseConnectionTestRuns.tsx","../../src/react/utils.ts","../../src/react/ClerkContextProvider.tsx","../../src/react/stripe-react/utils.ts","../../src/react/stripe-react/index.tsx","../../src/react/billing/useInitializePaymentMethod.tsx","../../src/react/billing/useStripeClerkLibs.tsx","../../src/react/billing/useStripeLoader.tsx","../../src/react/billing/payment-element.tsx","../../src/react/PortalProvider.tsx"],"sourcesContent":["'use client';\nimport React from 'react';\n\n/**\n * Assert that the context value exists, otherwise throw an error.\n *\n * @internal\n */\nexport function assertContextExists(contextVal: unknown, msgOrCtx: string | React.Context<any>): asserts contextVal {\n if (!contextVal) {\n throw typeof msgOrCtx === 'string' ? new Error(msgOrCtx) : new Error(`${msgOrCtx.displayName} not found`);\n }\n}\n\ntype Options = { assertCtxFn?: (v: unknown, msg: string) => void };\ntype ContextOf<T> = React.Context<{ value: T } | undefined>;\ntype UseCtxFn<T> = () => T;\n\n/**\n * Create and return a Context and two hooks that return the context value.\n * The Context type is derived from the type passed in by the user.\n *\n * The first hook returned guarantees that the context exists so the returned value is always `CtxValue`\n * The second hook makes no guarantees, so the returned value can be `CtxValue | undefined`\n *\n * @internal\n */\nexport const createContextAndHook = <CtxVal>(\n displayName: string,\n options?: Options,\n): [ContextOf<CtxVal>, UseCtxFn<CtxVal>, UseCtxFn<CtxVal | Partial<CtxVal>>] => {\n const { assertCtxFn = assertContextExists } = options || {};\n const Ctx = React.createContext<{ value: CtxVal } | undefined>(undefined);\n Ctx.displayName = displayName;\n\n const useCtx = () => {\n const ctx = React.useContext(Ctx);\n assertCtxFn(ctx, `${displayName} not found`);\n return (ctx as any).value as CtxVal;\n };\n\n const useCtxWithoutGuarantee = () => {\n const ctx = React.useContext(Ctx);\n return ctx ? ctx.value : {};\n };\n\n return [Ctx, useCtx, useCtxWithoutGuarantee];\n};\n","'use client';\n\nimport type { PropsWithChildren } from 'react';\nimport React, { useState } from 'react';\n\nimport type { BillingSubscriptionPlanPeriod, ClerkOptions, ForPayerType, InitialState, LoadedClerk } from '../types';\nimport { createContextAndHook } from './hooks/createContextAndHook';\n\nconst [ClerkInstanceContext, useClerkInstanceContext] = createContextAndHook<LoadedClerk>('ClerkInstanceContext');\n\nconst [InitialStateContext, _useInitialStateContext] = createContextAndHook<\n InitialState | Promise<InitialState> | undefined\n>('InitialStateContext');\n\n/**\n * Provides initial Clerk state (session, user, organization data) from server-side rendering\n * to child components via React context.\n *\n * Passing in a promise is only supported for React >= 19.\n *\n * The initialState is snapshotted on mount and cannot change during the component lifecycle.\n *\n * Note that different parts of the React tree can use separate InitialStateProvider instances\n * with different initialState values if needed.\n */\nexport function InitialStateProvider({\n children,\n initialState,\n}: {\n children: React.ReactNode;\n initialState: InitialState | Promise<InitialState> | undefined;\n}) {\n // The initialState is not allowed to change, we snapshot it to turn that expectation into a guarantee.\n // Note that despite this, it could still be different for different parts of the React tree which is fine,\n // but that requires using a separate provider.\n // eslint-disable-next-line react/hook-use-state\n const [initialStateSnapshot] = useState(initialState);\n const initialStateCtx = React.useMemo(() => ({ value: initialStateSnapshot }), [initialStateSnapshot]);\n return <InitialStateContext.Provider value={initialStateCtx}>{children}</InitialStateContext.Provider>;\n}\n\nexport function useInitialStateContext(): InitialState | undefined {\n const initialState = _useInitialStateContext();\n\n if (initialState instanceof Promise) {\n if ('use' in React && typeof React.use === 'function') {\n return React.use(initialState);\n } else {\n throw new Error('initialState cannot be a promise if React version is less than 19');\n }\n }\n\n return initialState;\n}\n\nconst OptionsContext = React.createContext<ClerkOptions>({});\n\n/**\n * @interface\n */\nexport type UseCheckoutOptions = {\n /**\n * Specifies if the checkout is for an Organization.\n *\n * @default 'user'\n */\n for?: ForPayerType;\n /**\n * The billing period for the Plan.\n */\n planPeriod: BillingSubscriptionPlanPeriod;\n /**\n * The ID of the Subscription Plan to check out (e.g., `cplan_xxx`).\n */\n planId: string;\n /**\n * The number of total seats to check out for\n */\n seatsQuantity?: number;\n /**\n * The specific price ID to check out for, used when the desired price ID is not the current default price\n */\n priceId?: string;\n};\n\nconst [CheckoutContext, useCheckoutContext] = createContextAndHook<UseCheckoutOptions>('CheckoutContext');\n\nconst __experimental_CheckoutProvider = ({ children, ...rest }: PropsWithChildren<UseCheckoutOptions>) => {\n return <CheckoutContext.Provider value={{ value: rest }}>{children}</CheckoutContext.Provider>;\n};\n\n/**\n * @internal\n */\nfunction useOptionsContext(): ClerkOptions {\n const context = React.useContext(OptionsContext);\n if (context === undefined) {\n throw new Error('useOptions must be used within an OptionsContext');\n }\n return context;\n}\n\n/**\n * @internal\n */\nfunction useAssertWrappedByClerkProvider(displayNameOrFn: string | (() => void)): void {\n const ctx = React.useContext(ClerkInstanceContext);\n\n if (!ctx) {\n if (typeof displayNameOrFn === 'function') {\n displayNameOrFn();\n return;\n }\n\n throw new Error(\n `${displayNameOrFn} can only be used within the <ClerkProvider /> component.\n\nPossible fixes:\n1. Ensure that the <ClerkProvider /> is correctly wrapping your application where this component is used.\n2. Check for multiple versions of the \\`@clerk/shared\\` package in your project. Use a tool like \\`npm ls @clerk/shared\\` to identify multiple versions, and update your dependencies to only rely on one.\n\nLearn more: https://clerk.com/docs/components/clerk-provider`.trim(),\n );\n }\n}\n\nexport {\n __experimental_CheckoutProvider,\n ClerkInstanceContext,\n OptionsContext,\n useAssertWrappedByClerkProvider,\n useCheckoutContext,\n useClerkInstanceContext,\n useOptionsContext,\n};\n","// Keys for `useOrganizationList`\nconst USER_MEMBERSHIPS_KEY = 'userMemberships';\nconst USER_INVITATIONS_KEY = 'userInvitations';\nconst USER_SUGGESTIONS_KEY = 'userSuggestions';\n\n// Keys for `useOrganization`\nconst DOMAINS_KEY = 'domains';\nconst MEMBERSHIP_REQUESTS_KEY = 'membershipRequests';\nconst MEMBERSHIPS_KEY = 'memberships';\nconst INVITATIONS_KEY = 'invitations';\n\n// Keys for `useAPIKeys`\nconst API_KEYS_KEY = 'apiKeys';\n\n// Keys for `useOrganizationCreationDefaults`\nconst ORGANIZATION_CREATION_DEFAULTS_KEY = 'organizationCreationDefaults';\n\n// Keys for `useOAuthConsent`\nconst OAUTH_CONSENT_INFO_KEY = 'oauthConsentInfo';\n\n// Keys for `usePlans`\nconst PLANS_KEY = 'billing-plans';\n\n// Keys for `useSubscription`\nconst SUBSCRIPTION_KEY = 'billing-subscription';\n\n// Keys for `usePaymentMethods`\nconst PAYMENT_METHODS_KEY = 'billing-payment-methods';\n\n// Keys for `usePaymentAttempts`\nconst PAYMENT_ATTEMPTS_KEY = 'billing-payment-attempts';\n\n// Keys for `useStatements`\nconst STATEMENTS_KEY = 'billing-statements';\n\n// Keys for `useCreditBalance`\nconst CREDIT_BALANCE_KEY = 'billing-credit-balance';\n\nexport const STABLE_KEYS = {\n // Keys for `useOrganizationList`\n USER_MEMBERSHIPS_KEY,\n USER_INVITATIONS_KEY,\n USER_SUGGESTIONS_KEY,\n\n // Keys for `useOrganization`\n DOMAINS_KEY,\n MEMBERSHIP_REQUESTS_KEY,\n MEMBERSHIPS_KEY,\n INVITATIONS_KEY,\n\n // Keys for billing\n PLANS_KEY,\n SUBSCRIPTION_KEY,\n PAYMENT_METHODS_KEY,\n PAYMENT_ATTEMPTS_KEY,\n STATEMENTS_KEY,\n\n // Keys for `useAPIKeys`\n API_KEYS_KEY,\n\n // Keys for `useOrganizationCreationDefaults`\n ORGANIZATION_CREATION_DEFAULTS_KEY,\n\n // Keys for `useOAuthConsent`\n OAUTH_CONSENT_INFO_KEY,\n\n // Keys for `useCreditBalance`\n CREDIT_BALANCE_KEY,\n} as const;\n\nexport type ResourceCacheStableKey = (typeof STABLE_KEYS)[keyof typeof STABLE_KEYS];\n\n/**\n * Internal stable keys for queries only used by our UI components.\n * These keys are not used by the hooks themselves.\n */\n\nconst PAYMENT_ATTEMPT_KEY = 'billing-payment-attempt';\nconst BILLING_PLANS_KEY = 'billing-plan';\nconst BILLING_STATEMENTS_KEY = 'billing-statement';\nconst USER_ENTERPRISE_CONNECTIONS_KEY = 'userEnterpriseConnections';\nconst ENTERPRISE_CONNECTION_TEST_RUNS_KEY = 'enterpriseConnectionTestRuns';\nconst ORGANIZATION_ENTERPRISE_CONNECTIONS_KEY = 'organizationEnterpriseConnections';\nconst ORGANIZATION_ENTERPRISE_CONNECTION_TEST_RUNS_KEY = 'organizationEnterpriseConnectionTestRuns';\nconst ORGANIZATION_DOMAINS_KEY = 'organizationDomains';\n\nconst CREDIT_HISTORY_KEY = 'billing-credit-history';\n\nexport const INTERNAL_STABLE_KEYS = {\n PAYMENT_ATTEMPT_KEY,\n BILLING_PLANS_KEY,\n BILLING_STATEMENTS_KEY,\n CREDIT_HISTORY_KEY,\n USER_ENTERPRISE_CONNECTIONS_KEY,\n ENTERPRISE_CONNECTION_TEST_RUNS_KEY,\n ORGANIZATION_ENTERPRISE_CONNECTIONS_KEY,\n ORGANIZATION_ENTERPRISE_CONNECTION_TEST_RUNS_KEY,\n ORGANIZATION_DOMAINS_KEY,\n} as const;\n\nexport type __internal_ResourceCacheStableKey = (typeof INTERNAL_STABLE_KEYS)[keyof typeof INTERNAL_STABLE_KEYS];\n","import type { __internal_ResourceCacheStableKey, ResourceCacheStableKey } from '../stable-keys';\n\n/**\n * @internal\n */\nexport function createCacheKeys<\n Params,\n T extends Record<string, unknown> = Record<string, unknown>,\n U extends Record<string, unknown> | undefined = undefined,\n>(params: {\n stablePrefix: ResourceCacheStableKey | __internal_ResourceCacheStableKey;\n authenticated: boolean;\n tracked: T;\n untracked: U extends { args: Params } ? U : never;\n}) {\n return {\n queryKey: [params.stablePrefix, params.authenticated, params.tracked, params.untracked] as const,\n invalidationKey: [params.stablePrefix, params.authenticated, params.tracked] as const,\n stableKey: params.stablePrefix,\n authenticated: params.authenticated,\n };\n}\n","/**\n * @internal\n */\nexport function defineKeepPreviousDataFn(enabled: boolean) {\n if (enabled) {\n return function KeepPreviousDataFn<Data>(previousData: Data): Data {\n return previousData;\n };\n }\n return undefined;\n}\n","import { QueryClient } from '@tanstack/query-core';\n\n/**\n * The QueryClient backing every clerk-query hook. Owned by `@clerk/shared` so the\n * `QueryObserver` that observes it and the `Query` objects inside it always\n * resolve to the same `@tanstack/query-core` (no cross-bundle drift between\n * the consumer-side `@clerk/shared` and the production CDN `clerk-js` bundle).\n *\n * Lazily instantiated on the client only. Server-side renders return\n * `undefined` so per-request renders never share a cache across requests.\n */\nlet clerkQueryClient: QueryClient | undefined;\nlet initialized = false;\n\nexport function getClerkQueryClient(): QueryClient | undefined {\n if (typeof window === 'undefined') {\n return undefined;\n }\n if (!initialized) {\n clerkQueryClient = new QueryClient();\n initialized = true;\n }\n return clerkQueryClient;\n}\n\n/**\n * Test-only: install a custom client (for deterministic defaults like\n * `staleTime: Infinity`) or pass `undefined` to simulate the \"no client\"\n * state without triggering lazy creation on subsequent reads.\n */\nexport function __setClerkQueryClientForTest(client: QueryClient | undefined): void {\n clerkQueryClient = client;\n initialized = true;\n}\n\n/**\n * Test-only: build and install a fresh `QueryClient` with deterministic\n * defaults (no retries, infinite stale time, no refetching). Returns the\n * client so the spec can read/write its cache directly.\n *\n * Avoids forcing every test consumer to depend on `@tanstack/query-core`.\n */\nexport function __createClerkTestQueryClient(): QueryClient {\n const client = new QueryClient({\n defaultOptions: {\n queries: {\n retry: false,\n staleTime: Infinity,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n refetchOnMount: false,\n },\n },\n });\n __setClerkQueryClientForTest(client);\n return client;\n}\n\n/**\n * Test-only: clear both the override and the initialization flag so the\n * next read lazy-creates a fresh client.\n */\nexport function __resetClerkQueryClientForTest(): void {\n clerkQueryClient = undefined;\n initialized = false;\n}\n","import type { QueryClient } from '@tanstack/query-core';\n\nimport { getClerkQueryClient } from './clerk-query-client';\n\nexport type RecursiveMock = {\n (...args: unknown[]): RecursiveMock;\n} & {\n readonly [key in string | symbol]: RecursiveMock;\n};\n\n/**\n * Creates a recursively self-referential Proxy that safely handles:\n * - Arbitrary property access (e.g., obj.any.prop.path)\n * - Function calls at any level (e.g., obj.a().b.c())\n * - Construction (e.g., new obj.a.b())\n *\n * Always returns itself to allow infinite chaining without throwing.\n */\nfunction createRecursiveProxy(label: string): RecursiveMock {\n // The callable target for the proxy so that `apply` works\n const callableTarget = function noop(): void {};\n\n // eslint-disable-next-line prefer-const\n let self: RecursiveMock;\n const handler: ProxyHandler<typeof callableTarget> = {\n get(_target, prop) {\n // Avoid being treated as a Promise/thenable by test runners or frameworks\n if (prop === 'then') {\n return undefined;\n }\n if (prop === 'toString') {\n return () => `[${label}]`;\n }\n if (prop === Symbol.toPrimitive) {\n return () => 0;\n }\n return self;\n },\n apply() {\n return self;\n },\n construct() {\n return self as unknown as object;\n },\n has() {\n return false;\n },\n set() {\n return false;\n },\n };\n\n self = new Proxy(callableTarget, handler) as unknown as RecursiveMock;\n return self;\n}\n\nconst mockQueryClient = createRecursiveProxy('ClerkMockQueryClient') as unknown as QueryClient;\n\n/**\n * Returns `[client, isLoaded]`. The real client is owned by `@clerk/shared`\n * and lazily instantiated on the browser only — SSR returns the proxy mock\n * + `isLoaded: false` so per-request renders never share a query cache.\n */\nconst useClerkQueryClient = (): [QueryClient, boolean] => {\n const client = getClerkQueryClient();\n return [client ?? mockQueryClient, Boolean(client)];\n};\n\nexport { useClerkQueryClient };\n","/**\n * Stripped down version of useBaseQuery from @tanstack/query-core.\n * This implementation allows for an observer to be created every time a query client changes.\n */\n\n'use client';\nimport type { DefaultedQueryObserverOptions, QueryKey, QueryObserver, QueryObserverResult } from '@tanstack/query-core';\nimport { noop, notifyManager } from '@tanstack/query-core';\nimport * as React from 'react';\n\nimport type { UseBaseQueryOptions } from './types';\nimport { useClerkQueryClient } from './use-clerk-query-client';\n\nexport type DistributivePick<T, K extends PropertyKey> = T extends unknown ? Pick<T, Extract<K, keyof T>> : never;\n\nexport type CommonQueryResult = 'data' | 'error' | 'isLoading' | 'isFetching' | 'status';\n\n/**\n * An alternative `useBaseQuery` implementation that allows for an observer to be created every time a query client changes.\n *\n * @internal\n */\nexport function useBaseQuery<TQueryFnData, TError, TData, TQueryData, TQueryKey extends QueryKey>(\n options: UseBaseQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>,\n Observer: typeof QueryObserver,\n): DistributivePick<QueryObserverResult<TData, TError>, CommonQueryResult> {\n const [client, isQueryClientLoaded] = useClerkQueryClient();\n const defaultedOptions = isQueryClientLoaded\n ? client.defaultQueryOptions(options)\n : (options as DefaultedQueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>);\n\n // Make sure results are optimistically set in fetching state before subscribing or updating options\n defaultedOptions._optimisticResults = 'optimistic';\n\n const observer = React.useMemo(() => {\n return new Observer<TQueryFnData, TError, TData, TQueryData, TQueryKey>(client, defaultedOptions);\n }, [client]);\n\n // note: this must be called before useSyncExternalStore\n const result = observer.getOptimisticResult(defaultedOptions);\n\n const shouldSubscribe = options.subscribed !== false;\n React.useSyncExternalStore(\n React.useCallback(\n onStoreChange => {\n const unsubscribe = shouldSubscribe ? observer.subscribe(notifyManager.batchCalls(onStoreChange)) : noop;\n\n // Update result to make sure we did not miss any query updates\n // between creating the observer and subscribing to it.\n observer.updateResult();\n\n return unsubscribe;\n },\n [observer, shouldSubscribe],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n );\n\n React.useEffect(() => {\n observer.setOptions(defaultedOptions);\n }, [defaultedOptions, observer]);\n\n if (!isQueryClientLoaded) {\n // Return a dummy result that matches RQ's pending state until the query client loads\n // (SSR, or on the client before clerk-js finishes bootstrapping it).\n // `isLoading` reflects whether the query *would* run once the client attaches — otherwise\n // consumers see `isLoading: false` with empty data and render a spurious \"no results\" state\n // in the window between clerk.loaded and the query client being ready.\n const isEnabled = options.enabled !== false;\n return {\n data: undefined,\n error: null,\n isLoading: isEnabled,\n isFetching: false,\n status: 'pending',\n };\n }\n\n // Handle result property usage tracking\n return !defaultedOptions.notifyOnChangeProps ? observer.trackResult(result) : result;\n}\n","import type { DefaultError, InfiniteData, QueryKey, QueryObserver } from '@tanstack/query-core';\nimport { InfiniteQueryObserver } from '@tanstack/query-core';\n\nimport type { DefinedInitialDataInfiniteOptions, UndefinedInitialDataInfiniteOptions } from './infiniteQueryOptions';\nimport type { DefinedUseInfiniteQueryResult, UseInfiniteQueryOptions, UseInfiniteQueryResult } from './types';\nimport { useBaseQuery } from './useBaseQuery';\n\nexport function useClerkInfiniteQuery<\n TQueryFnData,\n TError = DefaultError,\n TData = InfiniteData<TQueryFnData>,\n TQueryKey extends QueryKey = QueryKey,\n TPageParam = unknown,\n>(\n options: DefinedInitialDataInfiniteOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>,\n): DefinedUseInfiniteQueryResult<TData, TError>;\n\nexport function useClerkInfiniteQuery<\n TQueryFnData,\n TError = DefaultError,\n TData = InfiniteData<TQueryFnData>,\n TQueryKey extends QueryKey = QueryKey,\n TPageParam = unknown,\n>(\n options: UndefinedInitialDataInfiniteOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>,\n): UseInfiniteQueryResult<TData, TError>;\n\nexport function useClerkInfiniteQuery<\n TQueryFnData,\n TError = DefaultError,\n TData = InfiniteData<TQueryFnData>,\n TQueryKey extends QueryKey = QueryKey,\n TPageParam = unknown,\n>(\n options: UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>,\n): UseInfiniteQueryResult<TData, TError>;\n/**\n *\n */\nexport function useClerkInfiniteQuery(options: UseInfiniteQueryOptions) {\n return useBaseQuery(options, InfiniteQueryObserver as unknown as typeof QueryObserver);\n}\n","import type { DefaultError, QueryKey } from '@tanstack/query-core';\nimport { QueryObserver } from '@tanstack/query-core';\n\nimport type { DefinedInitialDataOptions, UndefinedInitialDataOptions } from './queryOptions';\nimport type { DefinedUseQueryResult, UseQueryOptions, UseQueryResult } from './types';\nimport type { CommonQueryResult, DistributivePick } from './useBaseQuery';\nimport { useBaseQuery } from './useBaseQuery';\n\nexport function useClerkQuery<\n TQueryFnData = unknown,\n TError = DefaultError,\n TData = TQueryFnData,\n TQueryKey extends QueryKey = QueryKey,\n>(\n options: DefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey>,\n): DistributivePick<DefinedUseQueryResult<NoInfer<TData>, TError>, CommonQueryResult>;\n\nexport function useClerkQuery<\n TQueryFnData = unknown,\n TError = DefaultError,\n TData = TQueryFnData,\n TQueryKey extends QueryKey = QueryKey,\n>(\n options: UndefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey>,\n): DistributivePick<UseQueryResult<NoInfer<TData>, TError>, CommonQueryResult>;\n\nexport function useClerkQuery<\n TQueryFnData = unknown,\n TError = DefaultError,\n TData = TQueryFnData,\n TQueryKey extends QueryKey = QueryKey,\n>(\n options: UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,\n): DistributivePick<UseQueryResult<NoInfer<TData>, TError>, CommonQueryResult>;\n\n/**\n *\n */\nexport function useClerkQuery(options: UseQueryOptions) {\n return useBaseQuery(options, QueryObserver);\n}\n","import { useRef } from 'react';\n\ntype Primitive = string | number | boolean | bigint | symbol | null | undefined;\n\n/**\n * A hook that retains the previous value of a primitive type.\n * It uses a ref to prevent causing unnecessary re-renders.\n *\n * @internal\n *\n * @example\n * ```\n * Render 1: value = 'A' → returns null\n * Render 2: value = 'B' → returns 'A'\n * Render 3: value = 'B' → returns 'A'\n * Render 4: value = 'B' → returns 'A'\n * Render 5: value = 'C' → returns 'B'\n * ```\n */\nexport function usePreviousValue<T extends Primitive>(value: T) {\n const currentRef = useRef(value);\n const previousRef = useRef<T | null>(null);\n\n if (currentRef.current !== value) {\n previousRef.current = currentRef.current;\n currentRef.current = value;\n }\n\n return previousRef.current;\n}\n","import { useEffect, useRef } from 'react';\n\nimport { useClerkQueryClient } from '../query/use-clerk-query-client';\nimport { usePreviousValue } from './usePreviousValue';\n\nexport const withInfiniteKey = <T extends string>(key: T) => [key, `${key}-inf`] as const;\n\ntype ClearQueriesOnSignOutOptions = {\n isSignedOut: boolean;\n stableKeys: string | readonly string[];\n /**\n * Whether the queries for this hook are keyed as authenticated.\n * If this is not `true`, the effect becomes a no-op.\n */\n authenticated?: boolean;\n /**\n * Optional callback that will run after queries are cleared on sign-out.\n */\n onCleanup?: () => void;\n};\n\n/**\n * Clears React Query caches associated with the given stable prefixes when\n * the authenticated state transitions from signed-in to signed-out.\n *\n * @internal\n */\nexport function useClearQueriesOnSignOut(options: ClearQueriesOnSignOutOptions) {\n const { isSignedOut, stableKeys, authenticated = true, onCleanup } = options;\n const stableKeysRef = useRef(stableKeys);\n\n const [queryClient] = useClerkQueryClient();\n const previousIsSignedIn = usePreviousValue(!isSignedOut);\n\n useEffect(() => {\n // If this hook's cache keys are not authenticated, skip all cleanup logic.\n if (authenticated !== true) {\n return;\n }\n\n const isNowSignedOut = isSignedOut === true;\n\n if (previousIsSignedIn && isNowSignedOut) {\n queryClient.removeQueries({\n predicate: query => {\n const [cachedStableKey, queryAuthenticated] = query.queryKey;\n\n return (\n queryAuthenticated === true &&\n typeof cachedStableKey === 'string' &&\n (Array.isArray(stableKeysRef.current)\n ? stableKeysRef.current.includes(cachedStableKey)\n : stableKeysRef.current === cachedStableKey)\n );\n },\n });\n\n onCleanup?.();\n }\n }, [authenticated, isSignedOut, previousIsSignedIn, queryClient]);\n}\n","import { useRef } from 'react';\n\nimport type { PagesOrInfiniteOptions } from '../types';\n\n/**\n * A hook that safely merges user-provided pagination options with default values.\n * It caches initial pagination values (page and size) until component unmount to prevent unwanted rerenders.\n *\n * @internal\n *\n * @example\n * ```typescript\n * // Example 1: With user-provided options\n * const userOptions = { initialPage: 2, pageSize: 20, infinite: true };\n * const defaults = { initialPage: 1, pageSize: 10, infinite: false };\n * useWithSafeValues(userOptions, defaults);\n * // Returns { initialPage: 2, pageSize: 20, infinite: true }\n *\n * // Example 2: With boolean true (use defaults)\n * const params = true;\n * const defaults = { initialPage: 1, pageSize: 10, infinite: false };\n * useWithSafeValues(params, defaults);\n * // Returns { initialPage: 1, pageSize: 10, infinite: false }\n *\n * // Example 3: With undefined options (fallback to defaults)\n * const params = undefined;\n * const defaults = { initialPage: 1, pageSize: 10, infinite: false };\n * useWithSafeValues(params, defaults);\n * // Returns { initialPage: 1, pageSize: 10, infinite: false }\n * ```\n */\nexport const useWithSafeValues = <T extends PagesOrInfiniteOptions>(params: T | true | undefined, defaultValues: T) => {\n const shouldUseDefaults = typeof params === 'boolean' && params;\n\n // Cache initialPage and initialPageSize until unmount\n const initialPageRef = useRef(\n shouldUseDefaults ? defaultValues.initialPage : (params?.initialPage ?? defaultValues.initialPage),\n );\n const pageSizeRef = useRef(shouldUseDefaults ? defaultValues.pageSize : (params?.pageSize ?? defaultValues.pageSize));\n\n const newObj: Record<string, unknown> = {};\n for (const key of Object.keys(defaultValues)) {\n // @ts-ignore - indexing into generic param to preserve unknown keys from defaults/params\n newObj[key] = shouldUseDefaults ? defaultValues[key] : (params?.[key] ?? defaultValues[key]);\n }\n\n return {\n ...newObj,\n initialPage: initialPageRef.current,\n pageSize: pageSizeRef.current,\n } as T;\n};\n\n/**\n * Returns an object containing only the keys from the first object that are not present in the second object.\n * Useful for extracting unique parameters that should be passed to a request while excluding common cache keys.\n *\n * @internal\n *\n * @example\n * ```typescript\n * // Example 1: Basic usage\n * const obj1 = { name: 'John', age: 30, city: 'NY' };\n * const obj2 = { name: 'John', age: 30 };\n * getDifferentKeys(obj1, obj2); // Returns { city: 'NY' }\n *\n * // Example 2: With cache keys\n * const requestParams = { page: 1, limit: 10, userId: '123' };\n * const cacheKeys = { userId: '123' };\n * getDifferentKeys(requestParams, cacheKeys); // Returns { page: 1, limit: 10 }\n * ```\n */\nexport function getDifferentKeys(\n obj1: Record<string, unknown>,\n obj2: Record<string, unknown>,\n): Record<string, unknown> {\n const keysSet = new Set(Object.keys(obj2));\n const differentKeysObject: Record<string, unknown> = {};\n\n for (const key1 of Object.keys(obj1)) {\n if (!keysSet.has(key1)) {\n differentKeysObject[key1] = obj1[key1];\n }\n }\n\n return differentKeysObject;\n}\n\n/**\n * Calculates the offset count for pagination based on initial page and page size.\n * This represents the number of items to skip before the first page.\n *\n * @param initialPage - The starting page number (1-based)\n * @param pageSize - The number of items per page\n * @returns The number of items to offset\n *\n * @example\n * ```typescript\n * calculateOffsetCount(1, 10); // Returns 0 (no offset for first page)\n * calculateOffsetCount(2, 10); // Returns 10 (skip first 10 items)\n * calculateOffsetCount(3, 20); // Returns 40 (skip first 40 items)\n * ```\n */\nexport function calculateOffsetCount(initialPage: number, pageSize: number): number {\n return (initialPage - 1) * pageSize;\n}\n\n/**\n * Calculates the total number of pages based on total count, offset, and page size.\n *\n * @param totalCount - The total number of items\n * @param offsetCount - The number of items to offset (from calculateOffsetCount)\n * @param pageSize - The number of items per page\n * @returns The total number of pages\n *\n * @example\n * ```typescript\n * calculatePageCount(100, 0, 10); // Returns 10\n * calculatePageCount(95, 0, 10); // Returns 10 (rounds up)\n * calculatePageCount(100, 20, 10); // Returns 8 (100 - 20 = 80 items, 8 pages)\n * ```\n */\nexport function calculatePageCount(totalCount: number, offsetCount: number, pageSize: number): number {\n return Math.ceil((totalCount - offsetCount) / pageSize);\n}\n\n/**\n * Determines if there is a next page available in non-infinite pagination mode.\n *\n * @param totalCount - The total number of items\n * @param offsetCount - The number of items to offset\n * @param currentPage - The current page number (1-based)\n * @param pageSize - The number of items per page\n * @returns True if there are more items beyond the current page\n *\n * @example\n * ```typescript\n * calculateHasNextPage(100, 0, 1, 10); // Returns true (page 1 of 10)\n * calculateHasNextPage(100, 0, 10, 10); // Returns false (last page)\n * calculateHasNextPage(25, 0, 2, 10); // Returns true (page 2, 5 more items)\n * calculateHasNextPage(20, 0, 2, 10); // Returns false (exactly 2 pages)\n * ```\n */\nexport function calculateHasNextPage(\n totalCount: number,\n offsetCount: number,\n currentPage: number,\n pageSize: number,\n): boolean {\n return totalCount - offsetCount > currentPage * pageSize;\n}\n\n/**\n * Determines if there is a previous page available in non-infinite pagination mode.\n *\n * @param currentPage - The current page number (1-based)\n * @param pageSize - The number of items per page\n * @param offsetCount - The number of items to offset\n * @returns True if there are pages before the current page\n *\n * @example\n * ```typescript\n * calculateHasPreviousPage(1, 10, 0); // Returns false (first page)\n * calculateHasPreviousPage(2, 10, 0); // Returns true (can go back to page 1)\n * calculateHasPreviousPage(1, 10, 10); // Returns false (first page with offset)\n * ```\n */\nexport function calculateHasPreviousPage(currentPage: number, pageSize: number, offsetCount: number): boolean {\n return (currentPage - 1) * pageSize > offsetCount;\n}\n","import { useCallback, useMemo, useRef, useState } from 'react';\n\nimport type { ClerkPaginatedResponse } from '../../types';\nimport { defineKeepPreviousDataFn } from '../query/keep-previous-data';\nimport { useClerkQueryClient } from '../query/use-clerk-query-client';\nimport { useClerkInfiniteQuery } from '../query/useInfiniteQuery';\nimport { useClerkQuery } from '../query/useQuery';\nimport type { CacheSetter, ValueOrSetter } from '../types';\nimport { useClearQueriesOnSignOut, withInfiniteKey } from './useClearQueriesOnSignOut';\nimport type { UsePagesOrInfiniteSignature } from './usePageOrInfinite.types';\nimport {\n calculateHasNextPage,\n calculateHasPreviousPage,\n calculateOffsetCount,\n calculatePageCount,\n useWithSafeValues,\n} from './usePagesOrInfinite.shared';\n\nexport const usePagesOrInfinite: UsePagesOrInfiniteSignature = params => {\n const { fetcher, config, keys } = params;\n\n const [paginatedPage, setPaginatedPage] = useState(config.initialPage ?? 1);\n\n // Cache initialPage and initialPageSize until unmount\n const initialPageRef = useRef(config.initialPage ?? 1);\n const pageSizeRef = useRef(config.pageSize ?? 10);\n\n const enabled = config.enabled ?? true;\n const isSignedIn = config.isSignedIn;\n const triggerInfinite = config.infinite ?? false;\n const cacheMode = config.__experimental_mode === 'cache';\n const keepPreviousData = config.keepPreviousData ?? false;\n\n const [queryClient] = useClerkQueryClient();\n\n // Compute the actual enabled state for queries (considering all conditions)\n const queriesEnabled = enabled && Boolean(fetcher) && !cacheMode && isSignedIn !== false;\n\n // Force re-render counter for cache-only updates\n const [forceUpdateCounter, setForceUpdateCounter] = useState(0);\n const forceUpdate = useCallback((updater: (n: number) => number) => {\n setForceUpdateCounter(updater);\n }, []);\n\n // Non-infinite mode: single page query\n const pagesQueryKey = useMemo(() => {\n const [stablePrefix, authenticated, tracked, untracked] = keys.queryKey;\n\n return [\n stablePrefix,\n authenticated,\n tracked,\n {\n ...untracked,\n args: {\n ...untracked.args,\n initialPage: paginatedPage,\n pageSize: pageSizeRef.current,\n },\n },\n ] as const;\n }, [keys.queryKey, paginatedPage]);\n\n const singlePageQuery = useClerkQuery({\n queryKey: pagesQueryKey,\n queryFn: ({ queryKey }) => {\n const { args } = queryKey[3];\n\n if (!fetcher) {\n return undefined as any;\n }\n\n return fetcher(args);\n },\n staleTime: 60_000,\n enabled: queriesEnabled && !triggerInfinite,\n // Use placeholderData to keep previous data while fetching new page\n placeholderData: defineKeepPreviousDataFn(keepPreviousData),\n });\n\n // Infinite mode: accumulate pages\n const infiniteQueryKey = useMemo(() => {\n const [stablePrefix, authenticated, tracked, untracked] = keys.queryKey;\n\n return [stablePrefix + '-inf', authenticated, tracked, untracked] as const;\n }, [keys.queryKey]);\n\n const infiniteQuery = useClerkInfiniteQuery<ClerkPaginatedResponse<any>, any, any, typeof infiniteQueryKey, any>({\n queryKey: infiniteQueryKey,\n initialPageParam: config.initialPage ?? 1,\n getNextPageParam: (lastPage, allPages, lastPageParam) => {\n const total = lastPage?.total_count ?? 0;\n const consumed = (allPages.length + (config.initialPage ? config.initialPage - 1 : 0)) * (config.pageSize ?? 10);\n return consumed < total ? (lastPageParam as number) + 1 : undefined;\n },\n queryFn: ({ pageParam, queryKey }) => {\n const { args } = queryKey[3];\n if (!fetcher) {\n return undefined as any;\n }\n return fetcher({ ...args, initialPage: pageParam, pageSize: pageSizeRef.current });\n },\n staleTime: 60_000,\n enabled: queriesEnabled && triggerInfinite,\n });\n\n useClearQueriesOnSignOut({\n isSignedOut: isSignedIn === false,\n authenticated: keys.authenticated,\n stableKeys: withInfiniteKey(keys.stableKey),\n onCleanup: () => {\n // Reset paginated page to initial\n setPaginatedPage(initialPageRef.current);\n\n // Force re-render to reflect cache changes\n void Promise.resolve().then(() => forceUpdate(n => n + 1));\n },\n });\n\n // Compute data, count and page from the same data source to ensure consistency\n const computedValues = useMemo(() => {\n if (triggerInfinite) {\n // Read from query data first, fallback to cache\n const cachedData = queryClient.getQueryData<{ pages?: Array<ClerkPaginatedResponse<any>> }>(infiniteQueryKey);\n const pages = queriesEnabled ? (infiniteQuery.data?.pages ?? cachedData?.pages ?? []) : (cachedData?.pages ?? []);\n\n // Ensure pages is always an array and filter out null/undefined pages\n const validPages = Array.isArray(pages) ? pages.filter(Boolean) : [];\n\n return {\n data:\n validPages\n .map((a: ClerkPaginatedResponse<any>) => a?.data)\n .flat()\n .filter(Boolean) ?? [],\n count: validPages[validPages.length - 1]?.total_count ?? 0,\n page: validPages.length > 0 ? validPages.length : initialPageRef.current,\n };\n }\n\n // When query is disabled (via enabled flag), the hook's data is stale, so only read from cache\n // This ensures that after cache clearing, we return consistent empty state\n const pageData = queriesEnabled\n ? (singlePageQuery.data ?? queryClient.getQueryData<ClerkPaginatedResponse<any>>(pagesQueryKey))\n : queryClient.getQueryData<ClerkPaginatedResponse<any>>(pagesQueryKey);\n\n return {\n data: Array.isArray(pageData?.data) ? pageData.data : [],\n count: typeof pageData?.total_count === 'number' ? pageData.total_count : 0,\n page: paginatedPage,\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- forceUpdateCounter is used to trigger re-renders for cache updates\n }, [\n queriesEnabled,\n forceUpdateCounter,\n triggerInfinite,\n infiniteQuery.data?.pages,\n singlePageQuery.data,\n queryClient,\n infiniteQueryKey,\n pagesQueryKey,\n paginatedPage,\n ]);\n\n const { data, count, page } = computedValues;\n\n const fetchPage: ValueOrSetter<number> = useCallback(\n numberOrgFn => {\n if (triggerInfinite) {\n const next = typeof numberOrgFn === 'function' ? (numberOrgFn as (n: number) => number)(page) : numberOrgFn;\n const targetCount = Math.max(0, next);\n const cachedData = queryClient.getQueryData<{ pages?: Array<ClerkPaginatedResponse<any>> }>(infiniteQueryKey);\n const pages = infiniteQuery.data?.pages ?? cachedData?.pages ?? [];\n const currentCount = pages.length;\n const toFetch = targetCount - currentCount;\n if (toFetch > 0) {\n void infiniteQuery.fetchNextPage({ cancelRefetch: false });\n }\n return;\n }\n return setPaginatedPage(numberOrgFn);\n },\n [infiniteQuery, page, triggerInfinite, queryClient, infiniteQueryKey],\n );\n\n const isLoading = triggerInfinite ? infiniteQuery.isLoading : singlePageQuery.isLoading;\n const isFetching = triggerInfinite ? infiniteQuery.isFetching : singlePageQuery.isFetching;\n const error = (triggerInfinite ? infiniteQuery.error : singlePageQuery.error) ?? null;\n const isError = !!error;\n\n const fetchNext = useCallback(() => {\n if (triggerInfinite) {\n void infiniteQuery.fetchNextPage({ cancelRefetch: false });\n return;\n }\n setPaginatedPage(n => Math.max(0, n + 1));\n }, [infiniteQuery, triggerInfinite]);\n\n const fetchPrevious = useCallback(() => {\n if (triggerInfinite) {\n // not natively supported by forward-only pagination; noop\n return;\n }\n setPaginatedPage(n => Math.max(0, n - 1));\n }, [triggerInfinite]);\n\n const offsetCount = calculateOffsetCount(initialPageRef.current, pageSizeRef.current);\n const pageCount = calculatePageCount(count, offsetCount, pageSizeRef.current);\n const hasNextPage = triggerInfinite\n ? Boolean(infiniteQuery.hasNextPage)\n : calculateHasNextPage(count, offsetCount, page, pageSizeRef.current);\n const hasPreviousPage = triggerInfinite\n ? Boolean(infiniteQuery.hasPreviousPage)\n : calculateHasPreviousPage(page, pageSizeRef.current, offsetCount);\n\n const setData: CacheSetter = value => {\n if (triggerInfinite) {\n queryClient.setQueryData(infiniteQueryKey, (prevValue: any = {}) => {\n const prevPages = Array.isArray(prevValue?.pages) ? prevValue.pages : [];\n const nextPages = (typeof value === 'function' ? value(prevPages) : value) as Array<\n ClerkPaginatedResponse<any>\n >;\n return { ...prevValue, pages: nextPages };\n });\n // Force immediate re-render to reflect cache changes\n forceUpdate(n => n + 1);\n return Promise.resolve();\n }\n queryClient.setQueryData(pagesQueryKey, (prevValue: any = { data: [], total_count: 0 }) => {\n const nextValue = (typeof value === 'function' ? value(prevValue) : value) as ClerkPaginatedResponse<any>;\n return nextValue;\n });\n // Force re-render to reflect cache changes\n forceUpdate(n => n + 1);\n return Promise.resolve();\n };\n\n const revalidate = async () => {\n await queryClient.invalidateQueries({ queryKey: keys.invalidationKey });\n const [stablePrefix, ...rest] = keys.invalidationKey;\n return queryClient.invalidateQueries({ queryKey: [stablePrefix + '-inf', ...rest] });\n };\n\n return {\n data,\n count,\n error,\n isLoading,\n isFetching,\n isError,\n page,\n pageCount,\n fetchPage,\n fetchNext,\n fetchPrevious,\n hasNextPage,\n hasPreviousPage,\n revalidate: revalidate as any,\n setData: setData as any,\n };\n};\n\nexport { useWithSafeValues };\n","import { eventMethodCalled } from '../../telemetry/events/method-called';\nimport type { APIKeyResource, GetAPIKeysParams } from '../../types';\nimport { useAssertWrappedByClerkProvider, useClerkInstanceContext } from '../contexts';\nimport { STABLE_KEYS } from '../stable-keys';\nimport type { PaginatedHookConfig, PaginatedResources } from '../types';\nimport { createCacheKeys } from './createCacheKeys';\nimport { usePagesOrInfinite, useWithSafeValues } from './usePagesOrInfinite';\n\n/**\n * @interface\n */\nexport type UseAPIKeysParams = PaginatedHookConfig<\n GetAPIKeysParams & {\n /**\n * If `true`, a request will be triggered when the hook is mounted.\n *\n * @default true\n */\n enabled?: boolean;\n }\n>;\n\n/**\n * @interface\n */\nexport type UseAPIKeysReturn<T extends UseAPIKeysParams> = PaginatedResources<\n APIKeyResource,\n T extends { infinite: true } ? true : false\n>;\n\n/**\n * The `useAPIKeys()` hook provides access to paginated API keys for the current user or organization.\n *\n * @example\n * ### Basic usage with default pagination\n *\n * ```tsx\n * const { data, isLoading, page, pageCount, fetchNext, fetchPrevious } = useAPIKeys({\n * subject: 'user_123',\n * pageSize: 10,\n * initialPage: 1,\n * });\n * ```\n *\n * @example\n * ### With search query\n *\n * ```tsx\n * const [searchValue, setSearchValue] = useState('');\n * const debouncedSearch = useDebounce(searchValue, 500);\n *\n * const { data, isLoading } = useAPIKeys({\n * subject: 'user_123',\n * query: debouncedSearch.trim(),\n * pageSize: 10,\n * });\n * ```\n *\n * @example\n * ### Infinite scroll\n *\n * ```tsx\n * const { data, isLoading, fetchNext, hasNextPage } = useAPIKeys({\n * subject: 'user_123',\n * infinite: true,\n * });\n * ```\n */\nexport function useAPIKeys<T extends UseAPIKeysParams>(params?: T): UseAPIKeysReturn<T> {\n useAssertWrappedByClerkProvider('useAPIKeys');\n\n const safeValues = useWithSafeValues(params, {\n initialPage: 1,\n pageSize: 10,\n keepPreviousData: false,\n infinite: false,\n subject: '',\n query: '',\n enabled: true,\n } as UseAPIKeysParams);\n\n const clerk = useClerkInstanceContext();\n\n clerk.telemetry?.record(eventMethodCalled('useAPIKeys'));\n\n const hookParams: GetAPIKeysParams = {\n initialPage: safeValues.initialPage,\n pageSize: safeValues.pageSize,\n ...(safeValues.subject ? { subject: safeValues.subject } : {}),\n ...(safeValues.query ? { query: safeValues.query } : {}),\n };\n\n const isEnabled = (safeValues.enabled ?? true) && clerk.loaded;\n\n return usePagesOrInfinite({\n fetcher: clerk.apiKeys?.getAll\n ? (params: GetAPIKeysParams) => clerk.apiKeys.getAll({ ...params, subject: safeValues.subject })\n : undefined,\n config: {\n keepPreviousData: safeValues.keepPreviousData,\n infinite: safeValues.infinite,\n enabled: isEnabled,\n isSignedIn: clerk.user !== null,\n initialPage: safeValues.initialPage,\n pageSize: safeValues.pageSize,\n },\n keys: createCacheKeys({\n stablePrefix: STABLE_KEYS.API_KEYS_KEY,\n authenticated: true,\n tracked: {\n subject: safeValues.subject,\n },\n untracked: {\n args: hookParams,\n },\n }),\n }) as UseAPIKeysReturn<T>;\n}\n","import { useCallback, useSyncExternalStore } from 'react';\n\nimport type { UserResource } from '@/types';\n\nimport { useClerkInstanceContext, useInitialStateContext } from '../../contexts';\n\nexport function useUserBase(): UserResource | null | undefined {\n const clerk = useClerkInstanceContext();\n const initialState = useInitialStateContext();\n const getInitialState = useCallback(() => initialState?.user, [initialState?.user]);\n\n const user = useSyncExternalStore(\n useCallback(\n callback => {\n return clerk.addListener(callback, { skipInitialEmit: true });\n },\n [clerk],\n ),\n useCallback(() => {\n if (!clerk.loaded || !clerk.__internal_lastEmittedResources) {\n return getInitialState();\n }\n return clerk.__internal_lastEmittedResources.user;\n }, [clerk, getInitialState]),\n getInitialState,\n );\n\n return user;\n}\n","import { useMemo } from 'react';\n\nimport { STABLE_KEYS } from '../stable-keys';\nimport { createCacheKeys } from './createCacheKeys';\n\nexport function useOAuthConsentCacheKeys(params: {\n userId: string | null;\n oauthClientId: string;\n scope?: string;\n redirectUri?: string;\n}) {\n const { userId, oauthClientId, scope, redirectUri } = params;\n return useMemo(() => {\n const args = {\n oauthClientId,\n ...(scope !== undefined && { scope }),\n ...(redirectUri !== undefined && { redirectUri }),\n };\n return createCacheKeys({\n stablePrefix: STABLE_KEYS.OAUTH_CONSENT_INFO_KEY,\n authenticated: true,\n tracked: {\n userId: userId ?? null,\n },\n untracked: {\n args,\n },\n });\n }, [userId, oauthClientId, scope, redirectUri]);\n}\n","import { eventMethodCalled } from '../../telemetry/events/method-called';\nimport type { LoadedClerk } from '../../types/clerk';\nimport { useAssertWrappedByClerkProvider, useClerkInstanceContext } from '../contexts';\nimport { defineKeepPreviousDataFn } from '../query/keep-previous-data';\nimport { useClerkQuery } from '../query/useQuery';\nimport { useUserBase } from './base/useUserBase';\nimport { useOAuthConsentCacheKeys } from './useOAuthConsent.shared';\nimport type { UseOAuthConsentParams, UseOAuthConsentReturn } from './useOAuthConsent.types';\n\nconst HOOK_NAME = 'useOAuthConsent';\n\n/**\n * The `useOAuthConsent()` hook loads OAuth application consent metadata for the **signed-in** user\n * (`GET /me/oauth/consent/{oauthClientId}`). Ensure the user is authenticated before relying on this hook\n * (e.g., redirect to sign-in on your custom consent route).\n *\n * @example\n * ```tsx\n * import { useOAuthConsent } from '@clerk/react/internal'\n *\n * const { data, isLoading, error } = useOAuthConsent({\n * oauthClientId: clientIdFromProps,\n * scope: scopeFr