import type { interfaces, ProviderProps } from '@servicetitan/react-ioc'; import { injectable } from '@servicetitan/react-ioc'; import includes from 'lodash/includes'; import type { QueryClientConfig } from '@tanstack/query-core'; import { PageClientType } from '../types/page-client-type'; import { PageClientStore } from './page-client.store'; import { QueryClientStore } from './query-client.store'; type SingletonProps = Required['singletons'][0]; /** * Helper function to create a QueryClientStore for dependency injection. * Use this in your provider's singletons array to enable TanStack Query integration. * * @param clientStore - Optional client type or custom QueryClientStore class * - `undefined` (default): Component-scoped client, disposed when component unmounts * - `'page'`: Page-level shared client with reference counting. Disposes when the last component using it unmounts * - `QueryClientConfig`: Component-scoped client with custom defaults (staleTime, retry, etc.) * - Custom class: Uses your custom QueryClientStore implementation * @returns Provider configuration for react-ioc * * @see QueryApiOptions.globalClient for query-level shared clients (supports 'page' and 'app') * @see client-helpers.ts for shared client types and lifecycle details * * @example * ```typescript * // Default client (component-scoped, no sharing) * export const App = provide({ * singletons: [getQueryClient(), MyStore], * })(observer(() => )); * ``` * * @example * ```typescript * // Page-level shared client (recommended for micro-frontends) * export const App = provide({ * singletons: [getQueryClient('page'), MyStore], * })(observer(() => )); * ``` * * @example * ```typescript * // Custom defaults (component-scoped only — shared clients use consistent defaults) * export const App = provide({ * singletons: [ * getQueryClient({ defaultOptions: { queries: { staleTime: 0, retry: false } } }), * MyStore, * ], * })(observer(() => )); * ``` */ export function getQueryClient( clientStore?: PageClientType | 'page' | interfaces.Newable | QueryClientConfig ): SingletonProps { // Detect overload: getQueryClient(config) — plain object as first arg if (clientStore && typeof clientStore === 'object') { const capturedConfig = clientStore as QueryClientConfig; class ConfiguredQueryClientStore extends QueryClientStore { constructor() { super(undefined, capturedConfig); } } injectable()(ConfiguredQueryClientStore); Object.defineProperty(ConfiguredQueryClientStore, 'name', { value: 'QueryClientStore' }); return { provide: QueryClientStore, useClass: ConfiguredQueryClientStore }; } const isPageType = includes([PageClientType.Page, PageClientType.PagePersist], clientStore); if (clientStore === 'page' || isPageType) { return { provide: QueryClientStore, useClass: PageClientStore }; } else if (clientStore && clientStore !== PageClientType.None) { return { provide: QueryClientStore, useClass: clientStore as interfaces.Newable }; } return QueryClientStore; }