@robohall/react-query-factory 2.2.0 → 3.0.0

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/README.md CHANGED
@@ -417,6 +417,54 @@ The `.infinite()` key includes an `'infinite'` segment to keep it separate from
417
417
 
418
418
  ---
419
419
 
420
+ ## Dependency injection
421
+
422
+ By default, whatever you pass as `params` is appended to the query key. That's exactly what you want for serializable inputs — but some `queryFn` inputs are **not** serializable and must not be in the key: an API client from React context, an auth token, a translator, a per-tenant SDK instance. Putting them in the key leaks them into the cache and devtools, and busts the cache every time they change identity.
423
+
424
+ Declare such inputs as an optional **third argument** to `queryFn` — a `deps` bag. It is supplied at the call site via `.inject(deps)`, is passed to `queryFn` (and `select`), and is **never** added to the query key:
425
+
426
+ ```typescript
427
+ const describeInstances = queryFactory({
428
+ queryKey: ['ec2:DescribeInstances'],
429
+ queryFn: (
430
+ params: DescribeInstancesCommandInput,
431
+ ctx,
432
+ deps: { client: EC2Client }, // ← non-serializable, never keyed
433
+ ) =>
434
+ deps.client.send(
435
+ new DescribeInstancesCommand({ ...params, NextToken: ctx.pageParam }),
436
+ { abortSignal: ctx.signal },
437
+ ),
438
+ });
439
+
440
+ function InstancesTable() {
441
+ const client = useContext(EC2ClientContext); // runtime dependency
442
+ const { data } = useQuery(
443
+ describeInstances({ MaxResults: 20 }).inject({ client }),
444
+ );
445
+ // query key is ['ec2:DescribeInstances', { MaxResults: 20 }] — no client in it
446
+ }
447
+ ```
448
+
449
+ When a factory declares deps, `.inject()` is **required by the type system** — the bare call returns a `PendingInjection` that is a compile error to pass to `useQuery`/`useInfiniteQuery`:
450
+
451
+ ```typescript
452
+ useQuery(describeInstances({ MaxResults: 20 })); // ❌ Type error — call .inject({ client })
453
+ useQuery(describeInstances({ MaxResults: 20 }).inject({ client })); // ✅
454
+ ```
455
+
456
+ A factory that declares **no** deps is unaffected — its calls return options directly and there is no `.inject` to call. Nothing about the common path changes.
457
+
458
+ Key points:
459
+
460
+ - **`deps` never enters the query key** — that's the whole purpose. If a value should be part of cache identity, pass it as `params`, not `deps`.
461
+ - **One shared bag.** `queryFn` and `select` receive the _same_ `deps`; their `deps` types must agree.
462
+ - **Invalidation needs no deps.** The pending object still exposes the real `queryKey`, so `queryClient.invalidateQueries(describeInstances({ MaxResults: 20 }))` works without injecting anything. (`prefetchQuery`, which actually runs the `queryFn`, does require `.inject()`.)
463
+ - **Composition inherits the requirement.** A select-only child of a factory that declares deps inherits the deps requirement automatically.
464
+ - `.inject()` works the same on `.infinite()`: `describeInstances.infinite(params).inject({ client })`.
465
+
466
+ ---
467
+
420
468
  ## Performance
421
469
 
422
470
  TanStack Query's default `staleTime` is `0` — data is considered stale immediately, so a background refetch fires on every mount, window focus, and reconnect. For a single-page query that's one API call; for a crawling factory it's the full crawl repeated. Set `staleTime` in the factory config to match how often the underlying data actually changes:
@@ -458,19 +506,20 @@ Creates a child factory. Two overloads:
458
506
 
459
507
  All fields except `reduce` and `shouldFetchNextPage` are the standard TanStack Query API — the same types and semantics you'd pass to `useQuery` or `useInfiniteQuery`. The factory doesn't reinvent them; it just requires certain combinations to be present in order to activate crawling.
460
508
 
