@robohall/react-query-factory 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,27 +1,14 @@
1
- import { QueryKey, NotifyOnChangeProps, QueryMeta, QueryFunctionContext, InfiniteData, GetNextPageParamFunction, GetPreviousPageParamFunction } from '@tanstack/react-query';
1
+ import { QueryObserverOptions, QueryKey, QueryFunctionContext, InfiniteData, GetNextPageParamFunction, GetPreviousPageParamFunction } from '@tanstack/react-query';
2
2
 
3
- /** Subset of TanStack Query options that apply to both regular and infinite queries. */
4
- interface StandardQueryOptions<TError = Error> {
5
- enabled?: boolean;
6
- staleTime?: number | ((query: {
7
- queryKey: QueryKey;
8
- }) => number);
9
- gcTime?: number;
10
- retry?: boolean | number | ((failureCount: number, error: TError) => boolean);
11
- retryDelay?: number | ((retryAttempt: number, error: TError) => number);
12
- refetchOnWindowFocus?: boolean | 'always';
13
- refetchOnReconnect?: boolean | 'always';
14
- refetchOnMount?: boolean | 'always';
15
- refetchInterval?: number | false | ((query: {
16
- queryKey: QueryKey;
17
- }) => number | false);
18
- refetchIntervalInBackground?: boolean;
19
- networkMode?: 'online' | 'always' | 'offlineFirst';
20
- notifyOnChangeProps?: NotifyOnChangeProps;
21
- throwOnError?: boolean | ((error: TError) => boolean);
22
- meta?: QueryMeta;
23
- structuralSharing?: boolean;
24
- }
3
+ /**
4
+ * All TanStack Query options that apply to both regular and infinite queries,
5
+ * derived directly from `QueryObserverOptions` so it stays in sync with TanStack.
6
+ *
7
+ * Fields owned by the factory (`queryKey`, `queryFn`, `select`) and internal
8
+ * implementation details (`behavior`, `_defaulted`, `_type`, `_optimisticResults`,
9
+ * `queryHash`) are omitted.
10
+ */
11
+ type StandardQueryOptions<TError = Error, TData = unknown> = Omit<QueryObserverOptions<TData, TError, TData, TData, QueryKey>, 'queryKey' | 'queryFn' | 'select' | 'behavior' | '_defaulted' | '_type' | '_optimisticResults' | 'queryHash'>;
25
12
  /**
26
13
  * Configuration passed to `queryFactory()`.
27
14
  *
@@ -31,32 +18,45 @@ interface StandardQueryOptions<TError = Error> {
31
18
  * single `TSelected` value.
32
19
  * - Call `factory.infinite(params)` to get a `useInfiniteQuery`-compatible config
33
20
  * where each virtual page is itself a crawl.
21
+ *
22
+ * When `getNextPageParam` is provided, `initialPageParam` is required. This
23
+ * mirrors TanStack's own API and ensures `TPageParam` is inferred from the
24
+ * concrete initial value (so `ctx.pageParam` in `queryFn` is typed correctly).
34
25
  */
35
- interface QueryFactoryConfig<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>> extends StandardQueryOptions<TError> {
26
+ type QueryFactoryConfig<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>> = StandardQueryOptions<TError, TData> & {
36
27
  /** Namespace segments. Params are appended as the final element at call time,
37
28
  * giving a full key of [...namespace, 'infinite'?, params, crawlOptions?]. */
38
29
  queryKey: QueryKey;
39
- queryFn?: (params: TParams, context: QueryFunctionContext<QueryKey, TPageParam>) => TData | Promise<TData>;
30
+ queryFn?: (params: TParams, context: QueryFunctionContext<QueryKey, [unknown] extends [TPageParam] ? never : TPageParam>) => TData | Promise<TData>;
40
31
  select?: (data: TData) => TSelected;
32
+ } & ({
41
33
  /** TanStack v5 generic order: GetNextPageParamFunction<TPageParam, TData> */
42
- getNextPageParam?: GetNextPageParamFunction<TPageParam, TData>;
34
+ getNextPageParam: GetNextPageParamFunction<TPageParam, TData>;
35
+ /** Required alongside getNextPageParam — drives TPageParam inference so
36
+ * ctx.pageParam in queryFn is typed as TPageParam, not unknown. */
37
+ initialPageParam: TPageParam;
43
38
  getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
44
- initialPageParam?: TPageParam;
45
- /** Called after each page to decide whether to keep crawling.
46
- * Receives the current combined result and the crawl options from the call site. */
47
- shouldFetchNextPage?: (combined: TSelected | undefined, crawlOptions: TCrawlOptions) => boolean;
48
39
  /** Reduces crawled pages incrementally into the final query result.
49
40
  * Called once per page; accumulator is undefined on the first call.
50
41
  * When set, enables crawling on both the regular and .infinite variants. */
51
42
  reduce?: (accumulator: TSelected | undefined, page: TData) => TSelected;
52
- }
43
+ /** Called after each page to decide whether to keep crawling.
44
+ * `combined` may be undefined when reduce is absent. */
45
+ shouldFetchNextPage?: (combined: TSelected | undefined, crawlOptions: TCrawlOptions) => boolean;
46
+ } | {
47
+ getNextPageParam?: never;
48
+ initialPageParam?: never;
49
+ getPreviousPageParam?: never;
50
+ shouldFetchNextPage?: never;
51
+ reduce?: never;
52
+ });
53
53
  /**
54
54
  * What `factory(params)` returns — pass directly to `useQuery()`.
55
55
  *
56
56
  * The `initialPageParam?: never` field is a structural guard that makes this
57
57
  * type incompatible with `useInfiniteQuery`, preventing accidental misuse.
58
58
  */
59
- type ResolvedQueryOptions<TData = unknown, TError = Error, TSelected = TData> = StandardQueryOptions<TError> & {
59
+ type ResolvedQueryOptions<TData = unknown, TError = Error, TSelected = TData> = StandardQueryOptions<TError, TData> & {
60
60
  queryKey: QueryKey;
61
61
  queryFn?: (context: QueryFunctionContext) => TData | Promise<TData>;
62
62
  select?: (data: TData) => TSelected;
@@ -69,7 +69,7 @@ type ResolvedQueryOptions<TData = unknown, TError = Error, TSelected = TData> =
69
69
  * The `select` field expects `InfiniteData<TData, TPageParam>`, which is a structural
70
70
  * guard making this type incompatible with `useQuery`.
71
71
  */
72
- type ResolvedInfiniteOptions<TData = unknown, TError = Error, TPageParam = unknown> = StandardQueryOptions<TError> & {
72
+ type ResolvedInfiniteOptions<TData = unknown, TError = Error, TPageParam = unknown> = Omit<StandardQueryOptions<TError, any>, 'persister'> & {
73
73
  queryKey: QueryKey;
74
74
  queryFn?: (context: QueryFunctionContext<QueryKey, TPageParam>) => TData | Promise<TData>;
75
75
  /** Structural guard: the InfiniteData parameter type makes this incompatible with useQuery,
@@ -99,6 +99,21 @@ interface QueryFactory<TParams = void, TData = unknown, TError = Error, TSelecte
99
99
  (params?: TParams, crawlOptions?: TCrawlOptions): ResolvedQueryOptions<TData, TError, TSelected>;
100
100
  infinite(params?: TParams, crawlOptions?: TCrawlOptions): ResolvedInfiniteOptions<TData, TError, TPageParam>;
101
101
  }
102
+ /**
103
+ * Creates a standalone query factory with pagination and reduce. When `reduce` is
104
+ * present, `shouldFetchNextPage` receives `TSelected` (never undefined) because
105
+ * reduce always runs before the crawl-stop check.
106
+ */
107
+ declare function queryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>>(config: StandardQueryOptions<TError, TData> & {
108
+ queryKey: QueryKey;
109
+ queryFn?: (params: TParams, context: QueryFunctionContext<QueryKey, [unknown] extends [TPageParam] ? never : TPageParam>) => TData | Promise<TData>;
110
+ select?: (data: TData) => TSelected;
111
+ getNextPageParam: GetNextPageParamFunction<TPageParam, TData>;
112
+ initialPageParam: TPageParam;
113
+ getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
114
+ reduce: (accumulator: TSelected | undefined, page: TData) => TSelected;
115
+ shouldFetchNextPage?: (combined: TSelected, crawlOptions: TCrawlOptions) => boolean;
116
+ }): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions>;
102
117
  /**
103
118
  * Creates a standalone query factory from a config object.
104
119
  *
@@ -140,10 +155,15 @@ declare function queryFactory<TChildParams extends TParentParams, TData = unknow
140
155
  * without changing what data is fetched. Parent and child `select` functions
141
156
  * are automatically composed: `child.select(parent.select(data))`.
142
157
  */
143
- declare function queryFactory<TChildParams extends TParentParams, TData = unknown, TError = Error, TParentSelected = TData, TChildSelected = TParentSelected, TParentParams = TChildParams, TPageParam = unknown, TParentCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TChildCrawlOptions extends Record<string, unknown> = TParentCrawlOptions>(parent: QueryFactory<TParentParams, TData, any, TParentSelected, TPageParam, TParentCrawlOptions>, config: Omit<QueryFactoryConfig<TChildParams, TData, TError, TChildSelected, TPageParam, TChildCrawlOptions>, 'queryKey' | 'queryFn' | 'select'> & {
158
+ declare function queryFactory<TChildParams extends TParentParams, TData = unknown, TError = Error, TParentSelected = TData, TChildSelected = TParentSelected, TParentParams = TChildParams, TPageParam = unknown, TParentCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TChildCrawlOptions extends Record<string, unknown> = TParentCrawlOptions>(parent: QueryFactory<TParentParams, TData, any, TParentSelected, TPageParam, TParentCrawlOptions>, config: StandardQueryOptions<TError, TData> & {
144
159
  queryKey?: QueryKey;
145
160
  queryFn?: never;
146
161
  select?: (data: TParentSelected) => TChildSelected;
162
+ getNextPageParam?: GetNextPageParamFunction<TPageParam, TData>;
163
+ initialPageParam?: TPageParam;
164
+ getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
165
+ reduce?: (accumulator: TChildSelected | undefined, page: TData) => TChildSelected;
166
+ shouldFetchNextPage?: (combined: TChildSelected | undefined, crawlOptions: TChildCrawlOptions) => boolean;
147
167
  }): QueryFactory<TChildParams, TData, TError, TChildSelected, TPageParam, TChildCrawlOptions>;
148
168
 
149
169
  export { type QueryFactory, type QueryFactoryConfig, type ResolvedInfiniteOptions, type ResolvedQueryOptions, type StandardQueryOptions, queryFactory };
package/dist/index.d.ts CHANGED
@@ -1,27 +1,14 @@
1
- import { QueryKey, NotifyOnChangeProps, QueryMeta, QueryFunctionContext, InfiniteData, GetNextPageParamFunction, GetPreviousPageParamFunction } from '@tanstack/react-query';
1
+ import { QueryObserverOptions, QueryKey, QueryFunctionContext, InfiniteData, GetNextPageParamFunction, GetPreviousPageParamFunction } from '@tanstack/react-query';
2
2
 
3
- /** Subset of TanStack Query options that apply to both regular and infinite queries. */
4
- interface StandardQueryOptions<TError = Error> {
5
- enabled?: boolean;
6
- staleTime?: number | ((query: {
7
- queryKey: QueryKey;
8
- }) => number);
9
- gcTime?: number;
10
- retry?: boolean | number | ((failureCount: number, error: TError) => boolean);
11
- retryDelay?: number | ((retryAttempt: number, error: TError) => number);
12
- refetchOnWindowFocus?: boolean | 'always';
13
- refetchOnReconnect?: boolean | 'always';
14
- refetchOnMount?: boolean | 'always';
15
- refetchInterval?: number | false | ((query: {
16
- queryKey: QueryKey;
17
- }) => number | false);
18
- refetchIntervalInBackground?: boolean;
19
- networkMode?: 'online' | 'always' | 'offlineFirst';
20
- notifyOnChangeProps?: NotifyOnChangeProps;
21
- throwOnError?: boolean | ((error: TError) => boolean);
22
- meta?: QueryMeta;
23
- structuralSharing?: boolean;
24
- }
3
+ /**
4
+ * All TanStack Query options that apply to both regular and infinite queries,
5
+ * derived directly from `QueryObserverOptions` so it stays in sync with TanStack.
6
+ *
7
+ * Fields owned by the factory (`queryKey`, `queryFn`, `select`) and internal
8
+ * implementation details (`behavior`, `_defaulted`, `_type`, `_optimisticResults`,
9
+ * `queryHash`) are omitted.
10
+ */
11
+ type StandardQueryOptions<TError = Error, TData = unknown> = Omit<QueryObserverOptions<TData, TError, TData, TData, QueryKey>, 'queryKey' | 'queryFn' | 'select' | 'behavior' | '_defaulted' | '_type' | '_optimisticResults' | 'queryHash'>;
25
12
  /**
26
13
  * Configuration passed to `queryFactory()`.
27
14
  *
@@ -31,32 +18,45 @@ interface StandardQueryOptions<TError = Error> {
31
18
  * single `TSelected` value.
32
19
  * - Call `factory.infinite(params)` to get a `useInfiniteQuery`-compatible config
33
20
  * where each virtual page is itself a crawl.
21
+ *
22
+ * When `getNextPageParam` is provided, `initialPageParam` is required. This
23
+ * mirrors TanStack's own API and ensures `TPageParam` is inferred from the
24
+ * concrete initial value (so `ctx.pageParam` in `queryFn` is typed correctly).
34
25
  */
35
- interface QueryFactoryConfig<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>> extends StandardQueryOptions<TError> {
26
+ type QueryFactoryConfig<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>> = StandardQueryOptions<TError, TData> & {
36
27
  /** Namespace segments. Params are appended as the final element at call time,
37
28
  * giving a full key of [...namespace, 'infinite'?, params, crawlOptions?]. */
38
29
  queryKey: QueryKey;
39
- queryFn?: (params: TParams, context: QueryFunctionContext<QueryKey, TPageParam>) => TData | Promise<TData>;
30
+ queryFn?: (params: TParams, context: QueryFunctionContext<QueryKey, [unknown] extends [TPageParam] ? never : TPageParam>) => TData | Promise<TData>;
40
31
  select?: (data: TData) => TSelected;
32
+ } & ({
41
33
  /** TanStack v5 generic order: GetNextPageParamFunction<TPageParam, TData> */
42
- getNextPageParam?: GetNextPageParamFunction<TPageParam, TData>;
34
+ getNextPageParam: GetNextPageParamFunction<TPageParam, TData>;
35
+ /** Required alongside getNextPageParam — drives TPageParam inference so
36
+ * ctx.pageParam in queryFn is typed as TPageParam, not unknown. */
37
+ initialPageParam: TPageParam;
43
38
  getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
44
- initialPageParam?: TPageParam;
45
- /** Called after each page to decide whether to keep crawling.
46
- * Receives the current combined result and the crawl options from the call site. */
47
- shouldFetchNextPage?: (combined: TSelected | undefined, crawlOptions: TCrawlOptions) => boolean;
48
39
  /** Reduces crawled pages incrementally into the final query result.
49
40
  * Called once per page; accumulator is undefined on the first call.
50
41
  * When set, enables crawling on both the regular and .infinite variants. */
51
42
  reduce?: (accumulator: TSelected | undefined, page: TData) => TSelected;
52
- }
43
+ /** Called after each page to decide whether to keep crawling.
44
+ * `combined` may be undefined when reduce is absent. */
45
+ shouldFetchNextPage?: (combined: TSelected | undefined, crawlOptions: TCrawlOptions) => boolean;
46
+ } | {
47
+ getNextPageParam?: never;
48
+ initialPageParam?: never;
49
+ getPreviousPageParam?: never;
50
+ shouldFetchNextPage?: never;
51
+ reduce?: never;
52
+ });
53
53
  /**
54
54
  * What `factory(params)` returns — pass directly to `useQuery()`.
55
55
  *
56
56
  * The `initialPageParam?: never` field is a structural guard that makes this
57
57
  * type incompatible with `useInfiniteQuery`, preventing accidental misuse.
58
58
  */
59
- type ResolvedQueryOptions<TData = unknown, TError = Error, TSelected = TData> = StandardQueryOptions<TError> & {
59
+ type ResolvedQueryOptions<TData = unknown, TError = Error, TSelected = TData> = StandardQueryOptions<TError, TData> & {
60
60
  queryKey: QueryKey;
61
61
  queryFn?: (context: QueryFunctionContext) => TData | Promise<TData>;
62
62
  select?: (data: TData) => TSelected;
@@ -69,7 +69,7 @@ type ResolvedQueryOptions<TData = unknown, TError = Error, TSelected = TData> =
69
69
  * The `select` field expects `InfiniteData<TData, TPageParam>`, which is a structural
70
70
  * guard making this type incompatible with `useQuery`.
71
71
  */
72
- type ResolvedInfiniteOptions<TData = unknown, TError = Error, TPageParam = unknown> = StandardQueryOptions<TError> & {
72
+ type ResolvedInfiniteOptions<TData = unknown, TError = Error, TPageParam = unknown> = Omit<StandardQueryOptions<TError, any>, 'persister'> & {
73
73
  queryKey: QueryKey;
74
74
  queryFn?: (context: QueryFunctionContext<QueryKey, TPageParam>) => TData | Promise<TData>;
75
75
  /** Structural guard: the InfiniteData parameter type makes this incompatible with useQuery,
@@ -99,6 +99,21 @@ interface QueryFactory<TParams = void, TData = unknown, TError = Error, TSelecte
99
99
  (params?: TParams, crawlOptions?: TCrawlOptions): ResolvedQueryOptions<TData, TError, TSelected>;
100
100
  infinite(params?: TParams, crawlOptions?: TCrawlOptions): ResolvedInfiniteOptions<TData, TError, TPageParam>;
101
101
  }
102
+ /**
103
+ * Creates a standalone query factory with pagination and reduce. When `reduce` is
104
+ * present, `shouldFetchNextPage` receives `TSelected` (never undefined) because
105
+ * reduce always runs before the crawl-stop check.
106
+ */
107
+ declare function queryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>>(config: StandardQueryOptions<TError, TData> & {
108
+ queryKey: QueryKey;
109
+ queryFn?: (params: TParams, context: QueryFunctionContext<QueryKey, [unknown] extends [TPageParam] ? never : TPageParam>) => TData | Promise<TData>;
110
+ select?: (data: TData) => TSelected;
111
+ getNextPageParam: GetNextPageParamFunction<TPageParam, TData>;
112
+ initialPageParam: TPageParam;
113
+ getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
114
+ reduce: (accumulator: TSelected | undefined, page: TData) => TSelected;
115
+ shouldFetchNextPage?: (combined: TSelected, crawlOptions: TCrawlOptions) => boolean;
116
+ }): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions>;
102
117
  /**
103
118
  * Creates a standalone query factory from a config object.
104
119
  *
@@ -140,10 +155,15 @@ declare function queryFactory<TChildParams extends TParentParams, TData = unknow
140
155
  * without changing what data is fetched. Parent and child `select` functions
141
156
  * are automatically composed: `child.select(parent.select(data))`.
142
157
  */
143
- declare function queryFactory<TChildParams extends TParentParams, TData = unknown, TError = Error, TParentSelected = TData, TChildSelected = TParentSelected, TParentParams = TChildParams, TPageParam = unknown, TParentCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TChildCrawlOptions extends Record<string, unknown> = TParentCrawlOptions>(parent: QueryFactory<TParentParams, TData, any, TParentSelected, TPageParam, TParentCrawlOptions>, config: Omit<QueryFactoryConfig<TChildParams, TData, TError, TChildSelected, TPageParam, TChildCrawlOptions>, 'queryKey' | 'queryFn' | 'select'> & {
158
+ declare function queryFactory<TChildParams extends TParentParams, TData = unknown, TError = Error, TParentSelected = TData, TChildSelected = TParentSelected, TParentParams = TChildParams, TPageParam = unknown, TParentCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TChildCrawlOptions extends Record<string, unknown> = TParentCrawlOptions>(parent: QueryFactory<TParentParams, TData, any, TParentSelected, TPageParam, TParentCrawlOptions>, config: StandardQueryOptions<TError, TData> & {
144
159
  queryKey?: QueryKey;
145
160
  queryFn?: never;
146
161
  select?: (data: TParentSelected) => TChildSelected;
162
+ getNextPageParam?: GetNextPageParamFunction<TPageParam, TData>;
163
+ initialPageParam?: TPageParam;
164
+ getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
165
+ reduce?: (accumulator: TChildSelected | undefined, page: TData) => TChildSelected;
166
+ shouldFetchNextPage?: (combined: TChildSelected | undefined, crawlOptions: TChildCrawlOptions) => boolean;
147
167
  }): QueryFactory<TChildParams, TData, TError, TChildSelected, TPageParam, TChildCrawlOptions>;
148
168
 
149
169
  export { type QueryFactory, type QueryFactoryConfig, type ResolvedInfiniteOptions, type ResolvedQueryOptions, type StandardQueryOptions, queryFactory };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robohall/react-query-factory",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "A factory abstraction for TanStack Query (React Query) with composable keys, crawling support, and automatic infinite query generation",
5
5
  "author": "Robert Hall",
6
6
  "license": "MIT",