461
- | Field | Type | Notes |
462
- | ----------------------------------- | ------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
463
- | `queryKey` | `QueryKey` | Namespace segments. Params are appended at call time. |
464
- | `queryFn` | `(params: TParams, ctx: QueryFunctionContext) => TData \| Promise<TData> \| AsyncIterable<TData>` | Same as TanStack, with an extra leading `params` argument. Returns an `AsyncIterable` to use iterator-based crawling. |
465
- | `select` | `(data: TData) => TSelected` | Exact TanStack API. Composed automatically on child factories. |
466
- | `getNextPageParam` | `GetNextPageParamFunction<TPageParam, TData>` | Exact TanStack API. Required (with `shouldFetchNextPage`) to activate cursor-based crawling. Required (with `initialPageParam`) for `.infinite()`. |
467
- | `initialPageParam` | `TPageParam` | Exact TanStack API. Drives `TPageParam` inference. Required for `.infinite()` to work at runtime. |
468
- | `getPreviousPageParam` | `GetPreviousPageParamFunction<TPageParam, TData>` | Exact TanStack API. Passed through on `.infinite()`. |
469
- | `shouldFetchNextPage` | `(combined: TSelected \| undefined, crawlOptions: TCrawlOptions) => boolean` | Library addition. **Required to activate crawling.** Called after each page — return `true` to keep fetching, `false` to stop. |
470
- | `reduce` | `(acc: TSelected \| undefined, page: TData) => TSelected` | Library addition. Optional. Folds crawled pages into a single `TSelected` value; when omitted the result is an array of all fetched raw pages (`TData[]`). |
471
- | + all `StandardQueryOptions` fields | | `staleTime`, `gcTime`, `retry`, `enabled`, `refetchOnWindowFocus`, `placeholderData`, `initialData`, `meta`, etc. Function-form callbacks are supported wherever TanStack accepts them. |
472
-
473
- ### `QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions>`
509
+ | Field | Type | Notes |
510
+ | ----------------------------------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
511
+ | `queryKey` | `QueryKey` | Namespace segments. Params are appended at call time. |
512
+ | `queryFn` | `(params: TParams, ctx: QueryFunctionContext, deps: TDeps) => TData \| Promise<TData> \| AsyncIterable<TData>` | Same as TanStack, with an extra leading `params` argument and an optional trailing `deps` argument for non-serializable dependencies (see [Dependency injection](#dependency-injection)). Returns an `AsyncIterable` to use iterator-based crawling. |
513
+ | `select` | `(data: TData, deps: TDeps) => TSelected` | Exact TanStack API, plus the same injected `deps` bag as `queryFn`. Composed automatically on child factories. |
514
+ | `getNextPageParam` | `GetNextPageParamFunction<TPageParam, TData>` | Exact TanStack API. Required (with `shouldFetchNextPage`) to activate cursor-based crawling. Required (with `initialPageParam`) for `.infinite()`. |
515
+ | `initialPageParam` | `TPageParam` | Exact TanStack API. Drives `TPageParam` inference. Required for `.infinite()` to work at runtime. |
516
+ | `getPreviousPageParam` | `GetPreviousPageParamFunction<TPageParam, TData>` | Exact TanStack API. Passed through on `.infinite()`. |
517
+ | `shouldFetchNextPage` | `(combined: TSelected \| undefined, crawlOptions: TCrawlOptions) => boolean` | Library addition. **Required to activate crawling.** Called after each page — return `true` to keep fetching, `false` to stop. |
518
+ | `reduce` | `(acc: TSelected \| undefined, page: TData) => TSelected` | Library addition. Optional. Folds crawled pages into a single `TSelected` value; when omitted the result is an array of all fetched raw pages (`TData[]`). |
519
+ | `deps` (3rd `queryFn` arg) | `TDeps` | Library addition. Inferred from the optional third `queryFn` parameter. A bag of non-serializable dependencies supplied at the call site via `.inject(deps)`; passed to `queryFn`/`select` but never added to the query key. See [Dependency injection](#dependency-injection). |
520
+ | + all `StandardQueryOptions` fields | | `staleTime`, `gcTime`, `retry`, `enabled`, `refetchOnWindowFocus`, `placeholderData`, `initialData`, `meta`, etc. Function-form callbacks are supported wherever TanStack accepts them. |
521
+
522
+ ### `QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, THasReduce, TDeps>`
474
523
 
475
524
  The callable factory returned by `queryFactory()`.
476
525
 
@@ -479,6 +528,8 @@ factory(params: TParams, crawlOptions?: TCrawlOptions): ResolvedQueryOptions //
479
528
  factory.infinite(params, crawlOptions?) : ResolvedInfiniteOptions // → useInfiniteQuery()
480
529
  ```
481
530
 
531
+ When the factory declares dependencies (`TDeps` is non-`void`), both calls instead return a `PendingInjection` and you must call `.inject(deps)` to obtain the usable options — see [Dependency injection](#dependency-injection).
532
+
482
533
  ### `ResolvedQueryOptions`
483
534
 
484
535
  Return type of `factory(params)`. Pass directly to `useQuery()`. Contains an `initialPageParam?: never` field that prevents accidental use with `useInfiniteQuery`.
@@ -507,6 +558,24 @@ import type { FactoryCrawlOptions } from '@robohall/react-query-factory';
507
558
  type CrawlOpts = FactoryCrawlOptions<typeof describeInstances>; // → { minResults?: number }
508
559
  ```
509
560
 
561
+ ### `FactoryDeps<F>`
562
+
563
+ Extracts the injected-dependencies type from a factory — the argument to `.inject()`. Resolves to `void` for factories that declare no dependencies.
564
+
565
+ ```typescript
566
+ import type { FactoryDeps } from '@robohall/react-query-factory';
567
+
568
+ type Deps = FactoryDeps<typeof describeInstances>; // → { client: EC2Client }
569
+ ```
570
+
571
+ ### `PendingInjection<TDeps, TResolved>`
572
+
573
+ Returned by `factory(params)` / `factory.infinite(params)` when the factory declares dependencies. Carries the real `queryKey` (so it can still be passed to `invalidateQueries` and other filter APIs) but its `queryFn` is branded so the object cannot be passed to `useQuery`/`useInfiniteQuery` until `.inject(deps)` supplies the dependencies. See [Dependency injection](#dependency-injection).
574
+
575
+ ### `WithInjection<TDeps, TResolved>`
576
+
577
+ Resolves to `TResolved` when `TDeps` is `void`, or to `PendingInjection<TDeps, TResolved>` otherwise. This is what makes `.inject()` required exactly when — and only when — a factory declares dependencies.
578
+
510
579
  ---
511
580
 
512
581
  ## Running the sandbox
@@ -515,4 +584,4 @@ type CrawlOpts = FactoryCrawlOptions<typeof describeInstances>; // → { minResu
515
584
  npm run sandbox
516
585
  ```
517
586
 
518
- Starts a Vite dev server with interactive demos covering every pattern: basic single-page fetch, async iterator queryFns, crawl-then-render, render-while-crawling, on-demand infinite pagination, client-side search with early stopping, factory composition, and scoped cache invalidation.
587
+ Starts a Vite dev server with interactive demos covering every pattern: basic single-page fetch, async iterator queryFns, crawl-then-render, render-while-crawling, on-demand infinite pagination, client-side search with early stopping, factory composition, dependency injection, and scoped cache invalidation.
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { QueryObserverOptions, QueryKey, QueryFunctionContext, InfiniteData, GetNextPageParamFunction, GetPreviousPageParamFunction } from '@tanstack/react-query';
1
+ import { QueryKey, QueryObserverOptions, QueryFunctionContext, InfiniteData, GetNextPageParamFunction, GetPreviousPageParamFunction } from '@tanstack/react-query';
2
2
 
3
3
  /**
4
4
  * All TanStack Query options that apply to both regular and infinite queries,
@@ -23,14 +23,18 @@ type StandardQueryOptions<TError = Error, TData = unknown> = Omit<QueryObserverO
23
23
  * mirrors TanStack's own API and ensures `TPageParam` is inferred from the
24
24
  * concrete initial value (so `ctx.pageParam` in `queryFn` is typed correctly).
25
25
  */
26
- type QueryFactoryConfig<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>> = StandardQueryOptions<TError, TData> & {
26
+ type QueryFactoryConfig<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TDeps = void> = StandardQueryOptions<TError, TData> & {
27
27
  /** Namespace segments. Params are appended as the final element at call time,
28
28
  * giving a full key of [...namespace, 'infinite'?, params, crawlOptions?]. */
29
29
  queryKey: QueryKey;
30
+ /** The optional third argument is a bag of non-serializable runtime dependencies
31
+ * (an API client, a token, a translator…). It is supplied at the call site via
32
+ * `factory(params).inject(deps)` and is deliberately NEVER part of the queryKey.
33
+ * Declaring it makes `.inject()` required before the options can reach useQuery. */
30
34
  queryFn?: (params: TParams, context: QueryFunctionContext<QueryKey, [
31
35
  unknown
32
- ] extends [TPageParam] ? never : TPageParam>) => TData | Promise<TData>;
33
- select?: (data: TData) => TSelected;
36
+ ] extends [TPageParam] ? never : TPageParam>, deps: TDeps) => TData | Promise<TData>;
37
+ select?: (data: TData, deps: TDeps) => TSelected;
34
38
  /** TanStack v5 generic order: GetNextPageParamFunction<TPageParam, TData> */
35
39
  getNextPageParam?: GetNextPageParamFunction<TPageParam, TData>;
36
40
  /** Drives TPageParam inference so ctx.pageParam in queryFn is typed as TPageParam.
@@ -82,6 +86,33 @@ type ResolvedInfiniteOptions<TData = unknown, TError = Error, TPageParam = unkno
82
86
  /** Required so this type satisfies useInfiniteQuery, which requires initialPageParam. */
83
87
  initialPageParam: TPageParam;
84
88
  };
89
+ declare const INJECTION_REQUIRED: unique symbol;
90
+ /**
91
+ * What `factory(params)` / `factory.infinite(params)` return when the factory's
92
+ * `queryFn`/`select` declare a non-serializable dependency bag (the third `queryFn`
93
+ * argument, `TDeps`).
94
+ *
95
+ * It carries the real `queryKey` — so it can still be handed to
96
+ * `invalidateQueries` and other filter APIs without supplying deps — but its
97
+ * `queryFn` is branded with a type that is NOT assignable to TanStack's
98
+ * `QueryFunction`. That makes it a compile error to pass directly to
99
+ * `useQuery`/`useInfiniteQuery`: the only way to obtain usable options is to call
100
+ * `.inject(deps)`, which returns the real `TResolved`.
101
+ *
102
+ * `deps` is deliberately never part of the query key.
103
+ */
104
+ interface PendingInjection<TDeps, TResolved> {
105
+ queryKey: QueryKey;
106
+ queryFn: {
107
+ readonly [INJECTION_REQUIRED]: 'Call .inject({ ...deps }) before passing this to useQuery/useInfiniteQuery';
108
+ };
109
+ inject(deps: TDeps): TResolved;
110
+ }
111
+ /**
112
+ * Resolves to `TResolved` when the factory declares no dependencies (`TDeps` is
113
+ * `void`), or to a `PendingInjection` that forces `.inject(deps)` when it does.
114
+ */
115
+ type WithInjection<TDeps, TResolved> = [TDeps] extends [void] ? TResolved : PendingInjection<TDeps, TResolved>;
85
116
  /**
86
117
  * A callable factory produced by `queryFactory()`.
87
118
  *
@@ -95,32 +126,38 @@ type ResolvedInfiniteOptions<TData = unknown, TError = Error, TPageParam = unkno
95
126
  * `params` is always optional. Calling with no arguments produces just the
96
127
  * namespace key, which is useful for broad cache invalidation:
97
128
  * `queryClient.invalidateQueries(factory())`
129
+ *
130
+ * When `TDeps` is non-`void` (the `queryFn` declares a third argument), both calls
131
+ * return a `PendingInjection` and the caller must `.inject(deps)` before the
132
+ * options can reach `useQuery`/`useInfiniteQuery`.
98
133
  */
99
- interface QueryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, THasReduce extends boolean = boolean> {
100
- (params?: TParams, crawlOptions?: TCrawlOptions): ResolvedQueryOptions<TData, TError, TSelected>;
101
- infinite(params?: TParams, crawlOptions?: TCrawlOptions): ResolvedInfiniteOptions<TData, TError, TPageParam, InfiniteData<TSelected, TPageParam>>;
134
+ interface QueryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, THasReduce extends boolean = boolean, TDeps = void> {
135
+ (params?: TParams, crawlOptions?: TCrawlOptions): WithInjection<TDeps, ResolvedQueryOptions<TData, TError, TSelected>>;
136
+ infinite(params?: TParams, crawlOptions?: TCrawlOptions): WithInjection<TDeps, ResolvedInfiniteOptions<TData, TError, TPageParam, InfiniteData<TSelected, TPageParam>>>;
102
137
  }
103
138
  /** Extracts the params type from a factory — the first argument of a factory call. */
104
139
  type FactoryParams<F> = F extends QueryFactory<infer TParams, any, any, any, any, any, any> ? TParams : never;
105
140
  /** Extracts the crawl options type from a factory — the second argument of a factory call. */
106
141
  type FactoryCrawlOptions<F> = F extends QueryFactory<any, any, any, any, any, infer TCrawlOptions, any> ? TCrawlOptions : never;
142
+ /** Extracts the injected-dependencies type from a factory — the argument to `.inject()`. */
143
+ type FactoryDeps<F> = F extends QueryFactory<any, any, any, any, any, any, any, infer TDeps> ? TDeps : never;
107
144
  /**
108
145
  * Creates a standalone query factory with pagination and reduce. When `reduce` is
109
146
  * present, `shouldFetchNextPage` receives `TSelected` (never undefined) because
110
147
  * reduce always runs before the crawl-stop check.
111
148
  */
112
- 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> & {
149
+ declare function queryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TDeps = void>(config: StandardQueryOptions<TError, TData> & {
113
150
  queryKey: QueryKey;
114
151
  queryFn?: (params: TParams, context: QueryFunctionContext<QueryKey, [
115
152
  unknown
116
- ] extends [TPageParam] ? never : TPageParam>) => TData | Promise<TData>;
117
- select?: (data: TData) => TSelected;
153
+ ] extends [TPageParam] ? never : TPageParam>, deps: TDeps) => TData | Promise<TData>;
154
+ select?: (data: TData, deps: TDeps) => TSelected;
118
155
  getNextPageParam?: GetNextPageParamFunction<TPageParam, TData>;
119
156
  initialPageParam?: TPageParam;
120
157
  getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
121
158
  reduce: (accumulator: TSelected | undefined, page: TData) => TSelected;
122
159
  shouldFetchNextPage?: (combined: TSelected, crawlOptions: TCrawlOptions) => boolean;
123
- }): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, true>;
160
+ }): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, true, TDeps>;
124
161
  /**
125
162
  * Creates a standalone query factory from a config object.
126
163
  *
@@ -131,24 +168,24 @@ declare function queryFactory<TParams = void, TData = unknown, TError = Error, T
131
168
  * });
132
169
  * // useQuery(usersFactory({ page: 1 }))
133
170
  */
134
- declare function queryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>>(config: QueryFactoryConfig<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions>): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, false>;
171
+ declare function queryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TDeps = void>(config: QueryFactoryConfig<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, TDeps>): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, false, TDeps>;
135
172
  /**
136
173
  * Creates a child factory whose queryFn returns an AsyncIterable (e.g. an AWS SDK v3
137
174
  * paginator). Inherits the parent's key namespace. Use this overload when switching
138
175
  * to a paginator-based fetch while keeping the same result shape and crawl options.
139
176
  */
140
- declare function queryFactory<TChildParams extends TParentParams, TData = unknown, TError = Error, TParentSelected = TData, TChildSelected = TParentSelected, TParentParams = TChildParams, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>>(parent: QueryFactory<TParentParams, TData, any, TParentSelected, TPageParam, any, any>, config: StandardQueryOptions<TError, TData> & {
177
+ declare function queryFactory<TChildParams extends TParentParams, TData = unknown, TError = Error, TParentSelected = TData, TChildSelected = TParentSelected, TParentParams = TChildParams, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TDeps = void>(parent: QueryFactory<TParentParams, TData, any, TParentSelected, TPageParam, any, any, any>, config: StandardQueryOptions<TError, TData> & {
141
178
  queryKey?: QueryKey;
142
179
  queryFn: (params: TChildParams, context: QueryFunctionContext<QueryKey, [
143
180
  unknown
144
- ] extends [TPageParam] ? never : TPageParam>) => AsyncIterable<TData>;
145
- select?: (data: TData) => TChildSelected;
181
+ ] extends [TPageParam] ? never : TPageParam>, deps: TDeps) => AsyncIterable<TData>;
182
+ select?: (data: TData, deps: TDeps) => TChildSelected;
146
183
  reduce?: (accumulator: TChildSelected | undefined, page: TData) => TChildSelected;
147
184
  shouldFetchNextPage?: (combined: TChildSelected | undefined, crawlOptions: TCrawlOptions) => boolean;
148
185
  getNextPageParam?: GetNextPageParamFunction<TPageParam, TData>;
149
186
  getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
150
187
  initialPageParam?: TPageParam;
151
- }): QueryFactory<TChildParams, TData, TError, TChildSelected, TPageParam, TCrawlOptions, boolean>;
188
+ }): QueryFactory<TChildParams, TData, TError, TChildSelected, TPageParam, TCrawlOptions, boolean, TDeps>;
152
189
  /**
153
190
  * Creates a child factory that inherits the query key and standard options from
154
191
  * `parent` and introduces a new `queryFn`. The child's query key is appended to
@@ -156,10 +193,10 @@ declare function queryFactory<TChildParams extends TParentParams, TData = unknow
156
193
  *
157
194
  * Use this overload when the child fetches different data than the parent.
158
195
  */
159
- declare function queryFactory<TChildParams extends TParentParams, TData = unknown, TError = Error, TChildSelected = TData, TParentParams = TChildParams, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>>(parent: QueryFactory<TParentParams, any, any, any, any, any, any>, config: Omit<QueryFactoryConfig<TChildParams, TData, TError, TChildSelected, TPageParam, TCrawlOptions>, 'queryKey' | 'queryFn'> & {
196
+ declare function queryFactory<TChildParams extends TParentParams, TData = unknown, TError = Error, TChildSelected = TData, TParentParams = TChildParams, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TDeps = void>(parent: QueryFactory<TParentParams, any, any, any, any, any, any, any>, config: Omit<QueryFactoryConfig<TChildParams, TData, TError, TChildSelected, TPageParam, TCrawlOptions, TDeps>, 'queryKey' | 'queryFn'> & {
160
197
  queryKey?: QueryKey;
161
- queryFn: NonNullable<QueryFactoryConfig<TChildParams, TData, TError, TChildSelected, TPageParam>['queryFn']>;
162
- }): QueryFactory<TChildParams, TData, TError, TChildSelected, TPageParam, TCrawlOptions, boolean>;
198
+ queryFn: NonNullable<QueryFactoryConfig<TChildParams, TData, TError, TChildSelected, TPageParam, TCrawlOptions, TDeps>['queryFn']>;
199
+ }): QueryFactory<TChildParams, TData, TError, TChildSelected, TPageParam, TCrawlOptions, boolean, TDeps>;
163
200
  /**
164
201
  * Creates a child factory that reuses the parent's `queryFn` and pagination
165
202
  * config. Useful for adding a `select` transform, narrowing params, or
@@ -167,49 +204,49 @@ declare function queryFactory<TChildParams extends TParentParams, TData = unknow
167
204
  * without changing what data is fetched. Parent and child `select` functions
168
205
  * are automatically composed: `child.select(parent.select(data))`.
169
206
  */
170
- 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, TParentHasReduce extends boolean = boolean>(parent: QueryFactory<TParentParams, TData, any, TParentSelected, TPageParam, TParentCrawlOptions, TParentHasReduce>, config: StandardQueryOptions<TError, TData> & {
207
+ 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, TParentHasReduce extends boolean = boolean, TParentDeps = void>(parent: QueryFactory<TParentParams, TData, any, TParentSelected, TPageParam, TParentCrawlOptions, TParentHasReduce, TParentDeps>, config: StandardQueryOptions<TError, TData> & {
171
208
  queryKey?: QueryKey;
172
209
  queryFn?: never;
173
- select?: (data: TParentSelected) => TChildSelected;
210
+ select?: (data: TParentSelected, deps: TParentDeps) => TChildSelected;
174
211
  getNextPageParam?: GetNextPageParamFunction<TPageParam, TData>;
175
212
  initialPageParam?: TPageParam;
176
213
  getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
177
214
  reduce?: (accumulator: TChildSelected | undefined, page: TData) => TChildSelected;
178
215
  shouldFetchNextPage?: (combined: TParentHasReduce extends true ? TChildSelected : TChildSelected | undefined, crawlOptions: TChildCrawlOptions) => boolean;
179
- }): QueryFactory<TChildParams, TData, TError, TChildSelected, TPageParam, TChildCrawlOptions, TParentHasReduce>;
216
+ }): QueryFactory<TChildParams, TData, TError, TChildSelected, TPageParam, TChildCrawlOptions, TParentHasReduce, TParentDeps>;
180
217
  /**
181
218
  * Creates a standalone factory whose queryFn returns an AsyncIterable (e.g. an AWS SDK v3
182
219
  * paginator). The library drives the crawl with `for await...of`; `getNextPageParam` and
183
220
  * `initialPageParam` are not required for `useQuery` mode. When `reduce` is present,
184
221
  * `shouldFetchNextPage` receives `TSelected` (never undefined).
185
222
  */
186
- 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> & {
223
+ declare function queryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TDeps = void>(config: StandardQueryOptions<TError, TData> & {
187
224
  queryKey: QueryKey;
188
225
  queryFn: (params: TParams, context: QueryFunctionContext<QueryKey, [
189
226
  unknown
190
- ] extends [TPageParam] ? never : TPageParam>) => AsyncIterable<TData>;
191
- select?: (data: TData) => TSelected;
227
+ ] extends [TPageParam] ? never : TPageParam>, deps: TDeps) => AsyncIterable<TData>;
228
+ select?: (data: TData, deps: TDeps) => TSelected;
192
229
  getNextPageParam?: GetNextPageParamFunction<TPageParam, TData>;
193
230
  initialPageParam?: TPageParam;
194
231
  getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
195
232
  reduce: (accumulator: TSelected | undefined, page: TData) => TSelected;
196
233
  shouldFetchNextPage?: (combined: TSelected, crawlOptions: TCrawlOptions) => boolean;
197
- }): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, true>;
234
+ }): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, true, TDeps>;
198
235
  /**
199
236
  * Creates a standalone factory whose queryFn returns an AsyncIterable, without a `reduce`
200
237
  * function. Result is `TData[]` (one element per yielded page).
201
238
  */
202
- 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> & {
239
+ declare function queryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TDeps = void>(config: StandardQueryOptions<TError, TData> & {
203
240
  queryKey: QueryKey;
204
241
  queryFn: (params: TParams, context: QueryFunctionContext<QueryKey, [
205
242
  unknown
206
- ] extends [TPageParam] ? never : TPageParam>) => AsyncIterable<TData>;
207
- select?: (data: TData) => TSelected;
243
+ ] extends [TPageParam] ? never : TPageParam>, deps: TDeps) => AsyncIterable<TData>;
244
+ select?: (data: TData, deps: TDeps) => TSelected;
208
245
  getNextPageParam?: GetNextPageParamFunction<TPageParam, TData>;
209
246
  initialPageParam?: TPageParam;
210
247
  getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
211
248
  reduce?: never;
212
249
  shouldFetchNextPage: (combined: TSelected | undefined, crawlOptions: TCrawlOptions) => boolean;
213
- }): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, false>;
250
+ }): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, false, TDeps>;
214
251
 
215
- export { type FactoryCrawlOptions, type FactoryParams, type QueryFactory, type QueryFactoryConfig, type ResolvedInfiniteOptions, type ResolvedQueryOptions, type StandardQueryOptions, queryFactory };
252
+ export { type FactoryCrawlOptions, type FactoryDeps, type FactoryParams, type PendingInjection, type QueryFactory, type QueryFactoryConfig, type ResolvedInfiniteOptions, type ResolvedQueryOptions, type StandardQueryOptions, type WithInjection, queryFactory };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { QueryObserverOptions, QueryKey, QueryFunctionContext, InfiniteData, GetNextPageParamFunction, GetPreviousPageParamFunction } from '@tanstack/react-query';
1
+ import { QueryKey, QueryObserverOptions, QueryFunctionContext, InfiniteData, GetNextPageParamFunction, GetPreviousPageParamFunction } from '@tanstack/react-query';
2
2
 
3
3
  /**
4
4
  * All TanStack Query options that apply to both regular and infinite queries,
@@ -23,14 +23,18 @@ type StandardQueryOptions<TError = Error, TData = unknown> = Omit<QueryObserverO
23
23
  * mirrors TanStack's own API and ensures `TPageParam` is inferred from the
24
24
  * concrete initial value (so `ctx.pageParam` in `queryFn` is typed correctly).
25
25
  */
26
- type QueryFactoryConfig<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>> = StandardQueryOptions<TError, TData> & {
26
+ type QueryFactoryConfig<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TDeps = void> = StandardQueryOptions<TError, TData> & {
27
27
  /** Namespace segments. Params are appended as the final element at call time,
28
28
  * giving a full key of [...namespace, 'infinite'?, params, crawlOptions?]. */
29
29
  queryKey: QueryKey;
30
+ /** The optional third argument is a bag of non-serializable runtime dependencies
31
+ * (an API client, a token, a translator…). It is supplied at the call site via
32
+ * `factory(params).inject(deps)` and is deliberately NEVER part of the queryKey.
33
+ * Declaring it makes `.inject()` required before the options can reach useQuery. */
30
34
  queryFn?: (params: TParams, context: QueryFunctionContext<QueryKey, [
31
35
  unknown
32
- ] extends [TPageParam] ? never : TPageParam>) => TData | Promise<TData>;
33
- select?: (data: TData) => TSelected;
36
+ ] extends [TPageParam] ? never : TPageParam>, deps: TDeps) => TData | Promise<TData>;
37
+ select?: (data: TData, deps: TDeps) => TSelected;
34
38
  /** TanStack v5 generic order: GetNextPageParamFunction<TPageParam, TData> */
35
39
  getNextPageParam?: GetNextPageParamFunction<TPageParam, TData>;
36
40
  /** Drives TPageParam inference so ctx.pageParam in queryFn is typed as TPageParam.
@@ -82,6 +86,33 @@ type ResolvedInfiniteOptions<TData = unknown, TError = Error, TPageParam = unkno
82
86
  /** Required so this type satisfies useInfiniteQuery, which requires initialPageParam. */
83
87
  initialPageParam: TPageParam;
84
88
  };
89
+ declare const INJECTION_REQUIRED: unique symbol;
90
+ /**
91
+ * What `factory(params)` / `factory.infinite(params)` return when the factory's
92
+ * `queryFn`/`select` declare a non-serializable dependency bag (the third `queryFn`
93
+ * argument, `TDeps`).
94
+ *
95
+ * It carries the real `queryKey` — so it can still be handed to
96
+ * `invalidateQueries` and other filter APIs without supplying deps — but its
97
+ * `queryFn` is branded with a type that is NOT assignable to TanStack's
98
+ * `QueryFunction`. That makes it a compile error to pass directly to
99
+ * `useQuery`/`useInfiniteQuery`: the only way to obtain usable options is to call
100
+ * `.inject(deps)`, which returns the real `TResolved`.
101
+ *
102
+ * `deps` is deliberately never part of the query key.
103
+ */
104
+ interface PendingInjection<TDeps, TResolved> {
105
+ queryKey: QueryKey;
106
+ queryFn: {
107
+ readonly [INJECTION_REQUIRED]: 'Call .inject({ ...deps }) before passing this to useQuery/useInfiniteQuery';
108
+ };
109
+ inject(deps: TDeps): TResolved;
110
+ }
111
+ /**
112
+ * Resolves to `TResolved` when the factory declares no dependencies (`TDeps` is
113
+ * `void`), or to a `PendingInjection` that forces `.inject(deps)` when it does.
114
+ */
115
+ type WithInjection<TDeps, TResolved> = [TDeps] extends [void] ? TResolved : PendingInjection<TDeps, TResolved>;
85
116
  /**
86
117
  * A callable factory produced by `queryFactory()`.
87
118
  *
@@ -95,32 +126,38 @@ type ResolvedInfiniteOptions<TData = unknown, TError = Error, TPageParam = unkno
95
126
  * `params` is always optional. Calling with no arguments produces just the
96
127
  * namespace key, which is useful for broad cache invalidation:
97
128
  * `queryClient.invalidateQueries(factory())`
129
+ *
130
+ * When `TDeps` is non-`void` (the `queryFn` declares a third argument), both calls
131
+ * return a `PendingInjection` and the caller must `.inject(deps)` before the
132
+ * options can reach `useQuery`/`useInfiniteQuery`.
98
133
  */
99
- interface QueryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, THasReduce extends boolean = boolean> {
100
- (params?: TParams, crawlOptions?: TCrawlOptions): ResolvedQueryOptions<TData, TError, TSelected>;
101
- infinite(params?: TParams, crawlOptions?: TCrawlOptions): ResolvedInfiniteOptions<TData, TError, TPageParam, InfiniteData<TSelected, TPageParam>>;
134
+ interface QueryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, THasReduce extends boolean = boolean, TDeps = void> {
135
+ (params?: TParams, crawlOptions?: TCrawlOptions): WithInjection<TDeps, ResolvedQueryOptions<TData, TError, TSelected>>;
136
+ infinite(params?: TParams, crawlOptions?: TCrawlOptions): WithInjection<TDeps, ResolvedInfiniteOptions<TData, TError, TPageParam, InfiniteData<TSelected, TPageParam>>>;
102
137
  }
103
138
  /** Extracts the params type from a factory — the first argument of a factory call. */
104
139
  type FactoryParams<F> = F extends QueryFactory<infer TParams, any, any, any, any, any, any> ? TParams : never;
105
140
  /** Extracts the crawl options type from a factory — the second argument of a factory call. */
106
141
  type FactoryCrawlOptions<F> = F extends QueryFactory<any, any, any, any, any, infer TCrawlOptions, any> ? TCrawlOptions : never;
142
+ /** Extracts the injected-dependencies type from a factory — the argument to `.inject()`. */
143
+ type FactoryDeps<F> = F extends QueryFactory<any, any, any, any, any, any, any, infer TDeps> ? TDeps : never;
107
144
  /**
108
145
  * Creates a standalone query factory with pagination and reduce. When `reduce` is
109
146
  * present, `shouldFetchNextPage` receives `TSelected` (never undefined) because
110
147
  * reduce always runs before the crawl-stop check.
111
148
  */
112
- 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> & {
149
+ declare function queryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TDeps = void>(config: StandardQueryOptions<TError, TData> & {
113
150
  queryKey: QueryKey;
114
151
  queryFn?: (params: TParams, context: QueryFunctionContext<QueryKey, [
115
152
  unknown
116
- ] extends [TPageParam] ? never : TPageParam>) => TData | Promise<TData>;
117
- select?: (data: TData) => TSelected;
153
+ ] extends [TPageParam] ? never : TPageParam>, deps: TDeps) => TData | Promise<TData>;
154
+ select?: (data: TData, deps: TDeps) => TSelected;
118
155
  getNextPageParam?: GetNextPageParamFunction<TPageParam, TData>;
119
156
  initialPageParam?: TPageParam;
120
157
  getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
121
158
  reduce: (accumulator: TSelected | undefined, page: TData) => TSelected;
122
159
  shouldFetchNextPage?: (combined: TSelected, crawlOptions: TCrawlOptions) => boolean;
123
- }): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, true>;
160
+ }): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, true, TDeps>;
124
161
  /**
125
162
  * Creates a standalone query factory from a config object.
126
163
  *
@@ -131,24 +168,24 @@ declare function queryFactory<TParams = void, TData = unknown, TError = Error, T
131
168
  * });
132
169
  * // useQuery(usersFactory({ page: 1 }))
133
170
  */
134
- declare function queryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>>(config: QueryFactoryConfig<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions>): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, false>;
171
+ declare function queryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TDeps = void>(config: QueryFactoryConfig<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, TDeps>): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, false, TDeps>;
135
172
  /**
136
173
  * Creates a child factory whose queryFn returns an AsyncIterable (e.g. an AWS SDK v3
137
174
  * paginator). Inherits the parent's key namespace. Use this overload when switching
138
175
  * to a paginator-based fetch while keeping the same result shape and crawl options.
139
176
  */
140
- declare function queryFactory<TChildParams extends TParentParams, TData = unknown, TError = Error, TParentSelected = TData, TChildSelected = TParentSelected, TParentParams = TChildParams, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>>(parent: QueryFactory<TParentParams, TData, any, TParentSelected, TPageParam, any, any>, config: StandardQueryOptions<TError, TData> & {
177
+ declare function queryFactory<TChildParams extends TParentParams, TData = unknown, TError = Error, TParentSelected = TData, TChildSelected = TParentSelected, TParentParams = TChildParams, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TDeps = void>(parent: QueryFactory<TParentParams, TData, any, TParentSelected, TPageParam, any, any, any>, config: StandardQueryOptions<TError, TData> & {
141
178
  queryKey?: QueryKey;
142
179
  queryFn: (params: TChildParams, context: QueryFunctionContext<QueryKey, [
143
180
  unknown
144
- ] extends [TPageParam] ? never : TPageParam>) => AsyncIterable<TData>;
145
- select?: (data: TData) => TChildSelected;
181
+ ] extends [TPageParam] ? never : TPageParam>, deps: TDeps) => AsyncIterable<TData>;
182
+ select?: (data: TData, deps: TDeps) => TChildSelected;
146
183
  reduce?: (accumulator: TChildSelected | undefined, page: TData) => TChildSelected;
147
184
  shouldFetchNextPage?: (combined: TChildSelected | undefined, crawlOptions: TCrawlOptions) => boolean;
148
185
  getNextPageParam?: GetNextPageParamFunction<TPageParam, TData>;
149
186
  getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
150
187
  initialPageParam?: TPageParam;
151
- }): QueryFactory<TChildParams, TData, TError, TChildSelected, TPageParam, TCrawlOptions, boolean>;
188
+ }): QueryFactory<TChildParams, TData, TError, TChildSelected, TPageParam, TCrawlOptions, boolean, TDeps>;
152
189
  /**
153
190
  * Creates a child factory that inherits the query key and standard options from
154
191
  * `parent` and introduces a new `queryFn`. The child's query key is appended to
@@ -156,10 +193,10 @@ declare function queryFactory<TChildParams extends TParentParams, TData = unknow
156
193
  *
157
194
  * Use this overload when the child fetches different data than the parent.
158
195
  */
159
- declare function queryFactory<TChildParams extends TParentParams, TData = unknown, TError = Error, TChildSelected = TData, TParentParams = TChildParams, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>>(parent: QueryFactory<TParentParams, any, any, any, any, any, any>, config: Omit<QueryFactoryConfig<TChildParams, TData, TError, TChildSelected, TPageParam, TCrawlOptions>, 'queryKey' | 'queryFn'> & {
196
+ declare function queryFactory<TChildParams extends TParentParams, TData = unknown, TError = Error, TChildSelected = TData, TParentParams = TChildParams, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TDeps = void>(parent: QueryFactory<TParentParams, any, any, any, any, any, any, any>, config: Omit<QueryFactoryConfig<TChildParams, TData, TError, TChildSelected, TPageParam, TCrawlOptions, TDeps>, 'queryKey' | 'queryFn'> & {
160
197
  queryKey?: QueryKey;
161
- queryFn: NonNullable<QueryFactoryConfig<TChildParams, TData, TError, TChildSelected, TPageParam>['queryFn']>;
162
- }): QueryFactory<TChildParams, TData, TError, TChildSelected, TPageParam, TCrawlOptions, boolean>;
198
+ queryFn: NonNullable<QueryFactoryConfig<TChildParams, TData, TError, TChildSelected, TPageParam, TCrawlOptions, TDeps>['queryFn']>;
199
+ }): QueryFactory<TChildParams, TData, TError, TChildSelected, TPageParam, TCrawlOptions, boolean, TDeps>;
163
200
  /**
164
201
  * Creates a child factory that reuses the parent's `queryFn` and pagination
165
202
  * config. Useful for adding a `select` transform, narrowing params, or
@@ -167,49 +204,49 @@ declare function queryFactory<TChildParams extends TParentParams, TData = unknow
167
204
  * without changing what data is fetched. Parent and child `select` functions
168
205
  * are automatically composed: `child.select(parent.select(data))`.
169
206
  */
170
- 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, TParentHasReduce extends boolean = boolean>(parent: QueryFactory<TParentParams, TData, any, TParentSelected, TPageParam, TParentCrawlOptions, TParentHasReduce>, config: StandardQueryOptions<TError, TData> & {
207
+ 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, TParentHasReduce extends boolean = boolean, TParentDeps = void>(parent: QueryFactory<TParentParams, TData, any, TParentSelected, TPageParam, TParentCrawlOptions, TParentHasReduce, TParentDeps>, config: StandardQueryOptions<TError, TData> & {
171
208
  queryKey?: QueryKey;
172
209
  queryFn?: never;
173
- select?: (data: TParentSelected) => TChildSelected;
210
+ select?: (data: TParentSelected, deps: TParentDeps) => TChildSelected;
174
211
  getNextPageParam?: GetNextPageParamFunction<TPageParam, TData>;
175
212
  initialPageParam?: TPageParam;
176
213
  getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
177
214
  reduce?: (accumulator: TChildSelected | undefined, page: TData) => TChildSelected;
178
215
  shouldFetchNextPage?: (combined: TParentHasReduce extends true ? TChildSelected : TChildSelected | undefined, crawlOptions: TChildCrawlOptions) => boolean;
179
- }): QueryFactory<TChildParams, TData, TError, TChildSelected, TPageParam, TChildCrawlOptions, TParentHasReduce>;
216
+ }): QueryFactory<TChildParams, TData, TError, TChildSelected, TPageParam, TChildCrawlOptions, TParentHasReduce, TParentDeps>;
180
217
  /**
181
218
  * Creates a standalone factory whose queryFn returns an AsyncIterable (e.g. an AWS SDK v3
182
219
  * paginator). The library drives the crawl with `for await...of`; `getNextPageParam` and
183
220
  * `initialPageParam` are not required for `useQuery` mode. When `reduce` is present,
184
221
  * `shouldFetchNextPage` receives `TSelected` (never undefined).
185
222
  */
186
- 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> & {
223
+ declare function queryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TDeps = void>(config: StandardQueryOptions<TError, TData> & {
187
224
  queryKey: QueryKey;
188
225
  queryFn: (params: TParams, context: QueryFunctionContext<QueryKey, [
189
226
  unknown
190
- ] extends [TPageParam] ? never : TPageParam>) => AsyncIterable<TData>;
191
- select?: (data: TData) => TSelected;
227
+ ] extends [TPageParam] ? never : TPageParam>, deps: TDeps) => AsyncIterable<TData>;
228
+ select?: (data: TData, deps: TDeps) => TSelected;
192
229
  getNextPageParam?: GetNextPageParamFunction<TPageParam, TData>;
193
230
  initialPageParam?: TPageParam;
194
231
  getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
195
232
  reduce: (accumulator: TSelected | undefined, page: TData) => TSelected;
196
233
  shouldFetchNextPage?: (combined: TSelected, crawlOptions: TCrawlOptions) => boolean;
197
- }): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, true>;
234
+ }): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, true, TDeps>;
198
235
  /**
199
236
  * Creates a standalone factory whose queryFn returns an AsyncIterable, without a `reduce`
200
237
  * function. Result is `TData[]` (one element per yielded page).
201
238
  */
202
- 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> & {
239
+ declare function queryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, TDeps = void>(config: StandardQueryOptions<TError, TData> & {
203
240
  queryKey: QueryKey;
204
241
  queryFn: (params: TParams, context: QueryFunctionContext<QueryKey, [
205
242
  unknown
206
- ] extends [TPageParam] ? never : TPageParam>) => AsyncIterable<TData>;
207
- select?: (data: TData) => TSelected;
243
+ ] extends [TPageParam] ? never : TPageParam>, deps: TDeps) => AsyncIterable<TData>;
244
+ select?: (data: TData, deps: TDeps) => TSelected;
208
245
  getNextPageParam?: GetNextPageParamFunction<TPageParam, TData>;
209
246
  initialPageParam?: TPageParam;
210
247
  getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
211
248
  reduce?: never;
212
249
  shouldFetchNextPage: (combined: TSelected | undefined, crawlOptions: TCrawlOptions) => boolean;
213
- }): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, false>;
250
+ }): QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions, false, TDeps>;
214
251
 
215
- export { type FactoryCrawlOptions, type FactoryParams, type QueryFactory, type QueryFactoryConfig, type ResolvedInfiniteOptions, type ResolvedQueryOptions, type StandardQueryOptions, queryFactory };
252
+ export { type FactoryCrawlOptions, type FactoryDeps, type FactoryParams, type PendingInjection, type QueryFactory, type QueryFactoryConfig, type ResolvedInfiniteOptions, type ResolvedQueryOptions, type StandardQueryOptions, type WithInjection, queryFactory };
package/dist/index.js CHANGED
@@ -31,6 +31,9 @@ var noNextPage = () => void 0;
31
31
  function isAsyncIterable(value) {
32
32
  return value != null && typeof value[Symbol.asyncIterator] === "function";
33
33
  }
34
+ function invokeQueryFn(queryFn, params, ctx, deps) {
35
+ return deps === void 0 ? queryFn(params, ctx) : queryFn(params, ctx, deps);
36
+ }
34
37
  function resolveKey(namespace, params, crawlOptions) {
35
38
  const withParams = params === void 0 ? namespace : [...namespace, params];
36
39
  if (!crawlOptions) return withParams;
@@ -55,22 +58,22 @@ function buildChildKey(parentKey, ownSegments, params, crawlOptions, infinite) {
55
58
  const withInfinite = infinite ? [...withOwn, "infinite"] : withOwn;
56
59
  return defined ? [...withInfinite, defined] : withInfinite;
57
60
  }
58
- function wrapGetNextPageParam(getNextPageParam, shouldFetchNextPage, crawlOptions, select) {
61
+ function wrapGetNextPageParam(getNextPageParam, shouldFetchNextPage, crawlOptions, select, deps) {
59
62
  return (lastPage, allPages, lastPageParam, allPageParams) => {
60
- const combined = select ? select(lastPage) : lastPage;
63
+ const combined = select ? select(lastPage, deps) : lastPage;
61
64
  if (!shouldFetchNextPage(combined, crawlOptions)) return void 0;
62
65
  return getNextPageParam(lastPage, allPages, lastPageParam, allPageParams);
63
66
  };
64
67
  }
65
68
  function buildCrawlingQueryFn(queryFn, getNextPageParam, initialPageParam, shouldFetchNextPage, reduce) {
66
- return async (params, crawlOptions, context) => {
69
+ return async (params, crawlOptions, deps, context) => {
67
70
  var _a, _b, _c;
68
71
  if ((_a = context.signal) == null ? void 0 : _a.aborted) {
69
72
  if (reduce) throw new DOMException("Aborted", "AbortError");
70
73
  return [];
71
74
  }
72
75
  const ctx = { ...context, pageParam: initialPageParam };
73
- const initialResult = queryFn(params, ctx);
76
+ const initialResult = invokeQueryFn(queryFn, params, ctx, deps);
74
77
  if (isAsyncIterable(initialResult)) {
75
78
  const pages2 = [];
76
79
  let acc2 = void 0;
@@ -102,7 +105,12 @@ function buildCrawlingQueryFn(queryFn, getNextPageParam, initialPageParam, shoul
102
105
  if (nextParam == null) break;
103
106
  currentParam = nextParam;
104
107
  ctx.pageParam = currentParam;
105
- page = await queryFn(params, ctx);
108
+ page = await invokeQueryFn(
109
+ queryFn,
110
+ params,
111
+ ctx,
112
+ deps
113
+ );
106
114
  }
107
115
  if (reduce) {
108
116
  if (acc === void 0) throw new DOMException("Aborted", "AbortError");
@@ -111,13 +119,28 @@ function buildCrawlingQueryFn(queryFn, getNextPageParam, initialPageParam, shoul
111
119
  return pages;
112
120
  };
113
121
  }
122
+ function buildAutoConsumeQueryFn(queryFn, reduce) {
123
+ return async (params, deps, context) => {
124
+ var _a;
125
+ const result = await invokeQueryFn(queryFn, params, context, deps);
126
+ if (!isAsyncIterable(result)) return result;
127
+ const pages = [];
128
+ let acc = void 0;
129
+ for await (const page of result) {
130
+ if ((_a = context.signal) == null ? void 0 : _a.aborted) break;
131
+ pages.push(page);
132
+ if (reduce) acc = reduce(acc, page);
133
+ }
134
+ return reduce ? acc !== void 0 ? acc : pages : pages;
135
+ };
136
+ }
114
137
  function buildInfiniteCrawlingQueryFn(queryFn, getNextPageParam, shouldFetchNextPage, reduce) {
115
- return async (params, crawlOptions, context) => {
138
+ return async (params, crawlOptions, deps, context) => {
116
139
  var _a, _b, _c;
117
140
  if ((_a = context.signal) == null ? void 0 : _a.aborted)
118
141
  throw new DOMException("Aborted", "AbortError");
119
142
  const ctx = { ...context, pageParam: context.pageParam };
120
- const initialResult = queryFn(params, ctx);
143
+ const initialResult = invokeQueryFn(queryFn, params, ctx, deps);
121
144
  if (isAsyncIterable(initialResult)) {
122
145
  const pages2 = [];
123
146
  const startParam = context.pageParam;
@@ -154,7 +177,12 @@ function buildInfiniteCrawlingQueryFn(queryFn, getNextPageParam, shouldFetchNext
154
177
  if (!shouldFetchNextPage(acc, crawlOptions)) break;
155
178
  currentParam = nextParam;
156
179
  ctx.pageParam = currentParam;
157
- page = await queryFn(params, ctx);
180
+ page = await invokeQueryFn(
181
+ queryFn,
182
+ params,
183
+ ctx,
184
+ deps
185
+ );
158
186
  }
159
187
  if (acc === void 0) throw new DOMException("Aborted", "AbortError");
160
188
  return { data: acc, nextPageParam: nextBatchParam };
@@ -184,62 +212,76 @@ function buildFactory(cfg) {
184
212
  shouldFetchNextPage,
185
213
  reduce
186
214
  ) : void 0;
215
+ const autoConsumeFn = !hasCrawling && rawQueryFn !== void 0 ? buildAutoConsumeQueryFn(rawQueryFn, reduce) : void 0;
187
216
  const infiniteCrawlingFn = hasInfiniteCrawling ? buildInfiniteCrawlingQueryFn(
188
217
  rawQueryFn,
189
218
  getNextPageParam,
190
219
  shouldFetchNextPage,
191
220
  reduce
192
221
  ) : void 0;
193
- const envelopeSelect = infiniteCrawlingFn ? (data) => ({
194
- ...data,
195
- pages: data.pages.map((e) => select ? select(e.data) : e.data)
196
- }) : void 0;
197
- const infiniteSelect = !infiniteCrawlingFn && select ? (data) => ({
198
- ...data,
199
- pages: data.pages.map(select)
200
- }) : void 0;
222
+ const bindSelect = (deps) => select === void 0 ? void 0 : deps === void 0 ? select : (data) => select(data, deps);
201
223
  const factory = function(params, crawlOptions = {}) {
202
224
  const queryKey = parentKey !== void 0 ? buildChildKey(parentKey, ownSegments, params, crawlOptions) : resolveKey(namespace, params, crawlOptions);
203
- const resolvedQueryFn = crawlingFn ? (ctx) => crawlingFn(params, crawlOptions, ctx) : rawQueryFn ? (ctx) => rawQueryFn(params, ctx) : void 0;
204
- return {
205
- ...standardOptions,
206
- queryKey,
207
- ...resolvedQueryFn !== void 0 && { queryFn: resolvedQueryFn },
208
- ...select !== void 0 && { select },
209
- [FACTORY_CONFIG]: cfg
225
+ const make = (deps) => {
226
+ const resolvedQueryFn = crawlingFn ? (ctx) => crawlingFn(params, crawlOptions, deps, ctx) : autoConsumeFn ? (ctx) => autoConsumeFn(params, deps, ctx) : void 0;
227
+ const boundSelect = bindSelect(deps);
228
+ return {
229
+ ...standardOptions,
230
+ queryKey,
231
+ ...resolvedQueryFn !== void 0 && { queryFn: resolvedQueryFn },
232
+ ...boundSelect !== void 0 && { select: boundSelect },
233
+ inject: (injected) => make(injected),
234
+ [FACTORY_CONFIG]: cfg
235
+ };
210
236
  };
237
+ return make(void 0);
211
238
  };
212
239
  factory.infinite = function(params, crawlOptions = {}) {
213
240
  const queryKey = parentKey !== void 0 ? buildChildKey(parentKey, ownSegments, params, crawlOptions, true) : resolveKey(infiniteNamespace, params, crawlOptions);
214
- if (infiniteCrawlingFn) {
241
+ const make = (deps) => {
242
+ if (infiniteCrawlingFn) {
243
+ return {
244
+ ...standardOptions,
245
+ queryKey,
246
+ queryFn: (ctx) => infiniteCrawlingFn(params, crawlOptions, deps, ctx),
247
+ getNextPageParam: getEnvelopeNextPageParam,
248
+ initialPageParam,
249
+ select: (data) => ({
250
+ ...data,
251
+ pages: data.pages.map(
252
+ (e) => select ? select(e.data, deps) : e.data
253
+ )
254
+ }),
255
+ ...getPreviousPageParam !== void 0 && { getPreviousPageParam },
256
+ inject: (injected) => make(injected),
257
+ [FACTORY_CONFIG]: cfg
258
+ };
259
+ }
260
+ const boundQueryFn = rawQueryFn ? (ctx) => invokeQueryFn(rawQueryFn, params, ctx, deps) : void 0;
261
+ const infiniteSelect = select ? (data) => ({
262
+ ...data,
263
+ pages: data.pages.map((p) => select(p, deps))
264
+ }) : void 0;
265
+ const infiniteGetNextPageParam = getNextPageParam && shouldFetchNextPage ? wrapGetNextPageParam(
266
+ getNextPageParam,
267
+ shouldFetchNextPage,
268
+ crawlOptions,
269
+ select,
270
+ deps
271
+ ) : getNextPageParam != null ? getNextPageParam : noNextPage;
215
272
  return {
216
273
  ...standardOptions,
217
274
  queryKey,
218
- queryFn: (ctx) => infiniteCrawlingFn(params, crawlOptions, ctx),
219
- getNextPageParam: getEnvelopeNextPageParam,
220
- initialPageParam,
221
- select: envelopeSelect,
275
+ ...boundQueryFn !== void 0 && { queryFn: boundQueryFn },
276
+ ...infiniteSelect !== void 0 && { select: infiniteSelect },
277
+ getNextPageParam: infiniteGetNextPageParam,
222
278
  ...getPreviousPageParam !== void 0 && { getPreviousPageParam },
279
+ ...initialPageParam !== void 0 && { initialPageParam },
280
+ inject: (injected) => make(injected),
223
281
  [FACTORY_CONFIG]: cfg
224
282
  };
225
- }
226
- const boundQueryFn = rawQueryFn ? (ctx) => rawQueryFn(params, ctx) : void 0;
227
- const infiniteGetNextPageParam = getNextPageParam && shouldFetchNextPage ? wrapGetNextPageParam(
228
- getNextPageParam,
229
- shouldFetchNextPage,
230
- crawlOptions,
231
- select
232
- ) : getNextPageParam != null ? getNextPageParam : noNextPage;
233
- return {
234
- ...standardOptions,
235
- queryKey,
236
- ...boundQueryFn !== void 0 && { queryFn: boundQueryFn },
237
- ...infiniteSelect !== void 0 && { select: infiniteSelect },
238
- getNextPageParam: infiniteGetNextPageParam,
239
- ...getPreviousPageParam !== void 0 && { getPreviousPageParam },
240
- ...initialPageParam !== void 0 && { initialPageParam },
241
- [FACTORY_CONFIG]: cfg
242
283
  };
284
+ return make(void 0);
243
285
  };
244
286
  return factory;
245
287
  }
@@ -265,7 +307,7 @@ function queryFactory(configOrParent, childConfig) {
265
307
  } else if (childConfig.select && parentCfg.select) {
266
308
  const p = parentCfg.select;
267
309
  const c = childConfig.select;
268
- resolvedSelect = (data) => c(p(data));
310
+ resolvedSelect = (data, deps) => c(p(data, deps), deps);
269
311
  } else {
270
312
  resolvedSelect = (_a = childConfig.select) != null ? _a : parentCfg.select;
271
313
  }
package/dist/index.mjs CHANGED
@@ -5,6 +5,9 @@ var noNextPage = () => void 0;
5
5
  function isAsyncIterable(value) {
6
6
  return value != null && typeof value[Symbol.asyncIterator] === "function";
7
7
  }
8
+ function invokeQueryFn(queryFn, params, ctx, deps) {
9
+ return deps === void 0 ? queryFn(params, ctx) : queryFn(params, ctx, deps);
10
+ }
8
11
  function resolveKey(namespace, params, crawlOptions) {
9
12
  const withParams = params === void 0 ? namespace : [...namespace, params];
10
13
  if (!crawlOptions) return withParams;
@@ -29,22 +32,22 @@ function buildChildKey(parentKey, ownSegments, params, crawlOptions, infinite) {
29
32
  const withInfinite = infinite ? [...withOwn, "infinite"] : withOwn;
30
33
  return defined ? [...withInfinite, defined] : withInfinite;
31
34
  }
32
- function wrapGetNextPageParam(getNextPageParam, shouldFetchNextPage, crawlOptions, select) {
35
+ function wrapGetNextPageParam(getNextPageParam, shouldFetchNextPage, crawlOptions, select, deps) {
33
36
  return (lastPage, allPages, lastPageParam, allPageParams) => {
34
- const combined = select ? select(lastPage) : lastPage;
37
+ const combined = select ? select(lastPage, deps) : lastPage;
35
38
  if (!shouldFetchNextPage(combined, crawlOptions)) return void 0;
36
39
  return getNextPageParam(lastPage, allPages, lastPageParam, allPageParams);
37
40
  };
38
41
  }
39
42
  function buildCrawlingQueryFn(queryFn, getNextPageParam, initialPageParam, shouldFetchNextPage, reduce) {
40
- return async (params, crawlOptions, context) => {
43
+ return async (params, crawlOptions, deps, context) => {
41
44
  var _a, _b, _c;
42
45
  if ((_a = context.signal) == null ? void 0 : _a.aborted) {
43
46
  if (reduce) throw new DOMException("Aborted", "AbortError");
44
47
  return [];
45
48
  }
46
49
  const ctx = { ...context, pageParam: initialPageParam };
47
- const initialResult = queryFn(params, ctx);
50
+ const initialResult = invokeQueryFn(queryFn, params, ctx, deps);
48
51
  if (isAsyncIterable(initialResult)) {
49
52
  const pages2 = [];
50
53
  let acc2 = void 0;
@@ -76,7 +79,12 @@ function buildCrawlingQueryFn(queryFn, getNextPageParam, initialPageParam, shoul
76
79
  if (nextParam == null) break;
77
80
  currentParam = nextParam;
78
81
  ctx.pageParam = currentParam;
79
- page = await queryFn(params, ctx);
82
+ page = await invokeQueryFn(
83
+ queryFn,
84
+ params,
85
+ ctx,
86
+ deps
87
+ );
80
88
  }
81
89
  if (reduce) {
82
90
  if (acc === void 0) throw new DOMException("Aborted", "AbortError");
@@ -85,13 +93,28 @@ function buildCrawlingQueryFn(queryFn, getNextPageParam, initialPageParam, shoul
85
93
  return pages;
86
94
  };
87
95
  }
96
+ function buildAutoConsumeQueryFn(queryFn, reduce) {
97
+ return async (params, deps, context) => {
98
+ var _a;
99
+ const result = await invokeQueryFn(queryFn, params, context, deps);
100
+ if (!isAsyncIterable(result)) return result;
101
+ const pages = [];
102
+ let acc = void 0;
103
+ for await (const page of result) {
104
+ if ((_a = context.signal) == null ? void 0 : _a.aborted) break;
105
+ pages.push(page);
106
+ if (reduce) acc = reduce(acc, page);
107
+ }
108
+ return reduce ? acc !== void 0 ? acc : pages : pages;
109
+ };
110
+ }
88
111
  function buildInfiniteCrawlingQueryFn(queryFn, getNextPageParam, shouldFetchNextPage, reduce) {
89
- return async (params, crawlOptions, context) => {
112
+ return async (params, crawlOptions, deps, context) => {
90
113
  var _a, _b, _c;
91
114
  if ((_a = context.signal) == null ? void 0 : _a.aborted)
92
115
  throw new DOMException("Aborted", "AbortError");
93
116
  const ctx = { ...context, pageParam: context.pageParam };
94
- const initialResult = queryFn(params, ctx);
117
+ const initialResult = invokeQueryFn(queryFn, params, ctx, deps);
95
118
  if (isAsyncIterable(initialResult)) {
96
119
  const pages2 = [];
97
120
  const startParam = context.pageParam;
@@ -128,7 +151,12 @@ function buildInfiniteCrawlingQueryFn(queryFn, getNextPageParam, shouldFetchNext
128
151
  if (!shouldFetchNextPage(acc, crawlOptions)) break;
129
152
  currentParam = nextParam;
130
153
  ctx.pageParam = currentParam;
131
- page = await queryFn(params, ctx);
154
+ page = await invokeQueryFn(
155
+ queryFn,
156
+ params,
157
+ ctx,
158
+ deps
159
+ );
132
160
  }
133
161
  if (acc === void 0) throw new DOMException("Aborted", "AbortError");
134
162
  return { data: acc, nextPageParam: nextBatchParam };
@@ -158,62 +186,76 @@ function buildFactory(cfg) {
158
186
  shouldFetchNextPage,
159
187
  reduce
160
188
  ) : void 0;
189
+ const autoConsumeFn = !hasCrawling && rawQueryFn !== void 0 ? buildAutoConsumeQueryFn(rawQueryFn, reduce) : void 0;
161
190
  const infiniteCrawlingFn = hasInfiniteCrawling ? buildInfiniteCrawlingQueryFn(
162
191
  rawQueryFn,
163
192
  getNextPageParam,
164
193
  shouldFetchNextPage,
165
194
  reduce
166
195
  ) : void 0;
167
- const envelopeSelect = infiniteCrawlingFn ? (data) => ({
168
- ...data,
169
- pages: data.pages.map((e) => select ? select(e.data) : e.data)
170
- }) : void 0;
171
- const infiniteSelect = !infiniteCrawlingFn && select ? (data) => ({
172
- ...data,
173
- pages: data.pages.map(select)
174
- }) : void 0;
196
+ const bindSelect = (deps) => select === void 0 ? void 0 : deps === void 0 ? select : (data) => select(data, deps);
175
197
  const factory = function(params, crawlOptions = {}) {
176
198
  const queryKey = parentKey !== void 0 ? buildChildKey(parentKey, ownSegments, params, crawlOptions) : resolveKey(namespace, params, crawlOptions);
177
- const resolvedQueryFn = crawlingFn ? (ctx) => crawlingFn(params, crawlOptions, ctx) : rawQueryFn ? (ctx) => rawQueryFn(params, ctx) : void 0;
178
- return {
179
- ...standardOptions,
180
- queryKey,
181
- ...resolvedQueryFn !== void 0 && { queryFn: resolvedQueryFn },
182
- ...select !== void 0 && { select },
183
- [FACTORY_CONFIG]: cfg
199
+ const make = (deps) => {
200
+ const resolvedQueryFn = crawlingFn ? (ctx) => crawlingFn(params, crawlOptions, deps, ctx) : autoConsumeFn ? (ctx) => autoConsumeFn(params, deps, ctx) : void 0;
201
+ const boundSelect = bindSelect(deps);
202
+ return {
203
+ ...standardOptions,
204
+ queryKey,
205
+ ...resolvedQueryFn !== void 0 && { queryFn: resolvedQueryFn },
206
+ ...boundSelect !== void 0 && { select: boundSelect },
207
+ inject: (injected) => make(injected),
208
+ [FACTORY_CONFIG]: cfg
209
+ };
184
210
  };
211
+ return make(void 0);
185
212
  };
186
213
  factory.infinite = function(params, crawlOptions = {}) {
187
214
  const queryKey = parentKey !== void 0 ? buildChildKey(parentKey, ownSegments, params, crawlOptions, true) : resolveKey(infiniteNamespace, params, crawlOptions);
188
- if (infiniteCrawlingFn) {
215
+ const make = (deps) => {
216
+ if (infiniteCrawlingFn) {
217
+ return {
218
+ ...standardOptions,
219
+ queryKey,
220
+ queryFn: (ctx) => infiniteCrawlingFn(params, crawlOptions, deps, ctx),
221
+ getNextPageParam: getEnvelopeNextPageParam,
222
+ initialPageParam,
223
+ select: (data) => ({
224
+ ...data,
225
+ pages: data.pages.map(
226
+ (e) => select ? select(e.data, deps) : e.data
227
+ )
228
+ }),
229
+ ...getPreviousPageParam !== void 0 && { getPreviousPageParam },
230
+ inject: (injected) => make(injected),
231
+ [FACTORY_CONFIG]: cfg
232
+ };
233
+ }
234
+ const boundQueryFn = rawQueryFn ? (ctx) => invokeQueryFn(rawQueryFn, params, ctx, deps) : void 0;
235
+ const infiniteSelect = select ? (data) => ({
236
+ ...data,
237
+ pages: data.pages.map((p) => select(p, deps))
238
+ }) : void 0;
239
+ const infiniteGetNextPageParam = getNextPageParam && shouldFetchNextPage ? wrapGetNextPageParam(
240
+ getNextPageParam,
241
+ shouldFetchNextPage,
242
+ crawlOptions,
243
+ select,
244
+ deps
245
+ ) : getNextPageParam != null ? getNextPageParam : noNextPage;
189
246
  return {
190
247
  ...standardOptions,
191
248
  queryKey,
192
- queryFn: (ctx) => infiniteCrawlingFn(params, crawlOptions, ctx),
193
- getNextPageParam: getEnvelopeNextPageParam,
194
- initialPageParam,
195
- select: envelopeSelect,
249
+ ...boundQueryFn !== void 0 && { queryFn: boundQueryFn },
250
+ ...infiniteSelect !== void 0 && { select: infiniteSelect },
251
+ getNextPageParam: infiniteGetNextPageParam,
196
252
  ...getPreviousPageParam !== void 0 && { getPreviousPageParam },
253
+ ...initialPageParam !== void 0 && { initialPageParam },
254
+ inject: (injected) => make(injected),
197
255
  [FACTORY_CONFIG]: cfg
198
256
  };
199
- }
200
- const boundQueryFn = rawQueryFn ? (ctx) => rawQueryFn(params, ctx) : void 0;
201
- const infiniteGetNextPageParam = getNextPageParam && shouldFetchNextPage ? wrapGetNextPageParam(
202
- getNextPageParam,
203
- shouldFetchNextPage,
204
- crawlOptions,
205
- select
206
- ) : getNextPageParam != null ? getNextPageParam : noNextPage;
207
- return {
208
- ...standardOptions,
209
- queryKey,
210
- ...boundQueryFn !== void 0 && { queryFn: boundQueryFn },
211
- ...infiniteSelect !== void 0 && { select: infiniteSelect },
212
- getNextPageParam: infiniteGetNextPageParam,
213
- ...getPreviousPageParam !== void 0 && { getPreviousPageParam },
214
- ...initialPageParam !== void 0 && { initialPageParam },
215
- [FACTORY_CONFIG]: cfg
216
257
  };
258
+ return make(void 0);
217
259
  };
218
260
  return factory;
219
261
  }
@@ -239,7 +281,7 @@ function queryFactory(configOrParent, childConfig) {
239
281
  } else if (childConfig.select && parentCfg.select) {
240
282
  const p = parentCfg.select;
241
283
  const c = childConfig.select;
242
- resolvedSelect = (data) => c(p(data));
284
+ resolvedSelect = (data, deps) => c(p(data, deps), deps);
243
285
  } else {
244
286
  resolvedSelect = (_a = childConfig.select) != null ? _a : parentCfg.select;
245
287
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robohall/react-query-factory",
3
- "version": "2.2.0",
3
+ "version": "3.0.0",
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",